[5/30] TIL - docker-compose[2], yml 파일, 실습

Sangwon Jwa·2024년 5월 30일

데브코스 TIL

목록 보기
40/54
post-thumbnail

📖 학습 주제


  1. docker-compose
  2. docker-compose.yml 파일
  3. 실습 - 멀티 컨테이너 소프트웨어 [2], [3]

✏️ 주요 메모 사항 소개


docker-compose

다시 한번 Docker-Compose란 다수의 Container로 소프트웨어가 구성되는 경우 사용할 수 있는 툴 + 환경설정 파일을 말한다.

  • docker-compose.yml 파일을 만들어서 설정하고 다양한 테스트 등도 수행이 가능하다. 다양한 버전을 만드는 것도 일반적이다 (dev, test, prod 등등)
  • 개별 Container를 따로 관리하는 것보다 훨씬 더 생산성이 높다
  • 환경설정 파일의 이름은 docker-compose.yml이나 docker-compose.yaml

docker-compose 명령어

  • docker-compose build : docker-compose.yml 파일의 build 속성에 따라 이미지를 빌드
  • docker-compose pull : 빌드를 할 때 로컬에 없는 이미지를 Docker Hub에서 읽어옴
  • docker-compose images : docker-compose로 실행이 된 컨테이너 들을 대상으로 어떤 이미지로 실행이 되었는지 출력
  • docker-compose push : docker-compose로 만들었던 이미지들을 Docker Hub으로 push (official 이미지는 push X)
  • docker-compose up : yml 파일의 컨테이너를 실행해주는 명령어
    • 3개의 과정으로 이루어진다 # build(pull) -> create -> start
    • docker-compose create
    • docker-compose start
  • docker-compose down : compose로 실행된 컨테이너들 종료후 삭제 ( stop + rm )
  • docker-compose stop : 컨테이너 중단 (stopped 상태로 만듬)
  • docker-compose rm : 중단된 컨테이너 삭제

docker-compose.yml 구성

docker-compose.yml 파일에는 크게 다음과 같은 3개의 섹션이 있다.

  1. services : 프로그램을 구성하는 서비스들을 지정

    • 각 서비스는 별개의 Docker Image 지정과 Docker Container 실행으로 구성됨
    • 즉 각 서비스는 자신의 Dockerfile을 갖고 있어야함 아니면 docker hub등에서 이미지를 다운로드
    • 서비스별로 포트번호, 환경변수, 디스크 볼륨등을 지정해야함
    • 서비스 이름은 아무 이름이나 가능
  2. volumes : 앞서 사용된 docker volume들을 지정

  3. networks : 앞서 사용된 network들을 지정

  • services 밑에 docker container가 여러개(frontend, backend, databse) 들어가 있다. 이 컨테이너가 실행되기 위해선 어디선가 docker image가 필요할 테니 build 속성이나 image 속성으로 정의를 해주어야 한다.

  • 각각의 컨테이너를 따로 구동할 때는 --network를 통해 수동적으로 네트워크 설정을 해주었지만, docker compose를 사용하면 같은 그룹내의 컨테이너들은 별다른 설정없이 이름을 가지고 연결을 할 수 있다.

docker-compose up 명령을 실행하게 되면, 먼저 docker-compose.yaml 이나 docker-compose.yml 파일을 찾게 된다. 둘다 존재한다면 에러가 발생하기 때문에 꼭 한개만 만들어 주도록 하자. 보통 테스트나 여러 버전을 만들 때 dev, test를 뒤로 붙일 때가 있는데 이 때 만약 특정 이름의 파일을 사용하고 싶다면 -f 옵션을 사용하면 된다.

  • EX) docker-compose -f docker-compose.mac.yml up

네트워킹

docker-compose를 실행하면 services에 준 이름으로 호스트 이름이 생성된다. 그 후 내부에 DNS 서버가 하나 생성되어 이름을 내부 IP로 변환해준다. docker끼리 네트워크 연결이 필요한 경우 이 내부 IP를 이용해서 사용하면 된다.

만약 별도로 네트워크를 구성하고 싶다면 yml 파일의 networks에 네트워크를 나열하고 네트워크를 적절하게 서비스에 지정해 주어야 한다. 네트워크 구성은 docker network ls 명령어를 사용하면 어떤 네트워크가 존재하는 지 확인할 수 있다.


실습 - 멀티 컨테이너 소프트웨어[2]

저번 시간에 수동으로 실행했던 voting application을 docker-compose를 사용해 한번에 실행해보자.

앞서 5개의 Container를 일일히 실행했을 때의 문제점은 Postgres를 실행하는 부분이 제대로 동작하지 않는다는 것이다. docker run -d --name=db -e POSTGRES_PASSWORD=password --network mynetwork postgres 이 명령을 실행할 때 문제가 생긴 것인데, worker/Program.cs의 코드를 보면 다음과 같은 부분이 있다.

이 worker 컨테이너가 redis에 기록이된 투표결과를 읽어와서 Postgres에 써주어야 하는데 위의 명령에서 Username을 알려주지 않았고, Password는 틀리게 작성했기 때문에 Postgres와 연결이 되지 않아서 발생한 문제이다. 따라서 vote 기능은 제대로 작동했지만, 이 vote의 결과가 Postgres에 적재되지 않아서 result의 값이 제대로 출력이 되지 않는 문제가 있었던 것이다.

이를 해결하려면 Container를 실행할 때 아래 2개의 환경변수를 넘겨주어야 한다

  1. POSTGRES_USER: "postgres"
  2. POSTGRES_PASSWORD: "postgres"

우리는 이것을 docker-compose 환경 설정 파일을 통해 넘기면서 해결해볼 예정이다.


docker-compose.yml 작성

yml 파일의 기본 구조는 다음과 같다. 5개의 컨테이너 들을 services에 설정해주고, networks와 volumes를 정의해주면 된다.

먼저 serices 부분에서 local에서 사용가능한 이미지는 사용을 하고, official image가 존재하는 redis나 postgres와 같은 이미지는 docker hub에서 다운로드 받도록 작성하자. postgres의 environment 설정을 이용해서 ID와 PASSWORD를 환경변수로 설정하자.

services:
  vote:
    build: ./vote
    # use python rather than gunicorn for local dev
    command: python app.py
    ports:
      - "5001:80"

  result:
    build: ./result
    # use nodemon rather than node for local dev
    entrypoint: nodemon server.js
    ports:
      - "5002:80"

  worker:
    build: ./worker

  redis:
    image: redis:alpine

  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_USER: "postgres"
      POSTGRES_PASSWORD: "postgres"

이미지 생성(build)

yml 파일을 작성했다면 docker-compose build 명령어를 사용해서 이미지를 만들어 보자. 시작하기 전에 앞서 만든 컨테이너들과 이미지들을 삭제해주자.

생성된 이미지를 확인하면 redis와 postgres가 없다. 그 두개의 컨테이너는 official image를 사용하기 때문에 docker-compose pull 명령어를 사용해서 Docker Hub에서 다운로드 받아야 한다.

pull까지 완료한 후 docker images를 실행하면 5개의 이미지가 모두 잘 생성된 것을 확인할 수 있다.


컨테이너 생성(up)

이제 만든 이미지들을 docker-compose up명령어를 이용해서 한번에 컨테이너로 구동해보자.

실행이 완료 되었다면 브라우저에 가서 잘 작동하는지 확인해보자. 이제 내가 선택한 결과에 따라서 result 페이지가 제대로 바뀌는 것을 볼 수 있다.

컨테이너를 중지하고 없애려면 docker-compose down 명령어를 사용해주자. 멈추기만 원한다면 stop을 사용하면 된다.


실습 - 멀티 컨테이너 소프트웨어[3]

실습2 에서는 services만을 포함해서 아주 간단한 yml 파일을 만들었다. 이번엔 networks와 volumes를 추가해서 docker-compose.yml 파일을 개선해보자.

networks

컨테이너를 front와 back으로 나누어서 사용자에게 노출이 되는 부분과 아닌 부분을 분리해서 네트워크로 설정해주자.

yml 파일에서 이를 적용하려면 각 service 마다 networks 키의 값을 지정해주고, 바깥의 networks에 network들을 기술해주면 된다.

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
      
networks:
  back-tier:
  front-tier: 

Volumes

투표를 할 때마다 그 결과를 저장하는 PostgreSQL은 데이터가 계속해서 저장되어야 한다. 따라서 docker의 volume을 이용해서 db의 내용을 persistent하게 유지시켜 주자.

services에서 PostgreSQL에 해당하는 db 컨테이너에 volumes 키를 설정하고 아래에서 volumes에 생성할 volume을 기술해주면 된다.

services:
 redis:
 db:
   volumes:
     - db-data:/var/lib/postgresql/data
 vote:
 result:
 worker:

volumes:
  db-data: 

추가 설정

우리가 작성한 yml 파일은 기본적인 것들만 기술한 아주 간단한 설정 파일이다. 원본 파일과 비교하여 '어떻게 더 개선할 수 있는 가'를 살펴보자.

위의 예제에서 추가된 설정 값들에 대해 알아보자.

  • command: 이미지 Dockerfile의 CMD를 덮어쓰는데 사용
  • entrypoint: 이미지 Dockerfile의 ENTRYPOINT를 덮어쓰는데 사용
  • healthcheck : 테스트로 지정된 명령어를 지정된 주기마다 실행
  • depends_on : 해당 서비스가 실행되기 위해서 먼저 실행되어야 하는 서비스들을 기술
    • condition으로 가능한 값
      • service_started : 의존하는 서비스가 시작되기만 하면 됨
      • service_healthy : 의존하는 서비스가 "healthy" 상태가 될 때까지 기다림
      • service_completed_successfully : 의존하는 서비스가 성공적으로 완료될 때까지 기다림
  • environment : DB의 ID나 PW와 같은 환경변수를 설정할 때 사용 (Dockerfile의 ENV)
  • build : context : 이 방식을 사용하면 더 많은 빌드 관련 정보를 넘겨줄 수 있다.

0개의 댓글