8 헬스 체크와 의존성 확인

seohan·2022년 3월 18일
0

소프트웨어를 컨테이너에서 바로 생산할 수 있도록 하는 여정에 있습니다. 프로덕션에서는 Kubernetes와 같은 컨테이너 플랫폼에서 앱을 실행하고 이러한 플랫폼에는 자가 치유 앱을 배포하는 데 도움이 되는 기능이 있습니다. 플랫폼에서 컨테이너 내부의 앱이 정상인지 확인하는 정보로 컨테이너를 패키징할 수 있습니다. 앱이 올바르게 작동하지 않으면 플랫폼에서 오작동하는 컨테이너를 제거하고 새 컨테이너로 교체할 수 있습니다.

이 장에서는 플랫폼에서 앱을 온라인 상태로 유지하는 데 도움이 되도록 이러한 검사를 컨테이너 이미지에 패키징하는 방법을 배웁니다.

8.1 도커 이미지에 상태 확인 빌드

도커는 컨테이너를 실행할 때마다 기본 수준에서 앱의 상태를 모니터링합니다. 컨테이너는 시작 시 Java 또는 셸 스크립트 또는 이진 실행 파일이 될 수 있는 특정 프로세스를 실행합니다. 도커는 프로세스가 여전히 실행 중인지 확인하고 중지되면 컨테이너가 종료 상태로 전환됩니다.

이는 모든 환경에서 작동하는 기본 상태 확인을 제공합니다. 개발자는 프로세스가 실패하고 컨테이너가 종료되는 경우 앱이 비정상임을 확인할 수 있습니다. 클러스터 환경에서 컨테이너 플랫폼은 종료된 컨테이너를 다시 시작하거나 대체 컨테이너를 생성할 수 있습니다. 그러나 이는 매우 기본적인 검사입니다. 프로세스가 실행되고 있는지 확인하지만 앱이 실제로 정상인지는 확인하지 않습니다. 컨테이너의 웹 앱은 최대 용량에 도달하고 모든 요청에 대해 HTTP 503 "Service Unavailable 응답을 반환하기 시작할 수 있지만 컨테이너의 프로세스가 계속 실행되는 한 e도커는 앱이 중단되더라도 컨테이너가 정상이라고 여깁니다.

Dockerfile에 로직을 추가하는 것만으로 도커 이미지에 실제 앱 상태 확인을 구축할 수 있는 깔끔한 방법을 제공합니다. 간단한 API 컨테이너로 이를 수행하지만 먼저 문제를 이해했는지 확인하기 위해 상태 확인 없이 실행합니다.

TRY 난수를 반환하는 간단한 REST API를 호스팅하는 컨테이너를 실행합니다. 앱에 버그가 있으므로 API에 대한 세 번의 호출 후에 비정상이 되고 모든 후속 호출이 실패합니다. 컨테이너를 실행하고 API를 사용합니다.

 # start the API container
 docker container run -d -p 8080:80 diamol/ch08-numbers-api
 
 # repeat this three times - it returns a random number
 curl http://localhost:8080/rng
 curl http://localhost:8080/rng
 curl http://localhost:8080/rng
 
 # from the fourth call onwards, the API always fails
 curl http://localhost:8080/rng
{"type":"https://tools.ietf.org/html/rfc7231#section-6.6.1","title":"An error occured while processing your request.","status":500,"traceId":"|1ab458e3-4d88f1db59554b88."}

컨테이너 상태를 체크하면

 # check the container status
 docker container ls

HEALTHCHECK 명령을 Dockerfile에 추가하여 컨테이너의 앱이 여전히 정상인지 확인하는 방법을 런타임에 정확히 알릴 수 있습니다. 이 명령은 도커가 컨테이너 내에서 실행할 명령을 지정하며, 이는 상태 코드를 반환합니다. 이 명령은 앱이 정상인지 확인하는 데 필요한 모든 것이 될 수 있습니다. 도커는 일정 간격으로 컨테이너에서 해당 명령을 실행합니다. 상태 코드에 모든 것이 정상이라고 표시되면 컨테이너가 정상입니다. 상태 코드가 연속으로 여러 번 실패하면 컨테이너가 비정상으로 표시됩니다.

목록 8.1은 버전 2로 빌드할 난수 API용 새 Dockerfile의 HEALTHCHECK 명령을 보여줍니다(ch08/exercises/numbers/numbers-api/Dockerfile.v2). 이 상태 확인은 curl 명령으로 컨테이너 내부에서 실행됩니다. /health URL은 버그가 트리거되었는지 확인하는 엔드포인트 입니다. 앱이 작동 중이면 200 "OK" 상태 코드를 반환하고 중단되면 500 "Internal Server Error"를 반환합니다.

목록 8.1 Dockerfile의 HEALTHCHECK 명령

 FROM diamol/dotnet-aspnet
 
 ENTRYPOINT ["dotnet", "/app/Numbers.Api.dll"]
 HEALTHCHECK CMD curl --fail http://localhost/health
 
 WORKDIR /app
 COPY --from=builder /out/ .

나머지 Dockerfile은 매우 간단합니다. 이것은 .NET Core 앱이므로 ENTRYPOINT는 dotnet 명령을 실행하고 Docker가 앱이 여전히 실행 중인지 확인하기 위해 모니터링하는 dotnet 프로세스입니다. 상태 확인은 앱이 정상인지 테스트하기 위해 API가 제공하는 /health 엔드포인트에 대한 HTTP 호출을 수행합니다. --fail 은 curl 명령이 상태 코드를 Docker에 전달한다는 것을 의미합니다. 요청이 성공하면 0을, 실패하면 0 이외의 숫자를 리턴합니다.

빌드 명령이 다른 파일 구조에서 어떻게 작동하는지 볼 수 있도록 해당 이미지의 새 버전을 빌드합니다. 일반적으로 앱 소스 폴더에 Dockerfile이 있고 Docker는 이를 찾아서 빌드를 실행합니다. 이 경우 Dockerfile의 이름이 다르고 소스 코드와 별도의 폴더에 있으므로 빌드 명령어에서 경로를 명시적으로 지정해야 합니다.

TRY ch08/exercises/numbers에서 Dockerfile.v2로 v2 태그의 새 이미지를 빌드합니다.


# build the image using the -f flag to specify the path to the Dockerfile:
$ docker image build -t diamol/ch08-numbers-api:v2 -f ./numbers-api/Dockerfile.v2 .

이미지가 빌드되면 상태 확인으로 앱을 실행할 준비가 된 것입니다. 상태 확인이 실행되는 빈도와 실패한 확인 횟수를 구성하여 앱이 비정상임을 의미할 수 있습니다. 기본값은 30초마다 실행하고 연속으로 세 번 실패하면 비정상 상태를 트리거하는 것입니다. API 이미지 버전 v2에는 상태 확인이 내장되어 있으므로 테스트를 반복하면 컨테이너의 상태를 확인할 수 있습니다.

TRY v2 이미지 태그를 사용하여 동일한 테스트를 실행하고 Docker가 컨테이너 내부에서 상태 확인을 실행할 수 있도록 명령 사이에 약간의 시간을 둡니다.

 # start the API container, v2
 docker container run -d -p 8081:80 diamol/ch08-numbers-api:v2
 
 # wait 30 seconds or so and list the containers
 docker container ls
 
 # repeat this four times - it returns three random numbers and then fails
 curl http://localhost:8081/rng
 curl http://localhost:8081/rng
 curl http://localhost:8081/rng
 curl http://localhost:8081/rng
{"type":"https://tools.ietf.org/html/rfc7231#section-6.6.1","title":"An error occured while processing your request.","status":500,"traceId":"|e2b9d571-4054dc815925a8da."}

이제 앱이 장애 상태에 있습니다. 90 초 대기 후에 컨테이너를 확인하면

 # now the app is in a failed state - wait 90 seconds and check
 docker container ls

부러진 비정상 상태의 앱이지만 컨테이너는 여전히 올라와 있습니다.

88ac1d8ccb30   diamol/ch08-numbers-api:v2     "dotnet /app/Numbers…"   2 minutes ago    Up 2 minutes (unhealthy)   0.0.0.0:8081->80/tcp     gracious_jang

이 비정상 상태는 도커 API의 이벤트로 게시되므로 컨테이너를 실행하는 플랫폼에 알림이 표시되고 앱을 수정하기 위한 조치를 취할 수 있습니다. 또한 컨테이너를 검사할 때 볼 수 있는 가장 최근의 상태 확인 결과를 기록합니다.

TRY 두 개의 API 컨테이너가 실행 중이며 생성할 때 이름을 지정하지 않았지만 --last 플래그와 함께 container ls를 사용하여 가장 최근에 생성된 컨테이너의 ID를 찾을 수 있습니다. 이를 container inspect에 입력하여 최신 컨테이너의 상태를 확인할 수 있습니다.

docker container inspect $(docker container ls --last 1 --format '{{.ID}}')

앱의 상태와 로그를 보여줍니다.

        "State": {
            "Status": "running",
            "Running": true,
            "Paused": false,
            "Restarting": false,
            "OOMKilled": false,
            "Dead": false,
            "Pid": 76187,
            "ExitCode": 0,
            "Error": "",
            "StartedAt": "2022-03-13T09:52:44.382090042Z",
            "FinishedAt": "0001-01-01T00:00:00Z",
            "Health": {
                "Status": "unhealthy",
                "FailingStreak": 9,
                "Log": [
                    {
                        "Start": "2022-03-13T09:55:14.8673515Z",
                        "End": "2022-03-13T09:55:15.036374417Z",
                        "ExitCode": 22,
                    }
                ]
        },

health check는 컨테이너 내부의 앱을 테스트하고 앱이 비정상임을 도커에 알립니다. 그러나 그림 8.3에서 비정상 컨테이너가 "실행 중" 상태임을 알 수 있으므로 Docker가 올바르게 작동하지 않는다는 것을 알고 있음에도 불구하고 여전히 작동 상태입니다.

Docker가 해당 컨테이너를 다시 시작하거나 교체하지 않은 이유는 무엇입니까?

간단한 대답은 도커 엔진이 단일 서버에서 실행되기 때문에 Docker가 안전하게 그렇게 할 수 없다는 것입니다. 도커는 해당 컨테이너를 중지하고 다시 시작할 수 있지만 이는 앱이 재활용되는 동안 다운타임을 의미합니다. 또는 도커가 해당 컨테이너를 제거하고 동일한 설정에서 새 컨테이너를 시작할 수 있지만 앱이 컨테이너 내부에 데이터를 쓸 수 있으므로 가동 중지 시간과 데이터 손실이 발생할 수 있습니다. 도커는 비정상 컨테이너를 수정하기 위한 조치를 취하는 것이 상황을 악화시키지 않을 것이라고 확신할 수 없으므로 컨테이너가 비정상임을 브로드캐스트하지만 실행 중인 상태로 둡니다. 상태 확인도 계속되므로 실패가 일시적이고 다음 확인이 통과하면 컨테이너 상태가 다시 정상으로 바뀝니다.

health 체크는 Kubernetes에서 관리하는 도커를 실행하는 여러 서버가 있는 클러스터에서 매우 유용합니다. 그런 다음 컨테이너가 비정상인 경우 컨테이너 플랫폼에 알림이 전송되고 조치를 취할 수 있습니다. 클러스터에 추가 용량이 있기 때문에 비정상 컨테이너가 계속 실행되는 동안 교체 컨테이너를 시작할 수 있으므로 앱 다운타임이 없어야 합니다.

8.2 의존성 검사로 컨테이너 시작하기

헬스 체크은 컨테이너 플랫폼이 앱을 계속 실행하는 데 도움이 되는 지속적인 테스트입니다. 여러 서버가 있는 클러스터는 새 컨테이너를 시작하여 일시적인 오류를 처리할 수 있으므로 일부 컨테이너가 응답을 중지하더라도 서비스 손실이 없습니다. 그러나 클러스터 전체에서 실행하면 분산된 앱에 새로운 문제가 발생합니다. 서로 의존할 수 있는 컨테이너의 시작 순서를 더 이상 제어할 수 없기 때문입니다.

난수 생성기 API에는 웹사이트가 있습니다. 웹 앱은 자체 컨테이너에서 실행되고 API 컨테이너를 사용하여 난수를 생성합니다. 단일 도커 서버에서 API 컨테이너가 웹 컨테이너보다 먼저 생성되도록 할 수 있으므로 웹 앱이 시작될 때 모든 의존성을 사용할 수 있습니다. Compose를 사용하여 명시적으로 캡처할 수도 있지만 클러스터형 컨테이너 플랫폼에서는 컨테이너의 시작 순서를 지정할 수 없으므로 API를 사용할 수 있기 전에 웹 앱이 시작될 수 있습니다.

그런 다음 발생하는 일은 앱에 따라 다릅니다. 난수 앱은 잘 처리하지 않습니다.

TRY 실행 중인 모든 컨테이너를 제거하므로 이제 API 컨테이너가 없습니다. 그런 다음 웹 앱 컨테이너를 실행하고 찾습니다. 컨테이너가 작동 중이고 앱을 사용할 수 있지만 실제로는 작동하지 않습니다.

 docker container rm -f $(docker container ls -aq)
 docker container run -d -p 8082:80 diamol/ch08-numbers-web
 docker container ls

이것은 원하지 않는 일입니다. 컨테이너는 괜찮아 보이지만 키 의존성을 사용할 수 없기 때문에 앱을 사용할 수 없습니다. 일부 앱에는 시작할 때 필요한 의존성이 있는지 확인하기 위해 로직이 내장되어 있을 수 있지만 대부분의 앱은 그렇지 않으며 난수 웹 앱이 그 중 하나입니다. API가 필요할 때 사용할 수 있다고 가정하므로 의존성 검사를 수행하지 않습니다.

이미지 내부에 해당 의존성 검사를 추가할 수 있습니다. 의존성 확인은 헬스 체크와 다릅니다. 앱이 시작되기 전에 실행되고 앱에 필요한 모든 것을 사용할 수 있는지 확인합니다. 모든 것이 있으면 의존성 검사가 성공적으로 완료되고 앱이 시작됩니다. 의존성이 없으면 검사가 실패하고 컨테이너가 종료됩니다. 도커에는 의존성 검사를 위한 HEALTHCHECK와 같은 내장 기능이 없지만 해당 논리를 시작 명령에 넣을 수 있습니다.

목록 8.2는 웹 앱용 새 Dockerfile의 최종 앱 단계를 보여줍니다(전체 파일은 ch08/exercises/numbers/numbers-web/Dockerfile.v2에 있음). CMD 명령은 API를 시작하기 전에 API를 사용할 수 있는지 확인합니다. 앱.

목록 8.2 스타트업 명령에서 의존성 검사가 있는 Dockerfile

 FROM diamol/dotnet-aspnet 
 ENV RngApi:Url=http://numbers-api/rng
 CMD curl --fail http://numbers-api/rng && \
       dotnet Numbers.Web.dll
 
 WORKDIR /app
 COPY --from=builder /out/ .

이 검사는 기본 이미지의 일부인 curl 도구를 다시 사용합니다. CMD 명령은 컨테이너가 시작될 때 실행되고 API에 대한 HTTP 호출을 수행합니다. 이는 사용 가능한지 확인하는 간단한 검사입니다. 이중 && 는 Linux 명령 셸에서 동일한 방식으로 작동합니다. 왼쪽 명령이 성공하면 오른쪽 명령이 실행됩니다.

내 API를 사용할 수 있는 경우 curl 명령이 성공하고 앱이 시작됩니다. .NET Core 웹 앱이므로 dotnet 프로세스를 모니터링하여 앱이 아직 활성 상태인지 확인합니다(이 Dockerfile에는 상태 확인이 없음). API를 사용할 수 없으면 curl 명령이 실패하고 dotnet 명령이 실행되지 않으며 컨테이너에서 아무 일도 일어나지 않아 종료됩니다.

TRY IT 난수 웹 이미지의 v2 태그에서 컨테이너를 실행합니다. 아직 API 컨테이너가 없으므로 이 컨테이너가 시작되면 실패하고 종료됩니다.

 docker container run -d -p 8084:80 diamol/ch08-numbers-web:v2
 docker container ls --all
4236de02e6c3   diamol/ch08-numbers-web:v2   "/bin/sh -c 'curl --…"   16 seconds ago   Exited (6) 15 seconds ago                          jolly_cohen

이 시나리오에서는 실행 중인 컨테이너보다 종료된 컨테이너가 있는 것이 좋습니다. 이것은 페일 패스트(fail-fast) 동작이며 대규모로 실행할 때 원하는 것입니다. 컨테이너가 종료되면 플랫폼은 새 컨테이너가 나타나 교체하도록 예약할 수 있습니다. API 컨테이너는 시작하는 데 시간이 오래 걸리므로 웹 컨테이너가 실행될 때 사용할 수 없습니다. 이 경우 웹 컨테이너가 종료되면 교체가 예약되고 시작될 때 API가 작동하여 실행됩니다.

상태 및 의존성 검사를 통해 앱을 컨테이너 플랫폼에서 좋은 시민이 되도록 패키징할 수 있습니다. 지금까지 사용한 검사는 curl을 사용한 매우 기본적인 HTTP 테스트였습니다. 이는 단순한 접근 방식이며 확인을 위해 외부 도구에 의존하지 않는 것이 좋습니다.

8.3 앱 체크 로직을 위한 커스텀 유틸리티 작성하기

이미지에는 앱 실행에 필요한 최소한의 이미지가 있어야 합니다. 추가 도구는 이미지 크기를 늘리고 업데이트 빈도와 보안 공격 표면도 늘립니다. 따라서 curl이 컨테이너 검사를 위한 훌륭한 도구이지만 사용자 정의 유틸리티를 작성하는 것이 좋습니다.

여기에는 많은 이점이 있습니다.

  • 이미지의 소프트웨어 요구 사항을 줄입니다. 검사 유틸리티를 실행하는 데 필요한 모든 것이 이미 응용 프로그램에 포함되어 있기 때문에 추가 도구를 설치할 필요가 없습니다.
    특히 Linux 및 Windows용 교차 플랫폼 도커 이미지를 게시하는 경우 셸 스크립트에서 표현하기 어려운 재시도 또는 분기가 있는 검사에서 더 복잡한 조건부 논리를 사용할 수 있습니다.

  • 유틸리티는 앱에서 사용하는 것과 동일한 앱 구성을 사용할 수 있으므로 여러 위치에서 URL과 같은 설정을 지정하지 않아도 되며 동기화되지 않을 위험이 있습니다.
    앱에서 사용하는 것과 동일한 라이브러리를 사용하여 플랫폼이 컨테이너에 로드할 것으로 예상하는 인증서가 있는지 데이터베이스 연결 또는 파일 경로를 확인하여 필요한 모든 테스트를 실행할 수 있습니다.

  • 유틸리티는 여러 상황에서 작동하도록 일반화될 수도 있습니다. API 이미지의 상태 확인과 웹 이미지의 의존성 확인에 사용할 수 있는 간단한 HTTP 확인 유틸리티를 .NET Core에 작성했습니다. 각 앱에 대해 다단계 Dockerfile이 있으며, 한 단계에서는 앱을 컴파일하고 다른 단계에서는 검사 유틸리티를 컴파일하며 최종 단계에서는 앱과 유틸리티에 복사합니다. 그림 8.6은 그 모습을 보여줍니다.

그림 8.6 다단계 빌드를 사용하여 앱과 함께 유틸리티를 컴파일 및 패키징

API용 Dockerfile.v3의 마지막 단계는 목록 8.3에 나와 있습니다. 상태 확인을 위한 명령은 이제 .NET Core 앱인 check 유틸리티를 사용하므로 더 이상 curl이 필요하지 않습니다.

목록 8.3 컬의 필요성을 제거하기 위해 상태 확인을 위한 사용자 정의 유틸리티 사용하기

FROM diamol/dotnet-aspnet
 ENTRYPOINT ["dotnet", "Numbers.Api.dll"]
 HEALTHCHECK CMD ["dotnet", "Utilities.HttpCheck.dll", "-u", "http://localhost/health"]
 WORKDIR /app
 COPY --from=http-check-builder /out/ .
 COPY --from=builder /out/ .

상태 확인의 동작은 거의 동일합니다. curl 버전과 차이점은 컨테이너를 검사할 때 자세한 로깅이 표시되지 않는다는 것입니다. 각 check에는 성공 또는 실패 여부를 나타내는 한 줄만 있습니다. 앱은 처음에 여전히 정상 상태로 보고해야 합니다. API를 몇 번 호출한 후에는 비정상으로 플래그가 지정됩니다.

TRY 기존 컨테이너를 모두 제거하고 난수 API 버전 3을 실행하십시오. 이번에는 더 빨리 트리거되도록 상태 확인 간격을 지정합니다. 컨테이너가 정상으로 나열되는지 확인한 다음 API를 사용하여 컨테이너가 비정상으로 전환되는지 확인합니다.

# clear down existing containers
 docker container rm -f $(docker container ls -aq)
 
 # start the API container, v3
 docker container run -d -p 8080:80 --health-interval 5s diamol/ch08-numbers-api:v3
 
 # wait five seconds or so and list the containers
 docker container ls
 
 # repeat this four times - it returns three random numbers and then fails
 curl http://localhost:8080/rng
 curl http://localhost:8080/rng
 curl http://localhost:8080/rng
 curl http://localhost:8080/rng
 
 # now the app is in a failed state - wait 15 seconds and check again
 docker container ls

HTTP 검사 유틸리티에는 다양한 시나리오에 유연하게 사용할 수 있는 많은 옵션이 있습니다. 웹 앱용 Dockerfile.v3에서 시작 시 의존성 검사에 동일한 유틸리티를 사용하여 API를 사용할 수 있는지 확인합니다.

목록 8.4는 Dockerfile의 마지막 단계를 보여줍니다. 이 경우 -t 플래그를 사용하여 유틸리티가 응답을 기다려야 하는 시간을 설정하고 -c 플래그는 유틸리티에 앱과 동일한 구성 파일을 로드하고 앱 구성에서 API에 대한 URL을 가져오도록 지시합니다.

목록 8.4 컨테이너 시작 시 의존성 검사를 위한 유틸리티 사용

 FROM diamol/dotnet-aspnet
 
 ENV RngApi:Url=http://numbers-api/rng
 
 CMD dotnet Utilities.HttpCheck.dll -c RngApi:Url -t 900 && \
       dotnet Numbers.Web.dll
 
 WORKDIR /app
 
 COPY --from=http-check-builder /out/ .
 COPY --from=builder /out/ .

다시 말하지만, 이것은 앱 이미지에서 curl을 제거하지만 동작은 시작 명령의 HTTP 유틸리티와 거의 동일합니다.

TRY 웹 앱 버전 3을 실행하면 API 검사를 수행할 때 HTTP 검사 유틸리티가 실패하기 때문에 컨테이너가 거의 즉시 종료되는 것을 볼 수 있습니다.

 docker container run -d -p 8081:80 diamol/ch08-numbers-web:v3
 docker container ls --all

당신의 출력은 그림 8.8과 같을 것입니다. API 컨테이너가 여전히 실행 중이지만 여전히 비정상임을 알 수 있습니다. 웹 컨테이너는 DNS 이름 numbers-api 를 찾고 있기 때문에 찾지 못했습니다. API 컨테이너를 실행할 때 해당 이름을 지정하지 않았습니다. API 컨테이너에 해당 이름을 사용했다면 웹 앱이 연결되어 사용할 수 있었겠지만 API의 버그가 트리거되어 응답하지 않기 때문에 여전히 오류가 표시됩니다.

고유한 check 유틸리티를 사용하면 이미지의 이식성이 향상됩니다다. 컨테이너 플랫폼마다 상태 확인 및 의존성 확인을 선언하고 사용하는 방법이 다르지만 이미지의 유틸리티에 필요한 모든 논리가 있는 경우 Compose, Kubernetes에서 동일한 방식으로 작동하도록 할 수 있습니다. .

8.4 Compose에서 health와 의존성 체크 정의

컨테이너가 의존성을 사용할 수 없을 때 컨테이너가 실패하고 종료하는 것이 좋은 생각인지 확신이 서지 않는다면 이것이 작동하는 이유를 알게 될 것입니다. Compose는 신뢰할 수 없는 앱을 복구하는 방향으로 어느 정도 갈 수 있지만 도커 엔진이 수행하지 않는 것과 같은 이유로 비정상 컨테이너를 대체하지 않습니다. 그러나 컨테이너가 종료되면 다시 시작하도록 설정할 수 있으며 이미지에 이미 상태 확인이 없는 경우 상태 확인을 추가할 수 있습니다.

목록 8.5는 docker-compose 파일에서 서비스로 선언된 난수 API를 보여줍니다(ch08/exercises/numbers/docker-compose.yml). 상태 확인에 HTTP 유틸리티를 사용하는 v3 컨테이너 이미지를 지정하고 상태 확인이 작동하는 방식을 구성하는 설정을 추가합니다.

목록 8.5 docker-compose 파일에서 healthcheck 매개변수 지정

numbers-api:
       image: diamol/ch08-numbers-api:v3
       ports:
           - "8087:80"
       healthcheck:
           interval: 5s
           timeout: 1s
           retries: 2
           start_period: 5s
       networks:
            - app-net

상태 확인을 세부적으로 제어할 수 있습니다. 도커 이미지에 정의된 실제 상태 확인 명령을 사용하고 있지만 실행 방법에 대한 사용자 지정 설정을 사용하고 있습니다.

  • interval: 확인 간격입니다(이 경우 5초).
  • timeout: 실패로 간주되기 전에 실행을 허용해야 하는 시간입니다.
  • retries: 컨테이너가 비정상으로 플래그 지정되기 전에 허용되는 연속 실패 횟수
  • start_period: 상태 확인을 실행하기 전에 앱에 약간의 시작 시간을 줄 수 있는 상태 확인을 트리거하기 전에 기다리는 시간

이러한 설정은 앱과 환경마다 다를 수 있습니다. 앱이 실패했음을 빠르게 알아내는 것과 비정상 컨테이너에 대한 잘못된 경보를 트리거하지 않도록 일시적인 오류를 허용하는 것 사이에는 균형이 있습니다. API에 대한 설정은 매우 공격적입니다. 상태 확인을 실행하려면 CPU와 메모리가 필요하므로 프로덕션 환경에서는 더 긴 간격으로 실행할 수 있습니다.

이미지에 선언되지 않은 컨테이너에 대해 Compose 파일에 상태 확인을 추가할 수도 있습니다. Listing 8.6은 동일한 Compose 파일에 있는 웹 앱에 대한 서비스를 보여주고 있으며 여기에 서비스에 대한 상태 확인을 추가하고 있습니다. API 서비스에 사용하는 것과 동일한 옵션 세트를 지정하고 있지만 Docker에 실행할 상태 확인 명령을 제공하는 테스트 필드도 있습니다.

목록 8.6 Compose에서 상태 확인 추가

   numbers-web:
       image: diamol/ch08-numbers-web:v3
       restart: on-failure
       ports:
           - "8088:80"
       healthcheck:
           test: ["CMD", "dotnet", "Utilities.HttpCheck.dll", "-t", "150"]
           interval: 5s
           timeout: 1s
           retries: 2
           start_period: 10s
       networks:
            - app-net

모든 컨테이너에 상태 확인을 추가하는 것이 좋지만 이 예는 이미지의 의존성 확인 및 restart: on-failure 설정과 함께 제공됩니다. 즉, 컨테이너가 예기치 않게 종료되면 Docker가 컨테이너를 다시 시작합니다. depends_on 설정이 없으므로 Compose는 임의의 순서로 컨테이너를 시작할 수 있습니다. API 컨테이너가 준비되기 전에 웹 컨테이너가 시작되면 의존성 검사가 실패하고 웹 컨테이너가 종료됩니다. 그 사이에 API 컨테이너가 시작되었으므로 웹 앱 컨테이너를 다시 시작하면 의존성 검사가 성공하고 앱이 완벽하게 작동합니다.

TRY ch08/exercises/numbers에서 실행 중인 컨테이너를 지우고 Compose로 난수 앱을 시작하십시오. 컨테이너를 나열하여 웹 앱이 먼저 시작된 다음 다시 시작되었는지 확인합니다.

 # clear down existing containers
 $ docker container rm -f $(docker container ls -aq)
 
 # start the app
 $ docker-compose up -d
 
 # wait five seconds or so and list the containers
 $ docker container ls
# and check the web app logs
$ docker container logs numbers-numbers-web-1

HTTPCheck: error. Url http://numbers-api/rng, exception Connection refused
HTTPCheck: status OK, url http://numbers-api/rng, took 185ms

http://localhost:8088로 이동하면 마침내 웹 앱을 통해 난수를 얻을 수 있습니다. 최소한 버튼을 세 번 클릭하면 번호를 받을 수 있습니다. 네 번째에는 API 버그가 발생하고 그 후에는 오류가 발생합니다. 그림 8.10은 드문 성공 중 하나를 보여줍니다.

Compose가 extends_on 플래그로 대신 할 수 있는데 왜 컨테이너 시작에 의존성 검사를 빌드하는 데 귀찮게 하느냐고 물을 수 있습니다. 그 이유는 Compose가 단일 시스템에 대한 의존성을 관리할 수만 있고 프로덕션 클러스터에서 앱의 시작 동작을 예측하기가 훨씬 어렵다는 것입니다.

8.5 체크가 자가 치유 앱에 파워를 제공하는 방법

많은 작은 구성 요소가 있는 분산 시스템으로 앱을 빌드하면 유연성과 민첩성이 향상되지만 관리가 더 복잡해집니다. 구성 요소 간에는 많은 의존성이 있으며 의존성을 모델링할 수 있도록 구성 요소가 시작되는 순서를 선언하고 싶지만 좋은 생각이 아닙니다.

단일 시스템에서 내 웹 컨테이너가 내 API 컨테이너에 의존하고 올바른 순서로 시작될 것임을 Compose에 알릴 수 있습니다. 프로덕션 환경에서는 12개의 서버에서 Kubernetes를 실행할 수 있으며 20개의 API 컨테이너와 50개의 웹 컨테이너가 필요할 수 있습니다. 시작 순서를 모델링하면 웹 컨테이너를 시작하기 전에 컨테이너 플랫폼이 20개의 모든 API 컨테이너를 먼저 시작합니까? 19개의 컨테이너가 정상적으로 시작되지만 20번째 컨테이너에 문제가 있어 시작하는 데 5분이 걸린다면 어떻게 될까요? 웹 컨테이너가 없으므로 앱이 실행되고 있지 않지만 50개의 웹 컨테이너가 모두 실행될 수 있으며 1개의 API 컨테이너를 사용할 수 없는 경우에는 제대로 작동합니다.

여기에서 의존성 확인과 헬스 체크가 필요합니다. 플랫폼이 시작 순서를 보장할 필요가 없습니다. 가능한 한 빨리 많은 서버에서 많은 컨테이너를 가동할 수 있도록 합니다. 이러한 컨테이너 중 일부가 의존성에 도달하지 못하면 빠르게 실패하고 다시 시작되거나 다른 컨테이너로 교체됩니다. 대규모 앱이 100% 서비스로 실행되기까지 몇 분 정도 뒤섞일 수 있지만 그 시간 동안 앱은 온라인 상태가 되어 사용자에게 서비스를 제공합니다. 그림 8.11은 프로덕션 클러스터에 있는 컨테이너의 수명 주기의 예를 보여줍니다.

그림 8.11 프로덕션 클러스터의 자가 치유 앱 -- 컨테이너를 다시 시작하거나 교체할 수 있습니다.

자가 치유 앱의 개념은 일시적인 오류가 플랫폼에서 처리될 수 있다는 것입니다. 앱에 메모리 부족을 유발하는 심각한 버그가 있는 경우 플랫폼은 컨테이너를 종료하고 새로운 메모리 할당이 있는 새 컨테이너로 교체합니다. 버그를 수정하지는 않지만 앱이 올바르게 작동하도록 유지합니다.

그래도 check는 조심해야 합니다. 헬스 체크는 주기적으로 실행되므로 너무 많은 작업을 수행하지 않아야 합니다. 균형을 찾아야 실행 시간이 너무 오래 걸리거나 컴퓨팅 리소스를 너무 많이 사용하지 않고 앱의 주요 부분이 작동하는지 검사가 테스트됩니다. 의존성 확인은 시작 시에만 실행되므로 사용하는 리소스에 대해 너무 걱정할 필요는 없지만 확인하는 항목에 주의해야 합니다. 일부 의존성은 제어할 수 없으며 플랫폼에서 문제를 해결할 수 없는 경우 컨테이너가 실패하면 도움이 되지 않습니다.

Check에 들어가는 로직을 해결하는 것은 어려운 부분입니다. Docker를 사용하면 이러한 검사를 쉽게 캡처하고 실행할 수 있으며, 올바르게 수행하면 컨테이너 플랫폼에서 앱을 계속 실행할 수 있습니다.

8.6 Lab

일부 앱은 리소스를 일관되게 사용하므로 초기 의존성 확인과 지속적인 상태 확인이 동일한 것을 테스트합니다. 메모리 호그를 시뮬레이트하는 앱입니다. 실행되는 동안 더 많은 메모리를 계속 할당하고 유지합니다. Node.js 앱이고 몇 가지 확인이 필요합니다.

  • 시작할 때 작동하기에 충분한 메모리가 있는지 확인해야 합니다. 그렇지 않은 경우 종료해야 합니다.
  • 런타임 동안 5초마다 허용된 것보다 더 많은 메모리가 할당되었는지 확인해야 합니다. 있다면 건강에 해롭다는 플래그를 지정해야 합니다.
  • 테스트 로직은 이미 memory-check.js 스크립트에 작성되어 있습니다. Dockerfile에 연결하기만 하면 됩니다.
  • 스크립트와 초기 Dockerfile은 소스 폴더 ch08/lab에 있습니다.

참고 앱은 실제로 메모리를 할당하지 않습니다. 컨테이너의 메모리 관리는 환경에 따라 복잡합니다. Windows의 도커 Desktop은 Linux의 도커 Community Edition과 다르게 작동합니다. 이 실습에서 앱은 메모리를 사용하는 척합니다.

profile
코드코드

0개의 댓글