10 여러 환경에서 컨테이너 실행

7장에서 Compose를 사용하여 다중 컨테이너 앱을 표현하고 Compose 명령줄로 관리하는 방법을 잘 이해했습니다. 그 이후로 우리는 상태 확인 및 모니터링을 통해 프로덕션 준비를 위해 도커 앱을 개선했습니다. 모든 환경에서 이러한 프로덕션 기능이 모두 필요한 것은 아니기 때문에 이제 Compose로 돌아갈 시간입니다. 이식성은 Docker의 주요 이점 중 하나입니다. 컨테이너에서 실행되도록 앱을 패키징하면 배포 위치에 관계없이 동일한 방식으로 작동하며 환경 간 드리프트를 제거하기 때문에 중요합니다.

드리프트는 수동 프로세스로 소프트웨어를 배포할 때 항상 발생합니다. 일부 업데이트가 누락되거나 일부 새로운 의존성이 잊혀져 프로덕션 환경이 사용자 테스트 환경과 다르며 시스템 테스트 환경과도 다릅니다. 배포 실패는 드리프트 때문에 발생하는 경우가 많으며 누락된 부분을 추적하고 올바르게 배치하는 데 엄청난 시간과 노력이 필요합니다. 모든 앱이 이미 의존성과 함께 패키징되므로 Docker로 이동하면 해당 문제가 해결되지만 여전히 다양한 환경에서 다양한 동작을 지원할 수 있는 유연성이 필요합니다. Compose는 이 장에서 다룰 고급 기능을 제공합니다.

10.1 많은 앱 배포하기

Compose는 다중 컨테이너 앱을 실행하기 위한 도구입니다. 개발자에게 적합하며 비 프로덕션 환경에서도 많이 사용됩니다. 조직은 종종 다양한 환경에서 여러 버전의 앱을 실행합니다. 버전 1.5는 프로덕션 환경에서, 버전 1.5.1은 핫픽스 환경에서 테스트 중이며, 버전 1.6은 사용자 테스트를 마무리 중이며, 버전 1.7은 시스템 테스트 중일 수 있습니다. 테스트 환경에는 프로덕션의 규모와 성능이 필요하지 않으므로 Compose가 이러한 환경을 실행하고 하드웨어에서 최대 활용도를 얻는 것은 좋은 사용 사례입니다.

이것이 작동하려면 환경 간에 약간의 차이가 있어야 합니다. 포트 80에서 트래픽을 수신하거나 서버의 동일한 파일에 데이터를 쓰려는 여러 컨테이너를 가질 수 없습니다. 이를 지원하도록 Compose 파일을 디자인할 수 있지만 먼저 Compose가 동일한 앱의 일부인 도커 리소스를 식별하는 방법을 이해해야 합니다. 명명 규칙 및 레이블을 사용하여 이를 수행하며 동일한 앱의 복사본을 여러개 실행하려면 기본값을 해결해야 합니다.

TRY ch10/exercises에서 이미 작업한 두 개의 앱을 실행한 다음 todo-list 앱의 다른 인스턴스를 실행해 보십시오.

 # run the random number app from chapter 8:
 docker-compose -f ./numbers/docker-compose.yml up -d
 
 # run the to-do list app from chapter 6:
 docker-compose -f ./todo-list/docker-compose.yml up -d
 
 # and try another copy of the to-do list:
 docker-compose -f ./todo-list/docker-compose.yml up -d

마지막 출력은 그림 10.1의 것과 같을 것입니다.

todo-list_todo-web_1 is up-to-date

다른 폴더의 Compose 파일에서 여러 응용 프로그램을 시작할 수 있지만 동일한 폴더에서 실행하여 응용 프로그램의 두 번째 인스턴스를 시작할 수는 없습니다. Compose는 이미 실행 중인 앱을 실행하도록 요청하는 것으로 생각하므로 새 컨테이너를 시작하지 않습니다.

Compose는 프로젝트 개념을 사용하여 다양한 리소스가 동일한 앱의 일부임을 식별하고 Compose 파일이 포함된 디렉터리의 이름을 기본 프로젝트 이름으로 사용합니다. Compose는 리소스를 생성할 때 프로젝트 이름에 접두사를 붙이고 컨테이너의 경우 숫자 카운터도 접미사로 추가합니다. 따라서 Compose 파일이 app1 이라는 폴더에 있고 web 이라는 하나의 서비스와 disk 라는 볼륨을 정의하는 경우 Compose는 app1_disk 라는 볼륨과 app1_web_1 이라는 컨테이너를 만들어 배포합니다. 컨테이너 이름 끝에 있는 카운터는 scale을 지원하므로 웹 서비스의 인스턴스를 두 개까지 확장하면 새 컨테이너 이름은 app1_web_2 가 됩니다. 그림 10.2는 todo-list 앱을 위해 컨테이너 이름이 어떻게 구축되는지 보여줍니다.

그림 10.2 Compose는 프로젝트 이름을 포함하여 관리하는 리소스의 이름을 빌드합니다.

Compose가 사용하는 기본 프로젝트 이름을 재정의할 수 있으며, 이를 통해 단일 도커 엔진의 서로 다른 컨테이너 세트에서 동일한 앱의 여러 복사본을 실행할 수 있습니다.

TRY 이미 실행 중인 todo-list 앱 인스턴스가 하나 있습니다. 다른 프로젝트 이름을 지정하여 다른 프로젝트를 시작할 수 있습니다.

$ docker-compose -f ./todo-list/docker-compose.yml -p todo-test up -d

다음 로그가 표시됩니다.

Creating network "todo-test_app-net" with the default driver
Creating todo-test_todo-web_1 ... done

컨테이너 목록을 확인하려면

$ docker container ls
CONTAINER ID   IMAGE                        COMMAND                  CREATED          STATUS                   PORTS                    NAMES
c2b53ba724d6   diamol/ch06-todo-list        "dotnet ToDoList.dll"    59 seconds ago   Up 59 seconds            0.0.0.0:58821->80/tcp    todo-test_todo-web_1
82ec7dab756c   diamol/ch06-todo-list        "dotnet ToDoList.dll"    5 minutes ago    Up 4 minutes             0.0.0.0:58802->80/tcp    todo-list_todo-web_1
d8291a2af30e   diamol/ch08-numbers-api:v3   "dotnet Numbers.Api.…"   5 minutes ago    Up 5 minutes (healthy)   80/tcp                   numbers_numbers-api_1
c4489542c430   diamol/ch06-todo-list        "dotnet ToDoList.dll"    2 hours ago      Up 2 hours               0.0.0.0:8030->80/tcp     todo-list-postgres_todo-web_1
674301aa6acc   diamol/postgres:11.5         "docker-entrypoint.s…"   2 hours ago      Up 2 hours               0.0.0.0:5433->5432/tcp   todo-list-postgres_todo-db_1

웹사이트는 임의의 포트를 사용하므로 실제로 앱을 사용하려면 할당된 포트를 찾아야 합니다.

$ docker container port todo-test_todo-web_1 80
0.0.0.0:58821

이 방식을 사용하면 다양한 앱의 복사본을 여러 번 실행할 수 있습니다. 동일한 Compose 파일을 사용하지만 다른 프로젝트 이름을 지정하여 난수 응용 프로그램의 또 다른 인스턴스도 배포할 수 있습니다. 이는 유용하지만 대부분의 경우 더 많은 제어가 필요할 것입니다. 각 릴리스에 사용할 임의의 포트를 찾아야 하는 것은 운영 또는 테스트 팀에 좋은 워크플로가 아닙니다. 다른 환경에서 다른 설정을 지원하기 위해 중복 Compose 파일을 만들고 변경해야 하는 속성을 편집할 수 있지만 Compose는 재정의를 사용하여 이를 더 잘 관리할 수 있습니다.

10.2 Compose 파일 재정의

팀은 Compose를 사용하여 다른 앱 구성을 실행하려고 하는 문제에 부딪쳤고 각 환경마다 하나씩 수많은 Compose 파일로 생깁니다. 그것은 작동하지만 유지 관리가 불가능합니다. 왜냐하면 해당 Compose 파일은 대개 90%는 중복된 콘텐츠이기 때문에 동기화되지 않고 드리프트 상황으로 돌아갑니다. 파일 재정의는 훨씬 깔끔한 접근 방식입니다. Compose를 사용하면 여러 파일을 함께 병합할 수 있으며 이후 파일의 속성이 병합의 이전 속성을 재정의합니다.

그림 10.4는 재정의를 사용하여 쉽게 유지 관리할 수 있는 Compose 파일 집합을 구성하는 방법을 보여줍니다. 앱의 기본 구조가 포함된 핵심 docker-compose.yml 파일로 시작합니다. 서비스는 모든 환경에 공통적인 속성으로 정의 및 구성됩니다. 그런 다음 각 환경에는 특정 설정을 추가하는 자체 재정의 파일이 있지만 코어 파일의 구성을 복제하지 않습니다.

그림 10.4 환경별 설정을 추가하는 재정의 파일로 중복 제거

이 방식은 유지 관리가 가능합니다. 최신 버전을 사용하도록 이미지 태그를 변경하는 것과 같이 모든 환경에 적용되는 변경을 수행해야 하는 경우 코어 파일에서 한 번만 수행하면 모든 환경으로 필터링됩니다. 하나의 환경만 변경해야 하는 경우 해당 단일 파일만 변경합니다. 각 환경에 대한 재정의 파일은 환경 간의 차이점에 대한 명확한 문서 역할도 합니다.

목록 10.1은 핵심 Compose 파일이 대부분의 앱 속성을 지정하고 이 배포가 할 일 앱의 v2를 사용하도록 재정의가 이미지 태그를 변경하는 매우 간단한 예를 보여줍니다.

 # from docker-compose.yml - the core app specification:
 services:
   todo-web:
       image: diamol/ch06-todo-list
       ports:
           - 80
       environment:
           - Database:Provider=Sqlite
       networks:
           - app-net
 
 # and from docker-compose-v2.yml - the version override file:
 services:
   todo-web:
         image: diamol/ch06-todo-list:v2

목록 10.1 단일 속성을 업데이트하는 Compose 재정의 파일

재정의 파일에서 관심 있는 속성을 지정하기만 하면 되지만 Docker Compose가 정의를 함께 연결할 수 있도록 기본 Compose 파일의 구조를 유지해야 합니다. 이 예제에서 재정의 파일은 이미지 속성의 값만 변경하지만 서비스 블록 아래의 todo-web 블록에 지정해야 Compose가 이를 코어 파일의 전체 서비스 정의와 일치시킬 수 있습니다.

Docker Compose는 docker-compose 명령에서 여러 파일 경로를 지정할 때 파일을 병합합니다. config 명령은 입력 파일의 내용을 확인하고 입력이 유효하면 최종 출력을 작성합니다. 이를 사용하여 재정의 파일을 적용할 때 어떤 일이 발생하는지 확인할 수 있습니다.

Try ch10/exercise 폴더에서 Docker Compose를 사용하여 목록 10.1의 파일을 병합하고 출력을 인쇄하십시오.

docker-compose -f ./todo-list/docker-compose.yml -f ./todo-list/docker-compose-v2.yml config

출력은

networks:
  app-net: {}
services:
  todo-web:
    environment:
      Database:Provider: Sqlite
    image: diamol/ch06-todo-list:v2
    networks:
      app-net: {}
    ports:
    - target: 80
version: '3.7'

Docker Compose는 파일이 명령에 나열된 순서대로 재정의를 적용하고 오른쪽의 파일은 왼쪽의 파일을 재정의합니다. 순서가 중요합니다. config 명령은 완전한 Compose 파일의 테스트 실행을 보여주기 때문에 여기에서 유용합니다. 출력은 모든 것을 알파벳순으로 정렬하므로 네트워크, 서비스, 버전 번호가 표시됩니다. 배포 프로세스의 일부로 해당 명령을 자동화하고 병합된 파일을 소스 제어에 커밋할 수 있습니다. 그러면 알파벳순으로 릴리스를 쉽게 비교할 수 있습니다.

이미지 태그에 재정의를 사용하는 것은 간단한 예일 뿐입니다. 숫자 폴더에는 난수 앱을 위한 보다 현실적인 작성 파일 세트가 있습니다.

  • docker-compose.yml -- 핵심 앱 정의. 네트워크 정의 없이 웹 및 API 서비스를 지정합니다.

  • docker-compose-dev.yml --개발버전 앱을 실행합니다. Docker 네트워크를 지정하고 서비스에 대해 게시할 포트를 추가하고 상태 및 종속성 검사를 비활성화합니다. 이는 개발자가 신속하게 준비하고 실행할 수 있도록 하기 위한 것입니다.

  • docker-compose-test.yml -- 테스트 환경에서 실행합니다. 이렇게 하면 네트워크를 지정하고 상태 확인 매개변수를 추가하고 웹 앱용 포트를 게시하지만 포트를 게시하지 않음으로써 API 서비스를 내부적으로 유지합니다.

  • docker-compose-uat.yml -- 사용자 승인 테스트 환경용. 이것은 네트워크를 지정하고, 웹 사이트에 대한 표준 포트 80을 게시하고, 서비스가 항상 다시 시작되도록 설정하고, 보다 엄격한 상태 확인 매개변수를 지정합니다.

목록 10.2는 dev 재정의 파일의 내용을 보여줍니다. 이미지가 지정되지 않았기 때문에 전체 앱 사양이 아니라는 것이 매우 분명합니다. 여기에 있는 값은 핵심 Compose 파일에 병합되어 핵심 파일에 일치하는 키가 있는 경우 새 속성을 추가하거나 기존 속성을 재정의합니다.

목록 10.2 docker-compose-dev 파일은 기본 Compose 파일의 변경 사항만 지정합니다.

services:
   numbers-api:
       ports:
           - "8087:80"
       healthcheck:
           disable: true
 
   numbers-web:
       entrypoint:
           - dotnet
           - Numbers.Web.dll
       ports:
           - "8088:80"
 
networks:
   app-net:
         name: numbers-dev

다른 재정의 파일은 동일한 패턴을 따릅니다. 각 환경은 웹 애플리케이션 및 API에 대해 서로 다른 포트를 사용하므로 단일 시스템에서 모두 실행할 수 있습니다.

TRY 기존 컨테이너를 모두 제거한 다음 여러 환경에서 난수 앱을 실행합니다. 각 환경에는 프로젝트 이름과 올바른 Compose 파일 세트가 필요합니다.

컨테이너 삭제

docker container rm -f $(docker container ls -aq)

개발 구성에서 앱 실행

 docker-compose -f ./numbers/docker-compose.yml -f ./numbers/docker-compose-dev.yml -p numbers-dev up -d

테스트 설정

docker-compose -f ./numbers/docker-compose.yml -f ./numbers/docker-compose-test.yml -p numbers-test up -d

and UAT:

 docker-compose -f ./numbers/docker-compose.yml -f ./numbers/docker-compose-uat.yml -p numbers-uat up -d

이제 각 배포에서 자체 Docker 네트워크를 사용하기 때문에 서로 격리된 세 개의 애플리케이션 복사본이 실행 중입니다. 조직에서 이들은 하나의 서버에서 실행되고 팀은 올바른 포트를 탐색하여 원하는 환경을 사용합니다. 예를 들어 UAT에는 포트 80, 시스템 테스트에는 포트 8080, 개발 팀의 통합 환경에는 포트 8088을 사용할 수 있습니다.

이제 별도의 환경으로 작동하는 세 가지 배포가 있습니다. http://localhost는 UAT, http://localhost:8080은 시스템 테스트, http://localhost:8088은 개발 환경입니다. 이들 중 하나를 찾아보면 동일한 애플리케이션을 볼 수 있지만 각 웹 컨테이너는 자체 네트워크의 API 컨테이너만 볼 수 있습니다. 이렇게 하면 앱이 별도로 유지되므로 개발 환경에서 계속 난수를 가져오면 API가 중단되지만 시스템 테스트 및 UAT 환경은 계속 작동합니다. 각 환경의 컨테이너는 DNS 이름을 사용하여 통신하지만 Docker는 컨테이너 네트워크 내 트래픽을 제한합니다. 그림 10.7은 네트워크 격리를 통해 모든 환경을 분리하는 방법을 보여줍니다.


Figure 10.7 Running multiple environments on one Docker Engine, using networks for isolation

Docker Compose는 클라이언트 측 도구이며 앱을 관리하려면 모든 Compose 파일에 액세스해야 함을 상기시킬 때입니다. 또한 사용한 프로젝트 이름을 기억해야 합니다. 테스트 환경을 정리하고 컨테이너와 네트워크를 제거하려면 일반적으로 docker-compose down을 실행하면 됩니다. 그러나 Compose는 up에서 사용한 것과 리소스를 매칭하기 위해 동일한 파일 및 프로젝트 정보가 모두 필요하기 때문에 이러한 환경에서는 작동하지 않습니다.

TRY 해당 테스트 환경을 제거해 보겠습니다. down 명령에 다양한 변형을 시도할 수 있지만 작동하는 유일한 것은 원래 up 명령과 동일한 파일 목록 및 프로젝트 이름을 가진 명령입니다.

기본 docker-compose.yml을 사용한 경우:

docker-compose down

프로젝트 이름 없이 재정의 파일을 사용했다면:

docker-compose -f ./numbers/docker-compose.yml -f ./numbers/docker-compose-test.yml down

하지만 프로젝트 이름을 지정했으므로 이것을 포함해야 함:

docker-compose -f ./numbers/docker-compose.yml -f ./numbers/docker-compose-test.yml -p numbers-test down

성공하였다면

Stopping numbers-test_numbers-web_1 ... done
Stopping numbers-test_numbers-api_1 ... done
Removing numbers-test_numbers-web_1 ... done
Removing numbers-test_numbers-api_1 ... done
Removing network numbers-test

이러한 오류는 Compose 재정의 파일에서 네트워크 이름이 명시적으로 지정되었기 때문에 발생했습니다. 두 번째 down 명령에서 프로젝트 이름을 지정하지 않았기 때문에 기본값인 폴더 이름 숫자를 사용했습니다. Compose는 numbers_numbers-web_1numbers_numbers-api_1 이라는 컨테이너를 찾았지만 실제로 프로젝트 접두사 numbers-test 로 생성되었기 때문에 찾지 못했습니다. Compose는 해당 컨테이너가 이미 사라졌고 네트워크를 정리하기만 하면 된다고 생각했는데 Compose 파일의 명시적 네트워크 이름이 프로젝트 접두사 없이 사용되었기 때문에 찾은 것입니다. Compose는 해당 네트워크를 제거하려고 시도했지만 다행히 Docker에서는 컨테이너가 연결된 네트워크를 제거할 수 없습니다.

이것은 Docker Compose에 주의해야 함을 보여줍니다. 단일 시스템에 수십 또는 수백 개의 애플리케이션을 배포하여 컴퓨팅 리소스에서 최대 가치를 얻을 수 있는 비 프로덕션 환경을 위한 탁월한 도구입니다. 재정의 파일을 사용하면 응용 프로그램 정의를 재사용하고 환경 간의 차이점을 식별할 수 있지만 관리 오버헤드를 인식해야 합니다. 배포 및 분해를 위한 스크립팅 및 자동화를 살펴봐야 합니다.

10.3 환경 변수 및 비밀로 구성 주입

Docker 네트워크를 사용하여 애플리케이션을 격리하고 Compose 재정의를 사용하여 환경 간의 차이점을 캡처할 수 있지만 환경 간에 애플리케이션 구성을 변경해야 합니다. 대부분의 응용 프로그램은 환경 변수 또는 파일에서 구성 설정을 읽을 수 있으며 Compose는 이러한 접근 방식을 모두 잘 지원합니다.

이 섹션의 모든 옵션을 다룰 것이므로 지금까지보다 Compose에 대해 좀 더 자세히 살펴보겠습니다. 이렇게 하면 구성 설정을 적용하기 위한 선택 사항을 이해하고 자신에게 적합한 것을 선택할 수 있습니다.

이 연습을 위해 todo-list 앱으로 돌아 왔습니다. 앱용 Docker 이미지는 구성 설정을 위한 환경 변수 및 파일을 읽도록 빌드되었습니다. 환경마다 달라야 하는 세 가지 항목이 있습니다.

  • 로깅 --로깅 수준의 세부 정보입니다. 이것은 개발 환경에서 매우 장황하게 시작하여 테스트 및 프로덕션에서는 덜 장황해질 것입니다.

  • 데이터베이스 공급자 --응용 프로그램 컨테이너 내에서 간단한 데이터 파일을 사용할지 아니면 별도의 데이터베이스를 사용할지 여부입니다.

  • 데이터베이스 연결 문자열 --앱이 로컬 데이터 파일을 사용하지 않는 경우 데이터베이스 연결에 대한 세부 정보입니다.

여기서는 재정의 파일을 사용하여 다양한 환경에 대한 구성을 주입하며 각 항목에 대해 다른 접근 방식을 사용하고 있으므로 Docker Compose의 옵션을 보여드릴 수 있습니다. 목록 10.3은 핵심 Compose 파일을 보여줍니다. 여기에는 구성 파일이 비밀로 설정된 웹 응용 프로그램에 대한 기본 정보만 있습니다.

Listing 10.3 Compose 파일은 secrets로 웹 서비스를 지정합니다.

services:
   todo-web:
       image: diamol/ch06-todo-list
       secrets:
           - source: todo-db-connection
             target: /app/config/secrets.json

secrets는 구성을 주입하는 유용한 방법이며 Docker Compose, Kubernetes를 지원합니다. 작성 파일에서 secretssourcetarget을 지정합니다. source는 컨테이너 런타임에서 secret이 로드되는 위치이고 targetsecrets이 컨테이너 내부에 표시되는 파일 경로입니다.

이 비밀은 todo-db-connection에서 오는 것으로 지정됩니다. 즉, Compose 파일에 정의된 해당 이름의 비밀이 있어야 합니다. 비밀 내용은 애플리케이션이 구성 설정을 검색하는 위치 중 하나인 대상 경로 /app/config/secrets.json 의 컨테이너에 로드됩니다.

이전 Compose 파일 자체는 secrets 섹션이 없기 때문에 유효하지 않으며, 서비스 정의에서 사용되기 때문에 todo-db-connection 비밀이 필요합니다. 목록 10.4는 서비스에 대한 몇 가지 추가 구성을 설정하고 비밀을 지정하는 개발용 재정의 파일을 보여줍니다.

 services:
   todo-web:
       ports:
           - 8089:80
       environment:
           - Database:Provider=Sqlite
       env_file:
           - ./config/logging.debug.env
 
 secrets:
   todo-db-connection:
         file: ./config/empty.json

이 재정의 파일에는 애플리케이션 구성을 주입하고 컨테이너에서 앱의 동작을 변경하는 세 가지 속성이 있습니다. 이들을 조합하여 사용할 수 있지만 각 접근 방식에는 다음과 같은 이점이 있습니다.

  • environment은 컨테이너 내부에 환경 변수를 추가합니다. 이 설정은 간단한 데이터 파일인 SQLite 데이터베이스를 사용하도록 앱을 구성합니다. 이것은 구성 값을 설정하는 가장 쉬운 방법이며 구성 파일에서 명확하게 알 수 있습니다.

  • env_file은 텍스트 파일에 대한 경로를 포함하며 텍스트 파일의 내용은 환경 변수로 컨테이너에 로드됩니다. 텍스트 파일의 각 줄은 등호로 구분된 이름과 값을 사용하여 환경 변수로 읽습니다. 이 파일의 내용은 로깅 구성을 설정합니다. 환경 변수 파일을 사용하면 여러 구성 요소 간에 설정을 공유하는 간단한 방법입니다. 각 구성 요소는 환경 변수 목록을 복제하지 않고 파일을 참조하기 때문입니다.

  • secrets는 서비스 및 네트워크와 같은 Compose 파일의 최상위 리소스입니다. 여기에는 로컬 파일 시스템의 파일인 todo-db-connection 의 실제 소스가 포함되어 있습니다. 이 경우 앱이 연결할 별도의 데이터베이스가 없으므로 비밀에 빈 JSON 파일을 사용합니다. 앱이 파일을 읽지만 적용할 구성 설정이 없습니다.

TRY Compose 파일과 todo-list-configured 디렉토리의 재정의를 사용하여 개발 구성에서 앱을 실행할 수 있습니다. curl을 사용하여 웹 앱에 요청을 보내고 컨테이너가 많은 세부 정보를 기록하는지 확인합니다.

컨테이너를 제거합니다.

docker container rm -f $(docker container ls -aq)

config를 재정의하고 앱을 로드 합니다.

docker-compose -f ./todo-list-configured/docker-compose.yml -f ./todo-list-configured/docker-compose-dev.yml -p todo-dev up -d

send some traffic into the app:

curl http://localhost:8089/list

check the logs:

docker container logs --tail 4 todo-dev_todo-web_1

Docker Compose는 항상 각 애플리케이션에 네트워크를 사용하므로 Compose 파일에 지정된 네트워크가 없는 경우에도 기본 네트워크를 만들고 여기에 컨테이너를 연결합니다.

개발자 배포는 앱 구성을 위해 환경 변수와 비밀을 사용합니다. Compose 파일에 지정된 값과 구성 파일은 컨테이너에 로드됩니다.

테스트 배포는 호스트 시스템의 환경 변수를 사용하여 컨테이너에 대한 값을 제공합니다. Compose 파일 자체를 변경하지 않고 환경을 변경할 수 있습니다. 구성이 다른 다른 서버에서 두 번째 테스트 환경을 가동하려는 경우에 유용합니다. 목록 10.5는 todo-web 서비스에 대한 사양에서 이를 보여줍니다.

목록 10.5 Compose 파일에서 환경 변수를 값으로 사용하기

   todo-web:
       ports:
           - "${TODO_WEB_PORT}:80"
       environment:
           - Database:Provider=Postgres
       env_file:
           - ./config/logging.information.env
       networks:
             - app-net

포트에 대한 ${} 설정은 해당 이름으로 환경 변수에서 대체됩니다. 따라서 이름이 TODO_WEB_PORT 이고 값이 8877 인 Docker Compose를 실행 중인 시스템에 변수가 설정되어 있으면 Compose가 해당 값을 주입하고 포트 사양은 실제로 "8877:80"이 됩니다. 이 서비스 사양은 docker-compose-test.yml 파일에 있습니다. 여기에는 데이터베이스 서비스와 데이터베이스 컨테이너 연결에 사용할 비밀도 포함됩니다.

개발 환경과 동일한 방법으로 Compose 파일과 프로젝트 이름을 지정하여 테스트 환경을 실행할 수 있지만 작업을 더 쉽게 만드는 Compose의 최종 구성 기능이 하나 있습니다. Compose가 현재 폴더에서 .env라는 파일을 찾으면 해당 파일을 환경 파일로 처리하고 내용을 환경 변수 세트로 읽어서 명령을 실행하기 전에 채웁니다.

TRY ch10/todo-list-configured에서 Docker Compose에 대한 매개변수를 지정하지 않고 실행합니다.

docker-compose up -d

그림 10.10은 Compose가 웹 및 데이터베이스 컨테이너를 생성했음을 보여줍니다. 그러나 핵심 Compose 파일은 데이터베이스 서비스를 지정하지 않습니다. 이름을 지정하지 않았지만 프로젝트 이름 todo_ch10도 사용했습니다. .env 파일은 테스트 재정의 파일을 지정할 필요 없이 기본적으로 테스트 환경을 실행하도록 Compose 구성을 설정합니다.

Listing 10.6 Configuring containers and Compose using an environment file

 # container configuration - ports to publish:
 TODO_WEB_PORT=8877
 TODO_DB_PORT=5432
 
 # compose configuration - files and project name:
 COMPOSE_PATH_SEPARATOR=;
 COMPOSE_FILE=docker-compose.yml;docker-compose-test.yml
 COMPOSE_PROJECT_NAME=todo_ch10

환경 파일은 테스트 구성에서 앱에 대한 기본 Compose 설정을 캡처합니다. 개발 구성이 기본값이 되도록 쉽게 수정할 수 있습니다. Compose 파일과 함께 환경 파일을 유지하면 어떤 파일 세트가 어떤 환경을 나타내는지 문서화하는 데 도움이 되지만 Docker Compose는 .env 라는 파일만 찾습니다. 파일 이름을 지정할 수 없으므로 여러 환경 파일이 있는 환경 간에 쉽게 전환할 수 없습니다.

Docker Compose의 구성 옵션을 둘러보는 데 시간이 조금 걸렸습니다. Docker를 사용하는 동안 많은 Compose 파일로 작업할 것이므로 모든 옵션에 익숙해야 합니다. 여기에서 모두 요약할 것이지만 일부는 다른 것보다 더 유용합니다.

  • environment 속성을 사용하여 환경 변수를 지정하는 것이 가장 간단한 옵션이며, Compose 파일에서 애플리케이션 구성을 쉽게 읽을 수 있습니다. 하지만 이러한 설정은 일반 텍스트이므로 연결 문자열이나 API 키와 같은 민감한 데이터에 사용해서는 안 됩니다.

  • secret 속성이 있는 구성 파일을 로드하는 것은 모든 컨테이너 런타임에서 지원되고 민감한 데이터에 사용할 수 있기 때문에 가장 유연한 옵션입니다. 비밀 소스는 Compose를 사용할 때 로컬 파일이거나 Docker Swarm 또는 Kubernetes 클러스터에 저장된 암호화된 비밀일 수 있습니다. 소스가 무엇이든 비밀의 내용은 애플리케이션이 읽을 수 있도록 컨테이너의 파일에 로드됩니다.

  • 설정을 파일에 저장하고 environment _file 속성을 사용하여 컨테이너에 로드하는 것은 서비스 간에 공유 설정이 많을 때 유용합니다. Compose는 로컬에서 파일을 읽고 개별 값을 환경 속성으로 설정하므로 원격 Docker 엔진에 연결할 때 로컬 환경 파일을 사용할 수 있습니다.

  • Compose 환경 파일 .env 는 기본 배포 대상이 될 환경에 대한 설정을 캡처하는 데 유용합니다.

10.4 확장 필드로 중복 줄이기

이 시점에서 Docker Compose에는 모든 상황을 충족할 수 있는 충분한 구성 옵션이 있다고 생각할 수 있습니다. 그러나 실제로는 매우 간단한 사양이며, 더 많이 사용하면 할수록 제한 사항이 있습니다. 가장 일반적인 문제 중 하나는 동일한 설정을 많이 공유하는 서비스가 있을 때 Compose 파일의 팽창을 줄이는 방법입니다. 이 섹션에서는 이 문제를 해결하는 Docker Compose의 마지막 기능 중 하나를 다룰 것입니다. 확장 필드를 사용하여 Compose 파일 전체에서 재사용할 수 있는 YAML 블록을 한 곳에서 정의하는 것입니다. 확장 필드는 강력하지만 잘 사용되지 않는 Compose의 기능입니다. 많은 중복과 오류 가능성을 제거하고 YAML 병합 구문에 익숙해지면 사용하기 쉽습니다.

이 장의 연습을 위한 image-gallery 폴더에는 확장 필드를 사용하는 docker-compose-prod.yml 파일이 있습니다. Listing 10.7은 확장 필드를 정의하고 최상위 블록(서비스, 네트워크 등) 외부에서 선언하고 앰퍼샌드 표기법으로 이름을 지정하는 방법을 보여줍니다.

Listing 10.7 Compose 파일 상단에 확장 필드를 정의

 x-labels: &logging
   logging:
       options:
           max-size: '100m'
           max-file: '10'
 
 x-labels: &labels
     app-name: image-gallery

확장 필드는 사용자 정의 정의입니다. 이 파일에는 logginglabels 라는 두 가지가 있습니다. 규칙에 따라 블록 이름 앞에 x가 붙기 때문에 x-labels 블록은 labels이라는 확장자를 정의합니다. logging 확장은 컨테이너 로그에 대한 설정을 지정하며 서비스 정의 내에서 사용할 수 있습니다. labels 확장은 서비스 정의의 기존 레이블 필드 내에서 사용할 수 있는 레이블에 대한 키/값 쌍을 지정합니다.

이러한 정의의 차이점에 유의해야 합니다. logging 필드에는 로깅 속성이 포함되어 있어 서비스에서 직접 사용할 수 있습니다. labels 필드는 레이블 속성을 포함하지 않으므로 기존 레이블 세트 내에서 사용해야 합니다. 목록 10.8은 두 확장을 모두 사용하는 서비스 정의를 통해 이를 명확하게 보여줍니다.

Listing 10.8 병합된 서비스 정의 내부의 확장을 사용

 services:
   iotd:
       ports:
           - 8080:80
       <<: *logging
       labels:
           <<: *labels
             public: api

확장 필드는 YAML 병합 구문 <<: 뒤에 별표가 접두사로 붙는 필드 이름과 함께 사용됩니다. 따라서 <<: *logging은 YAML 파일의 해당 지점에서 로깅 확장 필드의 값으로 병합됩니다. Compose가 이 파일을 처리할 때 로깅 확장의 서비스에 로깅 섹션을 추가하고 기존 레이블 섹션에 추가 레이블을 추가하여 레이블 확장 필드의 값을 병합합니다.

TRY Compose가 파일을 처리하는 방법을 확인하기 위해 이 앱을 실행할 필요는 없고 config 명령을 실행하기만 하면 됩니다. 모든 입력의 유효성을 검사하고 서비스 정의에 병합된 확장 필드와 함께 최종 Compose 파일을 인쇄합니다.

ch10/exercises/image-gallery에서

# check config for the production override:
docker-compose -f ./docker-compose.yml -f ./docker-compose-prod.yml config

전체 출력을 표시하지 않고 병합되는 확장 필드를 표시하기에 충분한 서비스 정의만 표시했습니다.

networks:
  app-net:
    name: image-gallery-prod
services:
  accesslog:
    image: diamol/ch09-access-log
    labels:
      app-name: image-gallery
    logging:
      options:
        max-file: '10'
        max-size: 100m
    networks:
      app-net: {}
  grafana:
    depends_on:
      prometheus:
        condition: service_started
    image: diamol/ch09-grafana
    labels:
      app-name: image-gallery
    logging:
      options:
        max-file: '10'
        max-size: 100m
    networks:
      app-net: {}
    ports:
    - published: 3000
      target: 3000

확장 필드는 Compose 파일에서 모범 사례를 보장하는 유용한 방법입니다. 동일한 로깅 설정과 컨테이너 레이블을 사용하는 것은 모든 서비스에 대한 표준을 설정하는 좋은 예입니다. 모든 앱에 사용할 수 있는 것은 아니지만 많은 양의 YAML을 복사하여 붙여넣으려는 경우 도구 상자에 있는 것이 좋습니다. 이제 더 나은 접근 방식을 갖게 되었습니다. 하지만 한 가지 큰 제한이 있습니다. 확장 필드는 여러 Compose 파일에 적용되지 않으므로 핵심 Compose 파일에서 확장을 정의한 다음 재정의에서 사용할 수 없습니다. 이는 Compose가 아닌 YAML의 제한 사항이지만 알아야 할 사항입니다.

10.5 Docker로 구성 워크플로 이해하기

소스 제어에 있는 일련의 아티팩트에 캡처된 시스템의 전체 배포 구성을 갖는 것은 매우 중요합니다. 이를 통해 해당 버전의 소스를 가져오고 배포 스크립트를 실행하기만 하면 모든 버전의 애플리케이션을 배포할 수 있습니다. 또한 개발자는 프로덕션 스택을 로컬에서 실행하고 자체 환경에서 버그를 재현하여 수정 작업을 신속하게 수행할 수 있습니다.

환경 간에는 항상 차이가 있으며 Docker Compose를 사용하면 환경 간의 차이점을 캡처하는 동시에 소스 제어에 있는 배포 아티팩트 집합을 계속 제공할 수 있습니다. 이 장에서는 Docker Compose를 사용하여 다양한 환경을 정의하는 방법을 살펴보고 세 가지 주요 영역에 중점을 두었습니다.

  • 애플리케이션 구성 --모든 환경에서 전체 스택을 실행하는 것은 아닙니다. 모니터링 대시보드와 같은 기능은 개발자가 사용하지 않거나 애플리케이션이 테스트 환경에서 컨테이너화된 데이터베이스를 사용하지만 프로덕션 환경에서는 클라우드 데이터베이스에 연결할 수 있습니다. 파일 재정의를 사용하면 공통 서비스를 공유하고 각 환경에 특정 서비스를 추가하여 이를 깔끔하게 수행할 수 있습니다.

  • 컨테이너 구성 --환경의 요구 사항 및 기능에 맞게 속성을 변경해야 합니다. 게시된 포트는 다른 컨테이너와 충돌하지 않도록 고유해야 하며 볼륨 경로는 테스트 환경에서는 로컬 드라이브를 사용할 수 있지만 프로덕션에서는 공유 스토리지를 사용할 수 있습니다. 재정의를 사용하면 각 애플리케이션에 대해 격리된 Docker 네트워크와 함께 이를 활성화하여 단일 서버에서 여러 환경을 실행할 수 있습니다.

  • 애플리케이션 구성 --컨테이너 내부의 애플리케이션 동작은 환경 간에 변경됩니다. 이로 인해 앱이 수행하는 로깅의 양이나 로컬 데이터를 저장하는 데 사용하는 캐시 크기가 변경되거나 전체 기능이 켜지거나 꺼질 수 있습니다. 재정의 파일, 환경 파일 및 비밀을 조합하여 Compose를 사용하여 이 작업을 수행할 수 있습니다.

그림 10.12는 섹션 10.3에서 실행한 할일 목록 앱을 보여줍니다. 개발 환경과 테스트 환경은 완전히 다릅니다. dev에서 앱은 로컬 데이터베이스 파일을 사용하도록 구성되고 테스트에서는 Compose도 데이터베이스 컨테이너를 실행하고 앱은 이를 사용하도록 구성됩니다. 그러나 각 환경은 격리된 네트워크와 고유한 포트를 사용하므로 동일한 시스템에서 실행할 수 있습니다. 이는 개발자가 로컬 테스트 환경을 가동하고 개발 버전과 비교해야 하는 경우에 적합합니다.


그림 10.12 Docker Compose를 사용하여 동일한 앱에 대해 매우 다른 환경 정의

여기서 가장 중요한 점은 구성 워크플로가 모든 환경에서 동일한 Docker 이미지를 사용한다는 것입니다. 빌드 프로세스는 모든 자동화 테스트를 통과한 태그가 지정된 버전의 컨테이너 이미지를 생성합니다. Compose 파일의 구성을 사용하여 연기 테스트 환경에 배포하는 릴리스 후보입니다. 연기 테스트를 통과하면 동일한 이미지 세트를 사용하고 Compose의 새 구성을 적용하는 다음 환경으로 이동합니다. Docker Swarm 또는 Kubernetes 배포 매니페스트를 사용하여 동일한 컨테이너 이미지를 프로덕션에 배포할 때 테스트가 모두 통과하면 궁극적으로 해당 버전을 출시하게 됩니다. 출시되는 소프트웨어는 모든 테스트를 통과한 동일한 소프트웨어이지만 이제 컨테이너 플랫폼에서 제공되는 프로덕션 동작이 있습니다.

10.6 Lab

이 실습에서는 할 일 앱에 대한 고유한 환경 정의 세트를 구축해 보시기 바랍니다. 개발 환경과 테스트 환경을 함께 구성하고 둘 다 동일한 시스템에서 실행할 수 있는지 확인합니다.

개발 환경은 기본값이어야 하며 docker-compose up 으로 실행할 수 있습니다. 설정해야

  • 로컬 데이터베이스 파일 사용
  • 포트 8089에 게시
  • todo-list 애플리케이션의 v2 실행

테스트 환경은 특정 Docker Compose 파일 및 프로젝트 이름으로 실행해야 합니다. 그 설정은

  • 별도의 데이터베이스 컨테이너 사용
  • 데이터베이스 저장소에 볼륨 사용
  • 포트 8080에 게시
  • 최신 todo-list 애플리케이션 이미지 사용

이 장의 할일 목록 구성 연습에 있는 Compose 파일과 여기에서 유사점이 있습니다. 주요 차이점은 볼륨입니다. 데이터베이스 컨테이너는 PGDATA라는 환경 변수를 사용하여 데이터 파일이 기록되어야 하는 위치를 설정합니다. Compose 파일의 볼륨 사양과 함께 사용할 수 있습니다.

좋은 웹페이지 즐겨찾기