웹사이트 검색

우분투에서 Docker Compose 설치 및 사용 방법


소개

Docker는 애플리케이션 프로세스를 컨테이너에서 관리하는 과정을 단순화합니다. 컨테이너는 일부 측면에서 가상 머신과 유사하지만, 더 가볍고 자원을 효율적으로 사용합니다. 이를 통해 개발자는 애플리케이션 환경을 여러 개의 독립된 서비스로 분리할 수 있습니다.

여러 서비스에 의존하는 애플리케이션의 경우, 모든 컨테이너가 함께 시작되고 통신하며 종료되도록 조정하는 것은 금방 복잡해질 수 있습니다. Docker Compose는 YAML 파일에 설정된 정의를 기반으로 다중 컨테이너 애플리케이션 환경을 실행할 수 있게 해주는 도구입니다. 이는 서비스 정의를 사용하여 네트워크와 데이터 볼륨을 공유할 수 있는 여러 컨테이너로 완전히 맞춤화된 환경을 구축할 수 있습니다.

이 가이드는 Ubuntu 서버에 Docker Compose를 설치하고 간단한 컨테이너를 실행하는 과정을 안내합니다. 그 후, WordPress 애플리케이션과 MySQL 데이터베이스를 사용하여 다중 서비스 환경을 구축하는 방법을 배우게 됩니다. 또한 서비스 확장, 사용자 정의 네트워크 정의, 모듈식 포함 지시문 사용 등 더 고급 주제도 다룹니다. 마지막으로, 이 글에서는 기존 docker-compose (v1)에서 최신 docker compose (v2)로의 마이그레이션 가이드와 포트 충돌 및 권한 오류와 같은 일반적인 문제 해결 방법을 자세히 설명합니다.

핵심 요점:

  • Docker Compose는 단일 YAML 파일을 사용하여 서비스, 네트워크 및 볼륨을 구성하고 멀티 컨테이너 애플리케이션을 정의하고 실행하는 도구입니다.
  • Docker Compose는 Docker의 공식 저장소를 추가하고 apt를 사용하여 docker-compose-plugin 패키지를 설치하여 Ubuntu에 설치됩니다.
  • 현대의 명령어는 docker compose (공백 포함)입니다. 이는 더 이상 사용되지 않는 docker-compose (하이픈 포함) v1 도구를 대체합니다.
  • docker compose up -d 명령을 사용하여 애플리케이션을 분리 모드에서 시작하고, docker compose down 명령으로 모든 컨테이너와 네트워크를 중지하고 제거할 수 있습니다.
  • depends_on 지시문은 데이터베이스 컨테이너가 웹 애플리케이션 컨테이너보다 먼저 시작되도록 하는 등 서비스의 시작 순서를 제어하는 데 도움을 줍니다.
  • 가장 흔한 문제는 '권한 거부' (docker 그룹에 사용자를 추가하면 해결), 포트 충돌 (YAML 파일에서 호스트 포트를 변경하면 해결), 그리고 YAML 문법 오류 (들여쓰기를 수정하면 해결)입니다.
  • 다음 명령어를 사용하여 서비스를 여러 인스턴스로 실행할 수 있습니다: docker compose up --scale <service_name>=<number>.
  • include 지시문을 사용하면 큰 docker-compose.yml 파일을 더 작고 관리하기 쉬운 구성 파일로 나눌 수 있습니다.

전제 조건

이 글을 따라가려면 다음이 필요합니다:

  • 루트(root) 권한이 아닌 사용자로서 sudo 권한이 있는 Ubuntu 로컬 머신 또는 개발 서버에 액세스할 수 있어야 합니다. 원격 서버를 사용하는 경우 활성화된 방화벽이 설치되어 있는 것이 좋습니다. 이러한 설정 방법에 대해서는 Ubuntu 초깃값 서버 설정 가이드를 참조하시기 바랍니다.
  • 서버나 로컬 머신에 Docker가 설치되어 있어야 하며, 'Ubuntu에 Docker 설치 방법 – 단계별 가이드'의 1단계와 2단계를 따라야 합니다.

참고: Docker Compose v2부터 Docker는 기존 docker-compose 명령어에서 벗어나 compose CLI 플러그인 명령어를 사용하는 방향으로 이동했습니다. 이는 저희의 '우분투에서 Docker Compose 설치 방법(단계별 가이드)'에 문서화되어 있습니다. 설치 방법은 다르지만, 일반적으로 실제 사용 시에는 docker-compose 명령어의 하이픈을 제거하여 docker compose로 사용하면 됩니다. 전체 호환성 세부 사항은 새 compose와 기존 docker-compose 간 명령어 호환성에 대한 공식 Docker 문서를 확인하세요.

1단계 — Docker Compose 설치

Ubuntu에 Docker Compose를 설치하는 방법에는 두 가지가 있습니다:

  • 저장소를 사용하여 설치
  • 수동으로 설치

이 섹션에서 두 가지 방법 모두에 대해 논의할 것입니다.

apt 저장소를 사용하여 Docker Compose 설치하기

먼저, Docker apt 저장소를 설정해 보겠습니다.

# Add Docker's official GPG key:

sudo apt-get update

sudo apt-get install ca-certificates curl

sudo install -m 0755 -d /etc/apt/keyrings

sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc

sudo chmod a+r /etc/apt/keyrings/docker.asc



# Add the repository to Apt sources:

echo \

  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \

  $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \

  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

sudo apt-get update

이제 다음 명령어를 사용하여 Docker Compose를 설치할 수 있습니다:

sudo apt install docker-compose-plugin

Docker Compose가 이제 시스템에 성공적으로 설치되었습니다. 설치가 제대로 되었는지 확인하려면 다음 명령어를 실행할 수 있습니다:

docker compose version

다음과 유사한 출력이 표시됩니다:

Docker Compose version v2.3.3

Docker Compose 수동 설치

Docker Compose의 최신 안정 버전을 확보하려면 이 소프트웨어를 공식 Github 저장소에서 다운로드해야 합니다.

먼저, 그들의 릴리스 페이지에서 최신 버전을 확인하세요. 이 글을 작성할 시점 기준으로, 가장 최신의 안정 버전은 v2.40.2입니다.

다음 명령어를 사용하여 다운로드하세요:

mkdir -p ~/.docker/cli-plugins/

curl -SL https://github.com/docker/compose/releases/download/v2.40.2/docker-compose-linux-x86_64 -o ~/.docker/cli-plugins/docker-compose

다음으로 docker compose 명령을 실행할 수 있도록 올바른 권한을 설정하세요:

chmod +x ~/.docker/cli-plugins/docker-compose

다음 섹션에서는 docker-compose.yml 파일을 설정하고 이 도구를 사용하여 컨테이너화된 환경을 실행하는 방법을 보게 될 것입니다.

2단계 — docker-compose.yml 파일 설정

docker-compose.yml 파일을 설정하고 Docker Compose를 사용하는 방법을 보여주기 위해, Docker Hub라는 공개 Docker 레지스트리에서 제공되는 공식 Nginx 이미지를 사용하여 웹 서버 환경을 만들 것입니다. 이 컨테이너 환경은 단일 정적 HTML 파일을 제공하게 됩니다.

먼저 홈 폴더에 새 디렉토리를 만들고, 그 디렉토리로 이동하세요:

mkdir ~/compose-demo

cd ~/compose-demo

이 디렉토리에서 Nginx 환경의 문서 루트 역할을 할 애플리케이션 폴더를 설정합니다:

mkdir app

선호하는 텍스트 편집기를 사용하여 app 폴더 안에 새 index.html 파일을 생성하세요:

nano app/index.html

다음 내용을 이 파일에 넣으세요:

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Docker Compose Demo</title>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/kognise/water.css@latest/dist/dark.min.css">
</head>
<body>

    <h1>This is a Docker Compose Demo Page.</h1>
    <p>This content is being served by an Nginx container.</p>

</body>
</html>

작업을 마쳤으면 파일을 저장하고 닫으세요. nano를 사용 중이라면 CTRL+X를 누른 다음, Y와 ENTER를 눌러 확인하면 됩니다.

다음으로, docker-compose.yml 파일을 만드세요:

nano docker-compose.yml

다음 내용을 docker-compose.yml 파일에 삽입하세요:

services:
  web:
    image: nginx:alpine
    ports:
      - "8000:80"
    volumes:
      - ./app:/usr/share/nginx/html

현대 Docker Compose에서는 version 필드가 선택 사항이며, Compose가 구성 버전을 자동으로 감지할 수 있기 때문에 자주 생략됩니다. 위 예제에는 version 필드가 포함되어 있지 않으며, 이는 대부분의 신규 프로젝트에서 권장되는 접근 방식입니다. 이전 버전 호환성을 위해서만 version을 명시하면 됩니다.

그 다음에는 services 블록이 있는데, 여기서 이 환경의 일부인 서비스들을 설정합니다. 귀하의 경우에는 web이라는 단일 서비스가 있습니다. 이 서비스는 nginx:alpine 이미지를 사용하며, ports 지시문을 통해 포트 리디렉션을 설정합니다. 호스트 머신(즉, Docker Compose를 실행하는 시스템)의 8000번 포트로 들어오는 모든 요청은 web 컨테이너의 80번 포트로 리디렉션되며, 이곳에서 Nginx가 실행됩니다.

volumes 지시어는 호스트 머신과 컨테이너 간에 공유 볼륨을 생성합니다. 이는 로컬 app 폴더를 컨테이너와 공유하며, 해당 볼륨은 컨테이너 내부의 /usr/share/nginx/html에 위치하게 되어 Nginx의 기본 문서 루트를 덮어쓰게 됩니다.

파일을 저장하고 닫으세요.

데모 페이지와 이를 제공할 컨테이너화된 웹 서버 환경을 만들기 위한 docker-compose.yml 파일을 설정했습니다. 다음 단계에서는 Docker Compose를 사용하여 이 환경을 실행할 것입니다.

3단계 — Docker Compose 실행

docker-compose.yml 파일이 준비되었으므로 이제 Docker Compose를 실행하여 환경을 시작할 수 있습니다. 다음 명령어는 필요한 Docker 이미지를 다운로드하고, web 서비스용 컨테이너를 생성하며, 백그라운드 모드에서 컨테이너화된 환경을 실행합니다:

docker compose up -d

Docker Compose는 먼저 로컬 시스템에서 정의된 이미지를 찾아보고, 이미지를 찾을 수 없으면 Docker Hub에서 이미지를 다운로드합니다. 다음과 같은 출력이 표시됩니다:

Creating network "compose-demo_default" with the default driver
Pulling web (nginx:alpine)...
alpine: Pulling from library/nginx
cbdbe7a5bc2a: Pull complete
10c113fb0c77: Pull complete
9ba64393807b: Pull complete
c829a9c40ab2: Pull complete
61d685417b2f: Pull complete
Digest: sha256:57254039c6313fe8c53f1acbf15657ec9616a813397b74b063e32443427c5502
Status: Downloaded newer image for nginx:alpine
Creating compose-demo_web_1 ... done

참고: docker compose up 실행 시 “permission denied” 오류가 발생하면, 이는 일반 사용자가 Docker 데몬 소켓에 접근할 권한이 없다는 의미입니다.

기본적으로 Docker 데몬은 /var/run/docker.sock 유닉스 소켓에 바인딩되며, 이 소켓은 root 사용자가 소유합니다. 이를 해결하려면, Docker 설치 과정에서 생성된 docker 그룹에 루트가 아닌 사용자를 추가해야 합니다.

다음 명령어를 실행하여 사용자를 docker 그룹에 추가하세요:

sudo usermod -aG docker ${USER}

이 명령을 실행한 후에는 그룹 변경 사항이 적용되도록 로그아웃했다가 다시 로그인해야 합니다. 또한 다음을 입력하여 현재 터미널 세션에 변경 사항을 적용할 수도 있습니다:

newgrp docker

이 명령어는 Docker 소켓과 관련된 권한 오류를 해결해야 합니다. 전체 과정은 'Ubuntu에 Docker 설치 - 단계별 가이드'의 2단계를 참조하세요.

이제 환경이 백그라운드에서 실행 중입니다. 컨테이너가 활성 상태인지 확인하려면 다음 명령을 실행할 수 있습니다:

docker compose ps

이 명령은 실행 중인 컨테이너와 그 상태, 현재 설정된 포트 리디렉션 정보를 보여줍니다:

       Name                     Command               State          Ports        
----------------------------------------------------------------------------------
compose-demo_web_1   /docker-entrypoint.sh ngin ...   Up      0.0.0.0:8000->80/tcp

이제 브라우저를 통해 데모 애플리케이션에 접속할 수 있습니다. 로컬 컴퓨터에서 이 데모를 실행 중이라면 localhost:8000로 접속하거나, 원격 서버에서 실행 중이라면 your_server_domain_or_IP:8000로 접속하면 됩니다.

이런 페이지가 보일 거예요:

docker-compose.yml 파일 내에서 설정한 공유 볼륨은 app 폴더의 파일을 컨테이너의 도큐먼트 루트와 동기화 상태로 유지합니다. index.html 파일을 변경하면, 해당 변경 사항은 자동으로 컨테이너에 반영되며 페이지를 새로고침할 때 브라우저에서도 확인할 수 있습니다.

다음 단계에서는 Docker Compose 명령어로 컨테이너화된 환경을 관리하는 방법을 확인할 수 있습니다.

4단계 — Docker Compose 명령어 익히기

이미 docker-compose.yml 파일을 설정하고 docker compose up으로 환경을 실행하는 방법을 보았습니다. 이제 Docker Compose 명령어를 사용하여 컨테이너화된 환경을 관리하고 상호작용하는 방법을 보게 될 것입니다.

Nginx 컨테이너에서 생성된 로그를 확인하려면 logs 명령어를 사용할 수 있습니다:

docker compose logs

다음과 유사한 출력이 표시됩니다:

Attaching to compose-demo_web_1
web_1  | /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration
web_1  | /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/
web_1  | /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh
web_1  | 10-listen-on-ipv6-by-default.sh: Getting the checksum of /etc/nginx/conf.d/default.conf
web_1  | 10-listen-on-ipv6-by-default.sh: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf
web_1  | /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh
web_1  | /docker-entrypoint.sh: Configuration complete; ready for start up
web_1  | 172.22.0.1 - - [02/Jun/2020:10:47:13 +0000] "GET / HTTP/1.1" 200 353 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36" "-"

컨테이너의 현재 상태를 변경하지 않고 환경 실행을 일시 중지하려면 다음을 사용할 수 있습니다:

docker compose pause
Pausing compose-demo_web_1 ... done

일시 정지 명령을 내린 후 실행을 재개하려면:

docker compose unpause
Unpausing compose-demo_web_1 ... done

stop 명령어는 컨테이너 실행을 종료하지만, 컨테이너와 관련된 데이터는 삭제하지 않습니다:

docker compose stop
Stopping compose-demo_web_1 ... done

이 컨테이너화 환경과 관련된 컨테이너, 네트워크 및 볼륨을 제거하려면 down 명령을 사용하십시오:

docker compose down
Removing compose-demo_web_1 ... done
Removing network compose-demo_default

이렇게 해도 Docker Compose가 환경을 실행할 때 사용하는 기반 이미지(사용자의 경우 nginx:alpine)는 제거되지 않는다는 점에 유의하세요. 이렇게 하면 나중에 docker compose up으로 환경을 다시 실행할 때, 이미지가 이미 시스템에 있기 때문에 과정이 훨씬 빨라집니다.

시스템에서 기본 이미지를 함께 제거하고 싶다면 다음을 사용할 수 있습니다:

docker image rm nginx:alpine
Untagged: nginx:alpine
Untagged: nginx@sha256:b89a6ccbda39576ad23fd079978c967cecc6b170db6e7ff8a769bf2259a71912
Deleted: sha256:7d0cdcc60a96a5124763fddf5d534d058ad7d0d8d4c3b8be2aefedf4267d0270
Deleted: sha256:05a0eaca15d731e0029a7604ef54f0dda3b736d4e987e6ac87b91ac7aac03ab1
Deleted: sha256:c6bbc4bdac396583641cb44cd35126b2c195be8fe1ac5e6c577c14752bbe9157
Deleted: sha256:35789b1e1a362b0da8392ca7d5759ef08b9a6b7141cc1521570f984dc7905eb6
Deleted: sha256:a3efaa65ec344c882fe5d543a392a54c4ceacd1efd91662d06964211b1be4c08
Deleted: sha256:3e207b409db364b595ba862cdc12be96dcdad8e36c59a03b7b3b61c946a5741a

참고: Docker 명령어에 대한 보다 자세한 참조는 'Ubuntu에 Docker 설치하는 방법 – 단계별 가이드'를 참고하세요.

5단계 — 다중 서비스 애플리케이션 구축

Docker Compose의 진정한 힘은 함께 작동하는 여러 서비스를 관리하는 데 있습니다. Nginx 예제는 단일 서비스였습니다. 이제 더 실용적인 다중 서비스 애플리케이션을 만들어 보겠습니다: MySQL 데이터베이스와 연결된 WordPress 웹사이트입니다.

이 설정에는 두 가지 서비스가 포함됩니다: wordpress (애플리케이션 실행)와 db (데이터베이스 실행). 컨테이너가 제거되더라도 데이터베이스 데이터가 유지되도록 Docker 볼륨도 사용할 것입니다.

이 애플리케이션을 위해 새 디렉토리를 만듭시다:

mkdir -p ~/compose-demo/wordpressapp

cd ~/compose-demo/wordpressapp

이 예제에서는 이미지만으로 모든 필요한 소프트웨어가 포함되어 있으므로 로컬 파일이 필요하지 않습니다.

새로운 docker-compose.yml 파일을 만드세요:

nano docker-compose.yml

다음 구성을 붙여넣으세요. 이 파일은 더 복잡하므로 각 부분을 살펴보겠습니다.

services:
  db:
    image: mysql:8.0
    container_name: mysql_db
    volumes:
      - db_data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: <^your_root_password_here<^>
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress_user
      MYSQL_PASSWORD: <^your_wordpress_password_here<^>
    restart: unless-stopped

  wordpress:
    image: wordpress:latest
    container_name: wordpress_app
    ports:
      - "8001:80"
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: wordpress_user
      WORDPRESS_DB_PASSWORD: <^your_wordpress_password_here<^>
      WORDPRESS_DB_NAME: wordpress
    volumes:
      - ./wp_content:/var/www/html/wp-content
    depends_on:
      - db
    restart: unless-stopped

volumes:
  db_data:

참고: 여기서는 설명을 위해 비밀번호 값을 하드코딩했습니다. 실제 환경에서 사용할 때는 자격 증명이 노출되지 않도록 .env 파일의 환경 변수를 사용하세요.

파일을 저장하고 닫으세요. <^...^> 자리표시자를 강력하고 안전한 비밀번호로 바꾸는 것을 잊지 마세요.

이 파일에 있는 새로운 지침을 살펴봅시다:

  • services: 이 블록은 여전히 우리의 컨테이너를 정의합니다. 이제 두 개가 있습니다: db와 wordpress.
  • image: 데이터베이스에는 mysql:8.0을 사용하고 애플리케이션에는 wordpress:latest 이미지를 사용하고 있습니다.
  • container_name: 컨테이너에 대해 사람이 읽기 쉬운 특정 이름을 설정합니다. 이는 자동 생성된 이름보다 참조하기 쉽습니다.
  • 환경: 이는 컨테이너에 전달되는 환경 변수 목록입니다. mysql 이미지에서는 이를 사용하여 루트 비밀번호를 설정하고 초기 데이터베이스 및 사용자를 생성합니다. wordpress 이미지에서는 이를 사용하여 데이터베이스에 연결하는 방법을 알 수 있습니다.
  • 볼륨 (서비스 수준):

    • db 서비스의 경우, db_data:/var/lib/mysql는 db_data라는 Docker 관리 볼륨을 컨테이너 내부의 MySQL 데이터 디렉토리에 매핑합니다. 이렇게 하면 데이터가 안전하게 유지됩니다.
    • wordpress 서비스의 경우, ./wp_content:/var/www/html/wp-content 는 로컬 디렉토리(wp_content)를 워드프레스 콘텐츠 디렉토리에 매핑합니다. 이를 통해 호스트 머신에서 테마와 플러그인을 직접 편집할 수 있습니다.
  • depends_on: 이것은 Compose에게 wordpress 서비스를 시작하기 전에 db 서비스를 시작하도록 지시합니다. 이것은 중요합니다. WordPress가 시작 시 데이터베이스를 찾을 수 없으면 실패하기 때문입니다.
  • volumes (최상위): 이 블록은 이름이 지정된 볼륨을 정의합니다. db_data:는 Docker가 관리하는 볼륨을 생성하며, 이는 지속적인 데이터를 처리하는 권장 방법입니다.

이제 이 다중 서비스 애플리케이션을 실행하세요:

docker compose up -d

Compose는 mysql과 wordpress 이미지를 모두 가져온 다음 컨테이너를 생성하며, 먼저 db 서비스를 시작합니다.

Creating network "compose-demo_default" with the default driver
Creating volume "compose-demo_db_data" with default driver
Pulling db (mysql:8.0)...
...
Pulling wordpress (wordpress:latest)...
...
Creating mysql_db        ... done
Creating wordpress_app ... done

이제 브라우저에서 localhost:8001 또는 <^your_server_domain_or_IP<^>:8001로 이동하여 새 WordPress 사이트에 접속할 수 있습니다. WordPress 설치 화면이 표시될 것입니다. 자세한 예시는 'Docker Compose로 WordPress 설치하는 방법'에 대한 저희 기사를 참고하세요.

6단계 — AI/ML 개발을 위한 Docker Compose 사용

웹 애플리케이션을 넘어, Docker Compose는 재현 가능한 데이터 과학 및 머신러닝(AI/ML) 환경을 만드는 데 매우 유용한 도구입니다. AI/ML 프로젝트는 특정 Python 버전, TensorFlow 또는 PyTorch와 같은 라이브러리, NVIDIA CUDA Toolkit과 같은 시스템 수준 드라이버를 포함한 복잡한 종속성으로 잘 알려져 있습니다. Docker Compose는 이 전체 환경을 구성 파일에 담아내어 '내 컴퓨터에서는 잘 되는데'라는 문제를 해결하며, 이는 재현 가능한 연구에 있어 매우 중요합니다.

이 예제에서는 다음으로 구성된 다중 서비스 AI/ML 환경을 만들게 됩니다:

  • JupyterLab: 맞춤형 Dockerfile에서 구축된 인터랙티브 개발용 컨테이너.
  • PostgreSQL: 실험 결과와 메타데이터를 저장하기 위한 데이터베이스 컨테이너.
  • GPU 접근: JupyterLab 컨테이너는 모델 학습에 일반적으로 필요한 호스트 머신의 NVIDIA GPU에 접근할 수 있도록 구성됩니다.

필수 조건: 이 예제는 호스트 머신에 NVIDIA GPU가 설치되어 있고 NVIDIA 컨테이너 툴킷이 설치되어 있어야 합니다. 그렇지 않으면 컨테이너가 GPU 리소스를 요청할 때 시작되지 않습니다.

파일 구조

먼저, 프로젝트를 위한 디렉토리를 만듭니다. 그 안에 docker-compose.yml 파일, jupyter 디렉토리, Jupyter용 Dockerfile, 그리고 requirements.txt 파일을 생성합니다. 구조는 다음과 같이 보일 것입니다:

ai-project/
├── docker-compose.yml
└── jupyter/
    ├── Dockerfile
    └── requirements.txt

컴포넌트 파일 만들기

1. requirements.txt 파일

이 파일에는 데이터 과학 환경에 필요한 파이썬 패키지가 나열되어 있습니다.

nano jupyter/requirements.txt

필요한 패키지를 추가하세요. 이 예제에서는 데이터 조작, 데이터베이스 연결, 딥러닝 프레임워크를 위한 라이브러리를 포함할 것입니다.

pandas
scikit-learn
tensorflow
jupyterlab
psycopg2-binary

파일을 저장하고 닫으세요.

2. Dockerfile

이 파일은 여러분의 맞춤형 JupyterLab 서비스를 정의합니다. 공식 Jupyter 이미지를 기반으로 사용하며 requirements.txt에 있는 패키지를 설치합니다.

nano jupyter/Dockerfile

다음 내용을 붙여 넣으세요:

# Start from a base image that includes Jupyter and scientific libraries
FROM jupyter/scipy-notebook:latest

# Copy our local requirements file into the container
COPY requirements.txt /tmp/requirements.txt

# Install the Python packages
RUN pip install --no-cache-dir -r /tmp/requirements.txt

이 파일은 Docker가 jupyter/scipy-notebook을 시작점으로 사용하고, requirements.txt를 컨테이너에 복사한 다음, pip를 사용하여 패키지를 설치하도록 지시합니다.

docker-compose.yml로 환경 정의하기

이제 주요 docker-compose.yml 파일을 생성합니다. 이 파일은 db 서비스와 맞춤형 jupyter 서비스를 모두 관리합니다.

nano docker-compose.yml

다음 구성을 붙여넣고, <^...^> 자리 표시자를 자신의 안전한 자격 증명으로 교체하세요.

services:
  db:
    image: postgres:15-alpine
    container_name: ai_postgres_db
    environment:
      POSTGRES_USER: <^your_db_user^>
      POSTGRES_PASSWORD: <^your_db_pass^>
      POSTGRES_DB: experiments
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U <^your_db_user^> -d experiments"]
      interval: 10s
      timeout: 5s
      retries: 5
    volumes:
      - postgres_data:/var/lib/postgresql/data
    restart: unless-stopped
    networks:
      - ai_net

  jupyter:
    build: ./jupyter
    container_name: ai_jupyter_lab
    ports:
      - "8888:8888"
    volumes:
      - ./notebooks:/home/jovyan/work
    environment:
      - POSTGRES_HOST=db
      - POSTGRES_USER=<^your_db_user^>
      - POSTGRES_PASSWORD=<^your_db_pass^>
      - POSTGRES_DB=experiments
    restart: unless-stopped
    networks:
      - ai_net
    depends_on:
      db:
        condition: service_healthy
    deploy:
      resources:
        reservations:
          devices:
            - driver: nvidia
              count: 1
              capabilities: [gpu]

volumes:
  postgres_data:
    name: ai_project_data

networks:
  ai_net:
    driver: bridge

이 구성 파일은 몇 가지 중요한 개념을 소개합니다:

  • build: ./jupyter: 이는 Docker Compose에 jupyter 서비스용 맞춤 이미지를 빌드하도록 지시합니다. 지정된 ./jupyter 디렉토리 안에서 Dockerfile을 찾습니다.
  • volumes: - ./notebooks:/home/jovyan/work: 이것은 로컬 디렉터리 notebooks를 컨테이너 안으로 바인드 마운트합니다. 이를 통해 생성하는 모든 Jupyter 노트북이 호스트 머신에 직접 저장되어, 컨테이너를 제거한 후에도 지속됩니다.
  • healthcheck: 문제 해결 섹션에서 보는 것처럼, 이 검사는 db 서비스가 단순히 실행 중인 것이 아니라 다른 서비스가 시작되기 전에 연결을 수락할 준비가 되었는지 확인합니다.
  • depends_on: ... condition: service_healthy: 이것은 jupyter 서비스가 시작되기 전에 db의 헬스체크가 통과할 때까지 기다리도록 지시합니다.
  • deploy.resources.reservations.devices: GPU 접근을 요청하는 블록입니다.

    • driver: nvidia: 사용할 호스트 드라이버를 지정합니다.
    • count: 1: GPU 하나를 요청합니다.
    • capabilities: [gpu]: 컨테이너가 GPU를 사용할 수 있는 필요한 기능을 갖추도록 보장합니다.

AI/ML 환경 실행

파일이 준비되었으니, 이제 서비스를 빌드하고 실행할 준비가 되었습니다.

  1. 당신의 ai-project 디렉토리에서 docker compose up 명령어를 실행하세요. 첫 번째 실행 시에는 Compose가 커스텀 jupyter 이미지를 빌드하도록 --build 플래그를 추가해야 합니다.

    docker compose up -d --build
  2. Compose는 먼저 jupyter 이미지를 빌드합니다(이 과정에서 TensorFlow를 다운로드하므로 몇 분 정도 걸릴 수 있음). 그 다음 postgres 이미지를 가져오고, 마지막으로 두 컨테이너를 모두 시작합니다.

    [+] Building 5.8s (9/9) FINISHED
     => [internal] load build definition from Dockerfile
    ...
    [+] Running 3/3
     ✔ Network ai-project_ai_net        Created
     ✔ Container ai_postgres_db         Started
     ✔ Container ai_jupyter_lab         Started
  3. 이제 브라우저에서 http://localhost:8888 (또는 <^your_server_ip^>:8888)로 이동하여 JupyterLab 인터페이스에 접속할 수 있습니다. 토큰을 입력하라는 요청이 나타나며, 이 토큰은 컨테이너 로그에서 확인할 수 있습니다:

    docker compose logs jupyter

    http://127.0.0.1:8888/lab?token=a1b2c3d4e5f6...와 유사한 줄을 찾아보세요

  4. 이제 Jupyter 노트북 안에서 호스트 이름 db와 제공한 자격 증명을 사용하여 데이터베이스에 연결할 수 있습니다. 또한 환경에서는 모델 학습을 위해 호스트의 GPU에 접근할 수 있습니다.

서비스 확장 및 맞춤형 네트워크 사용

Docker Compose에는 서비스를 확장하고 서비스 간 통신에 사용되는 네트워크를 관리하는 기능이 포함되어 있습니다.

복제본을 통한 서비스 확장

2단계에서 설정한 Nginx 웹 서버가 너무 많은 트래픽을 받고 있다고 가정해보세요. web 서비스를 여러 컨테이너 인스턴스로 확장할 수 있습니다. Docker Compose가 이를 자동으로 관리할 수 있습니다.

서비스를 확장하는 데에는 두 가지 주요 방법이 있습니다.

1. replicas 키 사용하기 (v2에서 권장)

원하는 인스턴스 수를 docker-compose.yml 파일에서 deploy와 replicas 키를 사용하여 직접 정의할 수 있습니다. 이 기능은 원래 Docker Swarm의 일부였지만 이제는 일반 Compose 배포에서도 사용할 수 있습니다.

2단계에서 Nginx docker-compose.yml를 수정하세요:

services:
  web:
    image: nginx:alpine
    ports:
      - "8000:80"
    volumes:
      - ./app:/usr/share/nginx/html
    deploy:
      replicas: 3

당신이 docker compose up -d를 실행하면, Compose는 세 개의 web 컨테이너를 생성합니다. 하지만 문제가 하나 있습니다. 세 컨테이너 모두 호스트 포트 8000에 바인딩하려고 시도합니다. 이로 인해 두 번째와 세 번째 컨테이너에서는 “포트가 이미 할당되어 있음” 오류가 발생합니다. 프로덕션 환경에서는 이를 해결하기 위해 web 서비스에서 ports 매핑을 제거해야 합니다. 이렇게 하면 웹 컨테이너들은 Docker 네트워크 내부에서만 접근할 수 있습니다. 별도의 로드 밸런서 서비스만이 공개 포트를 가지고 있어야 하며, 이 서비스가 세 개의 웹 복제본에 트래픽을 분배하게 됩니다.

예시 구성은 다음과 같이 보일 수 있습니다(이것은 고급 예시입니다):

services:
  web:
    image: nginx:alpine
    # No 'ports' mapping here.
    # The service is only accessible inside the 'web-net' network.
    volumes:
      - ./app:/usr/share/nginx/html
    deploy:
      replicas: 3
    networks:
      - web-net

  load_balancer:
    image: nginx:latest
    ports:
      - "80:80" # The load_balancer is the only service with a public port.
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf # A config file that load balances to 'web'.
    networks:
      - web-net
    depends_on:
      - web

networks:
  web-net:

이 구성에서 load_balancer는 포트 80에서 수신 대기하며 요청을 내부적으로 web_1, web_2, web_3로 라우팅합니다.

이 replicas 키는 Docker 네트워크 내에서 각 복제본이 호스트에 포트를 노출할 필요 없이, 복제본 간에 요청을 로드 밸런싱할 수 있는 리버스 프록시(예: Traefik 또는 다른 Nginx 인스턴스)와 함께 사용할 때 가장 유용합니다.

2. --scale 플래그 사용하기

스케일링의 일반적인 방법은 Compose v1에서 이어진 --scale 플래그입니다. 이 플래그는 실행 시 적용되며, replicas 키를 덮어씁니다.

그러나 포트 정의에는 주의해야 합니다. 서비스가 고정 호스트 포트 매핑을 정의한 경우(예: "8000:80"), docker compose up --scale를 실행하면 두 번째 및 세 번째 컨테이너가 모두 동일한 호스트 포트에 바인딩하려고 하므로 오류가 발생합니다.

포트를 노출하는 서비스에서 --scale를 사용하려면 고정된 호스트 포트 매핑을 사용하면 안 됩니다.

  • 옵션 1: 랜덤 호스트 포트에 매핑 (개발에 적합)

    컨테이너 포트만 지정하도록 docker-compose.yml 파일을 수정할 수 있습니다. 이렇게 하면 Docker가 각 컨테이너의 포트 80을 호스트 머신에서 사용할 수 있는 임의의 포트에 매핑하도록 지시합니다.

    services:
      web:
        image: nginx:alpine
        ports:
          - "80" # No fixed host port
        volumes:
          - ./app:/usr/share/nginx/html

    이제 scale 명령어를 실행하면:

    docker compose up -d --scale web=3

    결과를 확인하려면 docker compose ps를 실행하세요. 각 컨테이너는 서로 다른, 무작위로 할당된 호스트 포트에서 실행됩니다:

          Name                     Command               State          Ports        
    ----------------------------------------------------------------------------------
    compose-demo_web_1   /docker-entrypoint.sh ngin ...   Up      0.0.0.0:49154->80/tcp
    compose-demo-web_2   /docker-entrypoint.sh ngin ...   Up      0.0.0.0:49155->80/tcp
    compose-demo-web_3   /docker-entrypoint.sh ngin ...   Up      0.0.0.0:49156->80/tcp
  • docker-compose.yml - --scale에 맞게 수정

  • 옵션 2: 리버스 프록시 사용 (프로덕션에 적합)

    앞서 replicas 섹션에서 언급한 또 다른 해결책은 web 서비스에서 ports 지시문을 아예 제거하는 것입니다. 그런 다음 별도의 로드 밸런서 컨테이너(유일한 공개 포트를 가진)를 사용하여 Docker 네트워크 내에서 확장된 복제본으로 트래픽을 관리하고 분배하게 됩니다.

    세 개의 컨테이너를 모두 중지하고 제거하려면 명령어는 동일합니다:

    docker compose down

맞춤 네트워크 구성

기본적으로 Docker Compose는 애플리케이션을 위해 단일 bridge 네트워크를 생성합니다. 파일에 있는 모든 서비스는 이 네트워크에 연결되며, 이 때문에 wordpress 컨테이너가 단순히 서비스 이름(db)만으로 db 컨테이너를 찾을 수 있었습니다.

하지만 더 나은 격리와 제어를 위해 자체 맞춤 네트워크를 정의할 수 있습니다.

WordPress 예제를 사용자 정의 bridge 네트워크를 사용하도록 수정해 봅시다.

services:
  db:
    image: mysql:8.0
    ...
    networks:
      - app_net

  wordpress:
    image: wordpress:latest
    ...
    ports:
      - "8001:80"
    depends_on:
      - db
    networks:
      - app_net

volumes:
  db_data:

networks:
  app_net:
    driver: bridge

추가한 내용은 다음과 같습니다:

  • networks (최상위 레벨): 이는 app_net라는 새 네트워크를 정의하며, 표준 bridge 드라이버를 사용하도록 지정합니다.
  • networks (서비스 수준): db와 wordpress 모두에서, 이 키는 이들을 우리의 app_net 네트워크에 연결합니다.

만약 app_net에 연결하지 않은 세 번째 서비스(예: 분석 도구)가 있다면, 해당 서비스는 완전히 격리되어 db나 wordpress 컨테이너와 통신할 수 없습니다.

멀티 호스트 클러스터링을 위해 Docker Swarm을 사용할 때는 driver를 bridge에서 overlay로 변경합니다. bridge 드라이버는 단일 호스트 내의 컨테이너 간 통신을 위해 사용되며, 대부분의 Docker Compose 사용 사례에서는 표준입니다.

모듈식 구성 파일 사용

애플리케이션이 커짐에 따라 docker-compose.yml 파일이 커지고 관리하기 어려워질 수 있습니다. Docker Compose는 include 지시어를 지원하여 구성 파일을 여러 파일로 나눌 수 있습니다.

워드프레스와 데이터베이스 정의를 분리하고 싶다고 상상해 보세요. 그리고 개발 특화 설정(예: 데이터베이스 포트 바인딩)을 위한 공통 docker-compose.override.yml 파일을 가질 수도 있습니다.

디렉토리 구조는 다음과 같이 보일 수 있습니다:

compose-demo/
├── docker-compose.yml
├── docker-compose.db.yml
├── docker-compose.web.yml

이 파일은 오직 db 서비스를 정의할 것입니다.

services:
  db:
    image: mysql:8.0
    container_name: mysql_db
    volumes:
      - db_data:/var/lib/mysql
    environment:
      MYSQL_ROOT_PASSWORD: <^your_root_password_here<^>
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wordpress_user
      MYSQL_PASSWORD: <^your_wordpress_password_here<^>
    restart: unless-stopped

volumes:
  db_data:

이 파일은 오직 wordpress 서비스를 정의할 것입니다.

services:
  wordpress:
    image: wordpress:latest
    container_name: wordpress_app
    ports:
      - "8001:80"
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: wordpress_user
      WORDPRESS_DB_PASSWORD: <^your_wordpress_password_here<^>
      WORDPRESS_DB_NAME: wordpress
    volumes:
      - ./wp_content:/var/www/html/wp-content
    depends_on:
      - db
    restart: unless-stopped

이제 여러분의 주요 docker-compose.yml 파일은 매우 간단해집니다. 단순히 include를 사용하여 다른 파일들을 불러오기만 하면 됩니다.

include:
  - docker-compose.db.yml
  - docker-compose.web.yml

docker compose up -d를 실행하면, Compose는 세 파일 모두를 읽고 구성을 병합하여 db와 wordpress 서비스를 마치 하나의 파일에 정의된 것처럼 정확히 시작합니다. 이 접근 방식은 구성 설정을 훨씬 더 모듈화하고 재사용 가능하게 만듭니다.

참고: include: 지시문은 Docker Compose v2.20 이상이 필요합니다. 시스템에 더 오래된 버전이 설치되어 있다면, docker compose -f docker-compose.db.yml -f docker-compose.web.yml up를 사용하여 파일을 결합할 수 있습니다.

docker-compose (v1)에서 docker compose (v2)로 이전하기

1단계에서 설치한 docker compose 명령어는 'Compose v2'입니다. 이는 Docker CLI에 직접 내장된 Go 기반 플러그인입니다.

원래 버전인 'Compose v1'은 docker-compose(하이픈 포함)로 호출되는 별도의 Python 도구였습니다. 2023년 7월 이후로 Compose v1은 더 이상 지원되지 않으며 사용이 중단되었습니다.

주요 변경 사항 및 이전 버전 호환성

  • 명령어: 가장 눈에 띄는 변화는 명령어입니다. 하이픈(docker-compose)이 이제 공백(docker compose)으로 변경되었습니다.
  • 설치: v1은 pip로 설치되었습니다. v2는 Docker Desktop에 포함되어 있거나 1단계에서 했던 것처럼 CLI 플러그인으로 설치됩니다.
  • YAML 파일: 당신의 docker-compose.yml 파일은 거의 100% 이전 버전과 호환됩니다. Compose v2는 파일 버전 3.x를 완전히 지원합니다. 마이그레이션을 위해 YAML 파일을 변경할 필요는 없으며, 명령어만 변경하면 됩니다.
  • --project-name 플래그: -p 플래그도 여전히 작동하지만, 전체 플래그는 이제 --project_name 대신 --project-name입니다.

명령 마이그레이션 가이드

대부분의 명령어는 동일하며, 단지 하이픈이 제거되었을 뿐입니다. 다음은 일반적인 v1 명령어와 v2 명령어를 비교한 표입니다.

docker-compose (v1) 명령어docker compose (v2) 명령어노트
docker-compose up -d
docker compose up -d
구문에는 변화가 없습니다.
docker-compose down
docker compose down
구문에는 변화가 없습니다.
docker-compose ps
docker compose ps
구문에는 변화가 없습니다.
docker-compose logs
docker compose logs
구문에는 변화가 없습니다.
docker-compose stop
docker compose stop
구문에는 변화가 없습니다.
docker-compose build
docker compose build
구문에는 변화가 없습니다.
docker-compose exec web bash
docker compose exec web bash
구문에는 변화가 없습니다.
docker-compose run web bash
docker compose run web bash
`run`은 새 컨테이너를 생성합니다. `exec`는 기존 컨테이너에서 실행됩니다.
docker-compose up --scale web=3
docker compose up --scale web=3
--scale 플래그는 여전히 v2에서 지원됩니다.

보시다시피, 대부분의 일상적인 사용에서는 유일한 변화가 docker-compose -> docker compose 입니다. 스크립트를 사용하는 경우, 하이픈을 제거하기만 하면 쉽게 업데이트할 수 있습니다.

만약 여전히 오래된 docker-compose v1이 설치되어 있다면, 혼동을 피하기 위해 제거할 수 있습니다:

sudo pip3 uninstall docker-compose

또는 apt로 설치한 경우:

sudo apt remove docker-compose

일반적인 Docker Compose 문제 해결

Docker Compose를 사용하다 보면 파일 구문, 권한, 또는 컨테이너 실행 충돌과 관련된 문제가 발생할 수 있습니다. 대부분의 문제는 구성, 권한, 컨테이너 로그를 체계적으로 확인하여 진단하고 해결할 수 있습니다.

가장 흔한 오류와 그 해결 방법을 살펴보겠습니다.

권한 거부 (도커 소켓)

이것은 새로운 Docker 사용자가 가장 흔히 겪는 오류 중 하나입니다. docker compose up를 실행하면 Docker 데몬 소켓에 관한 오류 메시지가 표시됩니다.

permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock
  • 문제: 비루트 사용자에게는 root로 실행되는 Docker 데몬과 통신할 권한이 없습니다.

  • 해결책: Docker 설치 중 생성된 docker 그룹에 사용자를 추가해야 합니다.

    1. 사용자를 docker 그룹에 추가하세요:

      sudo usermod -aG docker ${USER}
    2. 새 그룹 멤버십을 적용하려면 로그아웃한 후 다시 로그인해야 합니다.

    3. 또는 다음을 입력하여 현재 터미널 세션에서 그룹 변경을 활성화할 수 있습니다:

      newgrp docker

    이렇게 하면 Docker 소켓과 관련된 권한 오류가 해결됩니다.

YAML 구문 및 들여쓰기 오류

Docker Compose가 실행되지 않으며 docker-compose.yml 파일이 잘못되었다고 보고합니다.

ERROR: The Compose file './docker-compose.yml' is invalid because:
services.web.ports contains an invalid type, it should be a list

또는 :

mapping values are not allowed in this context at line 5
  • 문제: docker-compose.yml 파일은 엄격한 YAML 문법에 의존합니다. 가장 흔한 실수는 잘못된 들여쓰기입니다. YAML은 구조를 정의할 때 탭이 아닌 공백을 사용합니다.
  • 해결 방법: docker-compose.yml 파일의 들여쓰기를 꼼꼼히 확인하세요.

    • 표준은 각 들여쓰기 단계마다 두 칸입니다.
    • 모든 같은 수준의 키(예: version, services, volumes)가 같은 열에서 시작되도록 하세요.
    • 모든 하위 키(예: image, ports, volumes가 서비스 아래에 있을 경우)가 부모 서비스(예: web)보다 두 칸 더 들여쓰기 되어 있는지 확인하세요.
    • YAML 린터가 있는 코드 편집기를 사용하여 구문 오류를 자동으로 강조 표시하세요.

포트 충돌

환경을 시작하려고 시도하지만, 주소가 이미 사용 중이라는 오류 메시지와 함께 명령이 실패합니다.

Error starting userland proxy: listen tcp 0.0.0.0:8000: bind: address already in use
  • 문제: 호스트 머신에서 이미 다른 프로세스가 매핑하려는 포트(이 경우 8000 포트)를 사용 중입니다. 이는 종종 다른 Docker 컨테이너나 로컬 개발 서버일 수 있습니다.

  • 해결책: 선택할 수 있는 두 가지 옵션이 있습니다:

    1. 다른 프로세스를 중지하세요. 이 명령어로 포트를 사용 중인 프로세스를 찾을 수 있습니다:

      sudo lsof -i :8000

      다른 Docker 컨테이너라면, docker stop <container_id> 명령어로 중지하세요.

    2. 호스트 포트를 docker-compose.yml 파일에서 변경하세요. 이것이 가장 간단한 해결 방법인 경우가 많습니다. ports 매핑을 "8000:80"에서 "8001:80"와 같이 다른 포트로 변경하세요.

      ...
      ports:
        - "8001:80" # Changed from 8000
      ...
    3. docker-compose.yml

서비스가 Connection Refused (depends_on) 오류로 실패합니다

다중 서비스 애플리케이션(예: WordPress와 MySQL 예제)에서 wordpress 컨테이너는 시작되지만, db 서비스에 연결하려고 할 때 로그에 Connection refused 또는 MySQL server has gone away가 표시될 수 있습니다.

  • 문제: depends_on를 사용하셨지만, 이 지시어는 db 컨테이너가 시작될 때까지만 대기합니다. 컨테이너 내부의 MySQL 애플리케이션이 완전히 초기화되어 연결을 받을 준비가 될 때까지 기다리지는 않습니다.

  • 해결 방법: 애플리케이션(이 경우 WordPress)은 연결을 재시도하도록 구성되어야 합니다. 대부분의 최신 이미지에는 이 재시도 로직이 내장되어 있습니다. 내장되지 않은 이미지의 경우, 건강 상태 점검(healthcheck)을 구현해야 합니다.

    당신은 db 서비스에 healthcheck를 추가할 수 있습니다. 그러면 wordpress 서비스의 depends_on는 데이터베이스가 단순히 "시작됨"이 아니라 "정상 상태(healthy)"가 될 때까지 기다리도록 구성할 수 있습니다.

MySQL 예제 헬스체크:

services:
  db:
    image: mysql:8.0
    ...
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p<^your_root_password_here<^>"]
      interval: 10s
      timeout: 5s
      retries: 5

  wordpress:
    image: wordpress:latest
    ...
    depends_on:
      db:
        condition: service_healthy # This now waits for the healthcheck
    ...

볼륨 및 바인드 마운트 오류

컨테이너 로그에서 권한 오류가 발생하거나, 컨테이너의 데이터 디렉터리가 비어 있는 것을 발견할 수 있습니다.

파일/디렉터리 권한

  • 문제: 컨테이너가 특정 사용자로 실행됩니다(예: 사용자 ID 33인 www-data). 그러나 마운트한 호스트 디렉터리는 당신의 사용자(예: 사용자 ID 1000인 ubuntu)가 소유하고 있습니다. 컨테이너 사용자에게는 호스트 디렉터리에 쓰기 권한이 없습니다.

  • 해결 방법: 호스트 디렉토리의 소유권을 컨테이너 내부의 사용자 ID와 일치하도록 변경하세요. 컨테이너의 사용자 ID는 docker compose exec <service_name> id 명령어를 실행하면 확인할 수 있습니다. 예를 들어, ID가 33이라면 (일반적으로 www-data의 경우):

    sudo chown -R 33:33 ./wp_content

상대 경로 문제

  • 문제: 당신의 docker-compose.yml 파일은 ./app과 같은 상대 경로를 사용하고 있지만, index.html 파일이 제공되지 않습니다.

  • 해결 방법: Docker Compose는 상대 경로를 docker compose up 명령을 실행하는 디렉토리를 기준으로 해석합니다. 항상 docker-compose.yml 파일이 있는 동일한 디렉토리에서 Compose 명령을 실행하세요.

네트워킹 및 서비스 검색

애플리케이션 컨테이너 로그에 Host not found 또는 Could not resolve host: db가 표시됩니다.

  • 문제: 여러분의 wordpress 컨테이너가 네트워크에서 db 컨테이너를 찾을 수 없습니다.
  • 해결책: 기본적으로 Docker Compose는 네트워크를 생성하고 모든 서비스를 해당 네트워크에 연결합니다. 서비스들은 서로의 서비스 이름을 사용하여 서로를 찾을 수 있습니다.

    1. 서비스 이름 확인: 애플리케이션 구성에서 호스트 이름(예: WORDPRESS_DB_HOST 환경 변수)이 docker-compose.yml의 서비스 이름(예: db)과 정확히 일치하는지 확인하세요.

    2. 네트워크 확인: docker compose ps를 사용하여 프로젝트 이름(e.g., compose-demo)을 찾습니다. 그런 다음 기본 네트워크를 확인합니다:

      docker network inspect compose-demo_default

      JSON 출력은 이 네트워크에 연결된 모든 컨테이너를 나열합니다. 서비스 중 하나가 누락되었다면, 해당 서비스가 격리될 수 있는 사용자 정의 networks 설정이 있는지 docker-compose.yml을 확인하세요.

명령 불일치 (v1 대 v2)

하이픈을 포함하여 docker-compose up를 입력하면 'command not found' 오류가 발생합니다.

docker-compose: command not found
  • 문제: 더 이상 사용되지 않는 Python 도구인 Compose v1 명령어를 사용하려고 하고 있습니다. 이 가이드는 Docker CLI에 직접 통합된 플러그인인 Compose v2를 설치합니다.
  • 해결 방법: 하이픈(-)을 공백으로 바꿔 올바른 명령어를 사용하세요.
docker-compose (v1)docker compose (v2)
docker-compose updocker compose up
docker-compose downdocker compose down
docker-compose psdocker compose ps
docker-compose 로그docker compose 로그

이 가이드를 따를 때는 항상 docker compose (공백 포함)을 사용하세요.

자주 묻는 질문

1. Docker Compose는 무엇에 사용되나요?

Docker Compose는 여러 컨테이너로 구성된 Docker 애플리케이션을 정의하고 실행하기 위한 도구입니다.

이는 모든 애플리케이션 구성 요소를 구성하기 위해 단일 YAML 파일(기본값은 docker-compose.yml)을 사용하며, 이러한 구성 요소를 서비스라고 합니다. 이 파일은 또한 서비스가 서로 통신할 수 있도록 하는 네트워크와 영구 데이터를 위해 사용되는 볼륨도 정의합니다.

이 단일 파일로 간단한 명령어만으로 전체 애플리케이션 스택을 관리할 수 있습니다:

  • docker compose up는 지정된 모든 컨테이너, 네트워크 및 볼륨을 포함하여 전체 애플리케이션을 시작하고 실행합니다.
  • `docker compose down` 은(는) 애플리케이션에서 생성한 모든 컨테이너, 네트워크, 볼륨을 중지하고 제거합니다.

이는 웹 서버(예: Nginx), 애플리케이션 백엔드(예: WordPress), 데이터베이스(예: MySQL)와 같이 여러 구성 요소가 필요한 애플리케이션을 관리하는 데 가장 유용합니다.

2. Ubuntu에 Docker Compose를 어떻게 설치하나요?

권장 방법은 Docker CLI용 플러그인으로 Docker Compose를 설치하는 것입니다. 이는 Docker의 공식 apt 저장소에서 docker-compose-plugin 패키지를 설치하여 수행됩니다.

  1. 먼저, Ubuntu 시스템에 Docker의 apt 저장소를 설정하기 위해 공식 Docker 문서를 따라 했는지 확인하세요.

  2. 패키지 목록을 업데이트하세요:

    sudo apt update
  3. Docker Compose 플러그인을 설치하세요:

    sudo apt install docker-compose-plugin
  4. 버전을 확인하여 설치를 검증하세요. 명령어에는 하이픈이 아니라 공백을 사용합니다.

    docker compose version

3. Docker Compose를 최신 버전으로 업데이트하려면 어떻게 해야 하나요?

Docker Compose(v2)는 apt를 사용하여 시스템 패키지로 설치되었기 때문에 표준 Ubuntu 소프트웨어 업데이트 과정을 통해 업데이트할 수 있습니다.

  1. 로컬 패키지 인덱스를 새로 고치세요:

    sudo apt update
  2. Compose 플러그인을 포함한 시스템 전체 업그레이드를 실행하세요:

    sudo apt upgrade

    또는 플러그인 자체만 업데이트하고 싶다면 다음 명령을 실행할 수 있습니다:

    sudo apt install --only-upgrade docker-compose-plugin

4. Docker Compose를 프로덕션 환경에서 사용할 수 있나요?

네, Docker Compose는 특히 단일 호스트에서 실행되는 애플리케이션의 경우 프로덕션 환경에서도 자주 사용됩니다.

애플리케이션의 서비스, 네트워크 및 볼륨의 수명 주기를 정의, 배포 및 관리하는 직관적인 방법을 제공합니다. 단일 서버 배포의 경우 매우 효과적이고 관리가 쉬운 솔루션입니다.

여러 호스트(multiple hosts)에 걸쳐 컨테이너를 조율해야 하는 더 복잡한 시나리오의 경우, 다른 도구들이 더 일반적으로 사용됩니다. 여기에는 Docker Swarm(유사한 Compose 파일 구문을 사용)과 Kubernetes(대규모 컨테이너 오케스트레이션에 대한 업계 표준)가 포함됩니다.

5. Docker와 Docker Compose의 차이점은 무엇인가요?

이 표는 Docker CLI와 Docker Compose CLI 간의 주요 차이점을 설명합니다.

기능도커 (Docker 엔진)docker compose (컴포즈 플러그인)
범위개별 Docker 객체를 관리합니다.완전한 멀티 컨테이너 애플리케이션을 단일 단위로 관리합니다.
주요 용도이미지 빌드(docker build), 단일 컨테이너 실행(docker run), 컨테이너 관리(docker ps), 이미지, 볼륨, 네트워크 관리.docker-compose.yml 파일에 정의된 여러 서비스를 조율하기.
명령어하나의 객체에 집중된 저수준 명령어. 예시: docker run -d -p 80:80 -v ./:/app nginx애플리케이션 전체를 위한 고급 명령어. 예: docker compose up
유추하나의 빌딩 블록 (단일 컨테이너).전체 건물(애플리케이션)의 청사진과 건설 관리자.

요약하면, docker는 단일 컨테이너와 상호작용할 때 사용하고, docker compose는 웹, 앱, 데이터베이스 등 전체 애플리케이션 스택을 한 번에 관리할 때 사용합니다.

6. Docker Compose로 여러 컨테이너를 어떻게 실행하나요?

여러 컨테이너를 docker-compose.yml 파일에서 서비스로 정의하여 실행할 수 있습니다.

  1. docker-compose.yml라는 이름의 파일을 만드세요.

  2. 이 파일 안에서 services: 키를 사용하여 실행하려는 각 컨테이너를 정의하세요.

    다음은 두 개의 컨테이너를 정의하고 실행하는 실제 예제입니다: 워드프레스 사이트와 MySQL 데이터베이스.

    services:
      db:
        # This is the first service (container)
        image: mysql:8.0
        environment:
          MYSQL_ROOT_PASSWORD: <^your_password_here<^>
          MYSQL_DATABASE: wordpress
        volumes:
          - db_data:/var/lib/mysql
    
      wordpress:
        # This is the second service (container)
        image: wordpress:latest
        ports:
          - "8001:80"
        environment:
          WORDPRESS_DB_HOST: db
          WORDPRESS_DB_PASSWORD: <^your_password_here<^>
        depends_on:
          - db
    
    volumes:
      db_data:
  3. docker-compose.yml

  4. 파일을 저장하고 동일한 디렉토리에서 터미널을 열세요.

  5. 두 컨테이너를 시작하려면 단일 명령어를 실행하세요:

    docker compose up -d

Docker Compose는 파일을 읽고, 서비스들을 위한 공유 네트워크를 생성하며, mysql과 wordpress 이미지를 모두 가져오고, 각 서비스에 대한 컨테이너를 시작합니다.

7. 개발 시 Docker Compose를 사용하는 이유는 무엇인가요?

Docker Compose는 여러 일반적인 문제를 해결하기 때문에 개발 환경에서 표준 도구로 사용됩니다.

  • 일관된 환경: 팀의 모든 개발자가 동일한 서비스(데이터베이스, 캐시, 웹 서버)를 동일한 버전과 설정으로 실행하도록 보장합니다. 이는 버전 관리에 커밋되는 docker-compose.yml 파일에 정의되어 있습니다. 이를 통해 '내 컴퓨터에서는 잘 되는데'라는 문제를 없앨 수 있습니다.

  • 단순함: 복잡한 설정 스크립트와 긴 docker run 명령어를 대체합니다. 개발자는 단지 docker compose up을 실행하여 전체 애플리케이션 스택을 시작하고, docker compose down을 실행하여 이를 중지하면 됩니다.

  • 서비스 격리: 개발자들은 의존성 충돌 없이 동일한 기기에서 여러 프로젝트를 작업할 수 있습니다. 프로젝트 A는 PostgreSQL 9.6을 사용하고 프로젝트 B는 PostgreSQL 14를 사용할 수 있으며, 각각의 데이터베이스는 자체 Compose 파일로 관리되는 격리된 컨테이너에서 실행됩니다.

  • 손쉬운 통합 테스트: Compose는 애플리케이션의 모든 종속성을 함께 시작하기 때문에, 서비스들이 서로 어떻게 상호작용하는지 검증하는 통합 테스트를 실행할 수 있는 완벽한 로컬 환경을 제공합니다.

결론

이 가이드에서는 Docker Compose를 설치하고 완전한 다중 컨테이너 애플리케이션을 구성했습니다. Nginx 웹 서버를 위한 기본 docker-compose.yml 파일로 시작하여 WordPress 애플리케이션과 MySQL 데이터베이스를 포함한 보다 복잡하고 현실적인 스택으로 진행했습니다. 서비스를 빌드하고 실행하는 것부터 중지하고 제거하는 것까지 전체 애플리케이션 수명 주기를 관리하는 방법을 배웠습니다.

이제 서비스 확장, 사용자 정의 네트워크 정의, include 지시어를 사용하여 구성 파일을 모듈화하는 방법 등 애플리케이션을 효과적으로 관리하기 위한 핵심 개념에 익숙해졌습니다. 마이그레이션 가이드와 문제 해결 단계를 따르면 포트 충돌, '권한 거부' 오류, YAML 구문 오류와 같은 일반적인 문제도 해결할 수 있습니다. 여기서 다룬 기술을 통해 일관되고 재현 가능한 개발 환경을 구축하고 단일 호스트 애플리케이션을 자신 있게 배포할 수 있습니다.

사용 가능한 모든 docker compose 명령어에 대한 완전한 참조는 공식 문서를 확인하세요.

Docker 관련 튜토리얼에 대해 더 알아보려면 다음 글을 확인해 보세요:

  • 우분투에 Docker 설치하는 방법 – 단계별 가이드
  • Docker Compose로 워드프레스 설치하는 방법

Linux-Console.net 커뮤니티와 함께 학습해 주셔서 감사합니다.