[AWS] ECR + ECS + Docker

Falcon·2022년 5월 19일
5

aws

목록 보기
20/35
post-thumbnail

🎯Goals

  • ECS 를 쓰는 이유를 안다.
  • Aamzon ECR Private repository 에 이미지를 업/다운로드 할 수 있다.
  • Amazon ECS 를 통해 지정된 EC2에 컨테이너를 실행시킬 수 있다.

When to use ECS?

  • EC2 등 서버 인스턴스 환경에 독립적인 컨테이너 환경 구축
  • 컨테이너 환경 구축 및 개발 후 프로덕션 환경에 배포 및 관리할 때.

Develop vs Production

DevelopProduction
BuildBind mountCOPY
Deploydocker compose (localhost)- Separate service

- Cloud Managed service(ECS)

Q. 굳이 ECS 같은 서비스를 쓰는 이유가 무엇인가?

A. 개발자가 직접 컨테이너를 VCS에 올리고 관리하고 pull 해오는 절차가 까다롭고 불편하기 때문이다.

코드 한줄 바뀔 때마다 이미지 build, push, pull 을 한다고 상상해보라. 끔찍하다.

AWS 의 ECR + ECS 는 컨테이너 애플리케이션 관리 및 운영에 도움을 주는 서비스다.

ECR

1. Repository 생성

2. Repository URI 보관


Docker image

도커에서는 이미지 생성시 기본적으로 [네임스페이스]/[이미지 이름]:[태그명] 을 갖는데, 네임스페이스는 자주 생략된다.
생략된 네임스페이스의 Default 는 DockerHub 가된다.

여기서는 ECR 레포지토리를 사용해야 하므로 네임스페이스가 위에서 복사한 ECR URI 가 된다.

1. Tagging image

$ docker tag [image-name]:[tag-name] [ECR-Repsotiroy-URI]/[image-name]:[tag-name]

2. ECR login

$ aws ecr get-login-password --region [region] \
| docker login --username AWS --password-stdin [aws_account_id].dkr.ecr.[region].amazonaws.com

# login succeed!

3. Push image to ECR Repository

# ECR-URI 는 태깅에서 지정한 [image-name]:[tag-name] 과 같다.
$ docker push [ECR-URI]/[image-name]:[tag-name]
# 예시
$ docker push [account-id].dkr.ecr.ap-northeast-2.amazonaws.com/hostname-test:v1.0.0  

4. Check the uploaded image


ECS 기본 구성요소

큰 그룹 순서로 나열하면

  • Cluster
  • Service
  • Task (Definition)
    등이 있다.

이중 가장 친숙한 개념이 Task Definition (태스크 정의) 탭이다.
Docker 유저라면 docker-compose 를 한 번 이상 써봤을 텐데, Task Definition 이 docker-compose 역할을 하고 있다고 보면 된다.

Cluster, Service 는 AWS 에서 오케스트레이션과 로드밸런싱, 보안 정책 등 관리를 위해 추가로 넣은 개념이다. (그냥 몇번 따라하고 대시보드 구성 살펴보면 이해된다.)

ECS 는 docker 와 달리 bridge network 를 기본 사용하지 않는다.
host network 를 사용한다.
즉, 하나의 Task Definition 에서 정의된 컨테이너들은 동일한 EC2 내에 호스트 네트워크를 그대로 사용한다.
따라서 localhost 로 컨테이너간 통신이 가능하다.

ECS using Fargate

Fargate is serverless service.
거진 Lambda 와 유사하다. Labmda 가 FaaS (Function as a Service) 라면 Fargate 는 Container serivce 라는 것 정도가 차이다.

1. Create ECS Cluster

Cluster: Logical group of services or tasks. Base infrastructure
ex) EC2 groups or Fargate

2. Task Definition 정의

Task 하나에 여러 컨테이너 매핑 가능.
보통 docker-compose 에서 생명주기를 함께하는 services 가 하나의 그룹이 되고 service 하나가 개별 컨테이너 1개가 된다.
이 예제에서는 docker-compose 기준 다음 3개의 컨테이너를 하나의 task 로 묶는다.

  1. practice-mongodb(mongodb)
  2. practice-backend(nodejs)
  3. practice-frontend (react)

컨테이너 정의(container definition)는 Docker 데몬에 전달되는 컨테이너에 대한 세부 정보 및 리소스 요구 사항을 제공합니다. 태스크 정의에는 하나 이상의 컨테이너 정의가 포함될 수 있습니다.
여러 컨테이너가 필요한 애플리케이션의 경우 다음 조건에서 컨테이너를 동일한 태스크 정의에 그룹화해야 합니다. - AWS Docs

하나의 Task 내의 모든 컨테이너는 같은 instance 에서 실행됨이 보장된다

3. Service 정의

스케쥴러 / 오케스트레이션 역할.
일정 개수 이상의 task 가 실행되도록 보장한다.

로드밸런서 설정은 서비스 생성에만 가능하니 주의

4. 배포 전략 설정

롤링 업데이트를 기본 지원한다.

Fargate 는 기본적으로 Task definition 을 변경할 때마다 modify 하는게 아니라 새로운 버전을 개정 (revision) 한다.
이런 방식을 택한 이유는 새 버전으로 배포를 시도할 때마다 자동 Rollback 처리하기 위함이다.

AWS 의 센스가 돋보이는 대목이다.

5. (Optional) Load balancer, Security group 설정

6. 볼륨 매핑

Cluster 에서 Fargate 또는 EC2 구성을 했을 텐데, Fargate 의 경우에는 bind mount 사용시 유의해야한다. Fargate 는 일시적으로 EC2 에 탑재되었다가 해제되기 때문에 volume 을 영속적으로 쓸 수가 없다.
이런 경우에는 EFS 를 써야한다.

ecs-excution-role 에 s3 랑 efs IAM Policy 붙여주는게 필요할 수 있음.

7. 실행

실행 에러 exec format error


만약 실행시 위와 같은 에러가 발생했다면 아마 나처럼 M1, M2 macOS 를 사용중일 것이다.
AWS 도 차츰 arm 아키텍처를 적극지원하지만, 아직은 대다수의 환경이 amd64(intel) 로 되어 있는 것은 어쩔 수없다.

원인

docker image build 는 M1 (arm64) 에서 했기 때문에 arm64 이미지를 생성한 상태고, ECS Fargate 아키텍쳐는 x86_64 (amd64) 기 때문이다.
즉 이미지를 만든 provider와 task executor 실행 환경이 다르기 때문에 발생한 문제다.

해결 방법

실행 환경과 동일한 x86_64(amd64) 기준으로 build 하면된다.
docker 는 Multiplatform build 에 사용하는 도구인 buildx 를 제공한다.

사용방법은 간단하다. 다음을 우선 따라하라.

처음 기본 상태는 다음과 같다.

근데 굳이 buildx 없이도 docker build --platform 옵션 쓰면 되지 않을까요? 🤔
안된다.

아래 메시지를 확인해보시라.

$ docker build . -t "practice-backend:v1.3" --platform=linux/arm64,linux/amd64

[+] Building 0.0s (0/0)                                                                                                                             
ERROR: multiple platforms feature is currently not supported for docker driver. 
Please switch to a different driver (eg. "docker buildx create --use")

2023-05-03 기준 아직 multiplatform 이미지 빌드를 원하면 그냥 buildx 를 쓰는게 맞다.


ECS on EC2

완전 관리를 위해서는 Fargate 를 쓰는게 편하겠지만
Fargate 는 인프라에 직접 SSH 로 접근해서 서버 인스턴스 구성을 바꾸거나, 로그를 보는 행위가 불가능하다.

개발자가 직접 운영 가능하는 EC2 에서 ECS 서비스를 운영하는 방식이다.
EC2 내에서 ECS 를 운영하면 ECS 자체에 대한 운영 요금이 과금되지 않는다.

1. Create ECS cluster

AWS - Elastic Container Service - Cluster create

2. Create IAM Role & Connect EC2 to Cluster

AmazonEC2ContainerServiceforEC2Role IAM 을 EC2 에 부여해야한다.

⚠️ IAM 권한이 없는 EC2 인스턴스는 컨테이너 인스턴스로 등록되지 않는다.

3. Task 정의

Task deploy according to application type

  • 서비스
    컨테이너를 한 클러스터 패밀리 내에 지정한 인스턴스 갯수에서 동시 실행되도록함.
    ex) 태스크 수 4 지정 -> 한 클러스터 내에 task-definition에서 정의한 패밀리 (컨테이너)를 총 4개의 인스턴스에 각각 1개씩 실행함.
    특정 서비스가 동작하지 않으면 다른 인스턴스를 실행시켜서라도 갯수를 자동으로 맞춰줌. (Auto-Scaling 과 유사)
    👉🏻 일반적으로 앱 실행시 이 방식으로 배포.

  • 태스크
    여러 function의 배치작업시 유리

4. Task definition 정의

기본적으로 다음과 같은 항목으로 구성됨.

  • Docker image
  • Command
  • CPU, Memory limit
    => 여러 image 를 담고 정의할 수 있음.

task-definition-example.json

{
//  Task definition 이름
  "family": "ecs_nginx_example",
// docker 에서 사용할 네트워크 모드 (Default: bridge)
  "networkMode": "bridge",
//  컨테이너 정의 (여러개 가능)
  "containerDefinitions": [
    {
//      컨테이너 이름
      "name": "nginx-print-hostname",
      "essential": true,
//      image URI in ECR Repository
      "image": "[aws-account-id].dkr.ecr.[region].amazonaws.com/[image-name]:[tag-name]",
      // CPU limit (0: no limit)
      "cpu": 0,
      // memory limit: 512 MB
      "memory": 512,
      // -p 80:80/tcp (호스트:컨테이너/프로토콜)
      "portMappings": [
        {
          "hostPort": 80,
          "containerPort": 80,
          "protocol": "tcp"
        }
      ]
    }
  ]
}

task-definition 업로드 to ECS

자세한 CLI 명령어 참고는 이 링크를 참조하자.

$ aws ecs register-task-definition \
    --cli-input-json file://[file-path]/[file-name].json

5. 서비스 정의 (아직 뭔지 잘 와닿지 않네)

서비스는 태스크 데피니션과 매핑됨.
task 실행 방식에 따라 2가지 타입이 있다.

Replica typeDaemon type
실행하려는 task 갯수 지정 필수모든 컨테이너 인스턴스에 해당하는 task 하나씩 실행

service-example.json

{
  "serviceName": "print-hostname",
  "taskDefinition": "ecs_nginx_example:7",
  // 태스크를 실행할 인스턴스 수
  "desiredCount": 1
}

서비스 생성

$ aws ecs create-service \
--cluster=[cluster-name] --cli-input-json file://[service-directory-path]/[filename].json

6. Auto-Scaling Group에 ELB 추가

Elastic Load Balance 가 처음이라면 이 문서를 보자. 혈압이 오를 것이다.
그냥 뇌비우고 유튜브 하나 보면서 따라하길 추천한다.
요새 개발자들은 3줄 요약도 읽기 귀찮아하는 머글들이 많아서..

SSH connection Error

SSH 연결시 아래와 같은 에러가 발생했다면?

❗ Authentication failed (publickey)

아래 2개중 하나가 원인일 것이다.

1. 키파일 지정 오류

실수로 SSH 연결시 실수로 다른 개인키 파일을 선택한 경우다.
EC2 - 세부 정보 - 키 페어 이름을 확인하고 올바른 키 파일을 선택하면 바로 연결 성공.

2. username

기본 사용자명을 잘못 입력한 경우다.
AMI 타입에 따라 기본 사용자명이 아래와 같이 달라진다.
자세한 사항은 공식 문서에서 확인하자.

AMI TypeDefault username
Ubuntu AMIubuntu
ECS optimized AMI ✅ec2-user

이 포스트에서는 ECS의 서비스를 실행할 EC2 인스턴스를 생성했으므로 ec2-user 로 연결해야한다.

Questions

  1. Task 가 무엇인가? 한줄 요약?
    컨테이너 실행 컴퓨팅 작업 단위
  2. Service 가 어떻게 ECS Cluster 내에서 Deploy 되는가?
  3. Cluster Monitoring 방법은?
  4. gitlab-ci + ECR + ECS Integration 방법?
    gitlab-ci job 내에서 aws ecr get login | docker login => ECR push / pull => trigger service?
  5. 컨테이너 인스턴스 갯수 Up Down 은 무엇으로 하는 것인지?
    Auto Scaling Group 에서 필수 인스턴스 숫자로 하면됨

🔗 Reference

profile
I'm still hungry

0개의 댓글