Docker&K8s

CH_03_03_컨테이너 친화적인 애플리케이션

dding-shark 2025. 7. 24. 14:35
728x90

3.3 컨테이너 친화적인 애플리케이션

컨테이너 환경의 장점을 최대한 활용하려면, 이식성이 높고 운영이 쉬운 '컨테이너 친화적인(Container-Friendly)' 애플리케이션을 구축해야 합니다. 이를 위해 컨테이너의 동작, 제어, 그리고 설정(Configuration) 관리 관점에서 반드시 이해해야 할 핵심 요소들을 살펴보겠습니다.


3.3.1 설정 파일을 이미지에 포함하여 빌드하기

nginx 컨테이너를 리버스 프록시로 사용하기 위해 upstream.conf와 같은 설정 파일을 이미지에 포함하여 빌드하는 경우를 생각해 봅시다. 만약 이 설정 파일을 변경해야 한다면 어떻게 해야 할까요?

가장 간단한 방법은 설정 파일을 수정한 뒤 docker builddocker compose up 명령을 다시 실행하여 이미지를 새로 빌드하고 컨테이너를 재배포하는 것입니다. 컨테이너는 파일 시스템을 포함한 실행 환경 전체를 캡슐화하고, 이 상태 그대로 어떤 환경에서든 동일하게 배포할 수 있는 이식성을 강점으로 하므로, 설정을 코드의 일부로 보고 함께 빌드하는 것은 결코 나쁜 선택이 아닙니다.

하지만 nginx의 리버스 프록시 설정처럼 변경 빈도가 낮은 파일과 달리, API 키, 데이터베이스 접속 정보, 기능 플래그(flag) 등은 배포 환경이나 상황에 따라 자주 변경될 수 있습니다. 이러한 값들을 변경할 때마다 매번 이미지를 다시 빌드하는 것은 비효율적입니다.

따라서 효율적인 관리를 위해서는 설정의 변경 빈도에 따라 저장 위치를 결정하는 것이 좋습니다.

  • 변경 빈도가 낮은 설정: 컨테이너 내부에 포함하여 안정성을 높입니다.
  • 변경 빈도가 잦은 설정: 컨테이너 외부에 두고 런타임에 주입하여 유연성을 확보합니다.

3.3.2 컨테이너 외부의 설정 사용하기

컨테이너 실행 시점에서 외부의 설정을 전달하는 방법은 크게 세 가지가 있습니다.

  • 커맨드라인 인수로 전달하기
  • 환경 변수로 전달하기
  • 설정 파일을 볼륨 마운트하여 전달하기

커맨드라인 인수로 전달하기

Dockerfile의 CMDENTRYPOINT를 통해 컨테이너 실행 시 기본 커맨드를 지정할 수 있습니다. docker run이나 docker-compose.yml에서 이 커맨드에 인수를 추가하거나 덮어쓰는 방식으로 외부의 값을 전달할 수 있습니다.

# docker-compose.yml
version: "3.9"
services:
  api:
    build: .
    command:
      - server 
      - --port=8080
      - --log-level=warn
      - --debug-mode=true

이 방식은 간단하지만, 전달해야 할 인수가 많아질수록 애플리케이션이 처리해야 할 로직이 복잡해지고 docker-compose.yml 파일이 길어져 가독성과 유지보수성이 떨어지는 단점이 있습니다.

환경 변수로 값 전달하기

컨테이너 외부에서 값을 전달하는 또 다른 일반적인 방법은 환경 변수를 이용하는 것입니다. docker run 명령어의 -e 옵션이나 docker-compose.ymlenvironment 항목을 통해 손쉽게 설정할 수 있습니다.

# docker run 명령어 사용 시
docker container run -e PORT=8080 -e LOG_LEVEL=warn ...
# docker-compose.yml
version: "3.9"
services:
  api: 
    build: .
    command:
      - server
    environment:
      PORT: 8080
      LOG_LEVEL: "warn"
      DEBUG: "true"

환경 변수는 많은 서드파티 소프트웨어와 프레임워크에서 표준처럼 지원하는 방식이라 매우 널리 쓰입니다. 하지만 커맨드라인 인수와 마찬가지로 JSON이나 XML처럼 구조가 복잡한 데이터를 전달하기 어렵고, 설정 값을 Git과 같은 저장소에서 관리할 경우 인코딩 문제나 보안 이슈가 발생할 수 있습니다.

설정 파일 전달하기

위 두 방법의 단점을 해결해 줄 수 있는 가장 강력하고 전통적인 방식은 설정 파일을 직접 전달하는 것입니다. 이 방식은 다음과 같은 장점 덕분에 첫 번째 고려사항으로 권장됩니다.

  • 복잡한 데이터 구조 지원: JSON, XML, YAML 등 원하는 형식으로 복잡하고 구조화된 설정을 쉽게 관리할 수 있습니다.
  • 환경별 설정 분리: dev.yaml, prod.yaml처럼 환경별 설정 파일을 만들어두고, 실행 시점에 필요한 파일만 주입하여 유연하게 환경을 구성할 수 있습니다.
  • 이미지 재빌드 불필요: 설정이 변경되어도 이미지를 새로 빌드할 필요 없이 컨테이너만 다시 시작하면 되므로 배포 과정이 매우 효율적입니다.

설정 파일은 볼륨 마운트(Volume Mount) 기능을 통해 컨테이너에 전달합니다.

# docker-compose.yml
version: "3.9"
services:
  api:
    build: .
    command: 
      - server
      # 컨테이너 내부 경로에 마운트된 설정 파일을 지정
      - --config-file=/etc/server/conf/dev.yaml
    volumes:
      # [호스트 경로]:[컨테이너 경로]
      # 호스트의 ./conf 디렉터리를 컨테이너의 /etc/server/conf 디렉터리에 연결
      - ./conf:/etc/server/conf

위 예시는 다음과 같이 동작합니다.

  1. volumes 설정에 따라, Docker는 호스트(Host) 머신의 ./conf 디렉터리를 컨테이너 내부의 /etc/server/conf 디렉터리로 마운트합니다.
  2. 이제 호스트의 ./conf 디렉터리에 있는 모든 파일(예: dev.yaml)은 컨테이너의 /etc/server/conf 경로에서 접근할 수 있습니다.
  3. command는 컨테이너 내부에서 실행될 때, 마운트된 경로에 있는 dev.yaml 파일을 설정으로 읽어들여 애플리케이션을 시작합니다.
728x90