Medium - Gentle Introduction to How AWS ECS Works with Example Tutorial

원문 - Tung Nguyen

Trend 파악을 Medium 기고문 요약 포스팅 - 예제로 알아보는 AWS ECS 동작방식

ECS는 AWS의 도커 컨테이너 서비스로 편집을 처리하고 도커 컨테이너를 제공해줍니다.

Summary of the ECS Terms

처음 우리가 알아야 할 것은 ECS의 용어에 대한 것입니다.

  • Task Definition - 이것은 도커 컨테이너가 어떻게 실행될 지 정의하는 청사진입니다. AWS에 익숙하다면 인스턴스의 LaunchConfig와 비슷하다고 생각하시면 됩니다. 해당 설정은 노출될 포트, 도커 이미지, cpu 공유, 메모리 요구사항, 실행 명령과 환경 변수들 입니다.
  • Task - 이것은 Task Definition에 정의된 설정으로 컨테이너를 실행하는 것입니다. Task Definition의 인스턴스라고 생각하셔도 됩니다.
  • Service - 동일한 Task Definition에 대해 장기적인 실행을 정의합니다. 한개 혹은 여러개의 컨테이너들이 동일한 Task Definition을 사용할 수 있습니다.
  • Cluster - EC2 인스턴스의 로직 그룹입니다. 인스턴스가 서버의 ecs-agent 소프트웨어를 실행하면 ECS 클러스터에 인스턴스가 등록됩니다. 이것은 /etc/ecs/ecs.config의 ECS_CLUSTER 변수를 설정해서 쉽게 변경할 수 있습니다.
  • Container Instance - 도커를 가지고 있고 ECS 클러스터의 일부분인 EC2 인스턴스이며 ecs-agent가 실행 중인 인스턴스입니다.

처음에 이런 용어들을 접했을 때 저자는 혼란스러웠던 기억이 있습니다. AWS는 해당 용어들을 쉽게 설명해주는 자세한 다이어그램을 제공합니다. 다음은 해당 다이어그램을 단순화 한 것입니다.

ECS Terms

위의 다이어그램에서 여러분은 4개의 작업과 컨테이너 도커들을 볼 수 있을겁니다. 저것이 ECS 서비스의 일부분입니다. 서비스와 Task들은 2개의 컨테이너 인스턴스로 확장되었습니다. 컨테이너 인스턴스는 ECS 클러스터라고 불리는 로지컬 그룹의 일부분 입니다. 위의 다이어그램에서 Task Definition은 보이지 않는데 이는 Task가 Task Definition의 인스턴스이기 때문입니다.

Tutorial Example

해당 예제에서 저는 삶의 의미를 나타내는 42를(은하수를 여행하는 히치하이커를 위한 안내서) 출력하는 작은 Sinatra 웹서비스를 만들 것입니다.

1. Create ECS Cluster with 1 Container Instance

클러스터를 만들기 전에 my-ecs-sg라고 하는 보안그룹을 만들어 봅시다.

aws ec2 create-security-group --group-name my-ecs-sg --description my-ecs-sg

이제 my-cluster라고 불리는 ECS 클러스터를 만들고 해당 클러스터에 속하는 ec2 인스턴스를 만들어봅시다. 생성된 my-ecs-sg 보안그룹을 사용합니다. EC2 Console / Network & Security / Security Groups에서 보안 그룹의 id를 가져올 수 있습니다. 키페어를 선택하는 것은 매우 중요한데 그래야 나중에 여러분이 인스턴스의 ssh 접속을 해서 동작하는 것을 확인할 수 있기 때문입니다.

Networking VPC 설정에서는 예제를 간단하게 유지하기 위해 기본설정으로 VPC와 연관된 모든 서브넷들을 설정했습니다. IAM Role에서는 ecsInstanceRole을 사용했습니다. ecsInstanceRole이 존재하지 않는다면 AWS docs을 참고해서 만드세요. 아래의 스크린샷에서 해당 설정을 확인할 수 있습니다

잠깐동안 기다렸다가 컨테이너 인스턴스가 my-cluster ECS 클러스터에 성공적으로 추가되었는지 확인하세요. ECS 인스턴스 탭에 Clusters / my-cluster를 클릭해서 확인할 수 있습니다.

2. Create a task definition that will be blueprint to start a Sinatra app

task definition을 만들기 전에 sintra docker image를 찾고 동작하는지 테스트해 봅시다. 저는 tongueroo/sintra 이미지를 사용했습니다.

$ docker run -d -p 4567:4567 --name hi tongueroo/sinatra
6df556e1df02e93b05aa46425fc539121f5e50afee630e1cd918b337c3b6c202
$ docker ps
CONTAINER ID        IMAGE                COMMAND             CREATED             STATUS              PORTS                    NAMES
6df556e1df02        tongueroo/sinatra   "ruby hi.rb"        2 seconds ago       Up 1 seconds        0.0.0.0:4567->4567/tcp   hi
$ curl localhost:4567 ; echo
42
$ docker stop hi ; docker rm hi
$

위에서는 sinatra 이미지를 사용해서 컨테이너를 시작했고 curl localhost:4657. Port 4567은 sinatra가 도커파일에 노출되는 지점입니다. 예상대로 42를 리턴합니다. 이제 sinatra 이미지가 동작하는 것을 확인했으니 task definition을 만들어봅시다. task-definition.json을 만들고 추가합시다.

{
  "family": "sinatra-hi",
  "containerDefinitions": [
    {
      "name": "web",
      "image": "tongueroo/sinatra:latest",
      "cpu": 128,
      "memoryReservation": 128,
      "portMappings": [
        {
          "containerPort": 4567,
          "protocol": "tcp"
        }
      ],
      "command": [
        "ruby", "hi.rb"
      ],
      "essential": true
    }
  ]
}

해당 작업은 깃허브의 task-definition을 통해서도 할 수 있습니다.

$ aws ecs register-task-definition --cli-input-json file://task-definition.json

task definition이 성공적으로 등록되었는지 ECS console에서 확인합시다

3. Create an ELB and Target Group to later associate with the ECS Service

이제 ELB를 만들고 타겟그룹을 만들어 봅시다. ELB를 만드는 이유는 다양한 컨테이너들의 요청을 로드밸런싱 하기 위해서이고 또한 테스트를 위해 sinatra앱이 인터넷에 노출되길 원하기 때문입니다. 가장 쉽게 ELB를 만드는 방뻐은 EC2 Console을 사용하는 것입니다.

EC2 Console / Load Balancing / Load Balancers 에 들어가서 Create Load Balancer를 클릭하고 Application Load Balancer를 선택하세요

마법사 첫단계 - 로드밸런스 설정

  • my-elb로 이름을 짓고 internet-facing을 선택합니다
  • HTTP 프로토콜과 포트번호 80으로 기본 리스너를 사용합니다.
  • Availability Zone에서는 VPC를 선택하고 여러분이 원하는 서브넷을 선택하세요. 저는 이전처럼 기본 VPC에 4개의 서브넷 모두를 선택했습니다. 이전 클러스터와 동일하게 서브넷들을 선택하는 것이 중요합니다. 만약 그렇지 않으면 ELB health check가 실패할 수 있고 컨테이너가 계속 파괴되고 재생성하는 무한루프에 빠지게 될 것입니다. 그러면 AZ의 ELB가 보이지 않게 됩니다.

마법사 두번째 단계 - 보안 세팅 설정

  • secure listener를 사용하면 경고문이 뜨지만 예제니까 SSL 사용하는 것을 넘어갑니다.

마법사 세번째 단계 - 보안 그룹 설정

  • my-elb-sg라는 이름의 보안그룹을 만들고 80번 포트와 0.0.0.0/0으로 열어두면 외부 네트워크가 80번 포트로 ELB에 접근할 수 있게 됩니다.

마법사 네번째 단계 - 라우팅 설정

  • 80번 포트로 my-target-group라는 타겟 그룹을 만듭니다.

마법사 다섯번째 단계 - 타겟 등록

  • ECS에서 이 부분은 약간 이상하긴 합니다. 우리는 여기서 실제로 어떤 타겟들도 추가하지 않을 것입니다, 왜냐하면 새로운 task들이 실행될 때마다 ECS가 자동적으로 타겟을 추가합니다, 그래서 간단히 여기서는 스킴합니다.

마법사 여섯번째 단계 - 리뷰

  • 자세한 정보를 살펴보고 생성을 누릅니다.

마법사를 이용해 ELB를 만들었고 my-elb-sg그룹을 80번 포트로 외부 네트워크에 열었습니다. 우리가 이전에 실행했던 my-scs-sg 보안그룹에 있는 인스턴스가 ELB로부터 오는 트래픽을 허용하는지 확인해야 합니다. 모든 ELB 트래픽이 컨테이너 인스턴스에 hit하도록 허용하기 위해서는 다음과 같이 입력하면 됩니다.

$ aws ec2 authorize-security-group-ingress --group-name my-ecs-sg --protocol tcp --port 1-65535 --source-group my-elb-sg

EC2 Console을 통해 보안그룹에 추가된 rules들을 확인합시다.

위의 보안 그룹 규칙으로 오직 80번 포트만 ELB에서 외부 네트워크에 노출되고 ELB로 오는 모든 트래픽들은 컨테이너 인스턴스로 갑니다.

4. Create a Service that runs the Task Definition

ECS 서비스를 만들기 위한 명령어는 json파일을 입력으로 사용할 수 있습니다. ecs-service.json파일을 만들어서 다음과 같이 입력합시다.

{
    "cluster": "my-cluster",
    "serviceName": "my-service",
    "taskDefinition": "sinatra-hi",
    "loadBalancers": [
        {
            "targetGroupArn": "FILL-IN-YOUR-TARGET-GROUP",
            "containerName": "web",
            "containerPort": 4567
        }
    ],
    "desiredCount": 1,
    "role": "ecsServiceRole"
}

targetGroupArn은 step3에서 ELB를 만들 때 생성된 것을 찾아서 입력하시면 됩니다. EC2 Console / Load Balancing / Target Groups에 들어가서 my-target-group를 확인하세요. 이제 my-service를 만들어 봅시다.

aws ecs create-service --cli-input-json file://ecs-service.json

ECS Console에서 컨테이너가 동작하고 있는 것을 확인할 수 있습니다. Clusters / mt-cluster / my-service에 들어가서 Tasks Tab을 봅시다.

5. Confirm Everything is Working

서비스가 제대로 동작하고 있는지 확인합시다. 모든 것이 제대로 동작하고 있는지 확인하려면 몇가지만 검사하면 됩니다. my-target-group이 보여지고 healthy target을 유지하고 있는지 확인합시다. Load Balancing / Target Groups에 my-target-group을 클릭해서 Targets tab을 봅시다. 건강하게 보고되고 있는 타겟이 보여야 합니다.

타겟이 헬씨하지 않다면 다음과 같은 것이 문제일 수 있습니다.

  • my-ecs-sg 보안 그룹이 my-elb-sg의 모든 트래픽을 허용하는 지 확인하세요
  • ELB의 보안그룹이 ECS Cluster와 컨테이너 인스턴스의 보안그룹과 동일한지 확인합니다.

인스턴스의 ssh로 접속해서 동작하고 있는 도커프로세스가 제대로 응답하는지 확인합시다. Clusters / ECS Instance 아래에 컨테이너 인스턴스를 클릭하면 여러분이 접속할 수 있는 퍼블릭 dns record를 얻을 수 있습니다.

$ ssh ec2-user@ec2-52-3-252-86.compute-1.amazonaws.com
$ docker ps
CONTAINER ID        IMAGE                            COMMAND             CREATED             STATUS              PORTS                               NAMES
9e9a55399589        tongueroo/sinatra:latest        "ruby hi.rb"        16 minutes ago      Up 16 minutes       8080/tcp, 0.0.0.0:32773->4567/tcp   ecs-sinatra-hi-1-web-d8efaad38dd7c3c63a00
4fea55231363        amazon/amazon-ecs-agent:latest   "/agent"            41 minutes ago      Up 41 minutes                                           ecs-agent
$ curl 0.0.0.0:32773 ; echo
42
$

위에서 저는 인스턴스에 도커 컨테이너가 동작하고 있고 42라는 텍스트를 정확히 보내는 것을 확인했습니다. 마지막으로 ELB의 외부 DNS 주소를 타이핑해서 확인해 봅시다. DNS 주소는 EC2 Console에서 Load Balancing / Load Balancers에서 my-elb를 클릭하면 됩니다.

6. Scale Up the Service to 4 Tasks

이번이 가장 쉬운 부분입니다. 컨테이너를 더욱 늘리고 싶다면 Clusters / my-cluster / my-service에서 Update Service를 클릭하세요. Number of tasks를 1에서 4까지 바꿀 수 있습니다. 그리고 조금 뒤에 4개의 태스크가 동작하고 있는 것을 확인할 수 있을겁니다.

7. Clean it All Up

다음의 자원들을 삭제하는 가장 빠른 방법은 EC2 Console을 사용하는 것입니다.

  • ELB: my-elb
  • ECS Service: my-service
  • Task Definition: sinatra-hi
  • Cluster: my-cluster
  • Security group: my-elb-sg, my-ecs-sg

Summary

  • ECS, 엘라스틱 컨테이너 서비스 생성.
  • 작업 정의를 하고 작업을 만듬, ec2 instance 만드는 것과 유사함
  • ECS의 보안그룹과 EC2 내에 로드밸런싱 보안그룹을 동일하게 설정해야함
  • ELB가 외부 네트워크와 노출되는 엔드포인트이고 해당 로드밸런스로 들어오는 모든 트래픽이 ECS로 가도록 설정해야 함

© 2019. All rights reserved.

Powered by Hydejack v8.1.1