AWS ECS 서비스 환경 구축기
데브옵스도 아닌 제가 이런 글을 작성해도 될지? 싶기도 하고, 아직 이해하지 못한 부분도 많지만
ECS를 통한 알파 환경을 구축해보며 트러블 슈팅한 내용들을 정리해 보겠습니다,
사실 포기도 몇번하려 했는데, 끝끝내 스웨거 화면을 보긴 했네요.
삽질 경험을 남겨 놓는다면 이후에 조금 더 편하게 인프라를 설계할 수 있을 것 같아 글을 남깁니다.
처음 도전해볼 누군가에게 이 글이 도움이 되면 더욱 좋겠네요/
1. VPC 설정
매번 AWS 계정 생성 시 자동으로 생성되는 VPC만 사용했었는데, 이번엔 아예 10.128.0.0/16로 새롭게 생성했습니다.
매번 AWS에서 제공해 주는대로 사용하다, 실질적으로 내부망을 설계 해볼 수 있었습니다.
VPC는 말 그대로 논리적인 가상 개념이고, 그 아래서 실질적으로 동작하는 것은 서브넷이었습니다.
서브넷은 VPC 하위 주소 범위를 나눠서 public, private으로 분배 했습니다.
이후 public subnet들과 연결된 라우팅 테이블의 0.0.0.0 port가 VPC 생성하며 받은 igw를 바라보도록 설정했습니다.
(이 인터넷 게이트웨이가 없다면, public IP를 할당 받아도 VPC 외부와 통신이 안되는 것으로 알고 있습니다.)
즉 10.128.~.~ 하위 주소의 IP를 제외한 모든 IP 요청은 외부로 나갑니다.
이후 IGW와 연결하지 않은, private route table을 생성했습니다.
다만 nat gateway를 통해서 외부와의 outbound 요청을 허용 시켰습니다. (ECR 통신용)
2. ALB / 대상 그룹 생성
ECS를 설정해주기 앞서, ALB와 대상그룹을 생성했습니다.
ALB 없이 직접 ECS 서비스를 공인 IP를 통해 노출할 경우, 트래픽 분산, SSL 종료, 헬스 체크와 같은 기능은 기본적으로 제공되지 않으므로 실 운영을 가정했을 때 필요했습니다.
SSL 설정도 ACM과 로드 밸런서를 통해 간단하게 처리했습니다. (ECS 서비스에서 SSL을 따로 적용해주는 방법은 잘 모르겠네요.)
ALB는 기본적으로 public Subnet에 위치하고 있습니다. 외부 요청(https://apis.alpha.uoslife.com)을 이 로드 밸런서가 수행합니다.
nslookup을 통해 얻은 ip 주소가 alb의 subnet 별로 배정된 public IP임을 볼 수 있습니다.
(저 public IP 주소는 고정적이지 않으므로, Route 53에서는 ALB의 DNS로 'apis.alpha.uoslife.com'을 매핑해줘야 합니다.)
3. ECS 설정
ECS 클러스터 -> 가상 인프라? 사실 클러스터 쪽은 별로 건드린게 없어서 잘 모르겠습니다.
(서비스나 태스크를 띄울 논리적 장치이며, AWS Fargate(서버리스) or Amazon EC2 인스턴스 중 선택하는 용도)
ECS 태스크 -> 컨테이너를 실행하는 기본 단위, 태스크 정의에는 컨테이너 이미지, CPU/메모리 요구사항, 포트 매핑, 환경 변수 등 실행에 필요한 모든 설정이 포함됩니다.
도커 위에 이미지같은 개념이나, ECS 위에서 돌아가는 이미지라고 생각하면 좋을 것 같네요
ECS 서비스 -> 태스크 정의를 통해 생성한 ECS 전용 이미지를 어떤 설정으로 올릴지 정하는 것
- 어떤 태스크를 몇 개 수행시킬지?
- 무중단 배포와 실패시 행동 설정
- 서비스의 배포 서브넷 설정 (Private)
- 앞서 설정한 로드 밸런서와 대상 그룹 설정
- 경보에 맞춰 Auto Scaling 설정
이러한 세부 설정을 모두 끝마치고 시간이 흐르면, 드디어 원하는 대로 정상적인 Task (Spring boot 서버)가 뜨게 됩니다.
4. Route 53 설정
DNS -> Alias 설정만 주의하시면 됩니다.
삽질의 기록
ECS Task의 ECR을 찾지를 못하겠어
ECS 서비스는 private subnet 위에 위치해 있어 public IP를 가진 ECR과 통신할 수가 없었습니다.
해결
private Route table에 public nat-gateway와 연결하여 외부에 요청을 할수 있도록 열어주었습니다.
다만 ECR이 VPC에 내부 IP를 가질 순 없었을까? 하는 생각이 드네요.
Elasticache redis 연결 실패
겨우겨우 ECR을 찾아 배포에 성공했으나, 같은 private subnet안에서 운영하고 있는 elasticache redis와 연결이 계속 거절 당했습니다.
클러스터 문제인지, 스프링 문제인지, 네트워크 문제인지 한참 찾다가
elasticache redis가 기본적으로 TLS를 지원하는 것을 알았습니다.
저 설정을 해제하고 클러스터를 생성하거나, spring.redis.ssl=true를 스프링에 설정해줘야 합니다.
모든 설정을 완료했고 정상인데, Connection time out 발생
대상 그룹 프로토콜을 ECS에 맞춰서 매핑해야 합니다.
ALB (80) -> ALB(443) -> 대상 그룹 (8081) -> ECS 서버로 가는 흐름이기에
대상 그룹 포트를 초기 설정인 80Port로 설정하여 매핑이 불가능 했던 것입니다.
+ 보안그룹 설정도 막힌 곳이 없는 지 확인하셔야 합니다.
(ecs의 경우, 8081 Port 오픈)
느낀 점
Iac도 아닌데, 보고 따라하는 것도 굉장히 힘들었습니다. 인프라 팀 최고..
이제 CI/CD를 구축해야 하는 데, 이 부분도 그렇게 쉽진 않아보이네요.
그래도 이렇게 한 번 구축해 놓으면, 돈이 들더라도 서비스의 운영다운 운영을 할 수 있지 않을까 싶습니다.
오토스케일링이 정상적으로 작동하는 지도 설정 후 확인해볼 예정입니다.
이렇게 한번 끝냄으로 이후에 EKS도 도전하기도 한층 쉬워졌습니다.
ECS가 태스크 기반해 서비스 설정에 맞춰 AWS에 운영을 떠넘긴다면, EKS는 조금 더 컨테이너 관리에 가까울 것 같습니다.
Subnet 관련도 매번 말로만 듣다가 직접 다뤄보니 이해가 쉬웠습니다.
이제 다시 스프링을 공부하러..