Series
클러스터 생성하기
그럼 이제 컨테이너를 실행할 ECS 클러스터를 생성해보죠.
(2023년부터 AWS의 ECS 웹콘솔이 새로운 디자인으로 변경되었습니다.)
EC2 키페어 생성
우선 ECS 인스턴스를 EC2로 할 예정이기 때문에 EC2 키페어를 먼저 생성하겠습니다.
EC2 - 네트워크 및 보안 - 키페어로 들어갑니다.
IAM 설정
ecs 정책 생성
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"ecs:ListServicesByNamespace",
"ecs:DiscoverPollEndpoint",
"ecs:PutAccountSettingDefault",
"ecs:CreateCluster",
"ecs:DescribeTaskDefinition",
"ecs:PutAccountSetting",
"ecs:ListServices",
"ecs:CreateCapacityProvider",
"ecs:DeregisterTaskDefinition",
"ecs:ListAccountSettings",
"ecs:DeleteAccountSetting",
"ecs:ListTaskDefinitionFamilies",
"ecs:RegisterTaskDefinition",
"ecs:ListTaskDefinitions",
"ecs:CreateTaskSet",
"ecs:ListClusters"
],
"Resource": "*"
},
{
"Sid": "VisualEditor1",
"Effect": "Allow",
"Action": "ecs:*",
"Resource": [
"arn:aws:ecs:*:{account_id}:cluster/*",
"arn:aws:ecs:*:{account_id}:task/*/*",
"arn:aws:ecs:*:{account_id}:capacity-provider/*",
"arn:aws:ecs:*:{account_id}:task-set/*/*/*",
"arn:aws:ecs:*:{account_id}:container-instance/*/*",
"arn:aws:ecs:*:{account_id}:service/*/*",
"arn:aws:ecs:*:{account_id}:task-definition/*:*"
]
}
]
}
신뢰 정책 수정
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "ecs-tasks.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
ECS 클러스터 생성
EC2의 인스턴스 유형은 아래 링크를 참고해주세요. 저는 간단한 샘플 테스트용 이기 때문에 t2.nano를 사용하였습니다.
https://aws.amazon.com/ko/ec2/instance-types/
특히 인스턴스 별 vCPU와 메모리에 따라 추후 Task의 사용할 수 있는 vCPU와 메모리가 달라지므로 매우 주의해야 합니다.
Task(작업) 정의하기
ECS에서 Task는 Docker 컨테이너 설정을 위해 사용됩니다.
어떤 Docker 이미지를 가지고 Docker 컨테이너를 생성하는지를 Task에서 정의할 수 있고, 하나의 Task에 여러 개의 Docker 컨테이너 설정을 해줄 수 있습니다.
-
시작 유형 호환성 선택(Fargate EC2 External) - 사용할 컨테이너 이미지 설정
- 애플리케이션을 위해 개방할 포트 설정
- CPU/메모리 리소스 할당 설정
- 작업의 컨테이너에 사용할 데이터 볼륨 설정
Dynamic Port Mapping 하기
배포가 될 때마다 테스크가 수정되며 reverse-proxy-container의 host port는 계속해서 바뀔 수 있습니다.
따라서 reverse-proxy-container의 host port는 0으로 설정하여 모든 포트가 가능하도록 해줍니다.
그리고 ECS 클러스터를 통해 생성된 EC2 인스턴스의 보안 그룹의 인바운드 규칙에 모든 TCP (0 - 65535)를 추가해줍니다.
테스크의 크기는 위에서 선택한 EC2의 vCPU와 메모리 입력하면 됩니다.
서비스 생성하기
대상 그룹 생성하기
로드 밸런서 생성하기
Application Load Balancer 선택
로드밸런서 보안 그룹 수정
ECS 서비스 생성하기
❗ 최소 실행 작업 비율과 최대 실행 작업 비율을 각각 0%와 100%로 해줘야 합니다. 롤링 업데이트 유형으로 배포가 되면 현재 실행 중인 컨테이너 버전을 최신 버전으로 바꾸는데 만약 최소 실행 작업 비율을 100%, 최대 실행 작업 비율을 200%으로 하게될 경우 도커의 port가 중복이 되기 때문에 배포가 진행이 안되며 에러가 발생합니다. 참고 : https://stackoverflow.com/questions/46018883/best-practice-for-updating-aws-ecs-service-tasks
서비스를 실행하면 배포가 안되는 것을 확인할 수 있습니다. 왜 그럴까요?
클러스터의 컨테이너 인스턴스, 클러스터를 생성할 때 선언한 EC2를 확인해보면 가용 메모리가 466mb인 것을 확인할 수 있습니다.
하지만 우리가 테스크를 정의할 때 테스크의 메모리를 500mb로 설정하였죠. 따라서 우린 테스크 메모리를 466mb보다 작게 설정해야 합니다.
테스크의 메모리를 450mb로 수정 후 이전의 배포 중이던 테스크는 중지하고 ECS 서비스를 업데이트해보겠습니다.
확인해보니 배포는 진행되지만 작업이 중단되었습니다.
확인해보니 테스크 정의 중 컨테이너 정의에서 reverse-proxy-container와 example-app-container간의 순서를 정의와 링크를 하지 않았습니다. 이를 위해 테스크를 수정해보겠습니다.
그리고 cloudwatch에서 로그를 확인하기 위해 Auto-configure CloudWatch Logs를 활성화하겠습니다.
example-app-container의 포트 매핑도 수정하겠습니다.
그리고 이전 단계와 똑같이 ECS 서비스를 업데이트했습니다.
이제 매우 정상적으로 작동하는 ECS 서비스를 확인할 수 있습니다!
ECS 환경 변수 설정하기
한번 Load balancers의 DNS로 API를 요청해보겠습니다.
localhost에서 실행한 컨테이너 앱에서 나왔던 저자 이름이 ECS에서 실행한 컨테이너 앱 상에서는 나오지 않았습니다. 저자의 이름은 환경변수로 설정하였는데 ECS 작업 정의 단계에서 환경변수를 설정하지 않았기에 당연히 저자의 이름은 나올 수가 없습니다.
ECS에서 환경 변수를 정의하는 방법으로는 크게 4가지가 있습니다.
- ECS 작업 정의에 변수를 저장합니다.
- 변수를 Amazon Simple Storage Service(Amazon S3) 버킷 내부의 environmentFiles 객체로 전달합니다.
- AWS Systems Manager Parameter Store에 변수를 저장합니다.
- AWS Secrets Manager 내부에 변수를 저장합니다.
출처 : https://repost.aws/knowledge-center/ecs-task-environment-variables
그 중에 첫번째는 추후 github actions등을 통해 배포하는 과정에서 어려움이 많습니다. 따라서 AWS Secrets Manager를 사용하거나 Amazon S3 버킷 내부의 environmentFiles를 사용하는 방법 중에서 이번엔 AWS Amazon S3 버킷 내부의 environmentFiles를 사용하겠습니다.
- AWS Secrets Manager 사용
AWS Secrets Manager 암호 생성
IAM 권한 설정
위에서 작업 정의를 위해 생성한 ecs-ec2-role 역할에 권한 정책을 추가하겠습니다.
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": ["secretsmanager:GetSecretValue"], "Resource": ["arn:aws:secretsmanager:{region}:{aws_account_id}:{secret:secret_name}"] } ] }
작업 정의의 새 개정 생성
컨테이너 정의 후 서비스를 업데이트합니다.
AWS Amazon S3 버킷 생성 후 environmentFiles 저장
버킷에 env 파일을 업로드하기 위해서는 파일 이름이 필수입니다.
IAM 권한 설정
environmentFiles을 저장한 버킷에서 object를 가져오기 위한 정책을 생성합니다.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:*"],
"Resource": ["arn:aws:s3:::ecs-sample-env/*"],
"Condition": {
"ArnLike": {
"aws:SourceArn": "arn:aws:ecs:ap-northeast-2:{account_id}:*"
},
"StringEquals": {
"aws:SourceAccount": "{account_id}"
}
}
}
]
}
S3 버킷 정책 생성
environmentFiles은 서비스의 보안적으로 중요한 변수들을 저장한 파일입니다. 따라서 S3 객체로 업로드하여도 퍼블릭으로 접근하면 당연히 안됩니다. 이를 위해 특정 역할에서만 접근하고 일부 액션만 가능하도록 설정해야 합니다.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::{account_id}:role/{ecs_task_role}"
},
"Action": "s3:*",
"Resource": "arn:aws:s3:::ecs-sample-env/*"
}
]
}
참고 자료 : https://inpa.tistory.com/entry/AWS-📚-S3-버킷-생성-사용법-실전-구축
작업 정의의 새 개정 생성
해당 env 파일을 사용하는 example-app-container 컨테이너의 환경 파일에 S3 버킷에 저장한 environmentFile의 ARN을 입력합니다.
ECS 서비스 업데이트
새로 생성된 작업 정의 버전으로 ECS 서비스를 업데이트합니다.
배포가 완료된 후 API를 호출해 보겠습니다.
환경변수로 설정한 저자의 이름이 정상적으로 출력됩니다!
다음 장엔 GitHub를 소스 코드 리포지토리에서 GitHub Actions를 사용하여 Amazon ECS에 배포된 애플리케이션을 위한 CI/CD 파이프라인을 구축하는 방법을 살펴보겠습니다.