🐳
컨테이너 가상화

Docker 완전 가이드

👥 방문자 수

애플리케이션을 격리된 컨테이너 환경에서 실행하는 Docker를 체계적으로 학습합니다. Dockerfile 작성부터 다중 컨테이너 배포를 위한 Compose까지 실무 핵심 지식을 완벽하게 정리했습니다.

Docker 27 Dockerfile Compose DevOps

1. Docker란?

Docker는 애플리케이션을 컨테이너라는 표준화된 유닛으로 패키징하여 어떤 환경에서도 동일하게 실행할 수 있게 돕는 플랫폼입니다. VM과 달리 호스트 OS 커널을 공유하므로 훨씬 가볍습니다.

항목가상 머신 (VM)Docker 컨테이너
부팅 시간수 분수 초 미만
이미지 크기수 GB수 MB ~ 수백 MB
OS 커널독립 Guest OSHost OS 공유
격리 수준완전한 하드웨어 격리프로세스 격리 (namespace)

2. 설치

# macOS / Windows: Docker Desktop 설치
# https://www.docker.com/get-started

# Linux (Ubuntu)
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER  # sudo 없이 사용
newgrp docker

docker --version       # Docker version 27.x.x
docker compose version # Docker Compose v2.x.xbash

3. 핵심 개념

용어설명
Image컨테이너 실행에 필요한 파일 시스템 스냅샷. 읽기 전용 레이어 스택
Container이미지의 실행 인스턴스. 읽기/쓰기 레이어 추가
Dockerfile이미지 빌드 지시문 파일
Registry이미지 저장·배포 서버 (Docker Hub, GHCR, ECR 등)
Volume컨테이너 외부의 영구 데이터 저장소
Network컨테이너 간 통신을 위한 가상 네트워크

4. 기본 명령어

# ── 이미지 ───────────────────────────────────────
docker pull nginx:alpine          # 이미지 다운로드
docker images                     # 로컬 이미지 목록
docker rmi nginx:alpine           # 이미지 삭제
docker image prune                # 미사용 이미지 정리

# ── 컨테이너 실행 ─────────────────────────────────
docker run -d \
  --name web \
  -p 8080:80 \
  -e ENV=production \
  -v $(pwd)/html:/usr/share/nginx/html \
  nginx:alpine

# 주요 옵션
# -d          백그라운드 실행
# --name      컨테이너 이름 지정
# -p 호스트:컨테이너  포트 매핑
# -e KEY=VAL  환경 변수
# -v 호스트:컨테이너  볼륨 마운트
# --rm        종료 시 자동 삭제

# ── 컨테이너 관리 ─────────────────────────────────
docker ps                         # 실행 중 컨테이너
docker ps -a                      # 전체 컨테이너
docker logs -f web                # 로그 스트리밍
docker exec -it web sh            # 컨테이너 내부 접속
docker stats                      # CPU·메모리 실시간 모니터링
docker stop web && docker rm web  # 중지 후 삭제
docker container prune            # 중지된 컨테이너 정리bash

5. Dockerfile

# Node.js 애플리케이션 Dockerfile
FROM node:20-alpine

# 비루트 사용자 생성 (보안)
RUN addgroup -S app && adduser -S app -G app

WORKDIR /app

# 레이어 캐싱 최적화: 의존성 먼저 복사
COPY package*.json ./
RUN npm ci --only=production

# 소스 복사
COPY --chown=app:app . .

# 비루트 사용자로 전환
USER app

EXPOSE 3000

# ENTRYPOINT: 고정 실행 명령어 (CMD와 조합)
ENTRYPOINT ["node"]
CMD ["server.js"]dockerfile
명령어설명
FROM베이스 이미지 지정
RUN빌드 시 셸 명령 실행 (새 레이어 생성)
COPY호스트 파일을 이미지로 복사
ENV환경 변수 설정
ARG빌드 시점 변수 (--build-arg로 전달)
EXPOSE컨테이너가 사용할 포트 문서화
ENTRYPOINT컨테이너 시작 명령어 (고정)
CMD기본 인자 (ENTRYPOINT 없으면 실행 명령)
HEALTHCHECK헬스 체크 명령 설정

6. 멀티스테이지 빌드

빌드 도구를 포함한 무거운 빌드 환경과 실제 실행 환경을 분리해 최종 이미지 크기를 최소화합니다.

# Go 애플리케이션 예시 — 빌드 결과물만 최종 이미지에 포함
FROM golang:1.22-alpine AS builder
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -ldflags="-w -s" -o /app ./cmd/server

# ── 최종 이미지: 바이너리만 포함 ──────────────────
FROM scratch          # 빈 이미지 (가장 작음)
COPY --from=builder /app /app
COPY --from=builder /etc/ssl/certs /etc/ssl/certs
EXPOSE 8080
ENTRYPOINT ["/app"]

# 결과: Go 빌드 이미지 ~800MB → 최종 이미지 ~10MBdockerfile
# Next.js 예시 — 빌드 → 의존성 → 실행 3단계
FROM node:20-alpine AS deps
WORKDIR /app
COPY package*.json ./
RUN npm ci

FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build

FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
RUN addgroup -S nextjs && adduser -S nextjs -G nextjs
COPY --from=builder --chown=nextjs:nextjs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nextjs /app/public ./public
USER nextjs
EXPOSE 3000
CMD ["node", "server.js"]dockerfile

7. 볼륨과 마운트

# ── Named Volume (권장) ────────────────────────────
docker volume create pgdata
docker run -d \
  --name postgres \
  -v pgdata:/var/lib/postgresql/data \
  -e POSTGRES_PASSWORD=secret \
  postgres:16-alpine

docker volume ls        # 볼륨 목록
docker volume inspect pgdata
docker volume rm pgdata

# ── Bind Mount (개발 환경) ─────────────────────────
docker run -d \
  -v $(pwd):/app \       # 호스트 경로를 컨테이너에 직접 마운트
  -w /app \
  node:20-alpine \
  npm run dev

# ── tmpfs Mount (메모리 임시 저장) ─────────────────
docker run --tmpfs /tmp:rw,size=100m nginxbash

8. 네트워크

# Docker 네트워크 드라이버
# bridge: 기본값, 같은 호스트의 컨테이너 간 통신
# host:   호스트 네트워크 직접 사용 (Linux만)
# none:   네트워크 비활성화
# overlay: Swarm/Kubernetes 멀티 호스트 통신

# 사용자 정의 bridge 네트워크 (컨테이너명으로 DNS 통신 가능)
docker network create mynet
docker run -d --name api  --network mynet my-api
docker run -d --name db   --network mynet postgres:16-alpine

# api 컨테이너에서 db 이름으로 접근 가능:
# postgresql://db:5432/mydb

docker network ls
docker network inspect mynet
docker network rm mynetbash

9. Docker Compose

# docker-compose.yml — 실무 수준 예시
services:
  api:
    build:
      context: .
      dockerfile: Dockerfile
      args:
        NODE_ENV: production
    ports: ["3000:3000"]
    environment:
      DATABASE_URL: postgresql://user:${DB_PASS}@db:5432/mydb
      REDIS_URL: redis://cache:6379
    depends_on:
      db:    { condition: service_healthy }
      cache: { condition: service_started }
    restart: unless-stopped
    volumes:
      - ./uploads:/app/uploads
    networks: [backend]

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: ${DB_PASS}
      POSTGRES_DB: mydb
    volumes:
      - pgdata:/var/lib/postgresql/data
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "user"]
      interval: 5s
      timeout: 3s
      retries: 5
    networks: [backend]

  cache:
    image: redis:7-alpine
    command: redis-server --maxmemory 256mb --maxmemory-policy allkeys-lru
    volumes: [redisdata:/data]
    networks: [backend]

volumes:
  pgdata:
  redisdata:

networks:
  backend:
    driver: bridgeyaml
# Compose 주요 명령어
docker compose up -d          # 전체 스택 백그라운드 실행
docker compose up -d api      # 특정 서비스만 실행
docker compose logs -f api    # 특정 서비스 로그
docker compose exec db psql -U user mydb  # 서비스 내부 명령
docker compose down           # 중지 + 컨테이너 삭제
docker compose down -v        # 볼륨까지 삭제bash

10. 이미지 레지스트리

# ── Docker Hub ────────────────────────────────────
docker login
docker tag myapp:latest username/myapp:1.0.0
docker push username/myapp:1.0.0

# ── GitHub Container Registry (GHCR) ──────────────
echo $GITHUB_TOKEN | docker login ghcr.io -u USERNAME --password-stdin
docker tag myapp ghcr.io/org/myapp:latest
docker push ghcr.io/org/myapp:latest

# ── 프라이빗 레지스트리 (로컬) ─────────────────────
docker run -d -p 5000:5000 --name registry registry:2
docker tag myapp localhost:5000/myapp
docker push localhost:5000/myappbash

11. 보안 & 베스트 프랙티스

# .dockerignore — 불필요한 파일 제외 (빌드 컨텍스트 최소화)
node_modules
.git
.env
*.log
coverage
.next
disttext
💡
이미지 최적화 체크리스트
✅ Alpine / Distroless 베이스 이미지 사용 — 공격 표면 최소화
✅ 멀티스테이지 빌드로 빌드 도구 제거
USER nonroot로 비루트 실행
.dockerignore로 빌드 컨텍스트 최소화
✅ 레이어 캐싱: COPY package.jsonRUN npm ciCOPY . . 순서 유지
HEALTHCHECK 설정으로 오케스트레이터 헬스체크 활성화
docker scout 또는 trivy로 취약점 스캔

12. 다음 단계

🚀
Docker 이후 로드맵

Kubernetes — 컨테이너 오케스트레이션 (자동 스케일링, 롤링 업데이트, 자가 치유)
Docker Swarm — 경량 클러스터 오케스트레이션 (소규모 팀)
CI/CD 통합 — GitHub Actions에서 자동 빌드 · 푸시 · 배포
Buildkit / BuildX — 병렬 빌드, 멀티 아키텍처 이미지 (ARM + AMD64)