개요
Ref.)https://blog.doctor-cha.com/ecs-in-depth
AWS ECS를 이용하여 애플리케이션을 배포하는 방법을 기록해둔다. 이전에 PROD 및 DEV 환경별로 구분하고, CI/CD를 통해 자동으로 배포되도록 하기 위해서 여러 과정들을 거쳤다.
- ECR로 Docker Image 옮기기
- AWS Credential(AcceesKey, SecretKey), github Actions - ECR CI 설정하기
- S3 이미지 업로드 구현, Profile 설정 및 불러오기, Swagger 이미지 업로드(multipart)
- 코틀린 logback 환경 분리, validated 검증, exception 처리, CD 적용
이 글에서 다룰 요소들
- 네트워크: VPC, 서브넷(서브네팅), 로드밸런서, 대상 그룹, 오토스케일링, NAT, igw,
- 애플리케이션: 애플리케이션으로 만든 docker image, ECR
- ECS: 클러스터 - 서비스 - 태스크 - EC2 구조, 네임스페이스 등
- 기타 AWS 서비스와 개념: RDS, 보안그룹, NAT, ASG(Auto Scailing Group)
1. 네트워크: IP, igw, 서브넷
배경
aws의 각 서비스들에 대한 사용법이나 개념들은 여러 참고할 문서들이 많은데, 네트워크 개념에 대해서 초보인 내가 학습할 좋은 레퍼런스가 부족했다. ECS로 인프라를 구성하기 위해서 반드시 이해하고 있어야할 부분이 이 부분인 것 같다.
IP나 서브넷, CIDR, igw, NAT 등에 대한 개념이 부족하거나 정확하지 않다면 아래 블로그의 시리즈 글들을 참조하여 4~5개 정도 읽어보면 상당히 도움이 된다! 여기서는 아주아주 간단하게 요약하고 ECS를 다룰 때 필요한 개념과 팁만 적어놓는다.
필요 요소
vpc 구성
AWS 콘솔에서 vpc를 검색 후 VPC를 생성하면 된다. 생성 자체는 아무 어려울게 없으니 아무렇게나 생성하면 된다.
그리고 CIDR을 설정하고 서브넷을 구성해준다. CIDR, 서브넷, 서브네팅 및 NAT 개념은 상기 참조 블로그에서 20분 정도만 공부해보면 알 수 있다. VPC를 이렇게 구성하면, 내가 사용할 서비스들이 운영되는 가상 네트워크 환경을 만드는 것이다.
정확한 개념은 아니고 실습을 하다보니 대략적인 감으로 기록해두는 내용인데, AWS의 네트워크는 내가 구성할 서비스마다 private한 가상 네트워크 환경을 구성해놓고 특정 요소(IP, NAT 등)를 통해서만 접근이 가능하도록 울타리를 쳐두는 것 같다. PROD용으로 로드밸런서(출입구), EC2(서버), RDS(DB) 등을 구성하고 이 요소들을 하나의 VPC로 묶은 다음 특정 IP를 통해서만 접근하도록 하고, 또 DEV용으로 같은 구성을 만들고 VPC로 울타리를 쳐서 각각 private 네트워크를 구성하는 것이다. 이렇게 하면 체계적인 네트워크 관리가 가능할 것 같다.
그리고 가용영역별로 VPC 하위에 서브넷을 구성한다. 서브넷은 IP 주소를 할당하는 규칙같은 것이다(이 내용도 상기 블로그 내용 참조). 예를 들어 10.10.0.6/20 이라고 서브넷을 설정하면 32비트 중에 20비트까지만 네트워크 주소이고, 나머지 12비트를 호스트 주소로 사용하므로 2^12 = 4096개의 IP 주소를 해당 서브넷에 할당한다는 것이 된다.
참고) 서브넷 계산기
아래 서브넷 계산기에 해당 주소를 넣어보면 그 결과를 알 수 있다. 이 결과를 바탕으로 서브넷들을 구성할 수 있다. 서브넷 1번은 위 주소대로 10.10.0.6/20 이라고 구성했다면, 그 다음 서브넷의 끝이 10.10.15.255라고 나오니까 그 다음 서브넷은 10.10.16.0/20으로 구성하면 된다.
서브넷 생성화면에 들어가서 아래처럼 입력해보면 당연히 안된다. 172.31.0.0/16의 CIDR 블록의 다음 블록은 계산기에 넣어봤을 때 172.32.0.0/16 이다. 이 주소부터 서브넷을 설정해주면 된다.
라우팅 테이블과 igw 개념
이제 서브넷을 라우팅 테이블로 연결하면 된다! 0.0.0.0/0은 모든 ip 주소를 의미한다. 그리고 대상이 igw-... 으로 된 것을 볼 수 있는데, igw는 인터넷 게이트웨이를 의미한다. 즉 인터넷상에 VPC를 노출하게 된다!
일반적인 방법으로는 igw 라우팅을 안하는 것이 정석이다. VPC를 구성하고 NAT(Network Address Translation)을 통해서만 우리 VPC에 접근하도록 해야한다. 다만 AWS의 NAT은 비용이 청구되므로 나중에 서비스가 이 비용을 감당할 수 있을 정도 이상이 된다면 그 때 처리하면 된다. 일단은 igw 대상은 굳이 안해도 되고(나중에 ECS 클러스터를 구성할 때 알아서 등록되도록 할 예정), local 대상만 등록하면 된다. 이것의 의미는 내가 구성할 VPC의 내부, 즉 local에서만 라우팅이 되도록 한다는 의미가 된다.
이제 VPC 구성을 어느정도 마쳤다.. 이제 VPC의 입구 역할을 하는 로드밸런서와 ASG 그룹, 대상 그룹에 대해 알아본다.
2. 로드밸런서, 대상 그룹
대상 그룹
이제 로드밸런서를 만들고 ECS가 생성하는 인스턴스들을 로드밸런서를 통하도록 만들 것이다. 그 전에, 아래 그림처럼 로드밸런서가 바라볼 대상그룹(Target Group)을 설정한다.
ref.) https://m.blog.naver.com/chloemoretz2000/222668714501
대상 그룹 생성 시 기본적으로 생성되는 설정을 따르고, 이름만 지정해주면 된다.
EC2의 사양이 너무 낮거나 로드가 많이 걸려서 느려질 것을 예상한다면 헬스 체크(상태 검사)의 정상 임계값의 수치를 늘리고, 제한 시간도 늘려주는 것이 유리하다.
로드밸런서
이후 로드밸런서를 생성한다. 앞선 글들에서 만들어본 경험이 있으니 간략하게만 적는다. Application LoadBalancer로 선택한다. 생성화면에서 체계 부분에 인터넷 경계라는 옵션이 있는데, 이것을 선택해준다. 위에서 서브넷을 만들면서 다루었던 부분이다. AWS 내부에서 우리가 생성하는 VPC private 네트워크와 외부 인터넷 망 사이에서 로드밸런싱을 해주는 구성을 만드는 것이다. 퍼블릭 서브넷이 필요하다는 말이 바로 위에서 다뤘던 igw 설정 부분이다.
아래에서도 VPC 선택 설명 부분에 '인터넷 게이트웨이'가 있는 VPC만 선택할 수 있다고 되어있다. 만약 위 부분에서 igw와 연결된 퍼블릭 서브넷을 만들었다면 여기서 해당 VPC를 선택할 수 있다. 나의 경우 igw가 CIDR로 등록되지 않은 내부용 VPC를 선택하고, igw처럼 퍼블릭으로 연결하는 설정은 ECS에서 처리해주었다. 어떤 방법이 맞는지는 모르겠으나, 개념은 알고 있으면 될 것 같다.
리스너는 인터넷에서 HTTPS 요청을 받을 수 있도록 443 포트를 열어주고 대상 그룹을 선택해준다.
3. 클러스터, 서비스, 태스크 구성
클러스터 구성
다음으로 ECS에 접속하여 클러스터를 생성한다. ECR에 이미지는 이미 푸시됐음을 가정한다. 이미지가 없다면 이 글 최상위에 적어둔 참조글을 보면 된다.
클러스터 이름을 적으면 기본 네임스페이스에 동일한 이름이 적힌다. 이 네임스페이스를 기반으로 ECS와 연관된 AWS의 서비스에서 ECS를 지칭한다. 왼쪽에 보면 네임스페이스 항목이 있는데, 나중에 클러스터를 생성하고 들어가보면 해당 클러스터의 이름으로된 네임스페이스가 생성된 것을 확인할 수 있다.
인프라는 Amazon EC2 인스턴스 형태로 실습한다. ECS가 설정된 Auto Scailing Group(ASG)에 따라서 자동으로 EC2 인스턴스의 개수, 리커버리 설정 등을 조정해준다. ASG 그룹은 그냥 새 ASG 그룹 생성으로 두고 일단 생성한다. 자세한 클러스터링 옵션들이 있는데, 이 옵션들은 나중에 상황에 맞게 조정하면 되고, 개념에 대해서도 ASG 옵션을 수정하다보면 자연스레 이해가 된다.
그리고 클러스터 생성 이후에 클러스터 이름 -> 인프라에 들어가서 ASG 설정이 제대로 되어 있는지 체크해야한다. ASG를 통해서 EC2의 정상 상태를 유지하게 된다. 만약 설정되어있지 않다면, 새 ASG 그룹 생성으로 생성된 ASG 그룹을 선택하여 설정해주면 된다.
스팟은 AWS에서 미사용하는 EC2를 당겨와서 사용하고, 나중에 끊어질지도 모르기 때문에 PROD 환경은 온디맨드를 추천한다. 그리고 프로비저닝에 대해서는 나중에 천천히 공부해도 된다(온디맨드로 해도 EC2가 1개만 운영되고 실습용으로 요청이 거의 없다면 비용은 몇십원 수준으로 나온다).
나의 경우 운영체제는 Amazon Linux 2023으로 설정하였고, EC2 인스턴스도 실습을 위해 t2 micro로 검색하여 선택해주었다. 그리고 원하는 용량은 최소0, 최대 1로 지정하여 EC2의 개수가 1개를 넘어가지 않도록 설정했다. (블루/그린 배포가 아니라 롤링 배포라서 가능하다.)
네트워크 설정에서는 앞서 만들어주었던 VPC를 선택해주고, 보안그룹은 로드밸런서로부터 들어오는 인바운드 규칙을 포함시키면 된다. 앞선 글에서 살펴봤듯이 로드밸런서의 보안그룹은 모든 인터넷 트래픽에서 로드밸런서로 들어올 수 있도록 하고, ECS로는 로드밸런서를 통해서만 인바운드, 아웃바운드가 되도록 보안 그룹을 설정하면 된다.
위에서 설명한 것처럼 본래는 ECS에서 퍼블릭 IP 설정이 불가능하게 하고, NAT를 통해서 접근가능하도록 해야한다. 다만 여기서는 ECS 자체에서 인터넷과 통신할 수 있도록 퍼블릭 IP 자동 지정 옵션을 켜주었다. 이렇게 설정하지 않고 NAT도 없다면 배포가 안되고 대기 중, 프로비저닝 중 상태로 유지되다가 서비스가 뻗는 상황이 반복되므로 유의해야한다.
태스크 정의
층위로 보면 클러스터 - 서비스 - 태스크 순서인데, 서비스를 구성하기 위해서 태스크 정의를 먼저 해둘 필요가 있다. 태스크 생성 버튼을 누르면 아래처럼 인프라 요구 사항부터 설정하게 된다.
클러스터를 생성할 때와 마찬가지로 EC2 인스턴스를 띄우는 태스크를 선택한다. 운영 체제/아키텍처를 선택 후 네트워크 모드는 bridge로 해주었다. awsvpc의 경우 Fargate용이고, bridge는 EC2 인스턴스용인 것 같던데, 정확하게는 모르겠다. 사이드 프로젝트 팀원분이 설정한 조건이라, 그대로 따라하였고 필요하다면 나중에 따로 알아봐야겠다. 그리고 클러스터 전체에서 태스크는 일부 자원만 쓸 것이므로 CPU와 메모리를 0.49, 0.46 GB로 낮춰주었다. 태스크 역할은 따로 설정하지 않고 태스크 실행 역할은 ecsTaskExecutionRole로 지정했다. IAM에서 설정할 수 있고, IAM에 들어가보면 AWS에서 기본적으로 세팅해놓은 Role임을 알 수 있다.
다음으로 태스크에서 실행할 컨테이너에 대한 설정을 해주었다. 이미지 URI는 ECR에 접속해서 복사해와야한다. 그리고 컨테이너 포트는 스프링-코틀린 앱이라 기본으로 설정되는 8080 포트로 설정해주었다. CPU와 메모리도 위 클러스터 생성 시에 정의한 대로 0.48, 0.46으로 제한해주었고, 애플리케이션을 실행하는 필요한 환경 변수 값들을 추가해주었다. application.yml 파일에서 설정한 ${...} 환경 변수 값들이다.
서비스 구성
이제 거의 다 끝났다. 생성했던 클러스터에 들어가서 서비스 생성 버튼을 누른다. 위에서 설정한 태스크가 어떤 컨테이너로된 EC2를 실행할 지에 대해 설정한 것이고, 서비스는 그 태스크를 몇개나, 얼마나, 언제 생성할 지 등을 정해주는 것이다.
용량 공급자 전략은 클러스터에서 지정한 기본값을 그냥 사용하면 된다. 만약 2개의 서비스가 있는데 가중치가 각각 1, 2라면 각 서비스가 1:2 의 비율로 컨테이너를 공급한다고 한다. 이런 오케스트레이션 개념은 쿠버네티스를 공부하면서 나중에 더 알게되지 않을까 싶다.
애플리케이션 유형은 서비스, 패밀리는 앞서 생성한 태스크를 선택하면 된다. 패밀리는 '태스트:개정' 으로 구성된 여러 개의 revision(개정)을 모두 일컫는 말이라고 한다.
서비스 유형은 복제본(REPLICA)로 하고, 아래 여러 설정 중 로드밸런서 설정만 하면 된다(나머지 설정은 잘 모름).
미리 로드밸런서, ASG 등을 만들어두었으므로 그냥 아래 사진처럼 기존에 생성했던 항목들을 선택해주면 된다.
서비스를 생성하고, 클릭해서 상세 화면을 보면 상세 및 지표에 아래와 같은 화면이 뜬다. 로드밸런서 설정이 잘 되었다면 로드 밸런서 상태에 대한 상세 내용이 나온다. 서비스 업데이트를 통해 새롭게 배포를 진행할 수 있으나, 일단 서비스 생성 시 위 설정에 따라 자동으로 배포가 되고 있을 것이다.
배포에 들어가서 배포 중인 상태를 확인한다. 리소스도 적게 주었고 EC2도 최소 사양이기 때문에 천천히 마음의 여유를 갖고 5분 정도는 기다려봐야한다.
에러 케이스 및 배포
만약 제대로 배포가 되지 않는다면, 콘솔에서 EC2에 들어가서 ECS에 의해 실행된 EC2 인스턴스에 연결하여 인스턴스 내부에서 docker ps, docker logs {컨테이너 이름}을 입력하여 상태를 확인해보면 된다. EC2 접속 전, 해당 EC2의 보안그룹에 SSH 유형으로 접속할 수 있는 인바운드 규칙을 추가해야함을 잊지 말자. 배포가 계속 실패하는 경우 보통 EC2에 들어가서 로그를 보면 애플리케이션의 문제인 경우가 대다수였다.
보안 그룹에 인바운드 규칙을 추가해도 EC2 접속도 안되고, 배포 상태가 계속 프로비저닝이나 대기중으로 뜬다면 네트워크 문제일 수 있다. 나의 경우 계속 대기 중이 떴었는데, VPC 상에서 igw 설정도 안되있고 ECS 생성 시 퍼블릭 IP 허용을 해놓지 않아서 인터넷과 통신을 할 수가 없어서 배포가 정상적으로 되지 않았었다.
그리고 앞선 글에서 살펴본대로 CD 설정을 해주었다면, 이제 CD를 처리하면 ECS에서 태스크의 개정 번호가 올라가면서 자동으로 배포가 되는 것을 확인할 수 있다.
추가 개인 기록
- VPC(dev-vpc)
vpc 및 서브넷, 가용영역 a, b, c 생성 후 public 서브넷은 igw 인터넷 게이트웨이에 라우팅 테이블상 연결. - 로드밸런서(dev-lb)
public에 IPv4, IPv6 모든 트래픽에 대하여 open 보안그룹(dev-lb-public) 추가
리스너 규칙 HTTPS 생성 및 ECS 대상 그룹(dev-api-bridge)로 전달
- 클러스터
dev-live 생성. 보안그룹(dev-live-ecs) 생성 및 로드밸런서와 연결
- 용량공급자
클러스터 생성 시 기본값으로 생성하여 용량 공급자 설정. 퍼블릭 IP 자동 할당을 통해 EC2 컨테이너 인스턴스가 퍼블릭으로 연결되도록 설정
용량공급자의 시작 템플릿도 클러스터 생성 시 기본 값으로 생성.
- 서비스, 태스크
상기 생성한 용량 공급자 및 로드밸런서 연결하여 서비스(dev-api-bridge) 생성. 태스크를 생성하고 ECR 이미지 연결 및 설정 내용 주입
참고하면 좋은 글
'Project > Poppin' 카테고리의 다른 글
mysql dump(docker instance) (1) | 2024.01.01 |
---|---|
코틀린 logback 환경 분리, validated 검증, exception 처리, CD 적용 (1) | 2024.01.01 |
스프링부트: 시큐리티- 회원가입, 로그인 기능 추가하기, swagger 로그인 하기, @ControllerAdvice (0) | 2023.12.25 |
S3 이미지 업로드 구현, Profile 설정 및 불러오기, Swagger 이미지 업로드(multipart) (0) | 2023.12.25 |
Thymeleaf로 input 확인 및 수정 Admin 페이지 만들기(jquery, script) (0) | 2023.12.17 |