Amazon ECS 서비스, 롤링 배포는 태스크를 어떻게 바꿀까
ECS 서비스는 원하는 개수의 태스크를 계속 띄워 두고, 새 버전으로 바꿀 때는 최소 정상 비율과 최대 비율 안에서 조금씩 교체한다.
기본값은 새 태스크를 먼저 띄우는 방식이라 남는 자원이 없으면 배포가 멈춘다.
이 글의 목차태스크 정의, 태스크, 서비스5
AWS에서 컨테이너를 실행해 주는 ECS의 콘솔에서 서비스를 만들면 원하는 태스크 수를 적는 칸이 나온다.
그 아래 배포 설정에는 최소 정상 비율(minimum healthy percent)과 최대 비율(maximum percent)이 있다.
따로 고치지 않으면 두 값은 100%와 200%로 잡힌다.
새 버전으로 바꾸는 동안 태스크가 몇 개까지 줄거나 늘어도 되는지를 정하는 값이다.
계산은 단순하지만, 기본값을 모르고 쓰면 배포가 아무 오류 없이 멈춰 버리기도 한다.
ECS에 나오는 이름 세 개부터 구분한다.
태스크 정의, 태스크, 서비스
태스크 정의는 무엇을 어떻게 실행할지 적은 명세다.
컨테이너마다 쓸 이미지, CPU와 메모리, 시작할 때 실행할 명령 같은 값을 JSON 형식의 텍스트 파일 하나에 적는다.
태스크는 그 태스크 정의대로 실제로 띄운 실행 단위 하나다.
컨테이너 하나로 이뤄지기도 하고, 함께 뜨는 여러 컨테이너로 이뤄지기도 한다.
서비스는 태스크가 정해 둔 개수만큼 계속 떠 있게 지키는 층이고, 그 개수를 원하는 개수(desired count)라고 부른다.
태스크 하나가 실패하거나 멈추면 서비스 스케줄러가 같은 태스크 정의로 새 태스크를 띄워 그 자리를 채운다.
사람이 지켜보지 않아도 개수가 유지되는 것은 이 덕분이다.
처음 쓸 때 자주 헷갈리는 지점이 여기서 나온다.
태스크 정의는 고칠 때마다 리비전 번호가 하나 올라간 새 정의로 저장되고, 기존 리비전도 그대로 남는다.
서비스가 새 리비전을 쓰게 하려면 서비스를 따로 업데이트해야 한다.
설정을 고쳤는데 왜 그대로냐는 질문의 답은 대개 이것이다.
태스크는 어디에서 도는가
태스크가 돌 자리도 있어야 한다.
처음 나왔을 때 ECS는 EC2 인스턴스로 클러스터를 꾸리고 그 위에 컨테이너를 배치하는 방식이었다.
이 방식에서는 인스턴스의 수와 크기를 직접 정할 수 있는 대신, 남는 자원과 모자란 자원도 직접 챙겨야 한다.
나중에 나온 Fargate는 이 인스턴스를 보이지 않게 감췄다.
태스크마다 CPU와 메모리만 정하면 그 아래 서버는 AWS가 준비한다.
배포에서 이 차이가 드러나는 곳은 새 태스크를 놓을 자리다.
EC2 방식에서는 클러스터에 남은 CPU와 메모리가 새 태스크를 띄울 수 있는지를 정한다.
바꿔 끼우는 동안의 계산
새 리비전으로 서비스를 업데이트하면, 기본 배포 방식인 롤링 업데이트는 도는 태스크를 한꺼번에 갈아 치우지 않고 조금씩 바꾼다.
그 폭을 정하는 것이 앞의 두 비율이다.
최소 정상 비율은 교체하는 동안 살아 있어야 하는 태스크 수의 하한이다.
원하는 개수에 이 비율을 곱하고 올림한다.
최소가 50%이고 원하는 개수가 4면 하한이 2라서, 기존 태스크 두 개를 먼저 멈추고 새 태스크 두 개를 띄울 수 있다.
최대 비율은 교체 중에 함께 존재할 수 있는 태스크 수의 상한이고, 곱한 값을 내림한다.
최대가 200%이고 원하는 개수가 4면 상한이 8이라서, 새 태스크 네 개를 먼저 띄운 뒤 기존 네 개를 정리할 수 있다.
기본값 100%와 200%가 바로 이 두 번째 방식이다.
기존 태스크를 하나도 내리지 않고 새 태스크부터 띄우니 처리 용량이 줄지 않는다.
다만 클러스터에 새 태스크를 그만큼 더 놓을 자원이 남아 있어야 이렇게 동작한다.
자원이 모자라면 새 태스크는 놓을 자리를 찾지 못하고, 최소 비율이 100%라 기존 태스크를 먼저 내릴 수도 없다.
서비스 이벤트에는 조건에 맞는 컨테이너 인스턴스가 없어 태스크를 배치하지 못했다는 메시지가 찍히고, 배포는 그 자리에 머문다.
| 두 값을 어떻게 잡나 | 교체 순서 | 잘못 잡으면 |
|---|---|---|
| 최소 50%, 최대 100% | 먼저 내리고 나중에 올림 | 교체하는 동안 처리 용량이 줄어듦 |
| 최소 100%, 최대 200% (기본값) | 먼저 올리고 나중에 내림 | 남는 자원이 없으면 새 태스크를 놓지 못함 |
| 원하는 개수 2에 최소 75%, 최대 125% | 내릴 수도 올릴 수도 없음 | 배포가 시작되지 못하고 멈춤 |
마지막 줄은 계산하면 하한도 2, 상한도 2다.
하나를 내리면 하한 아래로 내려가고, 하나를 더 띄우면 상한을 넘으니 스케줄러는 아무것도 하지 못한다.
이런 멈춤은 실패로 표시되지 않아서 알아채기 어렵다.
ECS는 배포 설정 때문에 태스크를 멈추지도 시작하지도 못했다는 서비스 이벤트를 남기므로, 배포가 조용하다면 콘솔의 서비스 화면에서 이벤트 탭부터 확인한다.
원하는 개수가 2개인 서비스를 새 리비전으로 바꾼다. 칸 하나가 태스크 하나를 올릴 자원이다. 교체가 진행되는 방식은 배포 설정과 남은 자원에 따라 달라진다.
실행 중 2개
하한 · 상한 2개 · 4개
배포 상태 대기
최소 50%·최대 100%는 기존 태스크를 내린 뒤 새 태스크를 올리고, 기본값인 최소 100%·최대 200%는 새 태스크를 먼저 띄우므로 남은 자원이 있어야 한다. 최소 75%·최대 125%는 하한과 상한이 모두 2개라 배포가 시작되지 못한다.
지금은 기존 리비전 2개가 실행 중이다. 아직 배포 전이다.
태스크 하나를 한 칸으로 단순화한 예시다. 실제 배치는 CPU·메모리 같은 자원 단위로 이뤄지고, 새 태스크가 정상으로 판정되기까지의 대기와 실패 감지는 생략했다.
실패한 배포를 알아채는 장치
새 태스크가 계속 뜨지 못하거나 헬스 체크에 실패한다면 언제 이 배포를 실패로 볼지도 정해야 한다.
ECS는 배포 회로 차단기와 CloudWatch 알람, 두 가지 방법으로 실패를 감지한다.
배포 회로 차단기(deployment circuit breaker)는 새 태스크가 실행 상태에 이르지 못하거나 헬스 체크에 실패하는 횟수를 세다가, 그 횟수가 기준에 이르면 배포를 실패로 바꾼다.
롤백 옵션을 켜 두면 마지막으로 완료된 배포로 되돌아간다.
기준은 기본값에서 원하는 개수의 절반을 올림한 수이고, 그 값이 3보다 작으면 3을, 200보다 크면 200을 쓴다.
원하는 개수가 4라면 절반인 2가 3보다 작으므로, 새 태스크의 실패가 세 번 이어지면 배포가 실패로 바뀐다.
되돌아갈 곳이 없으면 롤백도 없다.
회로 차단기가 완료 상태의 배포를 찾지 못하면 새 태스크를 띄우지 않고, 배포는 멈춘 채로 남는다.
롤백이 된다고 예전 상태가 그대로 살아나지는 않는다.
예전 리비전이 가리키는 이미지가 저장소에서 지워졌거나 비밀 값이 바뀌었다면 같은 태스크를 다시 만들 수 없다.
새 버전이 데이터 형식을 바꿨다면 옛 코드가 그 데이터를 읽을 수 있는지도 따로 확인해야 한다.
배포 설정은 가진 자원에 맞춘다
Fargate처럼 태스크마다 자원이 따로 마련되는 환경이라면 기본값 100%와 200%를 그대로 쓰는 경우가 많다.
처리 용량을 줄이지 않고 교체할 수 있기 때문이다.
여기에 회로 차단기와 롤백을 켜 두면 새 버전이 뜨지 못할 때 이전 버전으로 돌아간다.
EC2 클러스터에 여유 자원이 없다면 둘 중 하나를 고른다.
교체하는 동안 쓸 자원을 더 마련하거나, 최소 비율을 낮춰서 배포하는 동안 처리 용량이 잠시 줄어드는 것을 받아들인다.
어느 쪽이든 하한과 상한 사이에 태스크 하나는 멈추거나 시작할 틈이 있어야 한다.
AWS도 배포를 시작할 때 스케줄러가 적어도 태스크 하나는 멈추거나 시작할 수 있도록 두 값을 정하라고 권한다.