[Docker + CI/CD] Docker Compose

콩퓨터·2025년 1월 22일

CI/CD

목록 보기
7/10

Docker Compose

🤔 Docker Compose는 무엇일까?

🚀Docker Compose를 통해 여러 개의 컨테이너를 관리할 수 있다!

  • 단일 서버에서 여러 컨테이너를 하나의 서비스로 정의해 컨테이너 묶음으로 관리할 수 있는 작업 환경을 제공하는 도구.

☑️ Docker Compose를 사용하는 이유

사용하지 않으면?

테스트하려면 각 컨테이너를 하나씩 생성해야 한다.

  • ex. 웹 애플리케이션 테스트 시, 웹 서버 컨테이너와 데이터베이스 컨테이너를 각각 생성해야 한다.

1️⃣ 편하게 설정하기

  • Docker Compose는 여러 컨테이너를 한 파일에 정의해 설정할 수 있다.
  • 컨테이너가 사용할 이미지, 포트, 환경 변수 등을 설정 파일에 작성한다.
    ➡️ 여러 컨테이너를 한 번에 쉽게 설정 가능.

2️⃣ 자동으로 배포하기

  • 설정 파일이 있으면 Docker Compose가 알아서 컨테이너들을 생성하고 실행한다.

3️⃣ 의존성 관리

  • 컨테이너 간 의존성을 관리할 수 있다.
    - A 컨테이너가 B 컨테이너를 필요로 하면 B를 먼저 실행한 뒤 A를 실행.

4️⃣ 모니터링과 로깅

  • 컨테이너 상태를 모니터링하고, 로그를 수집할 수 있다.
    ➡️ 문제가 발생하면 빠르게 확인하고 해결 가능.

5️⃣ 확장성

  • 여러 컨테이너를 하나의 그룹으로 관리하고 확장하기 쉽다.
    - ex. 웹 앱 관련 컨테이너를 한꺼번에 관리 및 확장 가능.

6️⃣ 유연성

  • 개발, 테스트, 운영 환경에서 같은 설정 파일을 사용해 일관성을 유지할 수 있습니다.

7️⃣ 보안 강화

  • 컨테이너 네트워크를 분리하여 외부 접근을 제한할 수 있다.

8️⃣ 유지보수 용이

  • 설정 파일 하나로 관리하기 때문에 변경 시 파일만 수정하면 된다.
    ➡️ Docker Compose가 알아서 변경 사항을 적용.

✅ Docker Compose는 어디서 사용할까?

1️⃣ 개발 환경에서

  • 앱 개발 시, 필요한 서비스(DB, 캐시, 웹 API 등)를 정리해두고
    docker compose up 명령어로 모든 서비스를 한 번에 시작할 수 있다.
    ➡️ 프로젝트 실행 시간을 대폭 절약할 수 있다.

2️⃣ 자동화된 테스트 환경에서

테스트 환경을 별도로 정의하고 아래와 같은 명령어로 관리할 수 있다.

# 테스트 환경 실행
docker compose up -d

# 테스트 실행
./run_tests

# 테스트 환경 정리
docker compose down

3️⃣ 단일 호스트 배포에서

  • Docker Compose는 주로 개발 및 테스트 환경뿐 아니라 실제로 앱을 운영하는 환경(프로덕션)에도 쓸 수 있다.**
    ➡️ 새 버전 배포 시 효율적으로 사용 가능합니다.

✅ Docker Compose 장점

한 번에 여러 컨테이너 설정

  • 여러 컨테이너의 설정을 하나의 YAML 파일에 넣어서 관리
    ➡️ 이 파일 하나로 여러 컨테이너의 모든 환경을 설정하고, 그걸로 여러 컨테이너를 한번에 실행 가능

빠른 서비스 실행

  • 설정 값들을 저장해 두고 다시 쓸 수 있다.
    - 만약 설정이 바뀌지 않았다면, Docker Compose는 이전에 저장해둔 정보를 다시 사용해서 서비스를 더 빨리 시작 가능

같은 네트워크에서 쉽게 연결

  • docker-compose.yaml 파일에 있는 애플리케이션들은 모두 같은 네트워크에 자동으로 연결
    ➡️ 복잡한 네트워크 설정 없이도 여러 컨테이너가 서로 쉽게 통신 가능

✅ Docker Compose 실행 방법

1️⃣ 각 애플리케이션의 Dockerfile 작성

  • 실행할 애플리케이션을 정의하는 Dockerfile을 작성
    2️⃣ docker-compose.yaml 파일 작성
  • 애플리케이션과 필요한 서비스(DB, Redis 등)를 정의
    3️⃣ docker compose up 명령어로 실행
  • 정의한 모든 서비스와 애플리케이션이 함께 실행

✅ Docker Compose 파일

version: '3'
services:
  web:
    image: nginx:latest
    ports:
      - 80:80
    volumes:
      - ./web:/usr/share/nginx/html
    depends_on:
      - api
    links:
      - api:api
  api:
    image: java:latest
    volumes:
      - ./api:/app
    ports:
      - 8080:8080
    environment:
      - REDIS_HOST=redis
      - MYSQL_HOST=mysql
      - MYSQL_USER=root
      - MYSQL_PASSWORD=password
      - MYSQL_DATABASE=test
    depends_on:
      - mysql
      - redis
    links:
      - mysql:mysql
      - redis:redis
  redis:
    image: redis:latest
    ports:
      - 6379:6379
  mysql:
    image: mysql:latest
    ports:
      - 3306:3306
    volumes:
      - ./mysql:/var/lib/mysql
    environment:
      - MYSQL_ROOT_PASSWORD=password
      - MYSQL_DATABASE=test
      - MYSQL_USER=root
      - MYSQL_PASSWORD=password
  • version: Docker Compose의 버전 정의

  • services: 네 개의 서비스 정의

    • web 서비스는 Nginx 이미지를 사용하며, 포트 80번을 호스트 머신에 노출
    • api 서비스는 Java 이미지를 사용하며, 포트 8080번을 호스트 머신에 노출
    • redis 서비스는 Redis 이미지를 사용하며, 포트 6379번을 호스트 머신에 노출
    • mysql 서비스는 MySQL 이미지를 사용하며 포트 3306번을 호스트 머신에 노출
  • volumes:  web 서비스는 현재 디렉토리 내 web 디렉토리를 컨테이너에 연결.
    - api 서비스는 현재 디렉토리 내 api 디렉토리를 컨테이너에 연결.

    • mysql 서비스는 현재 디렉토리 내 mysql 디렉토리를 사용하여 MySQL 데이터를 영구적으로 저장.
  • depends_on: 각 서비스 간의 의존성을 정의
    - web 서비스는 api서비스에 의존

    • api 서비스는 mysql과 redis 서비스에 의존
  • links: 각 서비스 간의 링크를 정의
    - web 서비스는 api서비스에 링크.

    • api 서비스는 mysql과 redis 서비스에 링크.
  • 이 예제에서는 web 서비스와 api 서비스가 각각 독립적인 컨테이너로 실행된다. 

  • web 서비스는 api 서비스에 의존하며, api 서비스는 mysql과 redis 서비스에 의존한다. 

  • redis와 mysql 서비스는 각각 독립적인 컨테이너로 실행된다.

version: "3"
services:
	service1:
		# ...service1 설정
  service2:
    # ...service2 설정
networks:
	# 네트워크 설정, 선택적
volumes:
  # 볼륨 설정, 선택적

✅ Docker Compose 추가 기능

☑️ version

☑️ service

  • 컨테이너 대신 서비스 개념으로 간주
  • 컨테이너에서 설정할 수 있는 대부분의 설정이 들어감
services:
  web:
    build:
      context: .    # Dockerfile 의 위치
      dockerfile: Dockerfile    # Dockerfile 파일명
    container_name: testapp_web_1    # 생략하는 경우 
    # 자동으로 부여 docker run 의 --name 옵션과 동일
    ports: "8080:8080"  # docker run 의 -p 옵션과 동일
    expose: "8080"    # 호스트머신과 연결이 아니라 
    # 링크로 연결된 서비스 간 통신이 필요할 때 사용
    networks: testnetwork    # networks 를 최상위에 정의한다면 해당 이름을 사용
    # docker run의 --net 옵션과 동일
    volumes: .:/var/lib/nginx/html    # docker run 의 -v 옵션과 동일
    environment:
      - APPENV=TEST    # docker run 의 -e옵션과 동일
    command: npm start   # docker run 의 가장 마지막
    restart: always    # docker run 의 --restart 옵션과 동일
    depends_on: db    # 이 옵션에 지정된 서비스가 시작된 이후에 `web`서비스가 실행
    links: db # Docker가 네트워크를 통해 컨테이너를 연결하도록 정의합니다. 
    # 컨테이너를 연결할 때 Docker는 환경 변수를 만들고 
    # 컨테이너를 알려진 호스트 목록에 추가하여 서로를 검색할 수 있도록 합니다.
    deploy:    # 서비스의 복제본 개수 등 지정
      replicas: 3
      mode: replicated

☑️ volume

  • 도커 볼륨 혹은 호스트 볼륨을 마운트해서 사용한다.
  • 도커 볼륨의 경우 docker-compose.yml 파일에 선언된 볼륨만 docker-compose.yml 에서 사용가능
version: "3.9"
services:
  web:
    # ...
    volumes:
      - README.md:/docs/README.md # 호스트의 README.md 파일을 컨테이너 내부 /docs/README.md에 마운트   
      - logvolume01:/var/log # 선언된 도커 볼륨 logvolume01을 컨테이너 내부 /var/log에 마운트
# ...
volumes:
  logvolume01: {} # 도커볼륨 logvolume01 선언

☑️ networks

  • 서비스(컨테이너)가 소속된 네트워크를 지정한다.
  • 별도로 지정하지 않으면 default_${project} 형식의 네트워크가 자동으로 생성.
  • 같은 네트워크에 있어야 컨테이너 간 통신이 가능.

☑️ healthcheck

  • 서비스 컨테이너가 “healthy”한지 주기적으로 체크해야 한다.
  • Dockerfile에 정의된 설정을 따르지만, docker-compose.yaml에서 재정의할 수 있다.
  • 컨테이너 상태를 모니터링하여 문제가 발생하면 빠르게 대처 가능.

✅ Docker Compose CLI

docker-compose [COMMAND] [SERVICES...]의 형태로 사용하며, 특정 서비스(컨테이너)만 제어할 수 있다.

  • ex.web, redis 중에 web만 기동하려면 아래와 같이 실행
docker-compose up -d web

☑️ docker-compose up

-서비스 실행 시 다음 순서로 진행

  • 이미 생성된 경우 해당 단계를 건너뛴다. (멱등성)
  1. 서비스를 띄울 네트워크 생성
  2. 필요한 볼륨 생성 (혹은 이미 존재하는 볼륨과 연결)
  3. 필요한 이미지 풀(pull)
  4. 필요한 이미지 빌드(build)
  5. 서비스 실행 (의존성 설정 시 depends_on 순서대로 실행)

옵션

  • --build: 이미 빌드된 상태여도 강제로 빌드를 다시 진행.
  • -d: 서비스를 백그라운드에서 실행.
  • --force-recreate: 변경점이 없더라도 강제로 컨테이너를 재생성. 다시 말해, 기존 컨테이너를 종료하고 다시 생성.
  • docker-compose down : 서비스 중지 및 삭제, 컨테이너와 네트워크 삭제
  • --volume: 선언된 도커 볼륨도 삭제.
  • docker-compose stop & docker-compose start
    - stop: 실행 중인 서비스를 중지.
    - start: 멈춰 있는 서비스를 시작.
  • docker-compose ps : 현재 실행 중인 서비스 상태를 확인.
  • docker-compose logs : 컨테이너 로그 확인
  • -f : tail -f와 유사하게 로그를 실시간으로 확인.(follow)
  • docker-compose exec : 실행 중인 컨테이너에 명령어를 실행
docker-compose exec django ./manage.py makemigrations
docker-compose exec db psql postgres postgres
  • docker-compose run : 컨테이너를 기동시키고 특정 명령어를 실행한 후, 컨테이너를 종료 (일회성 명령어 실행 시 사용)
    - 비교
    • docker-compose exec : 이미 실행 중인 컨테이너에서 명령어 실행
      - docker-compose run: 컨테이너를 새로 기동하여 명령어 실행 후 종료
# 이미 실행된 web 컨테이너에서 echo "hello world" 실행
docker-compose exec web echo "hello world" 

# web 컨테이너를 새로 실행 -> echo "hello world" 실행 -> 컨테이너 종료
docker-compose run web echo "hello world" 

✅ 개발환경에서 Docker Compose 사용

☑️ docker-compose 로 실행

cd ~/spring-boot-sample

# 백그라운드로 모드로 실행
docker-compose up -d

# 로그 확인
docker-compose logs -f
  • docker-compose up -d 명령어를 사용하여 백그라운드에서 Redis와 MySQL을 실행
  • 이후 docker-compose logs -f 명령어로 실행된 서비스들의 로그 확인.

☑️ MySQL, Redis 연결 확인

  • Redis의 포트: 26379
  • MySQL의 포트: 23306
  • Redis 연결 테스트: http://localhost:8080/test-cache 경로에서 Redis를 활용한 5초 단위 캐시 적용을 확인.

☑️ docker-compose down 실행 후 애플리케이션 실행

  • docker-compose down 명령어로 Redis 서비스를 종료한 후 애플리케이션을 실행하면, Redis에 접속 불가.
    - Redis를 Docker Compose 파일로 정의하여 컨테이너로 실행하고 있기 때문에, docker-compose down 명령어로 Compose 환경을 종료하면 Redis 컨테이너가 함께 중지.
    - Redis 컨테이너가 종료되면 애플리케이션은 Redis 서버에 연결할 수 없게 되어 "Redis 접속 불가" 오류가 발생.
    - Redis 서비스를 정상적으로 사용하려면 docker-compose up -d로 Redis 컨테이너를 다시 실행.


Docker 모니터링 & 로깅

내가 실행하는 앱이 어떤 상태인지 Docker 모니터링을 통해 알아보고, 실행 과정을 기록한 로깅을 살펴보자 !!

✅ 도커 모니터링이란 ?

  • 도커 모니터링 : 컨테이너가 어떻게 돌아가고 있는지 지켜보는 것
  • 컨테이너의 성능, 사용 중인 자원(예: CPU, 메모리), 네트워크 사용량 등을 확인 가능.

✅ 왜 중요한가?

  • 컨테이너가 잘 돌아가고 있는지, 어떤 문제가 있는지 파악할 수 있다.
  • ex. 컨테이너가 너무 많은 메모리를 쓰고 있다면 조정 필요

✅ 어떤 방법으로 확인할까 ?

  • docker stats 명령어를 사용하면 실행 중인 컨테이너의 자원 사용량을 실시간으로 확인할 수 있다.
  • 외부 모니터링 도구를 사용해 더 자세한 정보를 얻거나, 여러 컨테이너의 데이터를 한눈에 볼 수 있다.

모니터링 정보를 통해 문제를 빨리 발견하고 해결 가능 !!
또한, 컨테이너를 효율적으로 관리하고 최적화할 수 있다 !!

✅ Container 리소스 모니터링

☑️ docker stats : 컨테이너 모니터링의 시작점

Docker Stats란?

  • docker stats : Docker에서 제공하는 간단하고 실용적인 모니터링 도구
  • 이 명령어를 사용하면 현재 실행 중인 Docker 컨테이너들이 얼마나 많은 자원(CPU, 메모리 등)을 사용하고 있는지 실시간으로 확인 가능
    ➡️ 컨테이너가 시스템 자원을 얼마나 사용하고 있는지 알면 성능 문제를 빨리 찾아내고 해결 가능. ex.메모리 사용량이 너무 높으면 시스템에 부하가 걸릴 수 있습니다.

docker stats 사용 방법

  • docker stats 명령어를 터미널에 입력, 현재 실행 중인 모든 컨테이너의 상태를 한눈에 볼 수 있다.

  • CPU 사용률, 메모리 사용량, 네트워크 I/O, 디스크 I/O 등 여러 중요한 정보를 보여준다.

    docker stats

  • 특정 컨테이너의 상태만 보고 싶다면, 컨테이너의 이름이나 ID를 명령어 뒤에 추가

    docker stats [컨테이너 이름 또는 ID]
    

☑️ htop : 시스템 모니터링의 필수 도구

htop이란?

  • htop : 리눅스 시스템을 모니터링하는 강력한 도구.
  • 시스템 자원 사용량과 프로세스를 실시간으로 확인하고, 프로세스를 종료하거나 관리할 수 있다.
    ➡️ CPU, 메모리 사용량 등의 정보를 실시간으로 모니터링할 수 있으며, 프로세스 목록을 확인하고 필요한 경우 종료할 수 있다.

htop 사용 방법

docker run --name test-tools -ti -d ubuntu:22.04
docker exec -ti test-tools /bin/bash
apt update; apt upgrade -y; apt install htop -y;

htop

exit

# test-tools라는 컨테이너가 실행 확인
docker stats

df

  • df :disk free의 약자로, 리눅스 시스템 전체의 디스크 사용량 확인 가능
docker exec -ti test-tools /bin/bash
df -h
exit

du

  • du : 디렉토리 별로 사용 공간을 나타냄
docker exec -ti test-tools /bin/bash
du -sh # 현재 디렉토리의 총 디스크 사용량을 GB 단위로 보여줌
du -h --max-depth=1 # 현재 디렉토리 한 단계 아래 디렉토리 까지만 사용량을 보여줌
exit


✅ Container 로깅

내가 만든 앱의 실행 과정을 기록한 로깅을 살펴보자 !!

  • Docker는 모든 컨테이너 로그의 표준 출력(stdout) 또는 표준 에러(stderr)를 캡처하여 json-file 로깅 드라이버를 사용해 json 형식으로 파일에 기록한다.
  • 로그 파일 위치
    - Ubuntu 에서는 /var/lib/docker/containers/[컨테이너ID]/[컨테이너ID]-json.log에 로그가 기록

▶️ 특정 컨테이너의 로그 보기

docker run --name logs-test --rm -d ubuntu:22.04 /bin/bash -c 'while true; do date; sleep 1; done'

# logs-test 컨테이너의 로그를 전체 출력하기
docker logs logs-test

# logs-test 컨테이너의 로그를 tailing하기
docker logs -f logs-test

# 마지막 10줄부터 로그를 계속 보기
docker logs -f --tail 10 logs-test

▶️ 로그 파일 설정 확인하기

docker inspect logs-test --format "{{.LogPath}}"

✅ 로그 로테이션 설정

  • 실제로 운영하다 보면 로그 파일의 크기가 계속 커질 수 있기 때문에 로그 파일의 최대 크기와 최대 파일 개수를 지정

▶️ Container 별 로깅 드라이버 구성

docker run -d \
--log-driver json-file \
--log-opt max-size=10m \
--log-opt max-file=10 \
--name nginxtest \
--restart always \
-p 80:80 \
-p 443:443 \
nginx:latest

nginx 를 Container로 실행시키고 log file 크기와 개수를 제한 확인

# Container 의 log file 크기와 개수 제한
docker run -d \
--log-driver json-file \
--log-opt max-size=1m \
--log-opt max-file=5 \
--name nginxtest \
--restart always \
-p 80:80 \
-p 443:443 \
nginx:latest

# 로그 보기
docker logs -f nginxtest

✅ docker compose 파일에서 설정

  • docker-compose.yml 파일에서 로그 설정을 추가하여 로그 파일의 크기와 개수를 제한할 수 있다.
services:
  app:
    ...
    logging:
      driver: 'json-file'
      options:
        max-size: '10m'
        max-file: '10'
  • 사용한 컨테이너 정리
docker stop nginxtest
docker container rm nginxtest

출처 : [TeamSparta]

profile
🔥💻🔥

0개의 댓글