Docker
목차
Part 4: Docker
- Docker 기본 개념
- Docker 이미지
- Dockerfile 작성
- Docker 컨테이너 관리
- Docker 네트워킹
- Docker 볼륨과 스토리지
- Docker Compose
- Docker 레지스트리
1. Docker 기본 개념
1.1 Docker란?
Docker의 정의
Docker는 컨테이너 기반 애플리케이션 개발, 배포, 실행 플랫폼이다.
Docker의 주요 가치
- Build once, run anywhere: 한 번 빌드하면 어디서나 실행
- Isolation: 애플리케이션 간 격리
- Portability: 환경 독립적 실행
- Lightweight: VM보다 가벼운 리소스 사용
- Fast: 빠른 시작과 배포
Docker의 구성 요소
Docker Client
- 사용자 인터페이스
docker명령어- Docker daemon과 REST API로 통신
Docker Daemon (dockerd)
- 백그라운드 서비스
- 이미지, 컨테이너, 네트워크, 볼륨 관리
- containerd와 통신
Docker Registry
- 이미지 저장소
- Docker Hub (공개 레지스트리)
- 프라이빗 레지스트리
Docker Objects
- Images: 읽기 전용 템플릿
- Containers: 이미지의 실행 인스턴스
- Networks: 컨테이너 간 통신
- Volumes: 영구 데이터 저장
1.2 Docker 설치
Linux (Ubuntu)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 오래된 버전 제거
sudo apt-get remove docker docker-engine docker.io containerd runc
# 필수 패키지 설치
sudo apt-get update
sudo apt-get install \
ca-certificates \
curl \
gnupg \
lsb-release
# Docker 공식 GPG 키 추가
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
# Repository 추가
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Docker 설치
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
# 설치 확인
sudo docker run hello-world
일반 사용자 권한 부여
1
2
3
4
5
6
7
8
9
# docker 그룹에 사용자 추가
sudo usermod -aG docker $USER
# 로그아웃 후 재로그인
# 또는 현재 세션에 적용
newgrp docker
# 권한 확인
docker run hello-world
Docker 버전 확인
1
2
3
4
5
# 클라이언트 및 서버 버전
docker version
# 상세 정보
docker info
1.3 Docker 기본 명령어
이미지 관련
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 이미지 검색
docker search nginx
# 이미지 다운로드
docker pull nginx
docker pull nginx:1.25
# 이미지 목록
docker images
docker image ls
# 이미지 삭제
docker rmi nginx
docker image rm nginx
# 사용하지 않는 이미지 정리
docker image prune
컨테이너 관련
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 컨테이너 실행
docker run nginx
docker run -d nginx # 백그라운드
docker run -it ubuntu bash # 대화형
# 실행 중인 컨테이너 목록
docker ps
docker container ls
# 모든 컨테이너 (중지된 것 포함)
docker ps -a
docker container ls -a
# 컨테이너 중지
docker stop <container>
# 컨테이너 시작
docker start <container>
# 컨테이너 재시작
docker restart <container>
# 컨테이너 삭제
docker rm <container>
# 강제 삭제 (실행 중이어도)
docker rm -f <container>
시스템 관리
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 디스크 사용량
docker system df
# 전체 정리 (사용하지 않는 모든 리소스)
docker system prune
# 모든 리소스 강제 정리 (볼륨 포함)
docker system prune -a --volumes
# 로그 확인
docker logs <container>
docker logs -f <container> # 실시간
# 리소스 사용량 모니터링
docker stats
docker stats <container>
2. Docker 이미지
2.1 이미지의 구조
레이어 기반 아키텍처
Docker 이미지는 여러 읽기 전용 레이어로 구성된다:
1
2
3
4
5
6
7
8
9
10
11
Image: nginx:latest
↓
Layer 5: nginx 설정 파일
↓
Layer 4: nginx 설치
↓
Layer 3: 패키지 업데이트
↓
Layer 2: 베이스 파일시스템
↓
Layer 1: 커널 부트 파일시스템
이미지 레이어 확인
1
2
3
4
5
# 이미지 히스토리
docker history nginx:latest
# 각 레이어의 크기와 생성 명령 확인
docker history --no-trunc nginx:latest
이미지 상세 정보
1
2
3
4
5
6
7
8
9
# 이미지 inspect
docker inspect nginx:latest
# JSON 형식으로 모든 메타데이터 출력
# - 레이어 정보
# - 환경 변수
# - 포트 설정
# - 볼륨 마운트 포인트
# - 엔트리포인트/CMD
2.2 이미지 태그
태그의 개념
태그는 이미지의 버전을 식별하는 레이블이다.
태그 형식
1
2
3
4
5
6
7
[registry/][namespace/]repository[:tag]
예시:
nginx:latest
nginx:1.25
docker.io/library/nginx:1.25-alpine
myregistry.com/myapp:v1.0.0
태그 규칙
1
2
3
4
5
6
7
8
9
10
11
12
# 태그 없이 pull하면 latest
docker pull nginx
# = docker pull nginx:latest
# 특정 버전
docker pull nginx:1.25
# Alpine 기반 (경량)
docker pull nginx:alpine
# 특정 OS/아키텍처
docker pull nginx:1.25-alpine-arm64
이미지 태깅
1
2
3
4
5
6
# 로컬 이미지에 태그 추가
docker tag nginx:latest myregistry.com/nginx:v1.0
# 여러 태그 가능
docker tag nginx:latest nginx:production
docker tag nginx:latest nginx:stable
2.3 이미지 레지스트리
Docker Hub
공식 공개 레지스트리:
1
2
3
4
5
6
7
8
# Docker Hub에서 pull (기본)
docker pull nginx
# 명시적 지정
docker pull docker.io/library/nginx
# 사용자 이미지
docker pull username/myimage
프라이빗 레지스트리
1
2
3
4
5
6
7
8
9
# 로그인
docker login myregistry.com
# Username, Password 입력
# 프라이빗 레지스트리에서 pull
docker pull myregistry.com/myapp:latest
# 로그아웃
docker logout myregistry.com
Harbor, GitLab Registry 등
엔터프라이즈 레지스트리:
- 접근 제어
- 이미지 스캐닝
- 복제 및 백업
- 취약점 관리
2.4 이미지 빌드
docker build 기본
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 현재 디렉토리의 Dockerfile 사용
docker build .
# 태그 지정
docker build -t myapp:latest .
# 특정 Dockerfile 지정
docker build -f Dockerfile.prod -t myapp:prod .
# 빌드 컨텍스트 제외 (.dockerignore)
# .dockerignore 파일 작성:
# node_modules
# .git
# *.log
빌드 캐시
Docker는 레이어를 캐시하여 빌드 속도를 향상시킨다:
1
2
3
4
5
# 캐시 무시하고 빌드
docker build --no-cache -t myapp:latest .
# 특정 레이어부터 다시 빌드
# (Dockerfile 수정 시 자동)
멀티 스테이지 빌드
빌드 단계를 분리하여 최종 이미지 크기 축소:
1
2
3
4
5
6
7
8
9
10
11
12
# 빌드 스테이지
FROM golang:1.21 AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp
# 실행 스테이지
FROM alpine:latest
COPY --from=builder /app/myapp /usr/local/bin/
CMD ["myapp"]
# 최종 이미지는 alpine만 포함 (작음)
BuildKit
차세대 빌드 엔진:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# BuildKit 활성화
export DOCKER_BUILDKIT=1
# 또는 /etc/docker/daemon.json
{
"features": {
"buildkit": true
}
}
# 장점:
# - 병렬 빌드
# - 빌드 캐시 개선
# - 비밀 정보 안전 처리
# - 더 나은 성능
2.5 이미지 공유
Docker Hub에 푸시
1
2
3
4
5
6
7
8
9
10
11
12
# Docker Hub 로그인
docker login
# 이미지 태그 (username 포함)
docker tag myapp:latest username/myapp:latest
# 푸시
docker push username/myapp:latest
# 특정 버전도 푸시
docker tag myapp:latest username/myapp:v1.0
docker push username/myapp:v1.0
프라이빗 레지스트리에 푸시
1
2
3
4
5
6
7
8
# 레지스트리 로그인
docker login myregistry.com
# 이미지 태그
docker tag myapp:latest myregistry.com/myapp:latest
# 푸시
docker push myregistry.com/myapp:latest
이미지 저장/로드
1
2
3
4
5
6
7
8
9
10
11
12
# 이미지를 tar 파일로 저장
docker save -o myapp.tar myapp:latest
# tar 파일에서 이미지 로드
docker load -i myapp.tar
# 여러 이미지 저장
docker save -o images.tar nginx:latest alpine:latest
# 압축
docker save myapp:latest | gzip > myapp.tar.gz
gunzip -c myapp.tar.gz | docker load
이미지 익스포트/임포트 (컨테이너)
1
2
3
4
5
6
7
8
9
10
11
12
# 실행 중인 컨테이너를 이미지로
docker commit <container> myapp:snapshot
# 컨테이너를 tar로 익스포트
docker export <container> -o container.tar
# tar에서 이미지 생성
docker import container.tar myapp:imported
# 차이점:
# - save/load: 이미지 레이어 보존
# - export/import: 단일 레이어로 압축
3. Dockerfile 작성
3.1 Dockerfile 기본 구조
Dockerfile이란?
Dockerfile은 Docker 이미지를 빌드하는 명령어 스크립트이다.
기본 예시
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 베이스 이미지
FROM node:18-alpine
# 작업 디렉토리 설정
WORKDIR /app
# 의존성 파일 복사
COPY package*.json ./
# 의존성 설치
RUN npm install --production
# 애플리케이션 코드 복사
COPY . .
# 포트 노출
EXPOSE 3000
# 실행 명령
CMD ["node", "server.js"]
3.2 주요 Dockerfile 명령어
FROM - 베이스 이미지
1
2
3
4
5
6
7
8
9
10
11
# 공식 이미지
FROM ubuntu:22.04
# 경량 이미지
FROM alpine:3.18
# 멀티 스테이지의 특정 스테이지
FROM node:18 AS builder
# Scratch (빈 이미지)
FROM scratch
WORKDIR - 작업 디렉토리
1
2
3
4
5
6
7
8
9
10
# 작업 디렉토리 설정
WORKDIR /app
# 이후 명령은 모두 /app에서 실행
# 디렉토리가 없으면 자동 생성
# 중첩 가능
WORKDIR /app
WORKDIR src
# 현재 위치: /app/src
COPY vs ADD
1
2
3
4
5
6
7
8
9
10
11
12
13
# COPY: 단순 파일/디렉토리 복사
COPY package.json /app/
COPY src/ /app/src/
# ADD: 복사 + 추가 기능
ADD https://example.com/file.tar.gz /app/
# URL에서 다운로드
ADD archive.tar.gz /app/
# 자동 압축 해제
# 권장: 일반적으로 COPY 사용
# ADD는 특별한 경우에만
RUN - 명령 실행
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Shell 형식
RUN apt-get update && apt-get install -y nginx
# Exec 형식
RUN ["apt-get", "update"]
# 여러 명령을 하나로 (레이어 최소화)
RUN apt-get update && \
apt-get install -y \
nginx \
curl && \
rm -rf /var/lib/apt/lists/*
# 각 RUN은 새 레이어 생성
# 최적화: 관련 명령을 하나의 RUN으로
ENV - 환경 변수
1
2
3
4
5
6
7
8
9
10
# 환경 변수 설정
ENV NODE_ENV=production
ENV PORT=3000
# 여러 변수 한번에
ENV NODE_ENV=production \
PORT=3000 \
LOG_LEVEL=info
# 빌드 시 및 런타임에 모두 사용
ARG - 빌드 인수
1
2
3
4
5
6
7
8
9
10
# 빌드 시에만 사용하는 변수
ARG VERSION=latest
ARG BUILD_DATE
# 사용
FROM node:${VERSION}
LABEL build-date=${BUILD_DATE}
# 빌드 시 전달
# docker build --build-arg VERSION=18 .
EXPOSE - 포트 노출
1
2
3
4
5
6
7
# 포트 노출 (문서화 목적)
EXPOSE 80
EXPOSE 443/tcp
EXPOSE 53/udp
# 실제 포트 매핑은 실행 시:
# docker run -p 8080:80 myapp
CMD vs ENTRYPOINT
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# CMD: 기본 명령 (덮어쓰기 가능)
CMD ["nginx", "-g", "daemon off;"]
# 실행 시 덮어쓰기:
# docker run myapp echo "hello"
# ENTRYPOINT: 항상 실행되는 명령
ENTRYPOINT ["nginx"]
CMD ["-g", "daemon off;"]
# 실행 시:
# docker run myapp -c /custom/nginx.conf
# = nginx -c /custom/nginx.conf
# 조합:
# ENTRYPOINT: 실행 파일
# CMD: 기본 인수
VOLUME - 볼륨 마운트 포인트
1
2
3
4
5
# 볼륨 마운트 포인트 선언
VOLUME /data
VOLUME ["/var/log", "/var/db"]
# 컨테이너 실행 시 익명 볼륨 자동 생성
USER - 실행 사용자
1
2
3
4
5
6
7
8
9
# 사용자 생성
RUN addgroup -S appgroup && \
adduser -S appuser -G appgroup
# 사용자 전환
USER appuser
# 이후 명령은 appuser로 실행
# 보안 모범 사례: root 사용 지양
LABEL - 메타데이터
1
2
3
4
5
6
7
8
9
# 메타데이터 추가
LABEL version="1.0"
LABEL description="My Application"
LABEL maintainer="devops@example.com"
# 여러 레이블
LABEL version="1.0" \
description="My Application" \
maintainer="devops@example.com"
3.3 Dockerfile 최적화
레이어 최소화
1
2
3
4
5
6
7
8
9
10
11
12
13
# 나쁜 예: 레이어가 많음
RUN apt-get update
RUN apt-get install -y nginx
RUN apt-get install -y curl
RUN apt-get clean
# 좋은 예: 하나의 레이어
RUN apt-get update && \
apt-get install -y \
nginx \
curl && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
캐시 활용
1
2
3
4
5
6
7
8
9
10
# 나쁜 예: 코드 변경 시 의존성도 재설치
COPY . /app
RUN npm install
# 좋은 예: 의존성 파일만 먼저 복사
COPY package*.json /app/
RUN npm install
COPY . /app
# package.json 변경 시에만 npm install 재실행
멀티 스테이지 빌드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 빌드 스테이지
FROM node:18 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# 프로덕션 스테이지
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3000
CMD ["node", "dist/server.js"]
# 최종 이미지: 빌드 도구 제외, 크기 감소
불필요한 파일 제외 (.dockerignore)
1
2
3
4
5
6
7
8
9
10
# .dockerignore
node_modules
npm-debug.log
.git
.gitignore
.env
.DS_Store
*.md
tests/
docs/
베이스 이미지 선택
1
2
3
4
5
6
7
8
9
10
11
12
# 크기 비교:
# node:18 (약 1GB)
FROM node:18
# node:18-slim (약 200MB)
FROM node:18-slim
# node:18-alpine (약 170MB)
FROM node:18-alpine
# Distroless (최소, 보안 강화)
FROM gcr.io/distroless/nodejs18
3.4 보안 모범 사례
최소 권한 원칙
1
2
3
4
5
6
7
8
# 나쁜 예: root로 실행
FROM nginx
# 좋은 예: 일반 사용자
FROM nginx
RUN addgroup -S appgroup && \
adduser -S appuser -G appgroup
USER appuser
민감 정보 제외
1
2
3
4
5
6
7
# 나쁜 예: 비밀키 포함
ENV API_KEY=secret123
# 좋은 예: 런타임에 주입
# docker run -e API_KEY=secret123 myapp
# 또는 Docker Secrets 사용
최신 패치
1
2
3
4
5
6
7
# 베이스 이미지 업데이트
FROM alpine:3.18
# 시스템 패키지 업데이트
RUN apk update && \
apk upgrade && \
rm -rf /var/cache/apk/*
취약점 스캔
1
2
3
4
5
# Trivy로 이미지 스캔
trivy image myapp:latest
# Docker Scout (Docker Desktop)
docker scout cves myapp:latest
4. Docker 컨테이너 관리
4.1 컨테이너 생명주기
컨테이너 상태
- Created: 생성됨, 아직 시작 안 함
- Running: 실행 중
- Paused: 일시 정지
- Stopped: 중지됨
- Deleted: 삭제됨
생명주기 명령
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 생성 (시작 안 함)
docker create nginx
# 생성 + 시작
docker run nginx
# 시작
docker start <container>
# 중지 (SIGTERM, 10초 후 SIGKILL)
docker stop <container>
# 강제 중지 (SIGKILL)
docker kill <container>
# 재시작
docker restart <container>
# 일시 정지
docker pause <container>
# 재개
docker unpause <container>
# 삭제
docker rm <container>
# 강제 삭제
docker rm -f <container>
4.2 docker run 옵션
기본 실행
1
2
3
4
5
6
7
8
9
10
11
# 포그라운드 실행
docker run nginx
# 백그라운드 실행 (-d, --detach)
docker run -d nginx
# 컨테이너 이름 지정
docker run --name mynginx nginx
# 실행 후 자동 삭제 (--rm)
docker run --rm nginx
대화형 모드
1
2
3
4
5
6
7
8
9
10
11
# 대화형 모드 (-it)
docker run -it ubuntu bash
# -i: STDIN 유지
# -t: TTY 할당
# 실행 중인 컨테이너에 접속
docker exec -it mynginx bash
# 특정 사용자로 실행
docker exec -it -u root mynginx bash
포트 매핑
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 단일 포트
docker run -p 8080:80 nginx
# 여러 포트
docker run -p 8080:80 -p 4443:443 nginx
# 호스트 IP 지정
docker run -p 127.0.0.1:8080:80 nginx
# UDP 포트
docker run -p 53:53/udp dns-server
# 호스트 포트 자동 할당
docker run -p 80 nginx
환경 변수
1
2
3
4
5
6
7
8
9
10
11
12
13
# 단일 환경 변수
docker run -e NODE_ENV=production myapp
# 여러 환경 변수
docker run -e NODE_ENV=production -e PORT=3000 myapp
# 파일에서 읽기
docker run --env-file .env myapp
# .env 파일 형식:
# NODE_ENV=production
# PORT=3000
# DB_HOST=db.example.com
볼륨 마운트
1
2
3
4
5
6
7
8
9
10
11
# Named 볼륨
docker run -v myvolume:/data nginx
# Bind mount
docker run -v /host/path:/container/path nginx
# 읽기 전용
docker run -v myvolume:/data:ro nginx
# tmpfs (메모리)
docker run --tmpfs /tmp nginx
네트워크
1
2
3
4
5
6
7
8
9
10
11
# 특정 네트워크
docker run --network mynetwork nginx
# 호스트 네트워크
docker run --network host nginx
# 네트워크 없음
docker run --network none nginx
# 네트워크 별칭
docker run --network mynetwork --network-alias db postgres
리소스 제한
1
2
3
4
5
6
7
8
9
10
11
12
# 메모리 제한
docker run -m 512m nginx
docker run --memory=512m nginx
# CPU 제한
docker run --cpus=1.5 nginx
# CPU 공유
docker run --cpu-shares=512 nginx
# 블록 I/O
docker run --device-write-bps=/dev/sda:10mb nginx
재시작 정책
1
2
3
4
5
6
7
8
9
10
11
# 항상 재시작
docker run --restart=always nginx
# 실패 시에만 재시작
docker run --restart=on-failure nginx
# 최대 재시작 횟수
docker run --restart=on-failure:3 nginx
# 명시적으로 중지하지 않으면 재시작
docker run --restart=unless-stopped nginx
4.3 컨테이너 모니터링
로그 확인
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 로그 출력
docker logs <container>
# 실시간 로그 (tail -f)
docker logs -f <container>
# 마지막 N줄
docker logs --tail 100 <container>
# 타임스탬프 포함
docker logs -t <container>
# 특정 시간 이후
docker logs --since 2023-01-01T00:00:00 <container>
docker logs --since 1h <container>
리소스 사용량
1
2
3
4
5
6
7
8
9
10
11
# 실시간 통계
docker stats
# 특정 컨테이너
docker stats <container>
# 스트리밍 없이 한 번만
docker stats --no-stream
# 출력:
# CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O
프로세스 확인
1
2
3
4
5
6
7
8
# 컨테이너 내 프로세스
docker top <container>
# ps aux 형식
docker top <container> aux
# 실행 중인 프로세스 확인
docker exec <container> ps aux
파일 시스템 변경사항
1
2
3
4
5
6
7
# 이미지 대비 변경된 파일
docker diff <container>
# 출력:
# A: 추가된 파일
# C: 변경된 파일
# D: 삭제된 파일
이벤트 모니터링
1
2
3
4
5
6
7
8
9
# 실시간 Docker 이벤트
docker events
# 특정 컨테이너
docker events --filter container=<container>
# 특정 이벤트 타입
docker events --filter event=start
docker events --filter event=stop
4.4 컨테이너 디버깅
실행 중인 컨테이너 접속
1
2
3
4
5
6
7
8
9
# Bash 실행
docker exec -it <container> bash
# sh 실행 (Alpine 등)
docker exec -it <container> sh
# 특정 명령 실행
docker exec <container> cat /etc/hosts
docker exec <container> env
컨테이너 inspect
1
2
3
4
5
6
7
# 전체 정보 (JSON)
docker inspect <container>
# 특정 필드 추출
docker inspect --format='' <container>
docker inspect --format='' <container>
docker inspect --format='' <container> | jq
파일 복사
1
2
3
4
5
6
7
8
# 컨테이너 → 호스트
docker cp <container>:/path/to/file ./local/path
# 호스트 → 컨테이너
docker cp ./local/file <container>:/path/to/
# 디렉토리 복사
docker cp <container>:/app ./app-backup
네트워크 디버깅
1
2
3
4
5
6
7
8
9
10
11
# 네트워크 정보 확인
docker exec <container> ip addr
docker exec <container> ip route
# 연결 테스트
docker exec <container> ping google.com
docker exec <container> curl http://api.example.com
# DNS 확인
docker exec <container> nslookup google.com
docker exec <container> cat /etc/resolv.conf
헬스체크
1
2
3
# Dockerfile에서 헬스체크 정의
HEALTHCHECK --interval=30s --timeout=3s --retries=3 \
CMD curl -f http://localhost/ || exit 1
1
2
3
4
5
6
7
8
9
# 실행 시 헬스체크 추가
docker run --health-cmd='curl -f http://localhost/ || exit 1' \
--health-interval=30s \
--health-timeout=3s \
--health-retries=3 \
nginx
# 헬스 상태 확인
docker inspect --format='' <container>
4.5 컨테이너 정리
중지된 컨테이너 삭제
1
2
3
4
5
6
7
8
# 모든 중지된 컨테이너 삭제
docker container prune
# 확인 없이 삭제
docker container prune -f
# 특정 레이블 필터
docker container prune --filter "label=env=test"
자동 삭제 (–rm)
1
2
3
4
5
# 종료 시 자동 삭제
docker run --rm nginx
# 임시 작업에 유용
docker run --rm -it ubuntu bash
대량 정리
1
2
3
4
5
# 실행 중이지 않은 모든 컨테이너 삭제
docker ps -aq -f status=exited | xargs docker rm
# 특정 이미지의 모든 컨테이너 삭제
docker ps -a --filter ancestor=nginx -q | xargs docker rm -f
5. Docker 네트워킹
5.1 Docker 네트워크 드라이버 상세
Bridge 네트워크 (기본)
Docker의 기본 네트워크 모드이다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 기본 브리지 네트워크
docker network inspect bridge
# 특징:
# - 네트워크: 172.17.0.0/16
# - 게이트웨이: 172.17.0.1 (docker0 브리지)
# - 컨테이너 간 IP로만 통신 (이름 해석 안 됨)
# 사용자 정의 브리지 생성
docker network create --driver bridge mybridge
# 서브넷 지정
docker network create --driver bridge \
--subnet=192.168.100.0/24 \
--gateway=192.168.100.1 \
mybridge
# 장점:
# - 자동 DNS 해석 (컨테이너 이름으로 통신)
# - 네트워크 격리
# - 동적 연결/해제 가능
사용자 정의 브리지 vs 기본 브리지
1
2
3
4
5
6
7
8
9
10
# 기본 브리지
docker run -d --name web1 nginx
docker run -d --name web2 nginx
docker exec web1 ping web2 # 실패! (IP로만 가능)
# 사용자 정의 브리지
docker network create mynet
docker run -d --name web1 --network mynet nginx
docker run -d --name web2 --network mynet nginx
docker exec web1 ping web2 # 성공! (DNS 해석됨)
Host 네트워크
컨테이너가 호스트의 네트워크 스택을 직접 사용한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
# Host 네트워크로 실행
docker run --network host nginx
# 특징:
# - 최고 성능 (네트워크 오버헤드 없음)
# - 포트 매핑 불필요 (컨테이너 포트 = 호스트 포트)
# - 네트워크 격리 없음
# - 호스트의 모든 네트워크 인터페이스 접근
# 주의:
# - 여러 컨테이너가 같은 포트 사용 불가
# - 보안 위험 (호스트 네트워크 노출)
# - Linux에서만 완전 지원 (Mac/Windows는 제한적)
None 네트워크
네트워크를 완전히 비활성화한다.
1
2
3
4
5
6
7
8
9
10
11
12
# None 네트워크로 실행
docker run --network none alpine
# 특징:
# - lo (루프백)만 존재
# - 외부 통신 완전 차단
# - 최대 격리
# 용도:
# - 네트워크가 필요 없는 배치 작업
# - 보안이 매우 중요한 작업
# - 커스텀 네트워크 설정
Overlay 네트워크
여러 Docker 호스트에 걸친 네트워크를 구성한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# Docker Swarm 초기화 필요
docker swarm init
# Overlay 네트워크 생성
docker network create \
--driver overlay \
--subnet 10.0.9.0/24 \
myoverlay
# 서비스 배포
docker service create \
--name web \
--network myoverlay \
--replicas 3 \
nginx
# 특징:
# - 멀티 호스트 통신
# - 자동 서비스 디스커버리
# - 내장 로드 밸런싱
# - 암호화 가능 (--opt encrypted)
# Kubernetes에서는 CNI 플러그인 사용
Macvlan 네트워크
컨테이너에 고유한 MAC 주소를 할당한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# Macvlan 네트워크 생성
docker network create -d macvlan \
--subnet=192.168.1.0/24 \
--gateway=192.168.1.1 \
-o parent=eth0 \
mymacvlan
# 컨테이너 실행
docker run --network mymacvlan \
--ip=192.168.1.100 \
nginx
# 특징:
# - 컨테이너가 물리 네트워크에 직접 연결된 것처럼 보임
# - 각 컨테이너가 고유 MAC 주소 가짐
# - 라우터/스위치가 컨테이너를 별도 호스트로 인식
# 용도:
# - 레거시 애플리케이션 (MAC 주소 기반 라이센싱)
# - 네트워크 모니터링 도구
# - DHCP 서버
# 주의:
# - 프로미스큐어스 모드 필요할 수 있음
# - 클라우드 환경에서는 지원 안 될 수 있음
5.2 네트워크 관리
네트워크 목록 및 정보
1
2
3
4
5
6
7
8
9
10
11
# 네트워크 목록
docker network ls
# 네트워크 상세 정보
docker network inspect bridge
# 특정 컨테이너의 네트워크 정보
docker inspect <container> --format '' | jq
# 네트워크에 연결된 컨테이너 목록
docker network inspect mynet --format ' '
네트워크 생성 옵션
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 기본 생성
docker network create mynet
# 드라이버 지정
docker network create --driver bridge mynet
# 서브넷 및 게이트웨이
docker network create \
--subnet 172.20.0.0/16 \
--gateway 172.20.0.1 \
mynet
# IP 범위 지정
docker network create \
--subnet 172.20.0.0/16 \
--ip-range 172.20.240.0/20 \
mynet
# IPv6 활성화
docker network create \
--ipv6 \
--subnet 2001:db8::/64 \
mynet
# Internal 네트워크 (외부 통신 차단)
docker network create --internal mynet
# 레이블
docker network create \
--label environment=production \
mynet
컨테이너 네트워크 연결
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 생성 시 네트워크 지정
docker run --network mynet nginx
# 실행 중인 컨테이너에 네트워크 추가
docker network connect mynet <container>
# IP 주소 지정
docker network connect --ip 172.20.0.10 mynet <container>
# 네트워크 별칭
docker network connect --alias db mynet postgres
# 네트워크 연결 해제
docker network disconnect mynet <container>
# 강제 연결 해제
docker network disconnect -f mynet <container>
네트워크 삭제
1
2
3
4
5
6
7
8
# 네트워크 삭제
docker network rm mynet
# 사용하지 않는 네트워크 정리
docker network prune
# 확인 없이 정리
docker network prune -f
5.3 포트 매핑 상세
포트 매핑 방식
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 기본 매핑 (모든 인터페이스)
docker run -p 8080:80 nginx
# 0.0.0.0:8080 → 컨테이너:80
# 특정 IP에만 바인딩
docker run -p 127.0.0.1:8080:80 nginx
# localhost에서만 접근 가능
# 특정 IP 범위
docker run -p 192.168.1.10:8080:80 nginx
# UDP 포트
docker run -p 53:53/udp dns-server
# TCP와 UDP 모두
docker run -p 8080:80/tcp -p 53:53/udp myapp
# 포트 범위
docker run -p 8000-8010:8000-8010 myapp
# 호스트 포트 자동 할당
docker run -P nginx
# Dockerfile의 EXPOSE 포트를 랜덤 포트로 매핑
포트 확인
1
2
3
4
5
6
7
8
# 컨테이너의 포트 매핑 확인
docker port <container>
# 특정 포트 확인
docker port <container> 80
# 모든 매핑 정보
docker inspect <container> --format '' | jq
포트 매핑과 iptables
1
2
3
4
5
6
7
8
# Docker가 생성한 iptables 규칙 확인
sudo iptables -t nat -L -n
# DOCKER 체인 확인
sudo iptables -t nat -L DOCKER -n
# 예시 규칙:
# DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:8080 to:172.17.0.2:80
5.4 컨테이너 간 통신
같은 네트워크 내 통신
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 네트워크 생성
docker network create myapp-net
# 데이터베이스 컨테이너
docker run -d \
--name db \
--network myapp-net \
-e POSTGRES_PASSWORD=secret \
postgres
# 애플리케이션 컨테이너
docker run -d \
--name web \
--network myapp-net \
-e DATABASE_URL=postgresql://postgres:secret@db:5432/mydb \
myapp
# web에서 db로 접근
docker exec web ping db # 성공!
docker exec web psql -h db -U postgres # 성공!
다중 네트워크
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 프론트엔드 네트워크
docker network create frontend
# 백엔드 네트워크
docker network create backend
# 웹 서버 (프론트엔드만)
docker run -d --name web --network frontend nginx
# API 서버 (양쪽 모두)
docker run -d --name api --network frontend myapi
docker network connect backend api
# 데이터베이스 (백엔드만)
docker run -d --name db --network backend postgres
# 결과:
# web → api (가능)
# api → db (가능)
# web → db (불가능, 격리됨)
네트워크 별칭
1
2
3
4
5
6
7
8
9
10
11
12
# 여러 별칭으로 참조
docker run -d \
--network mynet \
--network-alias db \
--network-alias database \
--network-alias postgres \
postgres
# 모든 별칭으로 접근 가능
docker exec web ping db
docker exec web ping database
docker exec web ping postgres
서비스 디스커버리
1
2
3
4
5
6
7
8
# 같은 서비스의 여러 인스턴스
docker run -d --name web1 --network mynet --network-alias web nginx
docker run -d --name web2 --network mynet --network-alias web nginx
docker run -d --name web3 --network mynet --network-alias web nginx
# 라운드 로빈 DNS
# "web"을 조회하면 세 인스턴스의 IP가 번갈아 반환됨
docker exec client nslookup web
5.5 Docker DNS
내장 DNS 서버
Docker는 127.0.0.11에 내장 DNS 서버를 제공한다.
1
2
3
4
5
6
7
8
9
10
# 컨테이너 내 DNS 설정 확인
docker exec web cat /etc/resolv.conf
# nameserver 127.0.0.11
# options ndots:0
# Docker DNS 서버가 다음을 해석:
# 1. 컨테이너 이름 → IP
# 2. 네트워크 별칭 → IP
# 3. 서비스 이름 → 여러 IP (라운드 로빈)
# 4. 외부 도메인 → 호스트 DNS로 전달
커스텀 DNS
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 컨테이너별 DNS 서버 지정
docker run --dns 8.8.8.8 nginx
# 여러 DNS 서버
docker run --dns 8.8.8.8 --dns 8.8.4.4 nginx
# DNS 검색 도메인
docker run --dns-search example.com nginx
# ping server → server.example.com 시도
# DNS 옵션
docker run --dns-option ndots:2 nginx
# /etc/hosts 추가
docker run --add-host myhost:192.168.1.100 nginx
전역 DNS 설정
1
2
3
4
5
6
7
8
9
# /etc/docker/daemon.json
{
"dns": ["8.8.8.8", "8.8.4.4"],
"dns-search": ["example.com"],
"dns-opts": ["ndots:2"]
}
# Docker 재시작
sudo systemctl restart docker
5.6 네트워크 트러블슈팅
연결 문제 진단
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 컨테이너 IP 확인
docker inspect <container> --format ''
# 네트워크 인터페이스 확인
docker exec <container> ip addr
# 라우팅 테이블
docker exec <container> ip route
# 연결 테스트
docker exec <container> ping google.com
docker exec <container> ping 8.8.8.8
# 포트 열림 확인
docker exec <container> nc -zv db 5432
# DNS 확인
docker exec <container> nslookup google.com
docker exec <container> dig google.com
네트워크 디버깅 컨테이너
1
2
3
4
5
6
7
8
9
10
# nicolaka/netshoot 사용 (추천)
docker run -it --rm --network container:<container> nicolaka/netshoot
# 사용 가능한 도구:
# - tcpdump: 패킷 캡처
# - curl, wget: HTTP 테스트
# - nmap: 포트 스캔
# - iperf: 대역폭 테스트
# - traceroute: 경로 추적
# - mtr: 네트워크 진단
패킷 캡처
1
2
3
4
5
6
7
8
9
10
11
12
13
# 컨테이너 내부에서
docker exec <container> tcpdump -i eth0 -w /tmp/capture.pcap
# 호스트의 veth에서
# veth 인터페이스 찾기
docker exec <container> cat /sys/class/net/eth0/iflink
ip link | grep <번호>
# 캡처
sudo tcpdump -i <veth> -w capture.pcap
# Wireshark로 분석
wireshark capture.pcap
일반적인 문제와 해결
문제: 컨테이너가 외부와 통신 안 됨
1
2
3
4
5
6
7
8
9
10
11
12
# 1. IP 포워딩 확인
cat /proc/sys/net/ipv4/ip_forward
# 1이어야 함
# 2. NAT 규칙 확인
sudo iptables -t nat -L POSTROUTING -n
# 3. 방화벽 확인
sudo iptables -L -n
# 4. DNS 확인
docker exec <container> cat /etc/resolv.conf
문제: 컨테이너 간 통신 안 됨
1
2
3
4
5
6
7
8
9
# 1. 같은 네트워크인지 확인
docker network inspect <network>
# 2. ICC(Inter-Container Communication) 활성화 확인
docker network inspect <network> | grep "com.docker.network.bridge.enable_icc"
# true여야 함
# 3. 방화벽 규칙 확인
sudo iptables -L DOCKER-ISOLATION -n
문제: DNS 해석 실패
1
2
3
4
5
6
7
8
9
10
11
12
# 1. Docker DNS 작동 확인
docker exec <container> nslookup google.com 127.0.0.11
# 2. 호스트 DNS 확인
cat /etc/resolv.conf
# 3. 컨테이너 DNS 설정 확인
docker exec <container> cat /etc/resolv.conf
# 4. 네트워크 재생성
docker network rm <network>
docker network create <network>
6. Docker 볼륨과 스토리지
6.1 스토리지 옵션 비교
Docker는 데이터 영속성을 위해 세 가지 마운트 타입을 제공한다.
볼륨 (Volumes) - 권장
Docker가 관리하는 영구 저장소:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 볼륨 생성
docker volume create myvolume
# 볼륨 위치
ls /var/lib/docker/volumes/myvolume/_data
# 장점:
# - Docker가 완전히 관리
# - 백업/복원 용이
# - 플랫폼 독립적
# - 여러 컨테이너가 안전하게 공유 가능
# - 볼륨 드라이버로 원격 스토리지 지원
# 단점:
# - 호스트에서 직접 접근하기 어려움
Bind Mount
호스트 디렉토리를 직접 마운트:
1
2
3
4
5
6
7
8
9
10
11
12
13
# Bind mount
docker run -v /host/path:/container/path nginx
# 장점:
# - 호스트 파일시스템에 직접 접근
# - 개발 시 편리 (코드 변경 즉시 반영)
# - 호스트의 모든 경로 사용 가능
# 단점:
# - 호스트 경로 의존성
# - 플랫폼 종속적
# - 보안 위험 (호스트 파일시스템 노출)
# - Docker가 관리하지 않음
tmpfs Mount
메모리에만 존재하는 임시 저장소:
1
2
3
4
5
6
7
8
9
10
11
12
# tmpfs mount
docker run --tmpfs /app/cache nginx
# 장점:
# - 매우 빠름 (메모리 속도)
# - 민감한 정보 임시 저장 (컨테이너 종료 시 자동 삭제)
# - 디스크 I/O 없음
# 단점:
# - 메모리 사용
# - 영구적이지 않음
# - Linux에서만 사용 가능
비교표
| 특성 | Volume | Bind Mount | tmpfs |
|---|---|---|---|
| Docker 관리 | O | X | O |
| 백업 용이성 | O | X | X |
| 성능 | 좋음 | 좋음 | 매우 좋음 |
| 플랫폼 독립 | O | X | X |
| 영구성 | O | O | X |
| 개발 편의성 | 중간 | 높음 | 낮음 |
6.2 볼륨 관리
볼륨 생성 및 조회
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 볼륨 생성
docker volume create myvolume
# 드라이버 지정
docker volume create --driver local myvolume
# 옵션 지정
docker volume create \
--opt type=nfs \
--opt o=addr=192.168.1.100,rw \
--opt device=:/path/to/dir \
nfs-volume
# 레이블
docker volume create --label env=prod myvolume
# 볼륨 목록
docker volume ls
# 볼륨 상세 정보
docker volume inspect myvolume
# 볼륨 사용 중인 컨테이너 확인
docker ps --filter volume=myvolume
볼륨 사용
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 명명된 볼륨 마운트
docker run -v myvolume:/data nginx
# 익명 볼륨 (자동 생성)
docker run -v /data nginx
# 읽기 전용
docker run -v myvolume:/data:ro nginx
# --mount 사용 (더 명시적)
docker run \
--mount type=volume,source=myvolume,target=/data \
nginx
# 읽기 전용 (--mount)
docker run \
--mount type=volume,source=myvolume,target=/data,readonly \
nginx
# 볼륨 드라이버 옵션
docker run \
--mount type=volume,source=myvolume,target=/data,volume-driver=local \
nginx
볼륨 삭제
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 볼륨 삭제
docker volume rm myvolume
# 여러 볼륨 삭제
docker volume rm vol1 vol2 vol3
# 사용하지 않는 볼륨 정리
docker volume prune
# 확인 없이 정리
docker volume prune -f
# 특정 레이블 필터
docker volume prune --filter "label=env=test"
6.3 Bind Mount 상세
Bind Mount 사용
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 기본 bind mount
docker run -v /host/path:/container/path nginx
# 절대 경로 필요
docker run -v $(pwd)/app:/app nginx
# 읽기 전용
docker run -v /host/path:/container/path:ro nginx
# --mount 사용 (권장)
docker run \
--mount type=bind,source=/host/path,target=/container/path \
nginx
# 읽기 전용 (--mount)
docker run \
--mount type=bind,source=/host/path,target=/container/path,readonly \
nginx
개발 환경에서 활용
1
2
3
4
5
6
7
8
9
10
# 소스 코드 동기화
docker run -d \
-v $(pwd)/src:/app/src \
-v $(pwd)/package.json:/app/package.json \
-p 3000:3000 \
node:18 \
npm run dev
# 코드 변경 시 자동 반영 (nodemon, webpack-dev-server 등)
# 컨테이너 재시작 불필요
권한 문제
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 문제: 컨테이너 내부 사용자와 호스트 사용자 UID 불일치
# 호스트: UID 1000
# 컨테이너: UID 33 (www-data)
# 해결 1: 컨테이너 사용자를 호스트 UID와 맞춤
docker run --user $(id -u):$(id -g) myapp
# 해결 2: Dockerfile에서 사용자 생성
RUN addgroup -g 1000 appgroup && \
adduser -u 1000 -G appgroup -D appuser
USER appuser
# 해결 3: chown으로 소유권 변경 (엔트리포인트 스크립트)
chown -R appuser:appgroup /data
보안 주의사항
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 위험: 호스트 루트 마운트
docker run -v /:/host nginx # 매우 위험!
# 위험: 민감한 디렉토리 마운트
docker run -v /etc:/host-etc nginx # 위험!
# 위험: Docker 소켓 마운트
docker run -v /var/run/docker.sock:/var/run/docker.sock myapp
# Docker API 완전 접근 = 호스트 제어 가능
# 안전한 사용:
# - 필요한 최소 경로만 마운트
# - 가능하면 읽기 전용
# - 민감한 디렉토리 피하기
6.4 tmpfs Mount
tmpfs 사용
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# tmpfs mount
docker run --tmpfs /tmp nginx
# 크기 제한
docker run --tmpfs /tmp:size=100M nginx
# --mount 사용
docker run \
--mount type=tmpfs,target=/tmp,tmpfs-size=100M \
nginx
# 여러 tmpfs
docker run \
--tmpfs /tmp \
--tmpfs /var/cache \
nginx
사용 사례
1
2
3
4
5
6
7
8
9
10
11
# 1. 캐시 디렉토리
docker run --tmpfs /app/cache myapp
# 2. 임시 파일 처리
docker run --tmpfs /tmp myapp
# 3. 민감한 정보 (비밀번호, 토큰 등)
docker run --tmpfs /secrets myapp
# 4. 세션 데이터
docker run --tmpfs /var/lib/sessions myapp
6.5 볼륨 드라이버
로컬 드라이버 옵션
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# NFS 볼륨
docker volume create \
--driver local \
--opt type=nfs \
--opt o=addr=192.168.1.100,rw \
--opt device=:/path/to/dir \
nfs-volume
# CIFS/SMB 볼륨
docker volume create \
--driver local \
--opt type=cifs \
--opt o=username=user,password=pass,addr=192.168.1.100 \
--opt device=//192.168.1.100/share \
cifs-volume
# tmpfs 볼륨
docker volume create \
--driver local \
--opt type=tmpfs \
--opt device=tmpfs \
--opt o=size=100m \
tmpfs-volume
서드파티 볼륨 드라이버
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# REX-Ray (클라우드 스토리지)
docker plugin install rexray/ebs
docker volume create \
--driver rexray/ebs \
--opt size=10 \
ebs-volume
# Convoy (스냅샷 지원)
docker volume create \
--driver convoy \
convoy-volume
# Flocker (컨테이너 이동 시 데이터 함께 이동)
docker volume create \
--driver flocker \
flocker-volume
6.6 데이터 백업 및 복원
볼륨 백업
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 방법 1: tar로 압축
docker run --rm \
-v myvolume:/data \
-v $(pwd):/backup \
alpine \
tar czf /backup/myvolume-backup.tar.gz /data
# 방법 2: 컨테이너를 통한 백업
docker run --rm \
-v myvolume:/source:ro \
-v $(pwd):/backup \
alpine \
sh -c "cd /source && tar czf /backup/backup.tar.gz ."
# 방법 3: 직접 복사
sudo cp -r /var/lib/docker/volumes/myvolume/_data ./backup
볼륨 복원
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# tar에서 복원
docker run --rm \
-v myvolume:/data \
-v $(pwd):/backup \
alpine \
tar xzf /backup/myvolume-backup.tar.gz -C /
# 새 볼륨에 복원
docker volume create myvolume-restored
docker run --rm \
-v myvolume-restored:/data \
-v $(pwd):/backup \
alpine \
tar xzf /backup/backup.tar.gz -C /data
볼륨 복사
1
2
3
4
5
6
7
8
9
10
11
12
13
# 한 볼륨에서 다른 볼륨으로 복사
docker run --rm \
-v source-volume:/source:ro \
-v target-volume:/target \
alpine \
sh -c "cp -av /source/. /target/"
# 또는 tar 파이프라인
docker run --rm \
-v source-volume:/source:ro \
-v target-volume:/target \
alpine \
sh -c "cd /source && tar c . | tar x -C /target"
데이터베이스 백업
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# PostgreSQL 백업
docker exec postgres pg_dump -U postgres mydb > backup.sql
# 볼륨을 통한 백업
docker run --rm \
-v postgres-data:/var/lib/postgresql/data \
-v $(pwd):/backup \
postgres \
pg_dump -U postgres -f /backup/mydb.sql mydb
# MySQL 백업
docker exec mysql mysqldump -u root -p mydb > backup.sql
# MongoDB 백업
docker exec mongo mongodump --out /backup
7. Docker Compose
7.1 Docker Compose란?
Docker Compose의 목적
Docker Compose는 여러 컨테이너 애플리케이션을 정의하고 실행하는 도구이다.
주요 기능
- 멀티 컨테이너 애플리케이션 정의 (YAML 파일)
- 한 번의 명령으로 전체 스택 시작/중지
- 환경별 설정 관리 (개발, 테스트, 프로덕션)
- 서비스 스케일링
- 의존성 관리
설치
1
2
3
4
5
6
7
8
9
# Docker Desktop은 Compose 포함
# Linux에서 별도 설치
sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" \
-o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
# 버전 확인
docker-compose --version
7.2 docker-compose.yml 기본
기본 구조
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
version: '3.8'
services:
web:
image: nginx:latest
ports:
- "8080:80"
volumes:
- ./html:/usr/share/nginx/html
networks:
- frontend
db:
image: postgres:15
environment:
POSTGRES_PASSWORD: secret
volumes:
- db-data:/var/lib/postgresql/data
networks:
- backend
networks:
frontend:
backend:
volumes:
db-data:
버전
1
2
3
4
5
6
7
# Compose 파일 버전 (3.8 권장)
version: '3.8'
# 버전별 주요 차이:
# - 3.x: Docker Swarm 지원
# - 2.x: 로컬 개발 중심
# - 1.x: 레거시 (사용 안 함)
7.3 서비스 정의
이미지 지정
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
services:
# 이미지 사용
web:
image: nginx:latest
# Dockerfile 빌드
app:
build: .
# Dockerfile 경로 지정
app:
build:
context: ./app
dockerfile: Dockerfile.dev
# 빌드 인수
app:
build:
context: .
args:
- VERSION=1.0
- BUILD_DATE=2024-01-01
포트 매핑
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
services:
web:
ports:
# 호스트:컨테이너
- "8080:80"
# IP 지정
- "127.0.0.1:8080:80"
# 여러 포트
- "8080:80"
- "4443:443"
# UDP
- "53:53/udp"
# 포트 범위
- "8000-8010:8000-8010"
환경 변수
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
services:
web:
environment:
# 직접 지정
NODE_ENV: production
PORT: 3000
# 배열 형식
- NODE_ENV=production
- PORT=3000
# 파일에서 로드
env_file:
- .env
- .env.prod
db:
environment:
# 호스트 환경 변수 참조
DB_PASSWORD: ${DB_PASSWORD}
볼륨
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
services:
web:
volumes:
# Named volume
- data:/app/data
# Bind mount
- ./app:/app
- ./config:/etc/nginx
# 읽기 전용
- ./config:/etc/nginx:ro
# tmpfs
- type: tmpfs
target: /tmp
volumes:
data:
driver: local
네트워크
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
services:
web:
networks:
- frontend
- backend
db:
networks:
backend:
# IP 주소 지정
ipv4_address: 172.20.0.10
networks:
frontend:
driver: bridge
backend:
driver: bridge
ipam:
config:
- subnet: 172.20.0.0/16
의존성
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
services:
web:
depends_on:
- db
- redis
db:
image: postgres
redis:
image: redis
# depends_on은 시작 순서만 제어
# 서비스가 준비될 때까지 기다리지 않음
# 준비 여부는 healthcheck나 wait-for-it 스크립트 사용
헬스체크
1
2
3
4
5
6
7
8
services:
web:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
재시작 정책
1
2
3
4
5
6
7
services:
web:
restart: always
# no: 재시작 안 함 (기본값)
# always: 항상 재시작
# on-failure: 실패 시에만
# unless-stopped: 명시적 중지 전까지
7.4 Docker Compose 명령어
기본 명령
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 서비스 시작 (빌드 포함)
docker-compose up
# 백그라운드 실행
docker-compose up -d
# 빌드만
docker-compose build
# 강제 재빌드
docker-compose up --build
# 특정 서비스만
docker-compose up web
# 스케일링
docker-compose up -d --scale web=3
서비스 관리
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 서비스 중지
docker-compose stop
# 특정 서비스 중지
docker-compose stop web
# 서비스 시작 (이미 생성된 컨테이너)
docker-compose start
# 서비스 재시작
docker-compose restart
# 서비스 일시 정지
docker-compose pause
# 재개
docker-compose unpause
정리
1
2
3
4
5
6
7
8
9
10
11
# 컨테이너 중지 및 삭제
docker-compose down
# 볼륨도 삭제
docker-compose down -v
# 이미지도 삭제
docker-compose down --rmi all
# 고아 컨테이너 제거
docker-compose down --remove-orphans
로그 및 모니터링
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 로그 확인
docker-compose logs
# 실시간 로그
docker-compose logs -f
# 특정 서비스
docker-compose logs -f web
# 마지막 N줄
docker-compose logs --tail=100
# 타임스탬프 포함
docker-compose logs -t
# 실행 중인 서비스 확인
docker-compose ps
# 프로세스 확인
docker-compose top
명령 실행
1
2
3
4
5
6
7
8
# 서비스에서 명령 실행
docker-compose exec web bash
# 새 컨테이너에서 일회성 명령
docker-compose run web python manage.py migrate
# 컨테이너 생성 없이 실행
docker-compose run --rm web python script.py
설정 검증
1
2
3
4
5
6
7
8
# 설정 파일 검증
docker-compose config
# 환경 변수 치환 후 출력
docker-compose config
# 특정 파일 지정
docker-compose -f docker-compose.prod.yml config
7.5 실전 예시
웹 애플리케이션 스택
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
version: '3.8'
services:
# Nginx 웹 서버
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/ssl:/etc/nginx/ssl:ro
- static-files:/static
depends_on:
- web
networks:
- frontend
# Django 웹 애플리케이션
web:
build: ./app
command: gunicorn myapp.wsgi:application --bind 0.0.0.0:8000
volumes:
- ./app:/app
- static-files:/app/static
environment:
- DEBUG=False
- DATABASE_URL=postgresql://postgres:secret@db:5432/mydb
- REDIS_URL=redis://redis:6379/0
depends_on:
- db
- redis
networks:
- frontend
- backend
# PostgreSQL 데이터베이스
db:
image: postgres:15
volumes:
- postgres-data:/var/lib/postgresql/data
environment:
- POSTGRES_DB=mydb
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=secret
networks:
- backend
# Redis 캐시
redis:
image: redis:alpine
volumes:
- redis-data:/data
networks:
- backend
# Celery Worker
celery:
build: ./app
command: celery -A myapp worker -l info
volumes:
- ./app:/app
environment:
- DATABASE_URL=postgresql://postgres:secret@db:5432/mydb
- REDIS_URL=redis://redis:6379/0
depends_on:
- db
- redis
networks:
- backend
networks:
frontend:
backend:
volumes:
postgres-data:
redis-data:
static-files:
개발 환경 vs 프로덕션
1
2
3
4
5
6
7
8
9
10
11
# docker-compose.yml (베이스)
version: '3.8'
services:
web:
build: .
environment:
- DATABASE_URL=postgresql://db/mydb
db:
image: postgres:15
1
2
3
4
5
6
7
8
9
10
11
# docker-compose.override.yml (개발 - 자동 로드)
version: '3.8'
services:
web:
volumes:
- ./app:/app
environment:
- DEBUG=True
ports:
- "8000:8000"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# docker-compose.prod.yml (프로덕션)
version: '3.8'
services:
web:
image: myregistry.com/myapp:latest
environment:
- DEBUG=False
restart: always
db:
volumes:
- db-data:/var/lib/postgresql/data
restart: always
volumes:
db-data:
1
2
3
4
5
# 개발
docker-compose up # .yml + .override.yml 자동 병합
# 프로덕션
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d
8. Docker 레지스트리
8.1 Docker Hub
Docker Hub 사용
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 로그인
docker login
# Username:
# Password:
# 이미지 태그
docker tag myapp:latest username/myapp:latest
docker tag myapp:latest username/myapp:v1.0
# 푸시
docker push username/myapp:latest
docker push username/myapp:v1.0
# 풀
docker pull username/myapp:latest
# 로그아웃
docker logout
자동 빌드 (Automated Builds)
Docker Hub는 GitHub/Bitbucket과 연동하여 자동 빌드를 지원한다:
- Docker Hub에서 저장소 생성
- GitHub 저장소 연결
- 빌드 규칙 설정
- Git 푸시 시 자동 빌드
프라이빗 저장소
1
2
3
4
5
# 프라이빗 저장소 풀 (로그인 필요)
docker pull username/private-repo:latest
# 무료 플랜: 1개 프라이빗 저장소
# 유료 플랜: 무제한
8.2 프라이빗 레지스트리 구축
Registry 컨테이너 실행
1
2
3
4
5
6
7
8
9
10
11
12
13
# 기본 레지스트리
docker run -d \
-p 5000:5000 \
--name registry \
-v registry-data:/var/lib/registry \
registry:2
# 이미지 푸시
docker tag myapp:latest localhost:5000/myapp:latest
docker push localhost:5000/myapp:latest
# 이미지 풀
docker pull localhost:5000/myapp:latest
TLS/SSL 설정
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 인증서 준비
mkdir -p certs
# certs/domain.crt, certs/domain.key
# TLS로 레지스트리 실행
docker run -d \
-p 443:443 \
--name registry \
-v registry-data:/var/lib/registry \
-v $(pwd)/certs:/certs \
-e REGISTRY_HTTP_ADDR=0.0.0.0:443 \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
-e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
registry:2
Basic 인증
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# htpasswd 파일 생성
mkdir auth
docker run --rm --entrypoint htpasswd \
httpd:2 -Bbn username password > auth/htpasswd
# 인증 활성화
docker run -d \
-p 5000:5000 \
--name registry \
-v registry-data:/var/lib/registry \
-v $(pwd)/auth:/auth \
-e REGISTRY_AUTH=htpasswd \
-e REGISTRY_AUTH_HTPASSWD_REALM="Registry Realm" \
-e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
registry:2
# 로그인
docker login localhost:5000
8.3 Harbor
Harbor란?
Harbor는 엔터프라이즈급 컨테이너 레지스트리이다.
주요 기능
- 웹 UI
- RBAC (역할 기반 접근 제어)
- 이미지 스캐닝 (Trivy, Clair)
- 이미지 서명
- 복제 (다중 레지스트리)
- Helm 차트 저장소
- 감사 로그
설치 (Docker Compose)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Harbor 다운로드
wget https://github.com/goharbor/harbor/releases/download/v2.9.0/harbor-offline-installer-v2.9.0.tgz
tar xzvf harbor-offline-installer-v2.9.0.tgz
cd harbor
# 설정
cp harbor.yml.tmpl harbor.yml
vi harbor.yml
# hostname 수정
# 인증서 경로 설정 (선택)
# 설치
sudo ./install.sh
# 접속
# https://your-harbor-domain
# admin / Harbor12345 (기본)
Harbor 사용
1
2
3
4
5
6
7
8
9
10
11
12
# 로그인
docker login harbor.example.com
# 프로젝트 생성 (UI에서)
# library, myapp 등
# 이미지 푸시
docker tag myapp:latest harbor.example.com/library/myapp:latest
docker push harbor.example.com/library/myapp:latest
# 이미지 풀
docker pull harbor.example.com/library/myapp:latest