도커는 소프트웨어 개발과 배포를 도와주는 컨테이너 기술.
우리는 도커를 사용하여 애플리케이션을 빌드, 배포, 실행하는 과정을 쉽게 관리
(도커는 안쓰이는 회사가 없다)
컨테이너란 단어만 이해한다면 도커가 좀 더 친숙하게 느껴질 것이다
예시) 스타크래프트 CD로 보면
CD가 Docker Image이며, 실행된 StrarCraft 프로그램이 Container라고 생각 할 수 있다
CD가 있다면, 친구네 가서도 똑같이 프로그램을 실행 시킬 수 있다
이것이 바로 컨테이너 기술의 핵심
한번 도커 이미지를 만들면 어디를 가서도 똑같이 도커 이미지를 실행 시킬 수 있는 것
이것이 컨테이너이다
컨테이너란?
컨테이너는 에플리케이션과 그 실행 환경을 함께 패키징하여 어디서든 동일하게 실행될 수 있도록 해주는 기술
1.이미지 : 실행 가능한 에플리케이션과 그 환경을 정의한 파일.
코드,런타임, 라이브러리 등을 포함하여, 변경 불가능(박제)
이미지는 Dockerfile로 만듬
2.컨테이너: 이미지를 실행한 상태. 이미지의 인스턴스로서, 에플리케이션이 실제로 동작하는 환경을 제공
1.일관성: "내 컴퓨터에서 잘 되는데...?"와 같은 문제가 줄어듬(돌아가는 환경 까지도 파일에 묶어버림)
2.이식성 : 컨테이너는 어디서든 동일한 환경을 제공하므로, 다양한 플랫폼에서 쉽게 에플리케이션을 실행할 수 있음
3.확장성 : 컨테이너를 이용한 마이크로서비스 아키텍처를 통해 애플리케이션을 쉽게 확장할 수 있음
(단순히 도커 이미지를 풀로 땡겨와서 실행시키면 서버를 증가 시킬 수 있음)
도커는 현대적 프로그램밍에 핵심을 보여준다
여러 상황에서 환경이 달라 동작하지 않을 수 있지만, 도커를 사용한다면 해결 가능!
윈도우라면 Hyper V
주의 ->
도커파일이란?
Dockerfile은 Docker 이미지를 빌드하기 위한 설정 파일로, Docker 이미지를 생성하는 데 필요한 명령어와 지침을 포함하고 있다. Dockerfile은 일반 텍스트 파일 형식으로 작성되며, Docker가 어떤 식으로 에플리케이션을 설정하고 실행할지에 대한 명세를 담고 있다.
Dockerfile을 외우기 보다는 Chatgpt를 이용하여 작성하는 것이 효율적일 수 있다.(추천)
예) 나의 스프링 프로젝트를 도커파일로 만들어줘
도커 이미지를 만들때 마다 build를 직접 해서 파일을 만들어줘야한다
하지만 이 과정을 도커파일에 추가 시킬 수 있다
도커파일에 빌드 과정을 포함시켜줘
maven과 gradle를 잘 확인하자
docker build -t test-docker-hello .
default는 Dockerfile을 바라본다
이 명령어 끝에 있는 .
은 무엇일까?
현재 디렉토리에 있는 Dockerfile을 빌드하겠단 뜻.
docker build -t test-docker-hello -f Dockerfile-dev .
Tip
로컬과 Docker를 왔다갔다하면서 개발하다보면 위와 같은 에러를 만날 수도 있다
어디서든 port가 이미 사용 중인 상황이라 실행이 불가하단 뜻
아래의 명령어를 실행시켜주자
kill $(lsof -t -i:{port})
ex) kill $(lsof -t -i:8080)
version: '3.8'
services:
myapp:
build:
context: .
dockerfile: Dockerfile
depends_on:
db:
condition: service_healthy
ports:
- "8080:8080"
db:
image: mysql:8.0
container_name: mysql
environment:
MYSQL_ROOT_PASSWORD: 1234
MYSQL_DATABASE: test
ports:
- "3306:3306"
healthcheck:
test: ["CMD-SHELL", "mysqladmin ping -h localhost -u root -p1234 && sleep 5"]
interval: 5s
retries: 10
참고
도커 컴포즈는 하나의 네트워크이다
따로 지정해 줄 수 있지만 안해준다면 디폴트 네트워크로 설정된다
실제로 도커 컴포즈 내부에 네트워크가 있고 그 안에 db가 있다
컨테이너 내부의 네트워크에서 서로의 네트워크가 다르다면 통신이 안된다
docker-compose를 실행해보자
docker-compose up
이러면 로그를 다 볼 수 있다
만약 로그를 보기 싫다면 -d
를 붙여주자
docker-compose up -d
잠깐!
docker compose를 이용할려면 localhost의 개념을 알아야한다
도커 컴포즈 내부에서는 localhost로 하면 안된다
왜냐하면 intellij로 실행하신 환경과, docker로 실행하신 환경은 분명 다르기 때문!!.
분리된 네트워크 환경이란 것을 꼭 기억해야한다!!!
개발할 때 프로퍼티를 분리해주어야한다!(로컬용, 예: 도커용)
dockerfile이 어디를 바라보는지 지정해 주어야 한다
예시)
FROM eclipse-temurin:21-jdk-alpine
WORKDIR /app
COPY build/libs/*.jar /app/myapp.jar
ENV SPRING_PROFILES_ACTIVE=dev
ENTRYPOINT ["java", "-jar", "/app/myapp.jar"]
ENV SPRING_PROFILES_ACTIVE=dev
와 같은 방식으로 Dockerfile을 세팅하시면 환경변수를 설정해줄 수 있다.
그 외에 여러가지 방법이 있고, 회사마다 다르지만
Dockerfile image
빌드 시 환경변수를 지정해줄 수도 있고,
docker-compose
실행 시 환경변수를 지정해줄 수도 있다,
아니면 아예 Dockerfile-dev
같은 식으로 Dockerfile
을 분리할 수도 있다.
(도커 컴포즈의 이용 이유)
만약 서버가 여러개라면 여러개의 서버를 먼저 다 연결시켜주는 환경설정을 해주어야 한다
도커 컴포즈로 환경설정을 묶어놓고 up으로 서버를 동시에 뛰어주면 된다
참고
도커 컴포즈 없이 컨테이너들 간에 통신을 하는 방법도 있긴 하다
도커 네트워크들을 서로 연결 시켜주는 방법이 있긴 하다
MSA -> 서버를 기능에 따라 쪼개는 것 (도메인을 분리하는 것)
바쁜 서버와 그렇지 않은 서버를 분리해서 관리가 가능
비용을 효율적으로 관리할 수 있다
다시 도커 컴포즈는 하나의 컨테이너에 여러개의 서버를 뛰우는 것
MSA에서 왜 도커컴포즈로 배포하면 안될까?
유연성이 떨어진다 -> 똑같은 컨테이너를 복제하면 안에 있는 디비는 서로의 정보를 모른다
만약 stateless하게 구조를 만들려면 db가 컨테이너 밖에 있어야한다
하나의 컨테이너 안에 모든 서버가 들어가 있다면 모놀리식 이랑 다를게 없다
모놀리식이란? 각각의 기능을 하는 서비스들을 하나의 서버에서 개발하는 방식
무조건 같이 컨테이너를 복제해야 한다
MSA식으로 하면 바쁜 기능을 하는 서버만 선택해서 늘릴 수가 있다
그래서 도커 컴포즈는 실제 배포용이라기 보다는 개발용이라고 볼 수 있다
one-container-per-Pod
배포상황에서는 하나의 컨테이너 안에 하나의 서버만 담아서 배포하는 것이 가장 기본적인 개념
그래야 서버를 유연하게 관리할 수가 있다
간단하게 말하면?
로컬에서 Github로 푸쉬를 하면 자동으로 서버가 배포되는 과정을 말한다
추상화
CI/CD는 마법이 아니다 어딘가에 실제로 존재하는 서버라는 것을 인지해야 한다
예시) GithubActions = 실제 서버
로컬에서 푸쉬하면 깃헙 액션에서 .jar파일을 만들고 도커 이미지화 해서 이미지 저장소(S3,DockerHub,AWS ECR)에 올려준다
그 이후에 깃헙 액션이 서버에 신호를 준다 (깃헙이 실제 서버이기 때문에 명령이 가능)
서버에게 이미지 저장소에 도커이미지가 올라갔으니 갖고와서 배포하라는 신호를 주고 서버가 이미지 저장소에
도커이미지를 가져와서 배포(컨테이너화)를 해준다
이것이 도커액션을 이용해서 도커 파일을 컨테이너화 하는 배포 설계 예시이다
CI/CD는 이해를 기반으로 플로우를 설계해야한다
CI/CD과정에서는 gradle은 필요없을 수가 없다
깃헙액션(서버)니까
도커이미지에 gradle을 정의하면 쓸데 없는 파일이 들어가서 이미지가 무거워질 수는 있지만
편리하게 build할 수 있기 때문에 편해진다.