# 개발, 테스트, 운영에서의 도커 활용

**핵심 원칙: "한 번 빌드하고, 어디서든 실행한다 (Build once, run anywhere)"**

도커의 가장 큰 장점은 환경 일관성입니다. 동일한 도커 이미지를 사용하여 개발, 테스트, 운영 환경을 구성함으로써 "제 PC에서는 됐는데..." 하는 문제를 최소화할 수 있습니다.

**1\. 개발 단계 (Development)**

* **목표**: 빠른 코드 변경 반영, 쉬운 디버깅, 실제 운영 환경과 유사한 환경 구성.
    
* **Docker 사용 방안**:
    
    * `Dockerfile` 작성: 애플리케이션 실행에 필요한 모든 의존성(OS, 라이브러리, 런타임 등)을 정의합니다.
        
        * 개발용 `Dockerfile`은 프로덕션용과 거의 동일하게 가져가되, 디버깅 도구나 개발용 라이브러리를 추가할 수 있습니다. (멀티 스테이지 빌드를 활용하면 최종 이미지에는 포함되지 않도록 할 수 있습니다.)
            
    * `docker-compose.yml` 활용:
        
        * 애플리케이션 컨테이너 외에 데이터베이스(MySQL, PostgreSQL, MongoDB 등), 메시지 큐(Redis, Kafka 등) 등 필요한 서비스를 함께 정의하여 로컬에서 전체 스택을 쉽게 실행할 수 있습니다.
            
        * **볼륨 마운트 (Volume Mounts)**: 로컬 소스 코드를 컨테이너 내부의 작업 디렉토리로 마운트합니다. 이렇게 하면 로컬에서 코드를 수정할 때마다 이미지를 다시 빌드할 필요 없이 변경 사항이 컨테이너에 즉시 반영됩니다 (예: `nodemon` 같은 도구와 함께 사용).
            
            ```yaml
            # 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`](http://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\. 서비스 구성 단계 (일반적인 흐름)**

이 부분은 위 단계들에 녹아 있지만, 일반적인 흐름으로 정리하면 다음과 같습니다.

1. **애플리케이션 코드 작성**: 기능을 개발합니다.
    
2. `Dockerfile` 작성: 애플리케이션을 실행할 수 있는 환경을 정의합니다.
    
    * `FROM <base_image>`
        
    * `WORKDIR /app`
        
    * `COPY package*.json ./` (또는 `requirements.txt` 등)
        
    * `RUN npm install` (또는 `pip install -r requirements.txt` 등)
        
    * `COPY . .`
        
    * `EXPOSE <port>`
        
    * `CMD ["npm", "start"]` (또는 `python` [`app.py`](http://app.py) 등)
        
3. `docker-compose.yml` 작성 (필요시): 여러 서비스(앱, DB 등)를 함께 관리합니다.
    
4. **이미지 빌드**: `docker build -t myapp:dev .`
    
5. **로컬 개발/테스트**: `docker-compose up`
    
    * 코드 수정 -&gt; 자동 반영 (볼륨 마운트 시)
        
    * 단위 테스트, 통합 테스트 실행
        
6. **CI/CD 파이프라인**:
    
    * Git Push -&gt; CI 서버에서 이미지 빌드 (`docker build -t myapp:${CI_COMMIT_SHA} .`)
        
    * 이미지를 Docker Registry에 푸시 (`docker push myregistry/myapp:${CI_COMMIT_SHA}`)
        
    * 테스트 환경에 배포 및 자동화된 테스트 실행
        
7. **운영 환경 배포**:
    
    * 테스트가 완료된 특정 태그의 이미지를 레지스트리에서 가져옵니다.
        
    * `docker-compose -f` [`docker-compose.prod`](http://docker-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`는 최신 안정 버전을 가리키도록 합니다.
        
* **교체 방법**:
    
    1. **CI/CD 파이프라인 활용 (권장)**:
        
        * **테스트 환경 배포**: CI 파이프라인에서 테스트할 이미지 태그(예: `myapp:build-123`)를 사용하여 테스트 환경(`docker-compose.test.yml` 또는 Kubernetes manifest)에 배포합니다.
            
        * **운영 환경 배포 (롤백/업그레이드)**:
            
            * **업그레이드**: 테스트가 성공한 이미지 태그(예: `myapp:1.0.0`)를 운영 환경 배포 스크립트/매니페스트에 지정하고 배포합니다.
                
            * **롤백**: 문제가 발생하면 이전 버전의 이미지 태그(예: `myapp:0.9.0`)로 변경하여 다시 배포합니다.
                
        * 오케스트레이션 도구(Kubernetes 등)는 롤링 업데이트, 블루/그린 배포, 카나리 배포 같은 전략을 지원하여 무중단 또는 점진적 교체를 가능하게 합니다.
            
    2. **수동 교체 (Docker Compose 예시)**:
        
        * **가정**: `docker-compose.yml` 파일이 있고, 환경별 설정은 별도의 `.env` 파일이나 환경 변수로 관리합니다.
            
        * **테스트 환경으로 전환**:
            
            ```bash
            # 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
            ```
            
        * **운영 환경으로 전환**:
            
            ```bash
            # 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 -f` [`docker-compose.prod`](http://docker-compose.prod)`.yml --env-file .prod.env up -d`
            
    * Kubernetes는 ConfigMaps, Secrets, 그리고 환경별 매니페스트 파일을 통해 구성을 관리합니다.
        

**결론**

도커를 사용하면 개발, 테스트, 운영 환경 전반에 걸쳐 일관성을 유지하고, 배포 과정을 자동화하며, 서비스 관리를 효율적으로 할 수 있습니다. 핵심은 잘 정의된 `Dockerfile`, 환경별 구성 관리(환경 변수, `docker-compose` 파일 분리 등), 그리고 CI/CD 파이프라인을 통한 자동화입니다.
