728x90
반응형
0. 목표 정의
- “내 컴에선 되는데?”를 없애기 위해
코드 + OS + 라이브러리 + 설정을 전부 Docker 이미지로 고정한다. - 로컬 / 테스트 서버 / 운영 서버 어디서든
docker compose up 한 방에 동일한 환경을 띄우는 것을 목표로 한다.
1. 기본 원칙
- 하나의 서비스 = 하나의 이미지
- FastAPI, 백엔드, 워커, DB 등은 각각 컨테이너로 분리.
- 이미지는 불변(Immutable)
- 컨테이너 안에 직접 pip install 하지 않고,
항상 Dockerfile 변경 → docker build로 새 이미지 생성.
- 컨테이너 안에 직접 pip install 하지 않고,
- 컨테이너는 휘발성
- 컨테이너 안에 중요한 데이터를 저장하지 않는다.
- 데이터는 반드시 볼륨/외부 DB에 저장.
- 환경 차이는 “환경 변수”로 제어
- 코드/이미지는 같고, 환경별(dev/stage/prod) 설정만 env로 분리.
2. 예시 프로젝트 구조
예를 들어 FastAPI + PostgreSQL 서비스라고 하면:
myapp/
├─ app/
│ ├─ __init__.py
│ ├─ main.py
│ └─ config.py
├─ requirements.txt
├─ Dockerfile
├─ docker-compose.yml
├─ .dockerignore
├─ .env # 공용 개발 환경설정 (운영용은 별도 관리)
└─ README.md
3. Dockerfile 설계 예시 (Python / FastAPI 기준)
# 1) 베이스 이미지 선택 (슬림, 재현성 위해 태그 고정)
FROM python:3.11-slim AS base
# 2) 시스템 패키지 설치 (필요할 때만 최소한으로)
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
&& rm -rf /var/lib/apt/lists/*
# 3) 작업 디렉토리
WORKDIR /app
# 4) 의존성 파일만 먼저 복사 → 캐시 활용
COPY requirements.txt .
# 5) 패키지 설치 (가상환경 없이 컨테이너 자체를 가상환경처럼 사용)
RUN pip install --no-cache-dir -r requirements.txt
# 6) 앱 코드 복사
COPY app ./app
# 7) 환경 변수 (예: uvicorn host/port는 나중에 override 가능)
ENV PYTHONUNBUFFERED=1
# 8) 실행 커맨드
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000"]
포인트:
- 베이스 이미지 태그는 반드시 고정 (python:3.11-slim) → 재현성 강화.
- requirements.txt 먼저 복사해서 의존성 설치 캐시 최대 활용.
- 컨테이너 자체가 격리된 환경이라 venv를 추가로 만들지 않아도 됨(단순화).
4. .dockerignore 설정
빌드 시不要 파일이 이미지에 포함되지 않도록:
.git
__pycache__
*.pyc
*.pyo
*.pyd
.env
.venv
tests
notebooks
- .env는 외부에서 주입하는 게 원칙 (이미지 안에 비번을 넣지 않는다).
- 로컬 가상환경, 캐시 폴더 등도 제외.
5. docker-compose로 “여러 서비스” 한 번에 띄우기
예: FastAPI + PostgreSQL
# docker-compose.yml
version: "3.9"
services:
api:
build: .
container_name: myapp-api
ports:
- "8000:8000"
env_file:
- .env
depends_on:
- db
db:
image: postgres:16
container_name: myapp-db
environment:
POSTGRES_USER: myuser
POSTGRES_PASSWORD: mypassword
POSTGRES_DB: mydb
volumes:
- db_data:/var/lib/postgresql/data
volumes:
db_data:
운영 시에는 .env 대신 KMS/Secret Manager 또는 별도의 .env.prod를 사용하도록 권장.
6. 환경 변수 관리 모범 사례
- 코드에서 하드코딩 금지
# app/config.py
import os
class Settings:
db_url: str = os.getenv("DATABASE_URL", "postgresql://myuser:mypassword@db:5432/mydb")
debug: bool = os.getenv("DEBUG", "false").lower() == "true"
settings = Settings()
- 환경별 .env 분리 (개발용)
# .env (dev)
DEBUG=true
DATABASE_URL=postgresql://myuser:mypassword@db:5432/mydb
운영에서는:
- .env 파일을 Git에 올리지 않는다.
- 서버/오케스트레이션(Kubernetes, ECS 등)에서 환경 변수로 직접 주입.
7. 재현성을 위한 버전/이미지 관리
- 이미지 태그 규칙 정하기
예:
- myapp-api:1.0.0
- myapp-api:1.0.1-hotfix
- myapp-api:latest는 개발/로컬용으로만 사용.
- Git 태그와 Docker 태그를 맞춘다
- Git 태그 v1.0.0 → Docker 태그 myapp-api:1.0.0
- 특정 버전에 버그가 생겨도 정확히 어떤 이미지인지 추적 가능.
- 빌드 명령 예시
# 로컬 빌드
docker build -t myapp-api:1.0.0 .
# 실행
docker run --rm -p 8000:8000 --env-file .env myapp-api:1.0.0
8. 개발/스테이징/운영 환경 분리 패턴
- 공통 compose 파일: docker-compose.yml
- 환경별 오버라이드 파일:
- docker-compose.dev.yml
- docker-compose.prod.yml
예시:
# docker-compose.dev.yml
services:
api:
environment:
DEBUG: "true"
volumes:
- .:/app # 코드 변경 시 바로 반영 (개발 모드)
운영:
# docker-compose.prod.yml
services:
api:
image: myregistry/myapp-api:1.0.0
restart: always
environment:
DEBUG: "false"
실행:
# 개발
docker compose -f docker-compose.yml -f docker-compose.dev.yml up
# 운영
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
9. CI/CD와 연계한 모범 배포 플로우 예시
- Git main 브랜치에 머지 → CI가 작동:
- 테스트 실행 (pytest 등)
- Docker 이미지 빌드
- 이미지 태깅 (예: myapp-api:gitsha 또는 myapp-api:1.2.3)
- 이미지 레지스트리(ECR, GCR, GHCR 등)에 push
- 배포 서버/오케스트레이터에서:
- 새 태그의 이미지 pull
- docker compose 혹은 Kubernetes manifest 업데이트
- 무중단 배포(blue-green, rolling 등) 적용
핵심: 운영 서버에서 빌드하지 않고, 검증된 이미지만 배포
→ 개발/테스트에서 돌린 것과 완전히 동일한 이미지가 운영까지 그대로 간다.
10. Docker 환경관리 모범 사례 정리
- Dockerfile:
- 베이스 이미지 태그를 고정한다.
- 필요 최소한의 OS 패키지만 설치한다.
- 의존성 설치를 위한 레이어(예: requirements.txt)를 위로 올려 캐시를 활용한다.
- 앱 실행은 CMD 또는 ENTRYPOINT로 명확히 지정한다.
- 보안/시크릿:
- 비밀번호/토큰을 Dockerfile에 쓰지 않는다.
- .env나 오케스트레이터의 Secret 기능을 사용한다.
- .env는 .gitignore에 반드시 포함한다.
- 로깅:
- 컨테이너 내부에서 파일로 로그 쓰기보다는 stdout/stderr로 출력.
- 로그 수집기는 호스트/플랫폼에서 수집.
- 상태 관리:
- 컨테이너는 언제든지 삭제/재시작 가능하다는 전제로 설계한다.
- DB, 파일 저장소, 캐시는 외부 서비스(볼륨, S3, RDS 등)에 둔다.
- 문서화:
- README.md에 “Docker로 실행하는 방법”을 항상 포함:
- 빌드 방법
- 환경 변수 목록
- docker compose로 올리는 명령
- README.md에 “Docker로 실행하는 방법”을 항상 포함:
728x90
반응형
'기술공부 > 개발_코드' 카테고리의 다른 글
| 개발 환경 관리 가이드 (0) | 2025.11.19 |
|---|---|
| 파이썬 가상환경 완전 정리: Mac / Windows + venv / conda 사용법 비교 가이드 (0) | 2025.11.18 |
| Neo4j Docker로 띄우기 (0) | 2025.11.17 |
| 배치처리의 장점 (0) | 2025.02.25 |
| 배치처리 vs. 개별처리 (0) | 2025.02.25 |