본문으로 바로가기
반응형

목적

아마존 AWS에 Docker-compose.yml파일을 통해 배포하는 방법에 대해 기술한다. 추가적으로 ALB(Application Load Balancer)를 통해 로드밸런싱을 진행하고 서비스/인스턴스에 Auto Scailing을 걸어서 자동으로 스케일업/다운할 수 있도록 한다.


작업 순서

1. ECS 클러스터 생성

2. ALB(Application Load Balancer) 생성

3. 도커 이미지 ECR에 저장

4. 작업 정의(Task Definition) 생성

5. CloudWatch 경보 생성

6. 서비스(Service) 생성

7. 인스턴스 스케일링 적용 



1. ECS 클러스터 생성

먼저 ECS클러스터부터 생성해야한다. 클러스터를 생성할 때 지정한 인스턴스의 개수에 따라 EC2 인스턴스가 실행되며 해당 인스턴스에 우리가 정의한 작업정의를 서비스 단위로 실행하는 형태이다. 전체적인 그림을 설명하자면, 클러스터 내부에 여러개의 서비스가 존재하고 하나의 서비스에 여러개의 작업정의가 묶여있는 형태라고 생각하면 된다. 먼저 AWS ECS콘솔로 들어간다.



클러스터 생성을 누른다.



두번째에 있는 EC2 Linux + 네트워킹을 선택하고 다음 단계를 누른다. (첫번째는 Fargate, 즉 서버리스 전용이며 세번째는 윈도우용이다)



클러스터 이름에는 원하는 클러스터 이름을 적는다. 프로비저닝 모델은 온디맨드와 스팟이 있는데, 스팟이 보다 비용을 저렴하게 절약할 수 있다. (자세한 내용은 AWS 스팟에 대해 검색하면 자세히 나온다) 테스트 용도이므로 인스턴스 유형은 t2.micro로 지정한다. 인스턴스 개수를 통해 처음에 몇개의 인스턴스를 실행할 지 지정해줄 수 있다. 마지막으로 키 페어를 지정해야 나중에 오류가 발생했을 때 직접 도커 컨테이너가 떠있는 EC2 인스턴스로 접속하여 확인할 수 있으므로 키 페어는 무조건 지정하도록 한다.



다음으로 네트워킹 설정이다. VPC와 서브넷1, 2 보안그룹 모두 기존에 사용하던것을 사용하면 된다. (새로 생성해도 상관없음) 모두 선택했으면 오른쪽 아래에 있는 생성 버튼을 누른다.



위와 같이 나온다면 정상적으로 클러스터가 생성된 것이다.


2. ALB(Application Load Balancer) 생성

이제 로드밸런서를 생성해줘야 한다. 포스팅 후반부에 오토 스케일링을 걸어줄 예정인데, 그러한 과정에서 하나의 통합된 Endpoint로 접속하게 하려면 로드 밸런서를 사용해야 한다. EC2 콘솔로 들어가서 로드 밸런싱 - 로드밸런서로 들어가서 로드밸런서 생성을 누른다.



로드밸런서의 유형은 위에 나온것처럼 Application Load Balancer/Network Load Balancer/Class Load Balancer 3가지이다. 그 중 우리는 Application Load Balancer를 사용할 예정이다. 가장 왼쪽에 있는 것을 선택하고 생성을 누른다.



로드 밸런서의 이름을 원하는 것으로 설정한다.



프로토콜과 포트를 지정한다. 나는 HTTP를 사용할 것이고 포트또한 80으로 사용할 것 이기에 따로 설정하지 않았다.



가용영역에서 VPC와 서브넷을 설정해줘야하는데 이전에 클러스터를 생성했을 때 지정한 VPC와 서브넷을 동일하게 적어준다. 참고로 서브넷 두개가 나오면 왼쪽에 있는 체크박스에 체크를 해줘야 한다.



HTTP를 그대로 사용할 예정이므로 다른 설정없이 다음으로 넘어간다.



보안 그룹 설정 또한 클러스터 생성 시 지정했던 기존 보안그룹을 선택하고 다음으로 넘어간다.



새 대상 그룹을 선택하고 로드 밸런서와 같이 그룹을 하나 생성한다. 여기서 생성한 그룹을 추후에도 사용할 예정이니 기억해둔다.  대상 유형은 인스턴스로 지정하고 프로토콜과 포트는 건드리지 않는다.


상태 검사는 추후에 ALB에 서비스등을 연결했을 때 관련된 인스턴스가 실제로 살아있는지 체크하는 경로이다. 해당 경로의 Response는 200이 나와야 ALB쪽에서 정상적으로 살아있다고 판단하기 때문에 API서버라면 Health Check 전용 Endpoint를 따로 하나 만들어두는 것도 좋은 방법이 될 수 있겠다. (물론 고급 상태 검사에서 200이 아닌 다른 상태 코드로 지정할수도 있다. 하지만 본 포스팅에서는 그대로 진행하도록 한다)



다음으로 대상을 등록해야하는데 여기서는 그냥 스킵하고 넘어간다. (추후 서비스 생성 시 등록할 예정이다) 다음을 누르면 마지막으로 검토 단계인데 해당 단계에서 잘못 설정한 부분이 없다면 생성을 누른다.


위와 같이 나온다면 정상적으로 로드 밸런서를 생성한 것이다.


3. 도커 이미지 ECR에 저장

다음으로 도커 이미지를 저장시켜야 한다. 여러가지 방법이 있겠지만 여기서는 AWS ECR서비스에 이미지를 푸시하기로 한다. 먼저 아래의 명령어로 빌드한다.


docker-compose -f 빌드할yml파일이름 build


해당 명령어를 입력하고 docker images를 통해 확인해보면 빌드된 이미지가 존재할것이다. 아래의 명령어로 태그하고 푸시한다.


docker tag 빌드된_이미지_이름 ECR주소

docker push ECR주소


4. 작업정의(Task Definition) 생성

위에서 설명했듯이 하나의 클러스터에 여러개의 서비스가 돌아가고 하나의 서비스에 여러개의 작업정의가 돌아간다. 따라서 서비스를 통해 구동시킬 작업정의를 생성해야 한다. 작업정의는 ecs-cli를 통해 생성할 예정이고 설치는 https://docs.aws.amazon.com/ko_kr/AmazonECS/latest/developerguide/ECS_CLI_installation.html 를 통해 진행할 수 있다.

먼저 ecs-params.yml라는 파일을 하나 생성한다. 해당 파일의 내용은 아래와 같다.


version: 1
task_definition:
task_size:
cpu_limit: 900
mem_limit: 0.9GB
services:
web_service:
cpu_shares: 650
mem_limit: 0.6GB
nginx:
cpu_shares: 250
mem_limit: 0.3GB


현재 예제에서는 Django를 구동하는 컨테이너인 web_service와 Nginx를 구동하는 컨테이너인 nginx 두가지를 사용하고 있다. 먼저 task_size에 cpu_limit을 900으로, mem_limit을 0.9GB로 지정했다. 이는 클러스터를 생성할 때 t2.micro 타입을 지정했기 때문이며 해당 인스턴스의 CPU/메모리 크기에 맞게 지정해준 것이다. (참고로 인스턴스의 CPU/메모리에 해당하는 값을 100% 사용하면 오류가 발생한다. 10%정도 여유 메모리를 남겨두고 할당해줘야 한다) 그리고 services아래에 실제 구동할 컨테이너들의 이름과 CPU/메모리 관련 설정을 해준다. 


다음으로 docker-compose-ecs.yml 파일을 하나 만든다. (이 파일은 도커 이미지 ECR에 저장 때 사용한 파일과 다른 파일이다. 해당 파일은 실제 도커 문법으로 작성된 것이고 이 파일은 ECS에 올리기 위한 문법으로 작성된 것이다) 내용은 아래와 같다.


version: "3"
services:
web_service:
image: ECR주소
ports:
- "8000:8000"
logging:
driver: awslogs
options:
awslogs-group: web_service
awslogs-region: ap-northeast-2
awslogs-stream-prefix: web_service

nginx:
image: ECR주소
ports:
- "80:80"
links:
- web_service
logging:
driver: awslogs
options:
awslogs-group: nginx
awslogs-region: ap-northeast-2
awslogs-stream-prefix: nginx


services - 컨테이너명 아래에 있는 image쪽에 업로드 된 도커의 이미지 주소를 적어줘야 한다. 포트도 명시해주고 로그를 위해 logging 부분도 위와 같이 적어준다. 이제 아래의 명령어를 입력하면 작업 정의가 생성된다.


ecs-cli compose --project-name 작업정의이름 --file docker-compose-ecs.yml --ecs-params ecs-params.yml --region ap-northeast-2 create --launch-type EC2


5. CloudWatch 경보 생성

다음으로 오토 스케일링을 걸기 위해 CloudWatch에 경보를 생성해야한다. 우리는 CPU가 50% 이상일 때와 20% 미만일 때 2가지를 생성할 것이다. (50%이상일 때는 스케일 아웃, 20% 미만일 때는 스케일 인) CloudWatch 콘솔로 들어가서 경보 - 경보 생성을 누른다.



지표 선택을 누른다.



ECS에 대한 알람을 설정해야 하므로 ECS를 누른다.



클러스터의 이름을 통해 생성해줄 것이다. ClusterName을 선택한다.



우리가 이전에 생성한 클러스터의 이름이 왼쪽에 나오고 오른쪽에 MemoryResevation/CPUReservation/MemoryUtilization/CPUUtilization 총 4개의 선택지가 존재한다. 우리는 CPU 사용률을 기반으로 알람을 설정할 예정이므로 가장 아래에 있는 CPUUtilization을 선택한다.



먼저 CPU사용률이 50% 이상일 때의 알람을 설정한다. 이름은 원하는것으로 적고 아래쪽에 조건에 50% 이상일때로 지정한다. 본 포스팅에서는 20% 미만일때에 대해서는 따로 설명하지 않겠다. (위와 같이 동일하게 지정하되, 조건에 <= 20 으로 생성)



참고로 아래쪽에 있는 작업 부분에 특정한 작업을 선택하지 않으면 생성할 때 알림 목록을 선택하라는 오류가 발생한다. 따라서 오른쪽 상단에 있는 삭제를 눌러서 삭제시킨 후 생성해줘야 한다.


6. 서비스(Service) 생성

이제 서비스를 생성해줄 차례이다. 이전에 생성한 클러스터 내부로 들어가서 서비스 - 생성을 누른다.



시작 유형은 EC2로 선택한다. 작업 정의는 위에서 생성한 작업정의를 선택하고 클러스터 또한 이전에 생성한 클러스터를 선택한다. 서비스 이름을 적고 서비스 유형은 따로 건드리지 않는다. 작업 개수는 클러스터를 생성했을 당시 시작 개수와 동일하게 맞춰줘야 한다. 하나의 인스턴스에 하나의 작업정의가 실행되기에 인스턴스의 개수보다 작업 개수가 많다면, 정상적으로 동작하지 않는다.



이 부분은 본 포스팅에서 다루는 주제가 아니므로 그대로 Rolling update를 선택한다.



ELB유형에 Application Load Balancer를 선택한다.



서비스를 실행시킬 때 사용하는 IAM을 선택한다. 아마 기본적으로 ecsServiceRole으로 설정되어 있을 것이다. ELB이름에 이전에 생성한 ALB를 지정해주고 로드를 밸런싱할 컨테이너를 선택한다. 본 예제에서는 Django <-> Nginx <-> User 형태이므로 Nginx를 선택했다. 선택하고 ELB에 추가 버튼을 누른다.



추가버튼을 누르면 위와 같이 설정할 수 있는 부분이 나오는데 대상 그룹 이름에 위에서 로드밸런서와 같이 생성한 그룹을 선택하면 생성 당시의 설정이 그대로 박힌다.



따로 활성화를 시키지 않을 예정이므로 체크 해제하고 다음 단계로 넘어간다.



이제 오토 스케일링을 걸어줘야한다. 아래쪽에 있는 옵션인 개수를 조정합니다 를 선택한다.



최소 작업 개수와 원하는 작업 개수, 최대 작업 개수를 지정한다. 스케일 아웃은 최대 작업 개수 이상이 될 수 없기에 적당히 설정해준다. IAM역할은 기본적으로 ecsAutoscaleRole이 설정되어 있을 것이므로 딱히 건드리지 않는다.



대상 추적이 아닌 단계 조정을 선택한다.



규모 확대 부분에 기존 경보 사용을 선택하여 이전에 CloudWatch에서 생성한 CPU >= 50 정책을 걸어준다. 조정 작업 부분에 추가를 선택하고 1개를 추가한다고 명시한다.



규모 축소 부분에 기존 경보 사용을 선택하여 이전에 CloudWatch에서 생성한 CPU <= 20 정책을 걸어준다. 조정 작업 부분에 제거를 선택하고 1개를 제거한다고 명시한다. 그리고 다음 단계를 누르면 지금까지 설정한 화면이 나오는데 틀린 부분이 없다면 서비스 생성을 누른다.



위와 같이 나온다면 정상적으로 서비스 생성이 진행되는 모습이다. 마지막 상태가 PENDING에서 RUNNING으로 바뀌면 서비스가 실행된 것이다.



이벤트 탭으로 들어가보면 위와 같이 어떠한 작업들을 수행했는지 확인할 수 있다. service ~ has reached a steady state 라는 문구가 나오면 작업정의를 서비스에 붙인 상태로 실행이 됐으며 ALB까지 붙었다는 것이다.


7. 인스턴스 스케일링

마지막으로 인스턴스에도 Auto Scailing을 걸어줘야한다. EC2 콘솔로 들어가서 Auto Scailing - Auto Scailing 그룹으로 들어간다.



우리가 클러스터를 생성할 때 같이 생성된 스케일링 그룹이 존재할 것이다. 클릭하여 선택하고 위쪽에 있는 작업을 누른다음 편집을 선택한다.



서비스를 실행시킬때와 같이 입력해주면 된다. 서비스 생성 당시 최소 작업 개수를 1로 했으므로 목표용량과 최소를 1로, 최대 작업 개수를 2로 설정했으므로 최대를 2로 적어줬다.



종료 정책은 기본적으로 Default일텐데 OldestInstance로 수정해줬다. 하나의 인스턴스에서 작업이 오랫동안 돌다보면 로그가 많이 쌓이면서 메모리 문제가 발생할 수 있으므로 스케일링 시 오래된 인스턴스부터 종료하는 정책으로 바꿔준 것이다.



다음으로 클릭한 상태에서 아래쪽을 보면 조정 정책 탭이 있다. 해당 탭으로 이동하여 정책 추가 버튼을 누른다.



그러면 위처럼 조정 정책을 생성할 수 있는데, 단순 조정 정책이 아닌 단계를 사용하여 조정 정책 생성을 클릭한다.



위처럼 화면이 바뀌면 정책 실행 요건에 CloudWatch에서 생성한 알람을 걸어두고 작업 수행에 1개를 추가하는 형태로 지정한다. 그리고 생성을 누른다. CPU Low도 위와 동일한 형태로 걸어주면 된다.



스케일 인/아웃을 정상적으로 트리거해줬다면 위와 같은 화면을 볼 수 있다. 이제 최초에 생성한 ALB주소를 통해 접속해보면 정상적으로 접속이 되는 것을 확인할 수 있다.


참고 사항

1. ALB 생성까지 약간의 시간이 소요된다.

2. 클러스터 생성 후 인스턴스 구동까지 약간의 시간이 소요된다.

3. 서비스 생성 후 인스턴스에 적용까지 약간의 시간이 소요된다.

4. 서비스 생성 후 ALB에 붙기까지 약간의 시간이 소요된다.

5. 혹시나 권한 문제가 발생할 수 있다. IAM문제이므로 ECS서비스가 구동될 때 사용하는 역할(본문에서는 ecsServiceRole)에 필요한 권한을 할당해주면 된다.


반응형