티스토리 뷰

개요

  • AWS Fargate는 별도로 인스턴스를 생성 관리하지 않고, 완전한 매니지드 서비스의 형태로 도커 컨테이너를 실행시킬 수 있는 아마존의 서비리스 컨테이너 상품이다. Docker 이미지가 리파지터리에 푸시되어 있다면, 클러스터작업 정의서비스의 순서로 생성하여 완전히 24시간 서비스 가능한 애플리케이션을 기동할 수 있다.
  • AWS Fargate를 사용하려면 상위 개념에서 특정 오케스트레이션 상품을 선택해야 한다. 현재 Amazon ECS, Amazon EKSAWS Fargate를 지원한다. 신기능이 출시되면 Amazon ECS에서 먼저 지원하고, Amazon EKS가 뒤를 이어 지원하는 편이다.)

AWS Fargate 업데이트 이력

  • 2020-08-17, Amazon EKS 기반 AWS Fargate에서 EFS 파일 시스템 마운트 지원을 시작했다.
  • 2020-07-31, Amazon ECS 기반 AWS Fargate에서 NLB를 이용한 UDP 로드 밸런싱 지원을 시작했다. [관련 링크]
  • 2020-04-24, Amazon ECS 기반 AWS Fargate에서 EFS 파일 시스템 마운트 지원을 시작했다. 작업 또는 서비스 실행시 플랫폼 버전을 1.4.0 이상으로 지정해야 한다. EFS 지원은 환경 변수 외에 애플리케이션의 상태를 관리할 수 있게 된 것이라 큰 의미를 가진다. [관련 링크]
  • 2019-07-30, Amazon ECS 기반 AWS Fargate에서 서비스 생성시 복수개의 로드 밸런서 대상 그룹 지원을 시작했다. Amazon ECS 콘솔에서는 지원하지 않으며 AWS CLI 등을 사용해야 한다. [관련 링크]
  • 2019-01-07, AWS Fargate의 가격 인하된 요금제가 시작되었다. 기존 대비 CPU는 20%, 메모리는 65% 가격 인하되었다.
  • 2018-11-09, AWS Fargate가 서울 리전에 출시했다.

AWS Fargate 요금제

  • AWS Fargate는 별도의 선결제 금액 없이 컨테이너의 CPU와 메모리 사용량에 기반하여 초 단위로 요금을 과금한다. (Docker 이미지 풀링을 시작하는 시점부터 해당 작업이 종료될 때까지 과금한다.) [관련 링크]
  • EC2에서의 RI(예약 인스턴스) 요금제는 존재하지 않으며, 1년 또는 3년 단위의 Compute Savings Plan 요금제를 이용하여 절약할 수 있다. 2020-11 현재 서울 리전을 예로 들면 온디맨드 대비 1년 전체 선결제시 27%, 3년 전체 선결제시 47%를 절약할 수 있다. 일정한 사용량과 사용 기간이 예측 가능하다면 시도해볼 만하다. 계약한 사용량을 초과한 부분에 대해서는 온디맨드 요금을 과금한다. [관련 링크]
  • 한편 온디맨드, Compute Savings Plans 외에 AWS Fargate Spot 구매 유형이 존재하는데 이를 이용하면 온디맨드 대비 최대 70%를 절약할 수 있다. [관련 링크1] [관련 링크2] 다만, 스팟의 특성상 언제든지 종료될 수 있기 때문에 운영보다는 개발, 테스트 환경에 적극적으로 사용하면 많은 비용을 절감할 수 있다. [관련 링크]

클러스터 생성

  • 클러스터Amazon ECS에서 가장 큰 개념이다. 모든 서비스는 특정 클러스터 내에 속하여 작동한다. 아래와 같이 생성한다.
Amazon ECS 콘솔 접속 → 클러스터 → [클러스터 생성] 클릭
→ 클러스터 템플릿 선택: [네트워크 전용] 클릭
→ 클러스터 이름: foobar-prod
→ [생성] 클릭
  • AWS CLI에서는 아래와 같이 동일한 내용을 실행할 수 있다.
# 클러스터 생성
$ aws ecs create-cluster --region {region} --cluster-name foobar-prod

# 클러스터 생성과 동시에 Container Insights 활성화
$ aws ecs create-cluster --region {region} --cluster-name foobar-prod --settings name=containerInsights,value=enabled
  • 클러스터 생성 전략은 시스템의 배포 단계로 구분하면 좋다. 예를 들어 foobar라는 시스템이라면 foobar-dev, foobar-stage, foobar-prod와 같은 식이다.

작업 정의 생성

  • 이제 작업 정의를 생성할 차례이다. 작업 정의는 쿠버네티스 생태계에서 파드와 유사한 개념이다. 작업 정의에 따라 작업 단독으로 또는 서비스에 소속되어 실행이 가능하다.
Amazon ECS 콘솔 접속 → 작업 정의 → [새 작업 정의 생성] 클릭 → [FARGATE] 클릭
→ 작업 정의 이름: foobar
→ 작업 역할: [ecsTaskExecutionRole] 선택
→ 네트워크 모드: [awsvpc] 선택
→ 작업 메모리(GB): (선택)
→ 작업 CPU(vCPU): (선택)
→ [컨테이너 추가] 클릭
→ 컨테이너 이름: foobar-api-prod
→ 이미지: xxxxx.dkr.ecr.ap-northeast-2.amazonaws.com/foobar-api-prod:latest
→ 포트 매핑: 8080/TCP
→ [추가] 클릭 → [생성] 클릭
  • 작업 정의시 작업 메모리작업 CPU는 해당 작업에 허용하는 최대 리소스 사용량(hard limit)을 의미한다. 예를 들어 작업 메모리에 2GB를 지정하였고, 작업에 속한 컨테이너가 지정된 작업 메모리 사용량을 초과할 경우 OutOufMemory 오류가 발생한다. 이 2개 값에 의해 사용 요금이 결정된다.
  • 컨테이너를 실행시킬 Docker 이미지 저장소는 Docker Hub, Amazon ECR만 지원한다. 그 외의 저장소는 지원하지 않는다. (Spring Boot 프로젝트의 Docker 이미지 생성과 업로드는 본 블로그의 이 글을 참고한다.)

작업 정의: 컨테이너 환경 변수 연동

  • 컨테이너에 환경 변수를 연동하는 방법은 크게 3가지로 분류할 수 있다.
  • 첫째, 라인 단위로 {Key}={Value} 형식으로 환경 변수를 입력하여 .env 확장자로 업로드한 후 컨테이너에 ARN 경로를 지정하여 연동하는 방식이다. 복수개의 환경 변수를 편리하게 관리할 수 있는 장점이 있다.
  • 둘째, 컨테이너 설정시 환경 변수의 값을 직접 하나씩 지정하는 것이다. (Value 방식)
  • 셋째, 환경 변수를 AWS Systems Manager Parameter Store에 등록한 후 해당 키 이름을 컨테이너 설정시 직접 하나씩 지정하는 것이다. (ValueFrom 방식)

작업 정의: 컨테이너 환경 변수 S3 연동

  • Amazon S3.env 파일을 업로드한 후, Task 생성 또는 개정시 해당 파일의 ARN 경로를 컨테이너에 지정하면 환경 변수가 연동된다.
환경 → Envionment Files → [+] 클릭 → Location: arn:aws:s3:::foo/bar.env 입력
  • 이 방식은 S3에 접근하게 되므로, 사전에 해당 Task 실행에 대한 IAM 역할 수정이 필요하다. Amazon S3에 업로드된 파일을 액세스하려면 s3:GetObject, s3:GetBucketLocation 2개 권한이 필요한데 기본 생성되어 있는 ecsTaskExecutionRole 역할에 AmazonS3ReadOnlyAccess 정책을 추가하면 된다.
  • IAM 역할 설정이 정상적으로 되지 않았을 경우, Task 실행시 아래 오류가 발생하며 중단된다.
ResourceInitializationError: failed to download env files: file download command: non empty error stream: AccessDenied: Access Denied status code: 403

작업 정의: EFS 파일 시스템 마운트

  • AWS Fargate 플랫폼 버전 1.4.0부터 EFS 파일 시스템 마운트를 지원하여 상태를 가진 공용 스토리지를 마운트할 수 있게 되었다. [관련 링크] 작업 정의 생성, 개정 시점에 생성한 EFS 파일 시스템을 추가하면 된다. 방법은 아래와 같다.
(작업 정의 화면 진입) → [볼륨 추가] 클릭
→ 이름: foobar
→ 볼륨 유형: [EFS] 선택
→ 파일 시스템 ID: (미리 생성된 EFS 파일 시스템 선택)
→ 루트 디렉토리: / (마운트로 노출될 EFS 파일 시스템의 최상단 디렉토리)
→ [추가] 클릭
  • 작업 정의에서 EFS 볼륨을 추가했다면, 다음으로 컨테이너 정의에 추가한 EFS 볼륨을 마운트할 차례이다. 컨테이너 단위로 n개의 EFS 볼륨을 마운트할 수 있다. 방법은 아래와 같다.
(EFS 볼륨을 적용할 컨테이너 이름 클릭) → 스토리지 및 로깅 → 탑재 지점
→ 소스 볼륨: foobar (작업 정의에서 추가한 EFS 볼륨을 선택)
→ 컨테이너 경로: /home/foobar (컨테이너에서 EFS 볼륨을 마운트할 경로 입력)
→ 읽기 전용: (읽기 전용 여부 체크)
→ [업데이트] 클릭

서비스 생성 및 실행

  • 클러스터, 작업 정의을 생성했다면 다음 단계는 서비스를 생성하고 실행하는 것이다. 서비스에서 정의한대로 작업으로 실행되어 기동된다.
  • 서비스 실행 2단계에서는 네트워크를 구성할 수 있는데 VPN로드 밸런서를 설정할 수 있다.
  • 로드 밸런싱 부분에서는 로드 밸런서 사용 유무 및 유형을 결정할 수 있다. 사전에 생성한 로드 밸런서를 지정할 수 있으며, 로드 밸런싱할 컨테이너에 연결할 대상 그룹을 지정할 수 있다. 대상 그룹의 경우 대상 유형이 IP 주소인 것만 지정이 가능하다. (대상 그룹 생성에 대한 자세한 내용은 이 글을 참고한다.)

작업 정의 갱신

  • 필요에 따라 기존 작성한 작업 정의를 갱신할 수 있다. 작업 정의를 갱신하면 기존 설정은 유지되고 새로운 버전이 생성된다. (예를 들어 기존 버전이 foobar:1 이었다면 foobar:2가 새로 생성된다.)
  • 변경된 작업 정의를 실행 중인 서비스에 적용하려면 아래와 같이 서비스 업데이트가 필요하다.
(개정된 작업이 속한 클러스터) 클릭
→ (개정된 작업이 샐행 중인 서비스) 클릭
→ [업데이트] 클릭
→ 버전 : (개정된 버전) 선택
→ [서비스 업데이트] 클릭
  • 서비스 업데이트를 실행하면 새로운 버전이 적용된 작업을 PROVISIONING하기 시작하는데 RUNNING 상태로 바뀔 때까지 기존 버전의 실행을 유지하여 무중단을 보장한다.

서비스 재배포

  • 일반적으로 AWS CodePipeline까지 구축하면 소스 코드 리파지터리의 변경점 발생에 따라 자동으로 서비스가 배포된다. 하지만 소스 코드 변경점 없이 환경 변수만 수정한다던지, 인스턴스 사양을 변경한다던지, 인스턴스 개수를 변경한다던지 등 다양한 상황에서 임의로 서비스를 재배포해야하는 경우가 있다. 이 경우, 아래와 같이 AWS CLI에서 옵션을 조합하여 서비스 재배포가 가능하다.
# [1] 현재 작업 정의 변경없이 재배포
$ aws ecs update-service --cluster {cluster-name} --service {service-name} --force-new-deployment

# [2] 특정 작업 정의를 지정해서 재배포
$ aws ecs update-service --cluster {cluster-name} --service {service-name} --task-definition {task-definition-name}:{revision} --force-new-deployment

# [3] 특정 작업 정의를 인스턴스 개수를 지정해서 재배포
$ aws ecs update-service --cluster {cluster-name} --service {service-name} --desired-count 2 --task-definition {task-definition-name}:{revision} --force-new-deployment

트러블슈팅: 작업, 서비스 실행시 오류

  • 작업 또는 서비스 실행시 아래 오류가 발생하는 경우가 있다. 이 경우, 플랫폼 버전: LATEST → 1.4.0로 변경하면 정상 작동한다.
작업을 실행할 수 없음
One or more of the requested capabilities are not supported.

트러블슈팅: 서비스 실행시 ELB 헬스 체크 실패 오류

  • 서비스 실행시 아래 오류가 발생하는 경우가 있다. 서비스가 정상적으로 실행되어도 로드 밸런서에서 헬스 체크에 실패한 것인데 이 경우, 서비스 속성에서 상태 검사 유예 기간을 기본값 0초에서 보다 여유 있게 300초(5분) 정도로 조정하면 해결된다.
Task failed ELB health checks in ...

트러블슈팅: 작업, 서비스 실행시 ECR 리파지터리 풀링 실패 오류

  • 작업 또는 서비스 실행시 아래 오류가 발생하는 경우가 있다. 이 경우, 원인이 복합적이라 다양한 방법의 해결책이 존재한다.
ResourceInitializationError: unable to pull secrets or registry auth: execution resource retrieval failed: unable to retrieve ecr registry auth: service call has been retried 1 time(s): RequestError: send request failed caused by: Post https://api.ecr....
  • VPC의 모든 서브넷이 퍼블릭으로 구성되었을 경우, 서비스 생성시 2단계: 네트워크 구성에서 자동 할당 퍼블릭 IPENABLED로 설정해야 한다. [관련 링크]

트러블슈팅: 서비스 생성시 로드 밸런서 복수개 대상 그룹 등록 불가

  • 서비스 생성시 컨테이너의 리스너 포트가 복수개일 경우, 로드 밸런서의 대상 그룹도 동일하게 대응해야 하는데 Amazon ECS 콘솔에서는 단 1개의 대상 그룹 등록만 허용된다. 이를 해결하려면, 서비스의 생성을 콘솔이 아닌 다른 방법으로 등록해야 한다. [관련 링크]
  • 아래는 AWS CLI를 이용하여 서비스를 등록하는 예이다. 서비스 등록을 위해 JSON 정의 파일을 직접 작성하는 것은 쉬운 일이 아니기 때문에, 먼저 콘솔에서 1개의 대상 그룹으로만 생성한 후에 생성된 서비스 정의 내용을 참고하여 명령어로 생성하면 된다.
# 기생성한 ECS 서비스 정보 조회, 이 내용을 참고하여 JSON 정의 파일 작성
$ aws ecs describe-services --region "us-east-2" --cluster "foobar" --services "foobar-prod"

# 생성했던 ECS 서비스 삭제

# ECS 서비스 생성, 대상 그룹을 복수개로 정의하여 등록
$ aws ecs create-service --region "us-east-2" --cli-input-json "file://foobar-prod.json"
{
  "cluster": "foobar-prod",
  "serviceName": "foobar-prod",
  "taskDefinition": "arn:aws:ecs:us-east-2:125257778789:task-definition/foobar-prod:1",
  "loadBalancers": [
    {
      "targetGroupArn": "arn:aws:elasticloadbalancing:us-east-2:125257778789:targetgroup/foobar-prod-5672/b69ee4d1856d94b5",
      "containerName": "foobar-prod",
      "containerPort": 5672
    },
    {
      "targetGroupArn": "arn:aws:elasticloadbalancing:us-east-2:125257778789:targetgroup/foobar-prod-15672/8383ce1f2a3bc178",
      "containerName": "foobar-prod",
      "containerPort": 15672
    }
  ],
  ...
}
  • 만약 특정 컨테이너 포트에 대해 하나는 퍼블릭 로드 밸런서, 하나는 프라이빗 로드 밸런서로 연결하고 싶을 경우 역시 복수개 대상 그룹을 지원하므로 가능하다. 즉, ECS에서의 로드 밸런서 설정은 포트가 동일해도 대상 그룹만 다르면 자유롭게 복수개 등록이 가능하다.

트러블슈팅: 고정 IP 주소 지정

  • AWS Fargate로 실행된 서비스의 각 작업에 고정 IP 주소를 확보하는 것은 불가능하다. 작업은 동적으로 생성되고 소멸되기 때문이다. 다만, 개별 작업이 아닌 서비스에 대해서는 아웃바운드로 노출되는 퍼블릭 IP 주소는 고정이 가능하다. 서비스를 프라이빗 서브넷에 위치하여 실행시키면 NAT Gateway의 퍼블릭 IP 주소가 노출되어 요청을 받는 쪽은 고정 IP 주소처럼 보이게 된다. [관련 링크]
  • 인바운드로 노출되는 IP 주소는 여전히 고정이 불가능하다. 하지만 서비스 생성 시점에 로드 밸런서를 앞단에 두면 로드 밸런서의 도메인 주소(또는 CNAME으로 등록한 내 도메인 주소)가 IP 주소 대신 고정 식별자 역할을 해줄 수 있다.

빌드/배포 파이프라인 생성

  • 서비스 생성 및 실행까지 완료했다면, 이제 소스 코드의 변경점 발생시 자동으로 빌드를 수행하고 배포할 수 있는 파이프라인을 구성해야 한다. AWS CodePipeline, AWS CodeBuild를 이용하여 파이프라인 자동화가 가능하다. 본 블로그의 이 글을 참고한다.

로그 모니터링

  • 컨테이너 오케스트레이션 환경에서는 모니터링의 대상이 유동적이다. AWS Fargate를 사용할 경우 자동으로 Amazon CloudWatch Metrics 수집이 활성화되어(수집된 로그는 15개월동안 유지) Amazon CloudWatch에서 로그 확인이 가능하다. [관련 링크]
  • Grafana를 설치했다면, CloudWatch 데이터 소스를 추가하여 손쉽게 직관적인 리소스 모니터링과 대시보드 이용이 가능하다. (자세한 설치 및 사용 방법은 본 블로그의 이 글을 참고한다.)

로그 모니터링: 애플리케이션 로그

  • AWS Fargate는 인스턴스가 아닌 작업 단위로 실행되므로 상태를 가지지 않기 때문에 직접적인 파일 로그 수집은 불가능하고 콘솔로 로그를 출력하도록 애플리케이션에서 사전에 설정해야 한다.
  • 콘솔로 출력된 작업 단위 로그는 Amazon CloudWatch의 로그 스트림에서 아래와 같이 확인 가능하다.
Amazon CloudWatch 콘솔 접속
→ [로그 그룹] 클릭 → /ecs/{task_definition_name} (클릭)
→ [로그 스트림] 클릭 → /ecs/{task_definition_name}/{task_id} (클릭)
  • 작업 단위로 모든 로그를 텍스트 파일로 내려 받고 싶다면 아래와 같이 명령을 실행하면 된다. (이 방법이 가장 전통적인 파일 로그에 가깝기 때문에 장애시 트러블슈팅이 수월하다.)
$ aws logs get-log-events --region "{region}" --log-group-name "/ecs/{task_definition_name}" --log-stream-name "ecs/{task_definition_name}/{task_id}" --output text > foobar.log
  • 애플리케이션 로그는 별도의 설정이 없을 경우 만기 없이 누적 저장된다. 불필요한 비용 지출이 발생하므로 로그의 최대 보관 기간을 아래와 같이 원하는 기간으로 설정할 수 있다.
$ aws logs put-retention-policy --region "{region}" --log-group-name "/ecs/{task_definition_name}" --retention-in-days 14

참고 글

댓글
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함