1편에서 이미지와 컨테이너를 다루는 명령어들을 정리했습니다. 2편에서는 내가 직접 이미지를 만드는 Dockerfile과, 여러 컨테이너를 묶어서 관리하는 Docker Compose를 다룹니다.
docker run 옵션을 외워서 매번 치는 건 한두 번이지, 실제로 쓰다 보면 이걸 파일로 관리하고 싶어집니다. Dockerfile과 Compose가 그 역할을 합니다.
Dockerfile
Dockerfile은 이미지를 만드는 레시피입니다. 어떤 베이스 이미지를 쓸지, 어떤 파일을 복사할지, 어떤 명령어를 실행할지를 순서대로 정의합니다.
기본 구조
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["python", "app.py"]
FROM — 베이스 이미지를 지정합니다. 모든 Dockerfile은 FROM으로 시작합니다.
FROM ubuntu:22.04
FROM python:3.11-slim # slim = 불필요한 패키지 제거한 경량 버전
FROM node:20-alpine # alpine = Alpine Linux 기반, 매우 작음
FROM scratch # 아무것도 없는 빈 이미지 (Go 같은 단독 실행 바이너리용)
WORKDIR — 이후 명령어가 실행될 작업 디렉토리를 지정합니다. 없으면 자동으로 만들어줍니다.
COPY / ADD — 호스트의 파일을 이미지 안으로 복사합니다. ADD보다 COPY를 쓰는 게 권장됩니다. 압축 해제나 URL 다운로드가 필요한 경우만 ADD를 씁니다.
COPY . . # 현재 디렉토리 전체를 WORKDIR로 복사
COPY requirements.txt . # 특정 파일만
RUN — 이미지 빌드 중 명령어를 실행합니다. RUN 하나가 레이어 하나이기 때문에, 여러 명령어는 &&로 연결해서 레이어를 줄이는 게 일반적입니다.
# 권장 — 레이어 1개
RUN apt-get update \
&& apt-get install -y curl \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
ENV / ARG
ENV APP_ENV=production # 런타임에도 유지되는 환경 변수
ARG VERSION=1.0 # 빌드 시점에만 쓰는 변수
EXPOSE — 컨테이너가 사용할 포트를 문서화합니다. 실제로 포트를 열지는 않고, -p로 매핑해야 합니다.
CMD / ENTRYPOINT
CMD ["python", "app.py"] # 기본 실행 명령 (docker run 시 덮어쓸 수 있음)
ENTRYPOINT ["python", "app.py"] # 고정 실행 명령
CMD는 docker run 뒤에 인수를 붙이면 덮어씌워지고, ENTRYPOINT는 뒤에 인수가 추가됩니다. 보통 ENTRYPOINT로 실행 파일을 고정하고, CMD로 기본 인수를 지정하는 조합을 씁니다.
ENTRYPOINT ["python"]
CMD ["app.py"] # docker run 이미지명 other.py 하면 other.py로 실행
USER — 보안상 root가 아닌 사용자로 실행하는 게 권장됩니다.
RUN useradd -m appuser
USER appuser
이미지 빌드
docker build -t myapp:1.0 . # 빌드
docker build -t myapp:latest -f Dockerfile.prod . # Dockerfile 파일 지정
docker build --build-arg VERSION=2.0 -t myapp . # ARG 값 전달
docker build --no-cache -t myapp . # 캐시 없이 빌드
.dockerignore
빌드 컨텍스트에서 불필요한 파일을 제외합니다. 없으면 node_modules나 .git이 통째로 전송돼서 빌드가 느려집니다.
.git
node_modules/
__pycache__/
.env
dist/
*.log
레이어 캐시 활용
Docker는 Dockerfile의 각 명령어 결과를 캐시합니다. 변경된 줄부터 이후는 캐시를 쓰지 않습니다. 자주 바뀌는 파일(소스 코드)은 뒤쪽에, 잘 안 바뀌는 것(의존성 설치)은 앞쪽에 두면 빌드가 빠릅니다.
# 비효율적 — 코드 변경마다 pip install이 다시 실행됨
COPY . .
RUN pip install -r requirements.txt
# 효율적 — requirements.txt가 바뀌지 않으면 캐시 사용
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
Docker Compose
여러 컨테이너를 함께 관리하는 도구입니다. 웹 서버 + DB + 캐시처럼 여러 서비스가 엮인 구조를 compose.yaml 파일 하나로 정의하고 한 번에 올리고 내립니다.
기본 구조
# compose.yaml
services:
web:
build: .
ports:
- "8000:8000"
environment:
- DB_HOST=db
depends_on:
- db
volumes:
- .:/app
db:
image: postgres:16
environment:
POSTGRES_PASSWORD: secret
POSTGRES_DB: mydb
volumes:
- pgdata:/var/lib/postgresql/data
redis:
image: redis:7-alpine
volumes:
pgdata:
같은 Compose 파일 안의 서비스끼리는 서비스 이름으로 서로를 찾을 수 있습니다. 위 예시에서 web 서비스가 DB_HOST=db로 postgres에 접근하는 것처럼요. 별도로 네트워크를 만들지 않아도 됩니다.
주요 필드
services:
서비스명:
image: 이미지명 # 기존 이미지 사용
build: . # Dockerfile로 직접 빌드
build:
context: .
dockerfile: Dockerfile.dev
ports:
- "호스트:컨테이너"
volumes:
- ./local:/container # bind mount
- named_vol:/path # named volume
environment:
KEY: value
env_file:
- .env
depends_on:
- 다른서비스명
restart: unless-stopped
command: python app.py # CMD 덮어쓰기
주요 명령어
docker compose up -d # 전체 서비스 백그라운드 시작
docker compose up --build # 이미지 재빌드 후 시작
docker compose up 서비스명 # 특정 서비스만 시작
docker compose down # 서비스 중지 + 컨테이너 삭제
docker compose down -v # 볼륨까지 삭제
docker compose down --rmi all # 이미지까지 삭제
docker compose ps # 서비스 상태 확인
docker compose logs -f # 전체 실시간 로그
docker compose logs -f web # 특정 서비스 실시간 로그
docker compose exec web bash # 실행 중인 서비스에 쉘 접속
docker compose run web pytest # 서비스 컨테이너로 명령어 실행 (새 컨테이너)
docker compose build # 이미지 빌드만 (실행 안 함)
docker compose pull # 이미지 업데이트
docker compose restart # 재시작
여러 Compose 파일 조합
개발/운영 환경 설정을 분리할 때 씁니다.
docker compose -f compose.yaml -f compose.dev.yaml up
# compose.dev.yaml — 개발 환경 오버라이드
services:
web:
volumes:
- .:/app # 코드 실시간 반영
command: uvicorn app:app --reload # 핫리로드
멀티 스테이지 빌드
빌드 환경과 실행 환경을 분리해서 최종 이미지를 작게 만드는 패턴입니다. 컴파일 언어에서 특히 유용합니다.
# 빌드 스테이지
FROM golang:1.21 AS builder
WORKDIR /app
COPY . .
RUN go build -o server .
# 실행 스테이지 — 컴파일 도구 없이 바이너리만
FROM alpine:3.18
COPY --from=builder /app/server /server
EXPOSE 8080
CMD ["/server"]
빌드 도구, 소스 코드, 중간 파일이 최종 이미지에 포함되지 않아서 이미지 크기가 크게 줄어듭니다.
정리 표
Dockerfile 명령어
| 명령어 | 용도 |
|---|---|
FROM |
베이스 이미지 지정 |
WORKDIR |
작업 디렉토리 설정 |
COPY |
파일 복사 |
RUN |
빌드 중 명령어 실행 |
ENV |
환경 변수 (런타임 유지) |
ARG |
빌드 시점 변수 |
EXPOSE |
포트 문서화 |
CMD |
기본 실행 명령 (덮어쓰기 가능) |
ENTRYPOINT |
고정 실행 명령 |
USER |
실행 사용자 지정 |
Docker Compose 명령어
| 명령어 | 동작 |
|---|---|
docker compose up -d |
전체 서비스 백그라운드 시작 |
docker compose up --build |
재빌드 후 시작 |
docker compose down -v |
컨테이너 + 볼륨 삭제 |
docker compose logs -f |
실시간 로그 |
docker compose exec 서비스 bash |
쉘 접속 |
docker compose ps |
서비스 상태 |
docker compose build |
이미지만 빌드 |
'블로그, 컴퓨터 > Cheatsheets' 카테고리의 다른 글
| Shell Script 정리 (2편) — 에러 처리, 문자열, 실용 패턴 (0) | 2026.05.28 |
|---|---|
| Shell Script 정리 (1편) — 변수, 조건문, 반복문, 함수 (0) | 2026.05.28 |
| Docker 명령어 정리 (1편) — 개념, 이미지, 컨테이너 (0) | 2026.05.27 |
| Git 명령어 정리 (2편) — 브랜치, 원격, 되돌리기, stash (0) | 2026.05.26 |
| Git 명령어 정리 (1편) — 기본 개념, 설정, 커밋, 로그 (0) | 2026.05.26 |