Choorai
Cycle 7

Docker - 컨테이너화

Docker로 애플리케이션을 컨테이너화하면 "내 컴퓨터에서는 되는데..."가 사라집니다. 어디서든 동일한 환경에서 동일하게 실행됩니다.

이 Cycle에서 배우는 것

  • 컨테이너의 개념과 장점 이해
  • Dockerfile 작성 및 이미지 빌드
  • Docker Compose로 멀티 컨테이너 관리
  • 클라우드 레지스트리에 이미지 배포

컨테이너란?

컨테이너는 애플리케이션과 그 실행에 필요한 모든 것 (코드, 라이브러리, 설정)을 하나의 패키지로 묶은 것입니다.

VM vs 컨테이너

가상 머신 (VM)

App
라이브러리
Guest OS (수 GB)
Hypervisor
Host OS

⚠️ OS 전체를 포함하여 무겁고 느림

컨테이너

App
라이브러리
컨테이너 엔진 (경량)
Host OS

✅ OS 커널 공유로 가볍고 빠름

Docker 핵심 개념

📦

이미지 (Image)

컨테이너의 "설계도". Dockerfile로 정의하고, 한 번 빌드하면 변경 불가 (불변).

🐳

컨테이너 (Container)

이미지를 실행한 "인스턴스". 여러 개 실행 가능, 삭제하면 데이터도 사라짐.

🏪

레지스트리 (Registry)

이미지를 저장하고 공유하는 "저장소". Docker Hub, GCR, GHCR 등.

왜 컨테이너를 사용하나요?

  • 환경 일관성: 개발/테스트/프로덕션 환경이 동일
  • 빠른 배포: 이미지만 다운받아 바로 실행
  • 격리: 다른 앱과 충돌 없이 독립 실행
  • 확장성: 같은 이미지로 여러 컨테이너 실행

Dockerfile 기본

Dockerfile은 이미지를 만드는 "레시피"입니다. 각 명령어가 한 줄씩 레이어를 쌓아 최종 이미지를 만듭니다.

기본 명령어

명령어 설명 예시
FROM 베이스 이미지 지정 FROM python:3.11-slim
WORKDIR 작업 디렉토리 설정 WORKDIR /app
COPY 파일 복사 COPY . .
RUN 빌드 시 명령 실행 RUN pip install -r requirements.txt
EXPOSE 포트 문서화 EXPOSE 8000
CMD 컨테이너 실행 명령 CMD ["uvicorn", "main:app"]

Python (FastAPI) Dockerfile

Dockerfile (FastAPI)
# Python 3.11 슬림 이미지 사용 (크기 최소화)
FROM python:3.11-slim

# 작업 디렉토리 설정
WORKDIR /app

# 의존성 파일 먼저 복사 (캐싱 최적화)
COPY requirements.txt .

# 의존성 설치
RUN pip install --no-cache-dir -r requirements.txt

# 소스 코드 복사
COPY . .

# 포트 노출 (문서화 목적)
EXPOSE 8000

# 컨테이너 실행 명령
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]

Node.js (Hono) Dockerfile

Dockerfile (Hono/Node.js)
# Node.js 20 LTS 알파인 이미지 (경량)
FROM node:20-alpine

# 작업 디렉토리 설정
WORKDIR /app

# 패키지 파일 먼저 복사 (캐싱 최적화)
COPY package*.json ./

# 의존성 설치 (프로덕션 전용)
RUN npm ci --only=production

# 소스 코드 복사
COPY . .

# 포트 노출
EXPOSE 3000

# 컨테이너 실행 명령
CMD ["node", "src/index.js"]

멀티 스테이지 빌드 (최적화)

빌드용 이미지와 실행용 이미지를 분리하여 최종 이미지 크기를 줄입니다.

Dockerfile (멀티 스테이지)
# Stage 1: 빌드
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Stage 2: 프로덕션
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3000
CMD ["node", "dist/index.js"]

이미지 빌드 & 실행

터미널
# 이미지 빌드
docker build -t my-api:latest .

# 컨테이너 실행
docker run -p 8000:8000 my-api:latest

# 백그라운드 실행
docker run -d -p 8000:8000 --name my-api my-api:latest

# 로그 확인
docker logs my-api

# 컨테이너 중지 & 삭제
docker stop my-api && docker rm my-api

Docker Compose

여러 컨테이너를 한 번에 정의하고 실행합니다. 프론트엔드, 백엔드, DB를 하나의 파일로 관리할 수 있습니다.

왜 Compose가 필요한가?

❌ docker run 반복

docker run -d postgres...

docker run -d redis...

docker run -d my-api...

docker run -d my-frontend...

✅ Compose 한 줄

docker compose up -d

모든 서비스 한 번에 시작!

docker-compose.yml 예시 (Python 스택)

docker-compose.yml
version: '3.8'

services:
  # PostgreSQL 데이터베이스
  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_USER: myuser
      POSTGRES_PASSWORD: mypassword
      POSTGRES_DB: mydb
    volumes:
      - postgres_data:/var/lib/postgresql/data
    ports:
      - "5432:5432"

  # FastAPI 백엔드
  api:
    build: ./backend
    ports:
      - "8000:8000"
    environment:
      DATABASE_URL: postgresql://myuser:mypassword@db:5432/mydb
    depends_on:
      - db

  # React 프론트엔드
  web:
    build: ./frontend
    ports:
      - "3000:3000"
    depends_on:
      - api

volumes:
  postgres_data:

docker-compose.yml 예시 (Node.js 스택)

docker-compose.yml (Node.js)
version: '3.8'

services:
  # PostgreSQL 데이터베이스
  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_USER: myuser
      POSTGRES_PASSWORD: mypassword
      POSTGRES_DB: mydb
    volumes:
      - postgres_data:/var/lib/postgresql/data
    ports:
      - "5432:5432"

  # Hono 백엔드
  api:
    build: ./backend
    ports:
      - "3001:3001"
    environment:
      DATABASE_URL: postgresql://myuser:mypassword@db:5432/mydb
    depends_on:
      - db

  # Vite 프론트엔드
  web:
    build: ./frontend
    ports:
      - "5173:5173"
    depends_on:
      - api

volumes:
  postgres_data:

주요 명령어

명령어 설명
docker compose up -d 모든 서비스 백그라운드 시작
docker compose down 모든 서비스 중지 & 삭제
docker compose logs -f api api 서비스 로그 실시간 확인
docker compose exec api sh api 컨테이너에 쉘 접속
docker compose build 이미지 다시 빌드

이미지 레지스트리

빌드한 이미지를 클라우드에 저장하면 어디서든 다운받아 실행할 수 있습니다.

주요 레지스트리 비교

Docker Hub

가장 널리 사용되는 공개 레지스트리

  • ✅ 공개 이미지 무제한
  • ✅ 간편한 사용법
  • ⚠️ 비공개 1개만 무료

GCR / Artifact Registry

Google Cloud의 레지스트리

  • ✅ Cloud Run과 최적 연동
  • ✅ 비공개 기본
  • ⚠️ 스토리지 비용 발생

GitHub Container Registry

GitHub와 통합된 레지스트리

  • ✅ GitHub Actions 연동
  • ✅ 공개 무료
  • ⚠️ 비공개 500MB 무료

GCR에 이미지 푸시

터미널 (GCR)
# 1. gcloud 인증
gcloud auth configure-docker asia-northeast3-docker.pkg.dev

# 2. 이미지 태깅
docker tag my-api:latest \
  asia-northeast3-docker.pkg.dev/PROJECT_ID/my-repo/my-api:latest

# 3. 이미지 푸시
docker push asia-northeast3-docker.pkg.dev/PROJECT_ID/my-repo/my-api:latest

# 4. Cloud Run에서 사용
gcloud run deploy my-api \
  --image=asia-northeast3-docker.pkg.dev/PROJECT_ID/my-repo/my-api:latest \
  --region=asia-northeast3

GitHub Container Registry 푸시

터미널 (GHCR)
# 1. GitHub Personal Access Token으로 로그인
echo $GITHUB_TOKEN | docker login ghcr.io -u USERNAME --password-stdin

# 2. 이미지 태깅
docker tag my-api:latest ghcr.io/USERNAME/my-api:latest

# 3. 이미지 푸시
docker push ghcr.io/USERNAME/my-api:latest

실전 팁 & 베스트 프랙티스

.dockerignore 설정

빌드 컨텍스트에서 불필요한 파일을 제외하여 빌드 속도를 높입니다.

.dockerignore
# 버전 관리
.git
.gitignore

# 의존성 (이미지에서 새로 설치)
node_modules
__pycache__
.venv
venv

# 빌드 산출물
dist
build
*.pyc

# 개발용 파일
.env.local
.env.development
*.log

# IDE
.vscode
.idea

# Docker 관련
Dockerfile
docker-compose*.yml
.dockerignore

레이어 캐싱 최적화

❌ 비효율적

COPY . .

RUN pip install -r requirements.txt

소스 변경 시 의존성도 매번 재설치

✅ 효율적

COPY requirements.txt .

RUN pip install -r requirements.txt

COPY . .

의존성 파일 미변경 시 캐시 사용

보안 주의사항

  • root 유저 피하기: USER 명령으로 non-root 사용자 설정
  • 시크릿 주의: Dockerfile에 비밀번호 하드코딩 금지
  • 최신 베이스 이미지: 보안 패치가 적용된 최신 버전 사용
  • 최소 권한: 필요한 패키지만 설치

디버깅 팁

터미널
# 실행 중인 컨테이너 확인
docker ps

# 컨테이너 로그 확인
docker logs -f my-container

# 컨테이너 내부 접속
docker exec -it my-container sh

# 이미지 히스토리 확인 (레이어별 크기)
docker history my-api:latest

# 사용하지 않는 리소스 정리
docker system prune -a

다음 단계

Docker로 컨테이너화를 완료했다면, 이제 CI/CD를 설정하여 코드 푸시만으로 자동 배포되도록 구성해보세요.

마지막 업데이트: 2026년 2월 22일 · 버전: v0.0.1

피드백 보내기

입력한 내용으로 새 이슈 페이지를 엽니다.

GitHub 이슈로 보내기