Docker 고급기능(볼륨, 환경변수, docker-compose)

choiJaewon·2026년 2월 19일
post-thumbnail

개요

이번에는 docker 의 기초기능에 이어서 docker의 고급 기능에 대해서 알아보고자 한다.



1. 데이터 관리와 볼륨 (Data Management & Volumes)

레이어와 컨테이너의 관계

docker build 명령어를 실행하면 도커 이미지가 생성된다. 이때 코드 및 환경은 Read-Only로 저장되는데, 그럼 데이터는 어떻게 관리할까?

도커 이미지는 여러 개의 이미지 레이어(Image Layer) 로 구성되고, 컨테이너가 실행될 때 최상단에 쓰기 가능한 컨테이너 레이어(Container Layer) 가 추가된다.

Container
├── Container Layer  ← Writable
├── Image Layer
├── Image Layer      ← Non-Writeable
├── Image Layer
└── Base Layer

도커에서의 데이터 종류

종류설명
ApplicationCode와 환경 (종속성). Read-Only로 저장되며 이미지와 컨테이너에 포함
임시 App 데이터컨테이너 내부에서 생성되는 데이터 (변수, 임시 파일 등). 메모리에 저장되고 컨테이너 실행 중에만 존재
Permanent App 데이터컨테이너가 종료되어도 남아있어야 하는 데이터. 데이터베이스, 로그 파일, 사용자 업로드 파일 등

💡 Permanent App 데이터를 다루려면 볼륨(Volume) 이 필요하다.


볼륨 (Volume)

볼륨이란?

볼륨 = 우리가 지정한 폴더

  • 도커 볼륨은 도커 컨테이너에서 생성된 데이터를 저장하는 디렉토리이다.
  • 컨테이너가 종료되어도 데이터가 남아있어야 하는 경우에 사용한다.
  • 호스트와 컨테이너 간 데이터 공유도 가능하다.
  • 볼륨은 컨테이너의 파일 시스템과 호스트의 파일 시스템 간에 데이터들을 공유한다.

볼륨은 호스트 머신에서 폴더들로 구성되고, 컨테이너가 생성 또는 시작될 때 마운트(Mount, mapped) 된다.


COPY vs VOLUME (Dockerfile)

Dockerfile에서 COPYVOLUME의 차이점을 명확히 구분해야 된다.

명령어설명
COPY파일을 이미지에 복사
VOLUME호스트의 파일을 컨테이너에 마운트
  • 마운트된 파일은 호스트 머신에서 수정하면 변경사항이 바로 반영된다.
  • 컨테이너가 종료 또는 삭제되어도 데이터는 남아있어

💡 마운트란? 다른 컴퓨터에 있는 디렉토리를 내 컴퓨터로 가져와서 사용하는 것


볼륨의 종류

1. Named Volume (명명된 볼륨)

이름을 가지고 있는 볼륨으로, Dockerfile에서는 생성할 수 없고 명령어로 생성해야 된다.

# 볼륨 생성
docker volume create <volume_name>

# 볼륨 목록 확인
docker volume ls

# 볼륨 삭제
docker volume rm <volume_name>

컨테이너 생성 시 Named Volume 연결:

docker run -v <volume_name>:<directory> <image_name>

2. Anonymous Volume (익명 볼륨)

이름이 없는 볼륨으로 임시 볼륨이라고도 한다.

  • 명명된 볼륨과 달리, 컨테이너가 삭제되면 자동으로 같이 삭제된다.

Bind Mount

볼륨은 도커 데몬이 관리하기 때문에 호스트와 컨테이너 간의 데이터 공유가 어렵다. 이럴 때 Bind Mount를 쓰면 된다.

  • 볼륨과 유사하지만 호스트의 디렉토리를 직접 컨테이너에 볼륨으로 사용
  • 코드처럼 지속적으로 업데이트가 필요한 데이터를 컨테이너에 바로 반영할 때 유용하다.

Bind Mount 생성:

docker run -v <host_directory>:<container_directory> <image_name>
  • Host 디렉토리는 절대 경로로 지정해야 된다.
    • macOS: $(pwd):/app
    • Windows: "%cd%":/app

Volume vs Bind Mount 비교

구분VolumeBind Mount
관리 주체Docker 데몬사용자 (호스트)
경로 지정볼륨 이름호스트 절대 경로
주요 용도DB, 영구 데이터 저장코드, 실시간 업데이트
컨테이너 삭제 시Named: 유지 / Anonymous: 삭제호스트 파일 유지
Docker Host
├── Volumes     → Docker Area (Docker 관리)
└── Bind Mounts → Host File System (사용자 관리)

결론은?

데이터 유지가 필요한가?
├── Yes
│   ├── 호스트 경로를 직접 지정하고 싶다 → Bind Mount
│   └── Docker가 관리해도 된다
│       ├── 이름이 필요하다 → Named Volume
│       └── 임시로만 사용 → Anonymous Volume
└── No → 컨테이너 레이어에 저장 (컨테이너 삭제 시 사라짐)

개발 환경에서 코드 변경 사항을 실시간 반영하려면 Bind Mount를,
운영 환경에서 DB나 업로드 파일 같은 영구 데이터 보관에는 Named Volume을 주로 쓰면 된다.

2. 환경 변수 & 네트워크

환경 변수 (Environment Variables)

ARG vs ENV

구분설명사용 범위
ARGDockerfile 내에서 사용되는 변수이미지 빌드 시에만 사용, CMD나 코드에서는 접근 불가
ENVDockerfile 내에서 사용되는 환경 변수컨테이너 실행 시에도 사용 가능, CMD나 코드에서 접근 가능

💡 ARG와 ENV를 함께 사용하면 이미지를 유연하게 빌드하고 컨테이너도 실행할 수 있다.


환경 변수 (ENV)

  • 컨테이너 내에서 사용되는 환경 변수를 설정하고 변경할 수 있다.
  • 환경 변수는 컨테이너 내에서 사용되는 변수이다.

실행 시 환경 변수 설정:

docker run -e (variable_name)=(value) (image_name)

Dockerfile에서 ENV 설정:

FROM python

WORKDIR /app

COPY . /app

ENV NUM 1000

CMD ["python", "main.py"]

인수 (ARG)

  • ARG는 Dockerfile 내에서 사용되는 변수이다,
  • ARG는 이미지 빌드 시에만 사용되고, ENV는 컨테이너 실행 시에 사용된다.
  • ARG를 사용하면 이미지 빌드 시에 변수를 설정할 수 있어

빌드 시 ARG 설정:

docker build --build-arg (variable_name)=(value) .

Dockerfile에서 ARG + ENV 함께 사용:

FROM python

ARG DEFAULT_NUM=1000

WORKDIR /app

COPY . /app

ENV NUM $DEFAULT_NUM

CMD ["python", "main.py"]

ARG로 빌드 시 기본값을 지정하고, 그 값을 ENV에 넘겨서 컨테이너 실행 시에도 쓸 수 있어!


도커 네트워크 (Docker Network)

도커 네트워크란?

  • 컨테이너 간 통신을 가능하게 하는 도커의 핵심 기능 중 하나이다.
  • 같은 네트워크 내에 있는 컨테이너들은 서로의 IP 또는 이름을 통해 통신할 수 있다.
  • 기본적으로 도커는 각 컨테이너가 격리된 상태로 실행되는데, 네트워크를 통해 격리된 상태를 유지하면서도 통신할 수 있다.

네트워크 생성:

docker network create (network_name)

# 예시
docker network create my-network

컨테이너 간의 통신 예시

MySQL과 Python 앱 컨테이너가 서로 통신하는 예시이다.

1. 네트워크 생성

docker network create my-network

2. MySQL 컨테이너 실행

docker run --name mysql-container --network my-network \
  -e MYSQL_ROOT_PASSWORD=1234 \
  -e MYSQL_DATABASE=testdb \
  -e MYSQL_USER=testuser \
  -e MYSQL_PASSWORD=1234 \
  -d mysql:latest

3. Python 컨테이너 실행

docker run --name python-container --network my-network \
  -e MYSQL_HOST=mysql-container \
  -e MYSQL_DATABASE=testdb \
  -e MYSQL_USER=testuser \
  -e MYSQL_PASSWORD=1234 \
  python-app

💡 --network 옵션으로 같은 네트워크에 묶으면, Python 컨테이너에서 mysql-container라는 이름만으로 MySQL에 접근할 수 있다!
IP를 직접 쓸 필요 없이 컨테이너 이름으로 통신이 가능해진다.


3. Docker compose

도커 컴포즈 (Docker Compose)

도커 컴포즈가 왜 필요할까?

다중 컨테이너 환경(예: MySQL + Python)을 운영할 때 다음과 같은 문제가 생긴다 :

  • 여러 개의 컨테이너를 실행할 때, 각 컨테이너마다 개별적으로 docker run 명령어를 실행해야한다.
  • 네트워크, 볼륨, 환경 변수 등 여러 설정을 수동으로 관리해야 해서 복잡도가 증가
  • 컨테이너 간의 의존성을 고려해 적절한 순서로 실행해야 하는데, 이를 일관되게 관리하기 어려움
  • 컨테이너를 재시작하거나 전체 환경을 재구성할 때 많은 반복 작업 필요
    -> 이런 문제들을 해결할 방법은?

Docker Compose란?

Docker Compose = 여러 컨테이너를 한 번에 build, run, stop할 수 있도록 도와주는 도구

  • 네트워크, 볼륨, 환경 변수 설정을 한 번에 정의하여 반복 작업을 줄일 수 있다.
  • 컨테이너 간의 의존성을 관리하고, 적절한 순서로 컨테이너를 실행한다.
  • 단일 명령어 docker-compose up을 통해 모든 컨테이너를 쉽게 시작, 정지 및 관리할 수 있다.

주의할 점

내용
Docker Compose는 도커 데몬이 실행 중인 환경에서만 사용 가능
Docker Compose는 Dockerfile을 대체하는 것이 아님
Docker Compose는 이미지와 컨테이너를 대체하는 것도 아님
여러 컨테이너를 하나의 호스트에서 관리하는 데 초점을 둔 도구이다.

Docker Compose 파일 구조

docker-compose.yaml 파일의 기본 구조는 각 서비스(컨테이너)를 정의하고 관리하기 위한 상위 레벨 요소들로 구성된다.

services:    # 여러 컨테이너를 정의
  컨테이너명:
    ...

volumes:     # 사용할 볼륨 정의

networks:    # 컨테이너 간 통신을 위한 네트워크 정의

services 세부 옵션

옵션설명
image컨테이너를 실행할 때 사용할 도커 이미지 지정
container_name컨테이너의 이름 지정 (미지정 시 Compose가 자동으로 생성)
context이미지를 빌드할 때 사용할 Dockerfile의 경로 지정
argsDockerfile 내에서 사용할 빌드 인수 정의 (ARG 명령어 활용)
build컨테이너 이미지를 직접 빌드할 때 사용. Dockerfile 경로나 빌드 컨텍스트를 지정하여 이미지를 생성
ports컨테이너 내부와 호스트 시스템 간의 포트 매핑. "호스트포트:컨테이너포트" 형태
environment컨테이너 실행 시 필요한 환경 변수 지정. KEY=VALUE 형식으로 작성
volumes호스트와 컨테이너 간의 파일 시스템을 공유하는 볼륨을 연결
networks컨테이너가 연결될 네트워크를 지정. 다른 서비스와의 통신을 위해 네트워크에 연결
depends_on한 서비스가 다른 서비스에 의존하는 경우, 해당 서비스가 먼저 실행될 수 있도록 지정

Docker Compose YAML 작성 규칙

  • 파일 이름: docker-compose.yaml로 지정해야 Docker Compose가 자동으로 인식한다.
  • 들여쓰기: YAML 파일은 들여쓰기(2칸 스페이스)를 통해 계층 구조를 표현해. 탭 사용하면 안 된다!
  • 순서 중요: 각 항목은 순서대로 지정해야 된다.
  • 주석: #로 주석 작성 가능

Docker Compose 주요 명령어

# 모든 서비스를 시작 (백그라운드 실행은 -d 옵션 추가)
docker-compose up
docker-compose up -d

# 현재 실행 중인 모든 컨테이너를 중지
docker-compose stop

# 현재 실행 중인 모든 컨테이너를 중지하고 네트워크와 함께 삭제
docker-compose down

# 실행 중인 컨테이너의 로그를 확인 (특정 서비스 로그만 보려면 서비스명 추가)
docker-compose logs
docker-compose logs 

env_file 설정

환경 변수를 docker-compose.yaml 안에 직접 작성하는 대신, .env 파일로 분리해서 관리할 수 있다.

  • .env 파일에 정의된 환경 변수를 불러올 수 있어
  • 컨테이너가 실행될 때 필요한 환경 변수를 KEY=VALUE 형식으로 저장한 파일을 사용한다.
services:
  web:
    env_file:
      - .env

💡 비밀번호나 API 키 같은 민감한 정보는 .env 파일로 분리하고 .gitignore에 추가하는 게 좋은 습관이다!


실습 예시 - docker-compose.yaml 전체 구조

services:

  # MySQL DB
  db:
    image: mysql:8.0
    container_name: mysql_db
    restart: unless-stopped
    environment:
      MYSQL_ROOT_PASSWORD: 1234
      MYSQL_DATABASE: mysql_db
      MYSQL_USER: testdb
      MYSQL_CHARSET: utf8mb4
      MYSQL_COLLATION: utf8mb4_unicode_ci
    ports:
      - "3306:3306"
    volumes:
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "--password=1234"]
      interval: 10s
      timeout: 5s
      retries: 5
      start_period: 30s

  # Spring Boot App (또는 Flask App)
  app:
    build:
      context: .
      dockerfile: Dockerfile
    container_name: myapp
    restart: unless-stopped
    depends_on:
      - db
    ports:
      - "8080:8080"
    environment:
      SPRING_DATASOURCE_URL: jdbc:mysql://db:3306/mysql_db?serverTimezone=Asia/Seoul&characterEncoding=UTF-8
      SPRING_DATASOURCE_USERNAME: root
      SPRING_DATASOURCE_PASSWORD: 1234
      JWT_SECRET: your_jwt_secret_key

volumes:
  mysql-data:

depends_on: db를 설정하면 MySQL이 먼저 실행된 후에 앱 컨테이너가 실행된다.


정리

docker-compose.yaml 하나로...
├── 여러 컨테이너를 한 번에 관리
├── 네트워크 자동 생성 및 연결
├── 볼륨 설정
├── 환경 변수 관리 (.env 파일 활용)
└── 컨테이너 의존성 순서 지정 (depends_on)

→ docker-compose up -d 한 줄이면 끝!

0개의 댓글