태스크 생명주기와 서비스

차분한열정·2022년 3월 13일

AWS ECS

목록 보기
4/6

1. 태스크 생명주기

하나의 태스크는 다음과 같은 생명주기를 갖는다.

(1) PROVISIONING
ECS가 태스크 시작 전 준비하는 단계로 예를 들어 만약 awsvpc 네트워크 모드를 사용한다면 ENI가 프로비저닝되어야 한다.

(2) PENDING
Container agenet가 그 다음 액션을 취하기를 기다리는 상태

(3) ACTIVATING
ECS가 태스크가 RUNNING 상태가 되기 직전에 이런 저런 작업을 하는 상태로 예를 들어 service discovery가 구성되어 있다면 해당 리소스가 생성되어야 하고, 서비스가 ELB 타깃 그룹을 사용하도록 구성되어 있다면 타깃 그룹 등록이 진행되어야 하는데 이 때 진행된다.

(4) RUNNING
태스크가 실행 중인 상태

(5) DEACTIVATING
ex) 타깃 그룹 등록 해제

(6) STOPPING
Container agenet가 그 다음 액션을 취하기를 기다리는 상태로 리눅스 컨테이너인 경우 Container agenet는 SIGTERM 시그널을 보내고 그 후에는 task definition에 정의되어 있던 StopTimeout 기간 동안 기다린 후에 SIGKILL 시그널을 보낸다.

(7) DEPROVISIONING
ex) ENI 분리 및 삭제

(8) STOPPED
태스크 정상 중지됨

2. Service scheduler concepts

서비스는 원하는 수만큼의 태스크가 클러스터 내에서 실행될 수 있도록 해준다. 만약 어떤 태스크들이 모종의 이유로 실행 도중 정지 또는 종료되었다면 ECS service scheduler는 task definition을 기반으로 또다른 태스크 인스턴스를 시작해서 그것들을 교체함으로써 원하는 수만큼의 태스크를 유지하는 방식이다.

Service scheduler(이하 '스케줄러')는 만약 반복적으로 정지 혹은 종료되는 태스크들의 경우 얼마나 자주 재시작을 할 것인지를 조절하는 로직을 갖고 있다. 만약 태스크가 RUNNING 상태로 들어가기 전에 정지되었다면 스케줄러는 점점 재시작 시도 빈도를 줄여나가고 service event message를 발송한다. 이렇게 함으로써 실패한 태스크에 의해 자원이 낭비되는 것을 막고 개발자에게 문제를 해결할 기회를 준다.

3. 배포(Deployment)

(1) 옵션

서비스를 배포(deploy)할 때 알아야할 서비스 관련 중요 설정이 있다.

  • maximumPercent
    a) 만약 서비스가 롤링 업데이트 되는 것으로 설정된 경우에 이 설정의 값은 배포가 진행 중일 동안 RUNNING 또는 PENDING 상태에 있어도 되는 상한선의 desiredCount 값 대비 비율을 의미하고
    b) 만약 서비스가 블루 그린 업데이트(Code Deploy 사용) 또는 External 타입 업데이트되는 것으로 설정되어 있고, EC2 launch type인 상황이라면 이 설정의 값은 container instance들이 DRAINING 상태에 있을 때 RUNNING 상태에 있어도 되는 태스크 수의 상한선의 desiredCount 값 대비 비율을 의미한다. 만약 서비스가 블루 그린 업데이트(Code Deploy 사용) 또는 External 타입 업데이트되는 것으로 설정되어 있고, Fargate launch type인 상황이라면 이 설정값은 서비스 설명에 표시는 되더라도 실제 배포 때 사용되지는 않는다.

이 설정의 기본 값은 200%이다.

  • minimumHealthyPercent
    a) 만약 서비스가 롤링 업데이트 되는 것으로 설정된 경우에 이 설정의 값은 배포가 진행 중일 동안 RUNNING 상태에 있어야 하는 하한선의 desiredCount 값 대비 비율을 의미하고
    b) 만약 서비스가 블루 그린 업데이트(Code Deploy 사용) 또는 External 타입 업데이트되는 것으로 설정되어 있고, EC2 launch type인 상황이라면 이 설정의 값은 container instance들이 DRAINING 상태에 있을 때 RUNNING 상태에 있어도 되는 태스크 수의 하한선의 desiredCount 값 대비 비율을 의미한다. 만약 서비스가 블루 그린 업데이트(Code Deploy 사용) 또는 External 타입 업데이트되는 것으로 설정되어 있고, Fargate launch type인 상황이라면 이 설정값은 서비스 설명에 표시는 되더라도 실제 배포 때 사용되지는 않는다.

이 설정의 기본 값은 100%이다.

(2) healthy?

*여기서 healthy하다고 판단하는 기준은
(1) load balancer를 사용하지 않는 경우
(1-1) health check가 정의된 essential 컨테이너가 있는 경우, 해당 health check들이 모두 통과해야 함
(1-2) 그 외의 경우 하나의 태스크가 RUNNING 상태가 되고 40초가 지난 경우

(2) load balancer를 사용하는 경우
(2-1) health check가 정의된 essential 컨테이너가 있는 경우, 해당 health check들이 모두 통과해야 하고, load balancer의 타깃 그룹 health check 또한 통과해야 함
(2-2) 그 외의 경우 load balancer의 타깃 그룹 health check를 통과해야 함

참고로 배포 방식이 rolling update인 경우 로드밸런서 사용은 optional이지만, blue/green 방식인 경우에는 required이다.

4. 서비스 업데이트

한번 서비스를 생성하고 나면 Service definition에 정의된

  • target group ARN
  • load balancer name
  • container name
  • container port

은 불변이다. 그리고 load balancer 설정을 새롭게 추가, 제거, 변경할 수도 없다. 만약 서비스에서 사용하는 task definition을 수정하는 경우에도 서비스 생성 시에 사용한 container name과 container port는 task definition에서 그대로 유지되어야 한다.

보통 서비스 업데이트를 하는 경우는

  • 태스크 수
  • 사용할 task definition
  • Fargate인 경우 platform version

등을 수정하기 위해서이다. 만약 새로운 컨테이너 이미지를 사용하고 싶다면 새로운 task definition revision을 만들고 force new deployment 옵션으로 배포하면 된다.

배포를 시작하면 서비스 스케줄러는 위에서 언급한 minimumhealthypercent와 maximumpercent 파라미터를 사용해서 배포 전략을 결정한다.

서비스 스케줄러가 업데이트 도중 기존 태스크를 교체할 때, 서비스는 다음과 같은 순서로 작업을 진행한다

(1) 태스크를 로드밸런서로부터 제거(만약 로드밸런서를 사용 중이었다면)
(2) 커넥션 drain을 기다림
(3) 태스크 내부의 컨테이너들에 docker stop과 동일하게 SIGTERM 시그널을 보내고 30초 대기
(4) 30초 안에 컨테이너들이 gracefully exit하지 않는다면 SIGKILL 시그널을 보내서, SIGKILL 시그널을 받고 30초 안에 강제 종료되도록 함

전반적으로 서비스 스케줄러는 minimumhealthypercent와 maximumpercent 파라미터를 기반으로 태스크들을 시작 및 정지시킨다고 보면 된다.

서비스를 관리 콘솔에서 업데이트할 때 Force new deployment 옵션을 주게 되면 현재 실행 중인 태스크들은 모두 종료되고, 새로운 태스크들이 실행된다.

5. Deployment circuit breaker

롤링 업데이트를 사용하는 경우에는 만약 배포를 했는데 steady state로 가지 못한다면 해당 배포가 failed 상태가 되도록 circuit breaker 로직을 설정할 수 있다. 그리고 이 로직은 ECS가 가장 최근의 정상 완료된 배포로 롤백할 수 있도록 트리거할 수도 있다.

aws ecs create-service \
     --service-name MyService \
     --deployment-controller type=ECS \
     --desired-count 2 \
     --deployment-configuration "deploymentCircuitBreaker={enable=true,rollback=true}" \ !!!!!
     --task-definition sample-fargate:1 \
     --launch-type FARGATE \
     --platform-os LINUX \
     --platform-version 1.4.0 \
     --network-configuration "awsvpcConfiguration={subnets=[subnet-12344321],securityGroups=[sg-12344321],assignPublicIp=ENABLED}"

failed 상태가 된 배포는 더이상 새로운 태스크를 실행하지 않는다.

그렇다면 언제 이 circuit breaker가 발동될까? 특정 threshold를 넘었을 때인데 해당 threshold 값은 0.5 * desired service count 이다. (threshold가 가질 수 있는 최솟값은 10, 최댓값은 200으로 그 이하나 이상으로 계산되면 10이나 200이 된다.)

배포 상태는 다음과 같은 두 개의 단계를 거쳐서 체크된다.

  1. 해당 배포 때 시작된 태스크가 RUNNING 상태로 진입했는지를 체크하고 만약 그렇지 못한 태스크들에 대해서 failure count를 1 증가, 만약 이때 해당 threshold를 넘기면 해당 배포는 바로 failed 상태가 된다.

  2. 태스크들에 다음과 같은 헬스 체크들을 수행했는데

  • Elastic Load Balancing load balancers
  • AWS Cloud Map service
  • Amazon ECS container health checks

만약 실패하면 failure count를 1 증가, 만약 이때 해당 threshold를 넘기면 해당 배포는 바로 failed 상태가 된다.

profile
성장의 기쁨

0개의 댓글