Docker Compose
주요 메모 사항
.dockerignore란?
.gitingnore와 같은 것
Image build 할 때 추가하지 말아야할 파일들이나 폴더 지정
앞서 살펴봤던 voting-application의 경우 dockerignore의 내용은 다음과 같음 (근데 gitignore로 되어 있다)
이외에 고려해볼만한 내용들은?
Dockerfile에서 COPY 명령
실수로 불필요한 파일 혹은 민감한 정보가 들어있는 파일들이 이미지로 들어가는 걸 막으려면 COPY 명령을 처음이나 파일이나 폴더별로 일일이 적어주는 것이 좋을 수 있음.
ㄴ>그러면서 .dockerignore의 내용 보강
맥에서 발생하는 port 5000 에러 (필자는 우분투라서 문제가 없었음)
맥에서 Container에 port 5000번을 호스트 포트로 사용하려고 하면 아래 에러 발생
ㄴ Error response from daemon: Ports are not available: exposing port TCP 0.0.0.0:5000 -> 0.0.0.0:0: listen tcp 0.0.0.0:5000: bind: address already in use
ㄴ 이는 MacOS Monterey에만 존재하는 문제로 해결책이 있긴 하지만 다른 포트번호를 쓰는 것이 더 좋음
Docker-Compose로 다수 Container로 실행해보기
전날 매뉴얼하게 실행해본 voting application를 docker-compose를 통해 실행
Docker-Compose란 무엇인가?
다수의 Container로 소프트웨어가 구성되는 경우 사용할 수 있는 툴 + 환경설정파일
ㄴ docker-compose.yml로 설정
ㄴ 여기서 다양한 테스트등도 수행가능
ㄴ 다양한 버전을 만드는 것도 일반적 (dev, test, prod 등등)
- 개별 Container를 따로 관리하는 것보다 훨씬 더 생산성이 높음
- 환경설정 파일의 이름은 docker-compose.yml이나 docker-compose.yaml
하지만 그만큼 배워야할 것도 많고 복잡해짐
사용법 자체는 간단: 소프트웨어를 구성하는 모든 컨테이너에게 적용됨
Docker-Compose
Docker Desktop의 일부로 설치가 됨
Docker Engine을 실행하고 먼저 터미널에서 버전 확인
ㄴ 만일 docker-compose가 없다고 나오면 먼저 docker-compose부터 실행
Docker Compose v.1.27+ 부터 v2와 v3가 합쳐짐
$ docker-compose --version
docker-compose.yml 작성
다양한 버전이 존재하는데 우리는 v2와 v3가 합쳐진 버전 사용 예정
services: 다음으로 프로그램을 구성하는 서비스들을 지정
ㄴ 각 서비스는 별개의 Docker Image 지정과 Docker Container 실행으로 구성됨
ㄴ 즉 각 서비스는 자신의 Dockerfile을 갖고 있어야함 아니면 docker hub등에서 이미지를 다운로드
ㄴ 서비스별로 포트번호, 환경변수, 디스크 볼륨등을 지정해야함
ㄴ 서비스 이름은 아무 이름이나 가능
volumes: 앞서 사용된 docker volume들을 지정
networks: 앞서 사용된 network들을 지정
ㄴ network은 지정하지 않으면 같은 docker-compose 그룹 내에서는 모두 연결이 됨
ㄴ “default”라는 이름으로 기본 네트웍이 만들어짐
처음 진행할 Demo 에서는 volumes와 networks는 사용해보지 않을 것! -> services만 사용
docker-compose vs. docker compose
v1: docker-compose
v2: docker compose
Docker 1.27부터 docker에 명령으로 compose가 추가됨
docker-compose 보다는 “docker compose”를 쓰는 것이 더 좋음
별도로 docker-compose를 설치할 필요가 없음. 하지만 아직까지 대부분의 문서가 docker-compose 중심으로 만들어져 있음
docker-compose.yaml or docker-compose.yml
docker compose 명령의 위 둘 중의 하나를 찾음 -> 만일 둘다 존재한다면 에러 발생함!
만일 다른 이름의 파일을 사용하고 싶다면 -f 옵션 사용
docker-compose -f docker-compose.mac.yml up
docker-compose.yml 작성 예
- frontend에서 build 를 key로 ./frontend 위치에 dockerfile을 찾아서 이미지를 빌딩하고 컨테이너를 실행
- backend에서도 위와 마찬가지로 실행, 환경변수로 DB_URL을 지정했음, 여기에서 주황색으로 표시한 database는 같은 의미라는 뜻
- database에서 image에 계정정보가 없는 것으로 공식 이미지라는 것을 알 수 있음, volumes에 vidly라는 이름으로 /data/db 위치에 마운트한 것 (컨테이너의 위치)
- volumes에 위에 database에서 선언해둔 volumes의 vidly를 포함시켰음
위에서 설명했지만 network를 따로 지정하지 않아도 구성되는데, services안에 있는 컨테이너는 frontend, backend, database 와 같은 host 이름을 가짐 -> 이 이름으로 default network에 구성되어 있음
->서로의 연결을 보장해줌
docker-compose로 이미지 생성과 관리
docker-compose build
ㄴ build 키로 지정된 것들 대상
docker-compose pull
ㄴ docker hub에서 이미지들을 읽어오려고 함
docker images
ㄴ (docker compose로 빌드한 경우) 각 개별 이미지 앞에 폴더 이름을 prefix로 붙임 (docker hub에서 읽어온 것 제외)
docker-compose images
ㄴ 컨테이너에 의해 실행되고 있는 이미지들만 보여줌
docker-compose push
ㄴ docker hub으로 이미지들을 푸시하려고 함
docker-compose로 소프트웨어 시작과 중단
docker-compose up # build => create => start
ㄴ docker-compose create
ㄴ docker-compose start
docker-compose down (container stop과 rm를 포함한 명령어임)
docker-compose stop
docker-compose rm
docker-compose ls # docker-compose를 그룹별로 보여줌
docker-compose ps
docker-compose 네트워킹
docker끼리 네트워크 연결이 필요한 경우
ㄴ services에 준 이름으로 호스트 이름이 생성됨
ㄴ 내부에 DNS 서버가 하나 생성되어 이름을 내부 IP로 변환해줌
별도로 네트워크를 구성하고 싶다면
ㄴ networks에 네트워크를 나열하고 네트워크를 적절하게 서비스에 지정해주어야함
docker network ls
voting application을 docker-compose로 실행해보기
앞서 5개의 Container를 일일히 실행했을 때의 문제점
Postgres를 실행하는 부분이 제대로 동작하지 않았음
$ docker run -d --name=db -e POSTGRES_PASSWORD=password --network mynetwork postgres
worker/Program.cs
var pgsql = OpenDbConnection("Server=db;Username=postgres;Password=postgres;");
var redisConn = OpenRedisConnection("redis");
이를 해결하려면 Container를 실행할 때 아래 2개의 환경변수를 넘겨주어야 함
ㄴ POSTGRES_USER: "postgres"
ㄴ POSTGRES_PASSWORD: "postgres"
ㄴ 이걸 docker-compose 환경 설정 파일을 통해 넘기면서 해결해볼 예정
docker-compose.yml로 포팅: 뼈대
이전에 작성했던 명령어들을 docker compose로, 제대로 동작하지 않았던 postgre도 변경할 예정
$ docker run -d --name=redis --network mynetwork redis
$ docker run -d --name=db -e POSTGRES_PASSWORD=password --network mynetwork postgres
$ docker run -d --name=vote -p 5001:80 --network mynetwork vote
$ docker run -d --name=result -p 5002:80 --network mynetwork result
$ docker run -d --name=worker --network mynetwork worker
-> 위 과정을 거치고 docker-compose up!
services 키
best practice 아래의 이미지를 보면 알겠지만 dockerfile의 위치를 ./ 위치로 지정했음
아래 이미지와 같은 구조를 구성해서 Demo 할 것!
Demo 시작
먼저 새로운 repo를 clone
기존에 만들었던 container와 image를 모두 삭제
확인
Clone한 파일 빌드
확인, 공식 이미지는 빌드가 안되어 있음
docker compose를 사용했기 때문에 repo 이름에 폴더 이름이 추가되어 있음
그래서 이번엔 pull
확인
위에서 설명했었지만 다시 한번 설명
docker compose up은 빌드 생성 시작을 한번에 진행하는 것
docker-compose up # build => create => start
그럼 웹에서 확인해보자
DB를 확인해보자
먼저 postgers 컨테이너에 postgres계정으로 쉘에 접근해보자
psql 명령어로 postgres 쉘에 접근, \c 로 접속한 정보를 알 수 있음
테이블과 해당 레코드를 확인
down 옵션으로 docker compose를 멈춰보자
여기에서 docker-compose 명령어를 사용하면 network도 삭제되는게 표시되는데, docker compose를 사용하면 안나오는 것 같다.
컨테이너가 종료되고 삭제되는데, 이미지는 남아있는 것을 알 수 있음
하지만 위와 같은 방식을 사용하면 문제점이 많음.
voting application의 docker-compose.yml 개선하기
networks
ㄴ back-tier : redis, worker, db, vote, result
ㄴ front-tier : vote, result
front와 back을 나눠서 network를 설정해보자. front-tier에서 db에 접근할 수 없도록
docker-compose.yml로 포팅: services들에 네트워크 지정
services:
기존에 작성했던 docker-compose.yml에서 networks를 선언해서 분리해보자
services:
redis:
…
networks:
- back-tier
db:
…
networks:
- back-tier
vote:
…
networks:
- back-tier
- front-tier
result:
…
networks:
- back-tier
- front-tier
worker:
…
networks:
- back-tier
보안에서 좀 더 우수해진 것 같음
docker-compose.yml로 포팅: volumes 정의
어느 컨테이너 서비스의 데이터가 계속해서 저장되어야 하는가?
ㄴ PostgreSQL
volumes:
db-data: (db의 내용이 persistent 해야 한다!)
docker-compose.yml로 포팅: services들에 볼륨 지정
여기까지 network와 volume를 조금 개선해 봤다.
근데 여기서 더 개선을 해보자면? 아래 계
voting application의 docker-compose.yml 최종 개선
docker-compose.yml로 포팅: vote 서비스 개선
redis: condition: service_healthy
ㄴ> redis가 컨테이너에서 healthy하게 실행 되었을 때, vote를 실행하겠다 라고 하는 것
docker-compose.yml의 command와 entrypoint
command: 이미지 Dockerfile의 CMD를 덮어쓰는데 사용
entrypoint: 이미지 Dockerfile의 ENTRYPOINT를 덮어쓰는데 사용
docker-compose.yml의 healthcheck - Dockerfile에서도 기술 가능 (docker- compose에서 덮어쓰기가 된다!)
healthcheck:
test: 상태가 성공적이면 0, 뭔가 잘못된다면 1 or fail을 리턴한다고 하
interval: 확인 하는 시간 간격
timeout: 확인하는데 걸리는 시간의 데드라인
retries: 최대 허용되는 실패 횟수 지정
start_period: 해당 상태 확인을 시작하기 전에 여유시간을 지정
다만 상태 확인을 실행할때 필요한 리소스(CPU, Memory)도 무시못한다고 한다!
docker-compose.yml의 depends_on - Service 간의 종속성 기술
ㄴ 해당 서비스가 실행되기 위해서 먼저 실행되어야 하는 서비스들을 여기 기술
depends_on -> vote가 실행되기 전에 redis 가 실행되어야 한다고 명시되어 있는 것임!
short form:
depends_on:
- db
- redis
long form:
depends_on:
db:
comdition: service_helthy
redis:
comdition: service_started
condition으로 가능한 값 링크
service_started: defalut 값임!, service가 시작한 후 depend_on이 시작!
ㄴ is an equivalent of the short syntax described above
service_healthy: service가 시작하고 관리되는 상태에 도달하면 depend_on이 시작됨
ㄴ specifies that a dependency is expected to be "healthy" (as indicated by healthcheck) before starting a dependent service.
service_completed_successfully: depend service가 종료코드 0으로 종료된 후에 service를 시작함
docker-compose.yml로 포팅: db 서비스 개선
docker-compose.yml의 environment
해당 서비스가 컨테이너 안에서 실행될 때 환경변수들을 지정 (Dockerfile의 ENV)
Map 문법:
environment:
RACK_ENV: development
SHOW: "true"
USER_INPUT:
Array 문법:
environment:
- RACK_ENV=development
- SHOW=true
- USER_INPUT
docker-compose.yml로 포팅: redis 서비스 개선 volumes 지
docker-compose.yml로 포팅: worker 서비스 개선, Build
위에 다른 서비스들과 비교해보면 build 가 뭔지 이해하기 더 쉬울 것
docker-compose.yml로 포팅: result 서비스 개선, entrypoint 덮어쓰기
최종 개선 docker-compose.yml
위에서 설명했던 개선점을 모두 적용한 yml 파일이다!
vote와 result의 포트번호를 각각 5001과 5002로 수정한 버전이 위의 버전
Monterey Mac에서 포트 5000번을 사용할 수 없기에 vote 앱의 포트번호를 수정해야함
공부하며 어려웠던 내용
dockerfile과 docker compose 를 많이 작성해봐야 할 것 같다. 익숙해지기 위한 연습이 필요할 듯
'프로그래머스 데브코스-데이터 엔지니어 > TIL(Today I Learned)' 카테고리의 다른 글
06/19 51일차 ELT 작성과 구글시트_슬랙 연동 (전반부) (0) | 2023.06.19 |
---|---|
06/15 50일차 개발환경 구축을 위한 Docker & K8s (5) (0) | 2023.06.16 |
06/14 48일차 개발환경 구축을 위한 Docker & K8s (3) (2) | 2023.06.14 |
06/13 47일차 개발환경 구축을 위한 Docker & K8s (2) (0) | 2023.06.13 |
06/12 46일차 개발환경 구축을 위한 Docker & K8s (1) (0) | 2023.06.12 |