개발, 테스트, 운영에서의 도커 활용
핵심 원칙: "한 번 빌드하고, 어디서든 실행한다 (Build once, run anywhere)"
도커의 가장 큰 장점은 환경 일관성입니다. 동일한 도커 이미지를 사용하여 개발, 테스트, 운영 환경을 구성함으로써 "제 PC에서는 됐는데..." 하는 문제를 최소화할 수 있습니다.
1. 개발 단계 (Development)
목표: 빠른 코드 변경 반영, 쉬운 디버깅, 실제 운영 환경과 유사한 환경 구성.
Docker 사용 방안:
Dockerfile작성: 애플리케이션 실행에 필요한 모든 의존성(OS, 라이브러리, 런타임 등)을 정의합니다.- 개발용
Dockerfile은 프로덕션용과 거의 동일하게 가져가되, 디버깅 도구나 개발용 라이브러리를 추가할 수 있습니다. (멀티 스테이지 빌드를 활용하면 최종 이미지에는 포함되지 않도록 할 수 있습니다.)
- 개발용
docker-compose.yml활용:애플리케이션 컨테이너 외에 데이터베이스(MySQL, PostgreSQL, MongoDB 등), 메시지 큐(Redis, Kafka 등) 등 필요한 서비스를 함께 정의하여 로컬에서 전체 스택을 쉽게 실행할 수 있습니다.
볼륨 마운트 (Volume Mounts): 로컬 소스 코드를 컨테이너 내부의 작업 디렉토리로 마운트합니다. 이렇게 하면 로컬에서 코드를 수정할 때마다 이미지를 다시 빌드할 필요 없이 변경 사항이 컨테이너에 즉시 반영됩니다 (예:
nodemon같은 도구와 함께 사용).# docker-compose.yml (개발용 예시) version: '3.8' services: app: build: context: . dockerfile: Dockerfile.dev # 개발용 Dockerfile (필요시) ports: - "3000:3000" # 로컬 3000 포트와 컨테이너 3000 포트 연결 volumes: - .:/usr/src/app # 현재 디렉토리를 컨테이너 /usr/src/app에 마운트 - /usr/src/app/node_modules # node_modules는 호스트와 동기화하지 않도록 (선택적) environment: - NODE_ENV=development - DB_HOST=db depends_on: - db db: image: postgres:13 environment: - POSTGRES_USER=devuser - POSTGRES_PASSWORD=devpass volumes: - postgres_data:/var/lib/postgresql/data volumes: postgres_data:
환경 변수: 개발용 데이터베이스 접속 정보, API 키 등을 환경 변수로 관리합니다.
.env파일을docker-compose.yml에서 참조하도록 설정할 수 있습니다.디버깅: 컨테이너 포트를 호스트에 매핑하여 디버거를 연결하거나,
docker logs <container_id>로 로그를 확인하고,docker exec -it <container_id> /bin/sh로 컨테이너 내부에 접속하여 상태를 확인할 수 있습니다.
2. 테스트 단계 (Testing)
목표: 개발된 기능의 정확성 검증, 통합 테스트, 성능 테스트 등을 격리된 환경에서 수행.
Docker 사용 방안:
동일한 Docker 이미지 사용: 개발 단계에서 사용한
Dockerfile(또는 프로덕션용Dockerfile)로 빌드된 이미지를 사용합니다. 이는 환경 차이로 인한 오류를 방지합니다.docker-compose.test.yml또는 환경 변수 활용:테스트용 데이터베이스, Mock 서버 등 테스트에 필요한 서비스를
docker-compose.yml파일로 구성합니다.테스트용 데이터베이스 연결 정보, 테스트용 API 키 등을 환경 변수로 주입합니다.
docker-compose -f docker-compose.yml -f docker-compose.test.override.yml up -d와 같이 오버라이드 파일을 사용할 수 있습니다.
CI/CD 파이프라인 통합:
Git에 코드가 푸시되면 CI 서버(Jenkins, GitLab CI, GitHub Actions 등)가 자동으로 도커 이미지를 빌드합니다.
빌드된 이미지를 사용하여
docker-compose(또는 Kubernetes 등)로 테스트 환경을 구성하고 자동화된 테스트 스크립트(단위 테스트, 통합 테스트, E2E 테스트)를 실행합니다.테스트가 성공하면 이미지를 도커 레지스트리(Docker Hub, AWS ECR, GCP GCR 등)에 푸시합니다. (예:
myapp:feature-branch-build123,myapp:staging-latest)
데이터 초기화: 각 테스트 실행 전에 데이터베이스를 초기 상태로 되돌리거나, 테스트용 데이터를 로드하는 스크립트를 컨테이너 시작 시 실행하도록 구성합니다.
3. 운영 단계 (Production)
목표: 안정적이고 확장 가능한 서비스 제공, 보안 강화, 모니터링.
Docker 사용 방안:
테스트 완료된 Docker 이미지 사용: 테스트 단계에서 검증된 도커 이미지를 레지스트리에서 가져와 배포합니다. (예:
myapp:v1.2.0,myapp:latest)최적화된
Dockerfile:멀티 스테이지 빌드 (Multi-stage builds): 빌드에 필요한 도구(컴파일러, 테스트 라이브러리 등)는 빌드 스테이지에서만 사용하고, 최종 런타임 이미지는 애플리케이션 실행에 필요한 최소한의 파일만 포함하여 이미지 크기를 줄이고 보안을 강화합니다.
불필요한 파일 제외 (
.dockerignore사용).보안 취약점이 없는 공식 베이스 이미지 사용 및 주기적 업데이트.
Non-root 유저로 애플리케이션 실행.
docker-compose.prod.yml또는 오케스트레이션 도구 활용:Docker Compose: 소규모 애플리케이션이나 단일 호스트 환경에서 적합합니다.
Kubernetes (K8s), Docker Swarm, AWS ECS, GCP GKE/Cloud Run 등: 대규모, 고가용성, 자동 확장(auto-scaling), 롤링 업데이트, 상태 점검(health checks) 등이 필요한 경우 오케스트레이션 도구를 사용합니다.
환경 변수 및 시크릿 관리:
운영용 데이터베이스 접속 정보, API 키, 인증서 등의 민감 정보는 환경 변수로 주입합니다.
오케스트레이션 도구의 시크릿 관리 기능(Kubernetes Secrets, AWS Secrets Manager, HashiCorp Vault 등)을 활용합니다.
로깅 및 모니터링:
컨테이너 로그는 표준 출력(stdout, stderr)으로 보내고, Fluentd, ELK Stack, Prometheus, Grafana 등의 도구를 사용하여 중앙에서 수집하고 모니터링합니다.
애플리케이션 상태 점검(Health checks)을
Dockerfile(HEALTHCHECK명령어)이나 오케스트레이션 도구에 설정하여 컨테이너가 비정상일 경우 자동으로 재시작하도록 합니다.
데이터 영속성: 데이터베이스 데이터, 사용자 업로드 파일 등 영속성이 필요한 데이터는 도커 볼륨(named volumes)이나 클라우드 스토리지 서비스를 사용합니다.
4. 서비스 구성 단계 (일반적인 흐름)
이 부분은 위 단계들에 녹아 있지만, 일반적인 흐름으로 정리하면 다음과 같습니다.
애플리케이션 코드 작성: 기능을 개발합니다.
Dockerfile작성: 애플리케이션을 실행할 수 있는 환경을 정의합니다.FROM <base_image>WORKDIR /appCOPY package*.json ./(또는requirements.txt등)RUN npm install(또는pip install -r requirements.txt등)COPY . .EXPOSE <port>CMD ["npm", "start"](또는pythonapp.py등)
docker-compose.yml작성 (필요시): 여러 서비스(앱, DB 등)를 함께 관리합니다.이미지 빌드:
docker build -t myapp:dev .로컬 개발/테스트:
docker-compose up코드 수정 -> 자동 반영 (볼륨 마운트 시)
단위 테스트, 통합 테스트 실행
CI/CD 파이프라인:
Git Push -> CI 서버에서 이미지 빌드 (
docker build -t myapp:${CI_COMMIT_SHA} .)이미지를 Docker Registry에 푸시 (
docker push myregistry/myapp:${CI_COMMIT_SHA})테스트 환경에 배포 및 자동화된 테스트 실행
운영 환경 배포:
테스트가 완료된 특정 태그의 이미지를 레지스트리에서 가져옵니다.
docker-compose -fdocker-compose.prod.yml up -d또는 오케스트레이션 도구를 통해 배포합니다.환경 변수(DB 접속 정보, API 키 등)는 해당 환경에 맞게 주입합니다.
5. 도커를 이용해 빠르게 테스트 단계와 운영 단계를 교체하는 방법
핵심은 이미지 태그와 환경 변수/구성 파일을 사용하는 것입니다.
이미지 태그 전략:
개발 중:
myapp:dev,myapp:feature-x테스트/스테이징: CI/CD에서 빌드 시 고유 태그(예: Git commit hash, 빌드 번호)를 붙입니다.
myapp:build-123,myapp:sha-abc123. 테스트가 완료되면 특정 태그에myapp:staging-latest와 같은 포인터 태그를 붙일 수 있습니다.운영: 안정적인 버전에 대해 시맨틱 버전 태그(예:
myapp:1.0.0,myapp:1.0.1)를 사용하고,myapp:latest는 최신 안정 버전을 가리키도록 합니다.
교체 방법:
CI/CD 파이프라인 활용 (권장):
테스트 환경 배포: CI 파이프라인에서 테스트할 이미지 태그(예:
myapp:build-123)를 사용하여 테스트 환경(docker-compose.test.yml또는 Kubernetes manifest)에 배포합니다.운영 환경 배포 (롤백/업그레이드):
업그레이드: 테스트가 성공한 이미지 태그(예:
myapp:1.0.0)를 운영 환경 배포 스크립트/매니페스트에 지정하고 배포합니다.롤백: 문제가 발생하면 이전 버전의 이미지 태그(예:
myapp:0.9.0)로 변경하여 다시 배포합니다.
오케스트레이션 도구(Kubernetes 등)는 롤링 업데이트, 블루/그린 배포, 카나리 배포 같은 전략을 지원하여 무중단 또는 점진적 교체를 가능하게 합니다.
수동 교체 (Docker Compose 예시):
가정:
docker-compose.yml파일이 있고, 환경별 설정은 별도의.env파일이나 환경 변수로 관리합니다.테스트 환경으로 전환:
# docker-compose.yml 에서 사용할 이미지 태그를 환경변수로 받도록 수정 # services: # app: # image: myregistry/myapp:${IMAGE_TAG:-latest} # ... # 1. 테스트 환경용 .env 파일 로드 또는 환경변수 설정 export IMAGE_TAG=staging-latest export DB_HOST=test-db-host # ... 기타 테스트용 환경변수 # 2. 기존 컨테이너 내리고 새 환경으로 올리기 docker-compose down docker-compose up -d운영 환경으로 전환:
# 1. 운영 환경용 .env 파일 로드 또는 환경변수 설정 export IMAGE_TAG=v1.2.0 export DB_HOST=prod-db-host # ... 기타 운영용 환경변수 # 2. 기존 컨테이너 내리고 새 환경으로 올리기 docker-compose down docker-compose up -d주의: 이 방법은 서비스 다운타임이 발생할 수 있습니다. 실제 운영에서는 오케스트레이션 도구나 로드 밸런서를 활용한 무중단 배포 전략을 권장합니다.
환경별 구성 관리:
docker-compose는-f옵션으로 여러 설정 파일을 병합하거나,.env파일을 통해 환경 변수를 다르게 설정할 수 있습니다.docker-compose -f docker-compose.yml -f docker-compose.override.yml -fdocker-compose.prod.yml --env-file .prod.env up -d
Kubernetes는 ConfigMaps, Secrets, 그리고 환경별 매니페스트 파일을 통해 구성을 관리합니다.
결론
도커를 사용하면 개발, 테스트, 운영 환경 전반에 걸쳐 일관성을 유지하고, 배포 과정을 자동화하며, 서비스 관리를 효율적으로 할 수 있습니다. 핵심은 잘 정의된 Dockerfile, 환경별 구성 관리(환경 변수, docker-compose 파일 분리 등), 그리고 CI/CD 파이프라인을 통한 자동화입니다.