▤목차
헬스 체크를 지원하는 도커 이미지 빌드하기
도커는 컨테이너를 시작할 때마다 애플리케이션의 기본적인 상태를 확인한다.
- 컨테이너를 실행하면 내부에서 실행되는 프로세스(앱 실행파일 | 닷넷 런타임 | 셸 스크립트 같은 특정한 프로세스)가 있는데 도커가 확인하는 것은 이 프로세스의 실행 사태다.
- 만약 이 프로세스가 종료되면 컨테이너도 종료상태가 된다.
만약 웹 애플케이션이 '500 Internal Server Error' 응답 받고 중지되어도 컨테이너는 정상이라고 판단한다.
웹 앱이 중지되어도 컨테이너가 정상적으로 작동하는 예시
컨테이너의 진입점 프로세스가 실행 중 상태이므로 도커는 애플리케이션도 정상상이라고 판단하여 STATUS 가 Up 인것을 확인할 수 있다.
Dokcerfile 에서 HEALTHCHECK 인스트럭션을 이용하면 인스트럭션에 정의된 정보를 이용해 동작 중인 애플리케이션의 상태가 정상인지 확인할 수 있다.
- HEALTHCHECK 동작방식
- 인스트럭션에 도커 컨테이너안에서 실행하는 명령을 지정
- 이 명령이 반환하는 상태코드를 보고 애플리케이션의 상태를 파악
- 도커는 일정간격으로 이 명령을 실행
- 상태 코드가 연속으로 일정 횟수 이상 실패로 나오면 해당 컨테이너를 이상 상태로 간주
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/ .
- ENTRYPOINT 에서 "dotnet" 명령을 실행 → 앱 상태를 확인하기 위해 모니터링하는 프로세스도 "dotnet"
- HEALTHCHECK CMD curl
- --fail = 정상이면 0 이외에는 다른 숫자 반환하도록 하는 옵션
- http://localhost/health = 버그가 발동했는지 확인하기 위한 또 다른 API 엔트포인트 (500:버그, 200:정상)
< HEALTHCHECK가 적용된 도커파일 사용해보기>
diamol/ch08/exercises/numbers 폴더로 가서 이미지 빌드
docker image build -t diamol/ch08-numbers-api:v2 -f ./numbers-api/Dockerfile.v2 .
실행시킨 앱의 건강상태 확인
docker run -d -p 8081:80 diamol/ch08-numbers-api:v2
docker container ls
버그 생성
curl http://localhost:8081/rng
curl http://localhost:8081/rng
curl http://localhost:8081/rng
curl http://localhost:8081/rng
컨테이너 건강상태 체크 (90초 정도 시간이 지나고 나서 해야 상태가 변함, 3번 건강상태를 체크해야 하기 때문)
docker container ls
에러가 발생하여 건강상태가 unhealthy 로 변함
- 3 번 연속 건상상태를 확인한 결과 실패하였기 때문에 컨테이너 상태가 이상(unhealthy)로 출력
- 컨테이너 상태가 이상이여도 종료되지는 않음
최근 컨테이너의 상태를 출력하여 더 자세히 확인해 보자
docker container inspect $(docker container ls --last 1 --format '{{.ID}}')
건강상태는 unhealthy 인데 앱은 runnging 상태인 것을 알 수 있다.
왜 이상 상태에 있는 컨테이너를 재시작하거나 다른 컨테이너로 교체하지 않은 것일까?
→ 도커가 컨테이너 재시작/교체 작업을 안전하게 처리할 수 없기 때문
클러스터는 항상 컨테이너를 추가로 실행할 여력이 있기 때문에 이상상태를 보이는 컨테이너는 두고, 대체컨테이너를 실행해 앱을 중단 시간없이 상태를 회복가능
디펜던시 체크가 적용된 켄테이너 실행하기
여러 컨테이너에 나뉘어 실행되는 분산 애플리케이션은 이상이 생긴 컨테이너를 교체할 때 처음 앱을 실행할 때처럼 컨테이너 간 의존관계를 고려하지 않기때문에 문제를 격는다.
도커가 동작하는 서버가 한 대뿐이라면 웹컨테이너를 실행하기전에 API 컨테이너가 실행되도록 가능하다.
하지만, 클러스터 환경의 컨테이너 플랫폼이라면 컨테이너의 순서까지 통제할수가 없어서 API 가 사용 가능한 상태가 되기 전에 웹 앱이 실행되는 일이 있을 수도 있다.
(예시) 컨테이너 상태는 정상인데 핵심 의존 관계를 만족하지 않아 앱이 정상적으로 동작하니 않는 상황
방식 : 실행 중인 모든 컨테이너를 제거해 동작 중인API 컨테이너가 없게한 후 앱 컨테이너를 실행한 다음 웹 브라우저에서 앱에 접근한다.
docker container rm -f $(docker container ls -aq)
docker container run -d -p 8082:80 diamol/ch08-numbers-web
docker container ls
이런 경우를 방지하기 위해
의존 관계를 만족하는지 점검하는 디펜던시 체크 기능도 도커 이미지에 추가할 수 있다.
디펜던시 체크
- 앱 실행전에 필요한 요구사항을 체크
- 명시된 모든 요구사항이 확인되면 디펜던시 체크가 성공하고 앱이 실행
- 인스트럭션으로 구현 된것은 아니고 앱 실행 명령에 로직을 추가하는 방법으로 구현
디펜던시 체크가 구현된 예시 (CMD 인스트럭션에 구현)
FROM diamol/dotnet-aspnet
ENV RngApi:Url=http://numbers-api/rng
CMD curl --fail http://numbers-api/rng && \
dotnet Numbers.Web.dll
먼저 API가 사용가능한 상태라면 curl 명령이 성공하고 이어지는 닷넷 코어 앱 실행 명령을 실행
디펜던시 체크가 설정된 컨테이너 실행
docker container run -d -p 8083:80 diamol/ch08-numbers-web:v2
도커 컨테이너 상태 확인 ▶ 실행 중인 API 가 없어 v2 는 종료된 것을 확인 가능
애플리케이션 체크를 위한 커스텀 유틸리티 만들기
curl은 웹 애플리케이션이나 API 를 테스트하는데 매우 유용한 도구다.
- 실무에서 개발하는 앱을 테스트하는 목적으로는 사용하지 않는다.
- 이유 = 사용하지 않을 도구를 추가하면
- 이미지 크기증가
- 외부 공격에 노출될 여지 증가
▶ 앱 체크에는 앱과 같은 언어로 구현된 별도의 커스텀 유틸리티를 사용
앱과 같은 언어로 구현된 커스텀 유틸리티의 장점
- 이미지에 추가적인 소프트웨어를 포함 시킬 필요가 없다.
- 재시도 횟수나 분기등 셸 스크립트로는 표현하기 까다로운 복잡한 체크 로직을 적용할 수 있다. 특히 리눅스와 윈도 양쪽에서 사용할 크로스 플랫폼 이미지라면 더욱 유용
- 앱과 같은 설정을 사용해 대상 URL을 여러 곳에 반복 정의하거나 수정에서 누락시키는 일을 방지할 수 있다.
- 컨테이너 실행 전에 확인이 필요한 모든 사항을 검증할 수 있다. (앱과 같은 라이브러리 환경에서 데이터베이스 접속이나 인증서 파일의 존재 유무등)
- 다양한 상황에서 동작이 가능하다
닷넷 코어로 구현한 간단한 HTTP 테스트 유틸리티를 사용해 API 이미지의 헬스 체크와 웹 이미지의 디펜던시 체크 앱 빌드 과정
마지막 단계 코드
FROM diamol/dotnet-aspnet
ENTRYPOINT ["dotnet", "Numbers.Api.dll"]
HEALTHCHECK CMD ["dotnet", "Utilities.HttpCheck.dll", "-u", "http://localhost/health"]
WOKDIR /app
COPY --from=http-check-builder /out/ .
COPY --from=builder /out/ .
HEALTHCHECK 에서 curl 대신 닷넷 코어로 구현된 테스트 유틸리티를 사용
<실습> 모든 컨테이너 삭제후 무작위 숫자 API를 v3 버전의 컨테이너로 실행한다. 이번에는 헬스 체크 간격을 조금 줄인다. 컨테이너의 상태가 정상인지 확인하고 API를 몇번 호출해 상태가 이상으로 바뀌는지 확인하라.
# 기존 컨테이너를 모두 삭제
docker container rm -f $(docker container ls -aq)
-a = 모든 컨테이너(중지된 컨테이너 포함)를 조회합니다.
-q = 컨테이너 ID만 출력
-aq = 모든 컨테이너의 ID를 출력
$(...) = 명령어 치환으로 ( )에서 얻은 결과를 가져온다.
# API를 v3 버전의 이미지로 실행한다.
docker container run -d -p 8080:80 --health-interval 5s diamol/ch08-numbers-api:v3
# 5초 정도 기다린 후 컨테이너 목록을 확인한다.
docker container ls
# API 를 네번 호출 - 세번은 성공, 마지막은 실패
curl http://localhost:8080/rng
# 앱에 버그가 발생했다. 15초 기다린 후 상태가 이상으로 바뀌는지 확인한다.
docker container ls
커맨드 실행 출력 내용
4번 째 요청 부터 버그가 발생 → HTTP 테스트 유틸리리티가 세 번 연속 실패를 반환 → unhealthy 상태로 변환
<실습> 웹 앱 버전 v3를 실행하라. API 가 없으므로 컨테이너가 바로 종료된다.
docker container run -d -p 8081:80 diamol/ch08-numbers-web:v3
docker container ls --all
diamol/ch08-numbers-web:v3 : 웹 앱 컨테이너의 디펜던스 체크가 실패해 컨테이너가 종료
diamol/ch08-numbers-api:v3 : api 컨테이너가 실행 중이지만 컨테이너 이름이 "number-api" 로 지정되지 않아서 웹 앱이 API 컨테이너를 발견하지 못한다.
도커 컴포즈에 헬스 체크와 디펜던시 체크 정의하기
디펜던시 체크에 실패했을 때 실행하던 컨테이너를 종료해야 하는 이유
▶ 단일 서버에서 앱을 실행 중이라면 이상이 생긴 컨테이너를 새 컨테이너로 교체하면 더 심각한 장애를 일으킬 수 있기 때문
▶ 하지만 종료된 컨테이너를 재시작하거나 이미지에 정의 되지 않은 헬스 체크를 추가할 수는 있다.
도커 컴포즈 파일에서 헬스 체크 옵션 설정하기
number-api:
image: diamol/ch08-numbers-api:v3
ports:
- "8087:80"
healthCheck:
interval: 5s
timeout: 1s
retries: 2
start_period: 5s
networks:
- app-net
이미지에 헬스 체크가 정의 되어 있지 않은 경우 컴포즈 파일에서 정의하는 법
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
<실습> 지금 있는 컨테이너를 모두 삭제하고 도커 컴포즈를 이용해 무작위 숫자 애플리케이션을 실행하라. 애플리케이션이 제대로 실행됐는지 알아보기 위해 실행 후 컨테이너 목록을 확인하라
# 컴포즈 파일이 있는 디렉터리로 이동
# 현재 컨테이너를 모두 삭제
docker container rm -f $(docker container ls -aq)
# 애플리케이션 실행
docker-compose ls
# 5초를 기다린 다음 컨테이너 목록을 확인
docker container ls
# 웹 애플리케이션 로그도 확인
docker container logs numbers-numbers-web-1
도커 컴포즈 파일에 depends_on 설정을 사용해 직접 디펜던시 체크를 하도록 하지 않는 이유
▶ 도커 컴포즈가 디펜던시 체크를 할 수 있는 범위가 단일 서버로 제한되기 떄문
헬스 체크와 디펜던시 체크로 복원력있는 애플리케이션을 만들 수 있는 이유
물리 서버가 한 대뿐인 환경이라면 도커 컴포즈에 웹 컨테이너보다 API 컨테이너를 먼저 실행시키라고 지시할 수 있다.
10 대의 물리 서버와 20개의 API 컨테이너와 50 여개 웹앱을 실행해야 한다면 어떻게 이 애플리케이션의 시작 절차를 설계해야할까?
---> API 컨테이너를 먼저 실행시킨 후 웹앱을 실행하도록 설계를 한 경우, 마지막 1 개의 API 가 실행이 늦어져 5분이나 걸리면 웹앱은 그 동안 하나도 실행되지 않아서 애플리케이션이 동작 중이라고 할 수가 없다.
▶ 여기서 문제는 API 컨테이너가 부족하더라도 웹 앱 컨테이너를 실행하는데는 문제가 없다.
!! 디펜던시 체크와 헬스 체크를 도입하면 보이는 효과
- 플랫폼이 실행 순서를 보장하게 할 필요가 없다.
- 가능한 빨리 컨테이너를 실행하면 된다.
- 일부 컨테이너가 의존관계를 만족하지 못한 상태라면 재실행되거나 다른 컨테이너로 교체된다.
운영 환경의 클러스터에서 이러나느 컨테이너의 생애주기
*애플리케이션의 자기수복 : 일시적인 오류를 플래폼이 해소해 주는 것
앱에 메모리 누수를 일으키는 까다로운 버그가 있더라도 플랫폼에서 해당 컨테이너를 메모리를 잃지 않은 새 컨테이너로 대체 - 버그를 수정하지 않았지만 애플리케이션은 계속 동작할 수 있다.
헬스 체크와 디펜던시 체크에 주의 할 점
- 헬스 체크는
- 주기적으로 실행되므로 시스템에 부하를 주는 내용이어서는 안 된다.
- 자원을 너무 많이 소모하지 않으면서 앱이 실질적으로 동작 중인지 검증할 수 있는 핵심적인 부분을 테스트해야 한다.
- 디펜던시 체크는
- 앱 시작 시에 한 번만 실행되므로 테스트 대상이 빠짐없이 정확하도록 주의해야 한다.
- 누락된 의존 관계가 있으면 이 문제를 플랫폼이 해결하지 못하면 앱에도 문제가 발생한다.
연습문제 : 메모리 누수 대처
조건
- 애플리케이션 시작 시 충분한 메모리가 있는지 확인하고, 메모리가 부족한 경우 컨테이너를 종료한다
- 애플리케이션 실행 중 4 초 간격으로 최대치를 초과해 메모리를 사용하는지 확인한다. 최대치를 초과했다면 해당 컨테이너의 상태를 이상으로 판정해야 한다.
- 테스트 로직은 memory-check.js 스크립트에 이미 작성돼 있다. Dockerfile 스크립트에서 테스트 스크립트를 그대로 사용하면 된다.
- 테스트 스크립트와 Dockerfile 슼크립트는 ch08/lab 디렉터리에 있다.
Dokerfile 스크립트
FROM diamol/node
ENV MAX_ALLOCATION_MB=4096 \
LOOP_ALLOCATION_MB=512 \
LOOP_INTERVAL_MS=2000
CMD ["node", "memory-hog.js"]
WORKDIR /app
COPY src/ .
Dockerfile solution
FROM diamol/node
ENV MAX_ALLOCATION_MB=4096 \
LOOP_ALLOCATION_MB=512 \
LOOP_INTERVAL_MS=2000
CMD node memory-hog.js && \
node memory-check.js
HEALTHCHECK --interval=5S \
CMD node memory-check.js
WORKDIR /app
COPY src/ .
문제 풀면서 틀린 부분
CMD ["node", "memory-hog.js", "memory-check.js"]
- 형태: JSON 배열 방식
- 실행: node memory-hog.js memory-check.js 로 실행
- 동작: node 명령어에 두 파일이 인자로 전달
- 결과: node는 첫 번째 파일(memory-hog.js)만 실행하고, 두 번째 인자(memory-check.js)는 실행되지 않고 단순히 인자로 전달
- 의도: 만약 memory-hog.js가 다른 스크립트를 받아서 실행하도록 설계되었다면 정상 동작하지만, 그렇지 않다면 memory-check.js는 무시됨.
'책 > 도커 교과서' 카테고리의 다른 글
[ 책 ] [ 도커교과서 ] 7장 도커 컴포즈 분산 애플리케이션 실행하기 (0) | 2024.12.23 |
---|---|
[책] [ 도커교과서 ] 6장 도커 볼륨을 이용한 퍼시스턴트 스토리지 (0) | 2024.12.15 |
[책] [ 도커교과서 ] 5장 도커 허브 등 레지스트리에 이미지 공유하기 (0) | 2024.12.13 |
[책] [ 도커교과서 ] 4장 애플리케이션 소스코드에서 도커 이미지까지 (0) | 2024.12.13 |
[ 책 ] [ 도커교과서 ] 3장 도커 이미지 만들기 (0) | 2024.12.08 |