[AWS/ECS] ECS 클러스터 구성 및 컨테이너 서비스하기
Amazon Elastic Container Service(Amazon ECS)는 클러스터에서 컨테이너를 손쉽게 실행, 중지 및 관리할 수 있게 하는 컨테이너 관리 서비스이다. 본 포스팅에서는 인스턴스로 구성된 ECS 클러스터를 생성하고, 해당 클러스터에서 컨테이너를 ALB를 통해 서비스하는 과정을 다룬다.
본 포스팅에서는 아래 사항들이 준비되었다는 가정 하에 진행된다.
- 이미지 저장소 (Amaon ECR, Docker hub 등)에 저장된 컨테이너 이미지
- 서비스와 연결될 LoadBalancer (Blue/Green의 경우 2개 필요)
작업 단계는 다음과 같이 세 단계로 진행된다.
- ECS 작업 정의
- ECS 클러스터 생성
- 서비스 생성
이미지는 Amazon ECR로부터 가져오며, internet-faced 로드밸런서를 사용하여 서비스를 제공한다.
1. ECS 작업 정의
ECS 작업 정의 (Task Definition)는 도커 이미지, 작업에서 사용할 컨테이너 수, 각 컨테이너의 리소스 할당에 대한 값을 정의해둔 내용으로서 서비스가 생성될 때 이 작업 정의를 참고하게된다.
1.1 시작유형 및 호환성 선택
작업 정의 생성을 선택하면 fargate, ec2, external 을 선택할 수 있으며, 각각의 설명은 아래와같다. 본 포스팅에서는 EC2 형식의 작업 정의를 생성한다.
- fargate: 작업 크기 기반 요금, 네트워크 모드를 awsvpc 선택해야 함, AWS 관리형 인프라, 관리할 Amazon EC2 인스턴스 없음
- EC2: 리소스 사용량 기반 요금, 여러 네트워크 모드 사용 가능, Amazon EC2 인스턴스를 사용한 자체 관리형 인프라
- external: 인스턴스 시간 기준 요금 및 사용한 다른 AWS 서비스에 대한 추가 요금, ECS Anywhere를 사용하는 자체 관리형 온프레미스 인프라
1.2 작업 및 컨테이너 정의
이 단계에서는 작업 정의 이름과 태스크 역할, 네트워크 모드를 선택한다.
태스크역할에 ecsTaskExecutaionRole이 없다면 관련 역할을 생성하며, 역할에 추가되는 정책(예. AmazonECSTaskExecutionRolePolicy)은 다음과 같다.
# AmazonECSTaskExecutionRolePolicy
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ecr:GetAuthorizationToken",
"ecr:BatchCheckLayerAvailability",
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "*"
}
]
}
또한, 컨테이너에서 사용할 docker 네트워크 모드를 설정해준다. 이때 값은 아래 4가지 선택이 가능하며 본 포스팅에서는 docker 기본 가상 네트워크 방식을 사용할 것이므로 브리지를 선택하였다.
- 기본 (default)
- 브리지 (bridge): 태스크에 docker 기본 가상 네트워크 사용
- 호스트 (host): EC2 인스턴스 ENI에 직접 매핑방식
- awsvpc: 태스크에 ENI와 기본 프라이빗 IPv4 주소가 할당, fargate 사용시 해당 네트워크 모드 사용해야 함
1.3 작업 실행 IAM 역할 및 작업 크기 선택
작업 실행 역할이 없는경우 자동으로 AWS에서 ecsTaskExecutionRole을 생성한다. 따라서 해당 역할이 없는 경우 비운채 진행하며, 존재하는 경우 해당 역할을 선택한다.
작업에 할당될 메모리와 CPU 총량을 선택한다. Fargate의 경우 할당, 사용한 만큼 컨테이너가 생성 (이 때 각 메모리에 따른 가능 CPU 총량이 정해져있음) 되므로 입력이 필수이며 EC2와 External 시작 유형은 선택적 미입력 가능하다.
이 때 EC2 인스턴스를 ECS 클러스터 노드로 사용한다면, 해당 스펙보다 작거나 같아야한다.
1.4 컨테이너 추가
- 컨테이너 이름과 컨테이너 생성에 사용될 이미지 url:tag 을 입력한다.
- 메모리 제한
- memory 하드 제한: 컨테이너가 사용할 메모리 양으로, 지정된 메모리가 초과되면 컨테이너는 중지된다. 이 때 생성된 컨테이너들의 메모리 양이 앞서 작업 크기 - 메모리에서 설정한 값보다 적어야함 (docker run --meory 에 해당)
- memoryReservation 소프트 제한: 컨테이너가 해당 값 이내로 메모리를 사용하도록 노력하며, 필요한 경우 하드제한 이내의 메모리 값 까지 할당하여 사용한다. (docker run --meory-reservation 에 해당)
- 포트 매핑
- 컨테이너 포트: 컨테이너 포트 번호로서 호스트 포트에 바인딩된다.
- 호스트 포트: 인스턴스에 허용될 포트(ALB를 사용할 경우, 호스트 포트 값을 0으로 설정하면 동적 포트 매핑을 지원)
- 동적 매핑 포트 범위: 49153-65535 (Docker 16.0 이상 기준이며, 예약포트 SSH용 22, Docker 포트 2375, 2376, Amazon ECS 컨테이너 포트 51678-51680는 제외된다)
2. ECS 클러스터 생성
2.1 템플릿 선택
AWS에서는 ECS 클러스터를 생성할 수 있는 클러스터 템플릿을 제공하며, 본 포스팅에서는 Linux 환경에서 구동을 테스트 할 예정이므로 EC2 Linux + 네트워킹을 선택한다.
- 네트워킹 전용 (AWS Fargate, External instance capacity를 사용할 경우 이 템플릿을 선택한다)
- EC2 Linux + 네트워킹
- EC2 Windows + 네트워킹
2.2 인스턴스 구성
ECS 클러스터 이름을 입력하고, 클러스터를 구성할 인스턴스를 설정한다. 인스턴스 개수는 클러스터가 생성 된 후 Auto Scaling Group을 통해 Scale in/out이 가능하며, 키 페어 선택시 해당 키 페어를 사용하여 클러스터의 인스턴스에 ssh 접속이 가능하다.
2.3 인스턴스 네트워킹 설정
컨테이너 인스턴스에대한 네트워킹을 설정한다. VPC와 서브넷, 보안그룹을 선택하며, 본 포스팅에서는 internet-faced ALB를 사용할 예정이므로 인스턴스는 모두 private subnet에 위치시며 퍼블릭 IP 자동 활당도 비활성화 한다.
인스턴스에 사용될 보안그룹에는 SSH와 ALB 보안그룹에 대한 인바운드 규칙이 허용되어야한다. 본 포스팅에서는 동적 포트 매핑을 사용하므로 ALB 포트 범위를 32768-65535로 지정해주었으나, 특정 포트를 사용하고자 할 경우 그 포트에 대한 ALB 보안그룹의 인바운드를 허용해주면 된다.
마지막으로 컨테이너 인스턴스 IAM 역할을 선택한다. 새 역할 생성 상태이면 AWS에서 자동으로 ecsInstanceRole이름의 역할을 생성한다.
클러스터가 정상적으로 생성되면, 콘솔에서 인스턴스 정보를 확인할 수 있으며, 이 컨테이너 인스턴스에 대한 Auto Scaling Group이 함께 생성된다.
3. 서비스 생성
ECS 클러스터에서 지정된 수의 작업 정의 인스턴스를 동시에 실행, 관리한다. 또한 작업이 실패, 중지되는 경우 ECS 서비스 스케줄러가 다른 작업을 시작, 대체하여 서비스에서 원하는 작업 개수를 유지한다.
3.1 서비스 구성
클러스터 내에서 실행, 유지관리할 작업 정의의 복사본 개수를 지정한다. 이 값들은 Additional Configuration 단계에서 선택된 배포 방법에 따라 요구 값이 달라진다.
- (좌) - Blue/Green 배포 선택 시
- (우) - Rolling update 선택 시 최소 정상 상태 백분율, 최대 백분율
ECS는 서비스에대해 Rolling과 Blue-Green 방식의 배포를 지원하며 Blue-Green 배포를 선택하는 경우 배포 구성과 CodeDeploy 서비스 역할을 생성, 선택 해야한다.
본 포스팅에서는 ECS 구성에 대해 다루므로 이 역할에 대한 자세한 내용은 생략하되, 다음 URL에 역할에 필요한 정책 정보가 담겨져있으니 참고하여 생성한다. (https://docs.aws.amazon.com/ko_kr/AmazonECS/latest/developerguide/codedeploy_IAM_role.html)
3.2 작업 배치
클러스터 내 인스턴스들에 작업이 배치되는 방식을 지정하는 부분이다. 본 포스팅에서는 추후 인스턴스가 증설되었을 때 고 가용성을 위해 AZ 균형 분산을 선택하였다. 다만, 클러스터 구성시 서브넷을 하나의 AZ에서만 선택하였거나, 클러스터 인스턴스가 1개 존재한다면 분산 되지 않고 해당 인스턴스 내에 작업들이 배치된다.
3.3 추가 구성 (Additional Configuration)
ECS 서비스가 연결 될 로드밸런서와 타겟 그룹을 선택할 수 있다.
로드밸런서를 선택 후 로드밸런서에 연결 할 타겟 그룹을 선택해야한다.
ECS 서비스는 Rolling과 Blue-Green 방식의 배포를 지원하는데 타겟 그룹은 배포 방식에 따라 필요 수가 달라진다.
Blue-Green 배포 방식을 선택할 경우 타겟그룹은 2개 (Blue, Green)를 선택해야 하며, 이 경우 CodeDeploy에는 자동으로 애플리케이션과 배포 그룹이 생성된다. 본 포스팅에서는 이를 확인하기위해 Blue-Green 배포를 선택, 설정하였다.
- ECS-TG-1: 기존 서비스의 트래픽을 담당할 타겟 그룹
- ECS-TG-2: 배포 후 전환할 타겟 그룹
그 결과, 다음과같이 CodeDeploy에 애플리케이션과 배포 그룹이 생성된 것을 확인할 수 있다. 테스트 과정에서 서비스 생성 시도를 여러번, 동일한 이름과 설정으로 진행하면 CodeDeploy 생성 과정에서 오류가 발생할 수 있다 (서비스 삭제시 CodeDeploy 리소스는 제거되지않음). 이 경우 해당 애플리케이션과 배포 삭제 후 재시도하면 정상 생성된다.
마지막으로 서비스가 정상적으로 동작되는지 확인해본다. (예. ALB-DNS:listener-port/path)
만일 정상 동작되지 않는다면 다음 내용을 확인해본다.
- ALB에 연결된 타겟 그룹 상태 확인
- ALB 보안그룹의 인바운드, 아웃바운드
- 클러스터 인스턴스의 인바운드, 아웃바운드
- 인스턴스 타입과 빌드된 이미지 환경 확인 (arm64, x86_64)
=> 이 경우 buildx 를 통해 멀티 아키텍트 이미지를 생성하면 되며, 다음 포스팅 내용을 참고하면 구성 가능하다.
2022.02.18 - [CICD] - [AWS/CodeBuild] 서울 리전 CodeBuild에서 빌드된 Docker 이미지를 arm64 인스턴스에서 사용가능하도록 하는 방법
[참고]
https://docs.aws.amazon.com/ko_kr/AmazonECS/latest/developerguide/codedeploy_IAM_role.html
https://docs.aws.amazon.com/ko_kr/AmazonECS/latest/userguide/task_definition_parameters.html
https://docs.aws.amazon.com/ko_kr/AmazonECS/latest/developerguide/Welcome.html