Skip to main content

Command Palette

Search for a command to run...

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

Updated
6 min read

핵심 원칙: "한 번 빌드하고, 어디서든 실행한다 (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. 서비스 구성 단계 (일반적인 흐름)

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

  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 등)

  3. docker-compose.yml 작성 (필요시): 여러 서비스(앱, DB 등)를 함께 관리합니다.

  4. 이미지 빌드: docker build -t myapp:dev .

  5. 로컬 개발/테스트: docker-compose up

    • 코드 수정 -> 자동 반영 (볼륨 마운트 시)

    • 단위 테스트, 통합 테스트 실행

  6. CI/CD 파이프라인:

    • Git Push -> CI 서버에서 이미지 빌드 (docker build -t myapp:${CI_COMMIT_SHA} .)

    • 이미지를 Docker Registry에 푸시 (docker push myregistry/myapp:${CI_COMMIT_SHA})

    • 테스트 환경에 배포 및 자동화된 테스트 실행

  7. 운영 환경 배포:

    • 테스트가 완료된 특정 태그의 이미지를 레지스트리에서 가져옵니다.

    • docker-compose -f 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 파일이나 환경 변수로 관리합니다.

      • 테스트 환경으로 전환:

          # 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 -f docker-compose.prod.yml --env-file .prod.env up -d
    • Kubernetes는 ConfigMaps, Secrets, 그리고 환경별 매니페스트 파일을 통해 구성을 관리합니다.

결론

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

15 views

More from this blog

[EF Core] 데이터 삭제 시 소프트 삭제 적용

DB에서 데이터를 삭제하면 일반적으로 복구할 수 없습니다. 또한 관계에 따라 영구 삭제 자체가 어려울 수도 있습니다. 그래서 데이터를 영구 삭제하는 대신 IsDeleted 속성을 true로 주고 IsDeleted 속성을 필터링해서 조회하는 방법을 사용하기도 합니다. 이를 소프트 삭제라고 합니다. 그런데 EF에서 알아서 데이터 삭제 시 소프트 삭제를 하고 쿼리시 IsDeleted 속성을 체크해서 삭제한 데이터를 제외한 데이터만 쿼리하게 하는 ...

Mar 18, 20243 min read19

[EF Core] ValueConverter를 이용해서 엔터티 속성의 도메인 관리

EF Core를 사용하면서 문자열 길이 등의 특성을 일일이 지정하는 것은 번거롭습니다. ... [MaxLength(32)] public string? 제목 { get; set; } 엔터티가 한 개일 때는 상관이 없으나 제목 유형이 여러 엔터티에 사용될 경우 유형을 지정하기 번거롭습니다. 속성 유형을 도메인으로 관리하면 참 편할텐데요, ValueConverter를 이용할 수 있습니다. 그런데 이것을 인터페이스 정적 추상를 사용해서 다음처럼 ...

Mar 16, 20242 min read8

디모이 블로그

154 posts

.NET 관련 기술을 선호하고 새로운 언어를 배우는데 관심이 있습니다.