Programming-[Infra]/Docker

도커 교과서(엘튼 스톤맨, 심효섭) - 7. 헬스, 디펜던시 체크

컴퓨터 탐험가 찰리 2023. 3. 30. 14:32
728x90
반응형

1. 헬스 체크

 

도커는 기본적으로 컨테이너의 애플리케이션 실행 파일, 자바, 닷넷 런타임, 셸 스크립트 같은 특정한 프로세스의 실행 상태를 확인한다. 프로세스가 종료되면 컨테이너도 종료된다. 그러나 프로세스는 실행 중이더라도 애플리케이션 내부적으로 에러가 발생해서 계속해서 에러를 응답하고 있는 상태이면 이런 기본 체크만으로는 부족하다. 이 때 활용할 수 있는 것이 헬스 체크이다.

 

HEALTHCHECK 인스트럭션

이미지를 빌드할 때, Dockfiler상에 HEALCHECK 인스트럭션을 추가해서 특정 기능을 수행하는 헬스체크를 만들 수 있다. 교재의 예제 파일의 Dockerfile 내용은 아래와 같다.

 

FROM diamol/dotnet-sdk AS builder

WORKDIR /src
COPY src/Numbers.Api/Numbers.Api.csproj .
RUN dotnet restore

COPY src/Numbers.Api/ .
RUN dotnet publish -c Release -o /out Numbers.Api.csproj

# app image
FROM diamol/dotnet-aspnet

ENTRYPOINT ["dotnet", "/app/Numbers.Api.dll"]
HEALTHCHECK CMD curl --fail http://localhost/health

WORKDIR /app
COPY --from=builder /out/ .

 

이렇게 하면 도커는 HEALTHCHECK 인스트럭션 뒤에 있는 curl --fail http://localhost/health를 실행하여 애플리케이션의 상태를 파악한다. 해당 url은 애플리케이션에서 추가해준 url인데, 버그가 있다면 500 Internal Server Error, 정상이라면 200 OK가 응답된다. --fail 옵션은 curl에서 전달받은 상태 코드를 성공인 경우 0, 실패하면 0 이외의 숫자를 받고 도커가 이를 정상으로 판단하는 기준으로 만든다.

 

이미지 빌드 -f 옵션

교재에서 제공해주는 애플리케이션의 이미지를 빌드한다. 다만 -f 옵션으로 다른 디렉터리 위치에서 Dockerfile을 찾아가서 빌드해본다.

cd ./ch08/exercises/numbers
docker image build -t diamol/ch08-numbers-api:v2 -f ./numbers-api/Dockerfile.v2 .

 

다시 말해 상위 폴더에서 numbers-api/Dockerfile.v2를 실행하여 이미지를 빌드한다는 뜻이다.

 

이 애플리케이션은 3번까지는 요청 성공, 4번째부터는 무조건 에러를 응답하도록 설계되었다. 또한 헬스 체크의 기준이 30초 간격으로 헬스 체크를 하되, 연속 3회 이상 실패마녀 애플리케이션이 이상 상태로 간주되도록 되어있다. 아래 명령어들을 입력하여 확인해본다.

docker container run -d -p 8081:80 diamol/ch08-numbers-api:v2
docker container ls    # 30초 정도 기다린 다음 컨테이너 목록 확인
curl http://localhost:8081/rng   # x4번 호출하기
docker container ls # 90초 기다린 다음 확인

 

실행 후 처음엔 STATUS가 health: starting이고, 30초 이후에는 healthy 상태로 변경된 것을 볼 수 있다.

 

4번 호출 시 랜덤한 숫자를 응답하다가, 4번째에 500 에러가 났다

 

이후 90초 이내에는 healthy 상태였으나, 90초 이후 unhealthy 상태로 변경된 것을 볼 수 있다.

 

이상 상태가 발생하면 도커 API를 통해 보고된다. 그리고 docker container inspect 명령어로 healthcheck 로그를 살펴볼 수 있다. --last 1 옵션으로 가장 최근에 만든 container 1개를 살펴보고, --format '{{.ID}}' 옵션으로 해당 컨테이너의 ID값만 추출하여 바깥쪽의 docker container inspect 명령어에 인자로 전달하였다.

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

 

State/Health 항목에서 연속 실패한 횟수(FailingStreak), 가장 최근에 수행한 헬스 체크 정보(Log)를 확인할 수 있다.

 

이상이 발생해도 아무런 작업을 취하지 않는다.

위 로그를 보면 컨테이너의 State는 계속해서 running 상태이다. 게다가 health check는 계속해서 이루어진다. 이것은 도커가 해당 컨테이너를 종료하고 재시작하는 등의 작업을 해주지는 않기 때문이다. 도커 엔진은 단일 서버에서 동작하기 떄문에 컨테이너를 재처리하면 그동안 애플리케이션이 동작하지 않고, 컨테이너에 보관된 데이터가 유실될 수 있다.

 

여러 대의 서버로 구성되는 도커 스웜, 쿠버네티스 등의 환경에서는 헬스 체크 시 컨테이너가 이상 상태라면 자동적으로 조치를 취한다. 여분의 컨테이너를 실행하고 이상 상태 컨테이너를 재실행하여 중단 시간없이 상태를 회복할 수 있다.

 

 

2. 디펜던시 체크

 

앞서 헬스 체크를 학습하며 실행했던 무작위 숫자를 반환하는 API는 웹페이지를 위한 컨테이너도 제공한다. 웹페이지에서 요청을 하면, API서버용 컨테이너에서 결과를 응답하여 웹페이지에서 이를 표시하는 것이다. 즉 의존성 관계가 있는 애플리케이션이다. 이런 경우 웹페이지 컨테이너를 실행하기 전에 API가 정상작동하는지 확인해야할 것이다. 

 

디펜던시 체크는 애플리케이션 실행 전에 실시하여 성공하지 못하면 애플리케이션이 실행되지 않도록 한다. 그리고 헬스 체크처럼 별도의 인스트럭션이 제공되는 것은 아니고, 애플리케이션 실행 명령에 로직을 추가하여 구현한다.

 

 

기본 디펜던시 체크 해보기

cat numbers-web/Dockerfile.v2

 

교재에서 제공하는 Dockerfile.v2를 cat으로 출력해보면 아래와 같은 내용을 확인할 수 있다.

FROM diamol/dotnet-sdk AS builder

WORKDIR /src
COPY src/Numbers.Web/Numbers.Web.csproj .
RUN dotnet restore

COPY src/Numbers.Web/ .
RUN dotnet publish -c Release -o /out Numbers.Web.csproj

# app image
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 --fail... 구문이 디펜던시 체크를 하는 부분이다. API로 요청을 보내서 API가 사용가능한지 점검 후, && 명령을 이용하여 뒤의 명령을 실행한다. 이 명령어는 리눅스와 윈도 셸 모두에서 같은 기능을 하는 명령어로, 앞의 명령이 성공하면 뒤의 명령을 실행한다.

 

 

커스텀 디펜던시 체크 유틸리티

앞서 curl을 이용하여 디펜던시 체크를 하는 방법은 리눅스와 윈도 모두에서 동작하기 때문에 유용하다. 그러나 도커 이미지에 curl이 들어가는 것은 필요한 최소한의 내용만 포함돼야한다는 원칙에 어긋난다. 게다가 curl을 포함시키는 것은 외부 공격에 노출될 여지를 만들 수 있으므로 일반적으로는 컨테이너의 애플리케이션과 같은 언어로 구현된 별도의 커스텀 유틸리티를 사용한다.

 

아래는 교재에서 제공하는 커스텀 유틸리티 Dockerfile의 일부이다.

# ...중략

# http check utility
FROM diamol/dotnet-sdk AS http-check-builder

WORKDIR /src
COPY src/Utilities.HttpCheck/Utilities.HttpCheck.csproj .
RUN dotnet restore

COPY src/Utilities.HttpCheck/ .
RUN dotnet publish -c Release -o /out Utilities.HttpCheck.csproj

# ... 중략

 

저자가 만들어놓은 Utilities.HttpCheck.csproj 파일을 복사하고 실행한다. 해당 디렉터리 위치에서 cs, csproj 확장자를 갖는 프로그램들을 볼 수 있었는데, dotnet 프로그램으로 짜여진 코드였다.

 

이런 식으로 향후 어떤 언어로 코딩을 한다면 그 언어에 맞게 헬스 체크나 디펜던시 체크를 하는 라이브러리, 패키지 등을 이용하면 될 것 같다.

 

 

 

3. 도커 컴포즈에 헬스, 디펜던시 체크 적용

 

도커 컴포즈에서는 헬스 체크 옵션을 세세하게 지정할 수 있다.

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

 

헬스 체크에도 저자가 만든 커스텀 체크 유틸리티를 적용하여 dotnet으로 실행하도록 'test: ' 구문에 적용하였다. 각 옵션별 기능은 아래와 같다.

  • restart: on-failure - 체크 실패 시, 컨테이너를 재시작하게 한다
  • interval - 헬스 체크 실시 간격
  • timeout - 실패로 간주하는 응답까지 걸리는 제한 시간
  • retries - 컨테이너를 상태 이상으로 간주하는 연속 실패 횟수
  • start_period - 컨테이너 실행 후 첫 헬스 체크를 실시하는 간격. 이 시간이 컨테이너를 최초 실행하는데 걸리는 시간보다 적으면 문제가 될 수 있다.

 

728x90
반응형