개발하는 자몽

[TIL / AWS] SpringBoot 서버리스로 배포하기: ECR + Fargate(ECS) + ALB + Private Link 본문

Architecture & Tool/AWS

[TIL / AWS] SpringBoot 서버리스로 배포하기: ECR + Fargate(ECS) + ALB + Private Link

jaamong 2025. 8. 7. 23:54

📌공유도 있지만, 기록이 더 큰 목적...  Windows 11, Gradle/SpringBoot.

AWS에서 "아.. Fargate 좋은데... 안쓰나... 진짜 좋은데..." 라고 계속 홍보하는 것 같아서 이번 프로젝트에서는 도대체 얼마나 좋길래? 하고 사용해봤다.

후기! EC2 보다 비용이 좀(꽤) 나가지만, 편리하다. 서버 설정 자체는 신경을 안쓰게 되긴하는데 인프라는 건들게 너무... 많다... 자세히는, 퍼블릭 서브넷에 배포한다면 정말 금방 끝낼 수 있다. 하지만 프라이빗 서브넷에 배포한다면... 좀... 귀찮아진다... (새삼 Render가 진짜 배포하기 쉽다...)

배포하는 과정에서 Private Link 관련으로 삽집을 많이해서 기록용으로 남겨둔다. 

 

사전 준비

  • Docker 계정
  • AWS CLI 설치
  • AWS CLI를 사용할 수 있는 AWS IAM 계정 (충분히 권한이 있는지)

 

Fargate

  • Fargate는 서버리스 컴퓨팅 서비스로 컨테이너를 실행하기 위해 사용할 수 있다. ECS와 함께 사용해야 한다(단독 사용 X).
    • ECS는 Elastic Container Service의 줄임말로, 이름대로 완전 관리형 컨테이너 오케스트레이션 서비스이다. 쿠버네티스가 아닌 도커 컨테이너 관리를 위한 서비스이다. 쿠버네티스는 EKS라고 따로 있다. 
  • Fargate는 EC2와 달리 사용자가 서버나 클러스터를 관리할 필요가 없지만, 실제로는 EC2 위에서 실행된다.
  • EC2와 동일 스펙으로 두고 보았을 때 요금이 더 비싸다. (솔직히 EC2에 비해 조금... 부담될 수도 있다.)
  • CloudWatch와 자동 연동 된다. 
  • 리소스(Task) 생성 시 VPC 내부 서브넷에 위치한다. 

ECR

  • ECR은 컨테이너 이미지를 저장 및 관리할 수 있는 서비스이다. 여기에 빌드한 Docker 이미지를 올려서 ECS(Fargate)를 통해 배포할 수 있다. 
  • 컨테이너 이미지 레이어를 S3에 저장한다. 
  • VPC 밖에 위치한다. 
    • 따라서 Fargate(VPC 내부)에서 ECR(S3)에 저장된 컨테이너 이미지를 가져오려면 인터넷 통신이 필요함
      • Fargate의 위치가 퍼블릭 서브넷이고, 생성 시 공인 IP가 자동 할당되도록 설정했다면 문제없음
      • 프라이빗 서브넷이면 공인 IP가 할당되어도 인터넷 통신이 불가능하므로 ECR(S3)에서 컨테이너 이미지를 가져올 수 없음 → NAT Gateway 사용 또는 Private Link 구성으로 해결해야 함

Private Link

  • VPC 엔드포인트, Gateway Endpoints(S3 또는 DynamoDB)를 사용해서 VPC 밖에 있는 두 서비스 사이에서 인터넷이 아닌 사설(private) 통신이 가능하도록 하는 서비스
  • 둘 중에 무엇을 선택할지는 비용을 따지는 편. 발생하는 비용은 각자 서비스의 데이터 처리량 등을 고려하여 계산.

 

 

Fargate로 SpringBoot 애플리케이션 배포하기

  1. Dockerfile 작성하기
  2. 도커 이미지 빌드 및 도커 허브에 push (이미지 이름 기억해 두기)
  3. ECR에서 Private Repository 생성
  4. 생성한 레포지토리를 선택하고 푸시 명령 보기 클릭, 가이드 보면서 순차적으로 진행
    • ECR 레지스트리에 Docker 클라이언트 인증 시 AWS CLI default 프로필 외에 다른 프로필 사용 시 아래와 같이 진행
      aws ecr get-login-password --region ap-northeast-2 --profile {profile_alias}| docker login --username AWS --password-stdin {account_id}.dkr.ecr.ap-northeast-2.amazonaws.com
    • 태깅할 때 태그는 앞으로 생성될 이미지 태그와 겹치지 않게 고유한 태그로 생성할 것
  5. 클러스터 생성: 클러스터는 서비스나 태스크의 논리적인 그룹이다. 
    1. ECS > 클러스터 > 클러스터 생성
    2. 인프라: AWS Fargate
    3. 클러스터 이름 작성이랑 인프라 선택만 하고 완료하기 
  6. 작업(Task) 정의: Task에 필요한 명세를 정의한다. Amazon ECS에서 Docker 컨테이너를 실행하려면 작업 정의(Task Definition)가 필요함. 이전에 생성한 도커 이미지를 참조하는 작업 정의를 생성한다.
    • ECS > 태스크 정의 > 새 태스크 정의 생성 > 새 태스크 정의 생성
      • 태스크 정의 패밀리: 고유한 이름 지정
      • 인프라
        • 시작 유형: AWS Fargate
        • 태스크 역할
          • 태스크 역할: 건들지 않음 
          • 태스크 실행 역할: Amazon ECS를 처음 사용하는 경우 `ecsTaskExcutionRole IAM` 역할이 존재 X. 이 경우는 Task execution role 설정에서 Create new role을 선택하면 자동으로 `ecsTaskExcutionRole` IAM 역할이 생성됨.
        • 애플리케이션에 필요한 사양에 맞춰서 진행
      • 컨테이너
        • 이름: 임의 지정
        • 이미지 URI: ECR에 올린 도커 이미지의 URI로 ECR > 프라이빗 레지스트리 > 리포지토리 > {생성한 리포지토리}에서 이미지 URI를 복사할 수 있음
        • 필수 컨테이너: 예
        • 프라이빗 레지스트리: 비활성화
        • 포트 매핑: 여기에서는 스프링부트의 8080번 포트로 지정. 이 부분은 각자의 환경에 맞춰 설정. 로드밸런싱을 사용한다면 여기에서 로드밸런서의 요청을 받을 포트를 설정.
      • 로깅
        • `awslogs-region`을 잘 확인하고, 나머지는 위와 같이 설정한다.
      • 나머지는 기본 상태로 두고 작업 정의를 완료한다. 
  7. ECS 작업 IAM 역할 수정: 앞 단계에서 자동 생성된 ECS 작업의 IAM 역할인 `ecsInstanceRole`에 `CloudWatchLogsFullAccess`를 추가
    1. IAM > 역할 > ecs 검색 > `ecsInstanceRole` 선택
    2. 권한 탭 > 우측 권한 추가 메뉴 > 정책 연결 클릭
    3. 검색창에서 `CloudWatchFullAcess` 검색 > ` CloudWatchFullAcessV2` 선택 > 권한 추가 클릭
    4. 추가된 정책 확인
  8. ALB 구성 및 생성: private subnet에 위치한 ECS와 연결하여 외부 트래픽 진입점이 될 ALB를 생성한다.
    • 대상 그룹 생성
      1. EC2 > 대상 그룹 > 대상 그룹 생성
      2. 대상 유형: IP address
      3. 타겟 그룹 이름: 자유롭게 설정(보통 tg를 이름에 넣어서 대상 그룹임을 명시하는 편)
      4. 프로토콜 : 포트: HTTP : 8080(ALB가 요청을 보내줄 포트, 배포할 컨테이너(ECS)의 실행 포트로 입력. 모르겠다면 애플리케이션의 실행포트로 입력)
      5. VPC: 로드 밸런서를 호스팅 할 VPC 선택(ECS가 있는 VPC로)
      6. 상태 검사: 애플리케이션에 헬스 체크 API가 있다면 여기에 입력
      7. 나머지는 기본값으로 놔두고 다음 클릭
      8. 대상 등록: 아무것도 건들지 않고, 대상도 등록하지 않고 생성 완료하기. 나중에 ECS가 생성될 때 생성된 태스크가 자동으로 등록됨.
    • ALB 생성
      1. EC2 > 로드 밸런서 > 로드 밸런서 생성
      2. ALB 생성
      3. 로드 밸런서 이름: 자유롭게 설정(tg처럼 이름에 alb를 추가해서 명시하는 편)
      4. 체계(schema): 인터넷 경계(internet-facing)
      5. 네트워크 매핑: 대상 그룹과 동일한 VPC
        • 선택 후, 가용 영역 및 서브넷: 2개 이상 선택
      6. 보안 그룹: 이 ALB를 위해 생성해 둔 것이 없다면 새롭게 생성. 보안 그룹은 아래 조건을 만족하면 됨.
        • 새로 생성 시 아웃바운드는 건들지 않고, 외부 트래픽을 받을 수 있도록 인바운드만 설정
          • 유형: HTTP
          • 포트: 80
          • 소스: 0.0.0.0/0
      7. 리스너 및 라우팅: 외부 트래픽을 어떤 프로토콜과 포트로 받을지 결정하여 이 통로만 열어두고(리스너) , 받은 요청을 어디로 보낼지(라우팅) 설정
        • 프로토콜: HTTP
        • 포트: 80
        • 대상 그룹: 방금 생성한 대상 그룹 선택. 여기로 요청이 라우팅 된다. 
        • 요약 정보를 확인하고, 모두 맞다면 완료하기
  9. ECS 서비스 생성: Amazon ECS를 사용하여 Amazon ECS 클러스터에서 지정된 작업 정의 인스턴스를 동시에 실행하고 관리할 수 있다. 이를 서비스라고 한다.
    1. ECS > 생성한 클러스터 선택 > 서비스 탭 > 생성 버튼 클릭
    2. 서비스 세부 정보 설정
    3. 환경 > 컴퓨팅 구성
      • 컴퓨팅 옵션: 시작 유형
      • 시작 유형: FARGATE
      • 플랫폼 버전: LATEST
    4. 배포 구성
      • 스케줄링 전략: 복제본
      • 원하는 태스크: 서비스(여기서는 개발하는 프로덕트를 의미) 상황에 맞게 (여기서는 1개만 함)
        • Task: 특정 애플리케이션 기능을 수행하는 하나 이상의 컨테이너
        • Service: 동일한 다수의 Task 그룹
      • 나머지는 기본값으로 두기
    5. 네트워킹 설정
      1. VPC: VPC는 이미 생성된 것을 사용하거나 다른 서비스/프로젝트와 구분 지어 사용하고 싶다면 새롭게 생성. 잘 모르겠다면 default VPC 사용도 상관 X.
      2. 서브넷: 프라이빗 서브넷(private subnet)으로 선택.
        • 퍼블릭 서브넷(public subnet)도 가능함. 이 경우 다음을 참고.
          • ALB & VPC 엔드포인트나 NAT 없이도 외부 트래픽을 받을 수 있음
          • 퍼블릭 IP 옵션을 활성화 → 하나의 퍼블릭 IP에 대해서 시간당 0.005 USD의 요금이 부과됨
          • ALB와 VPC 엔드포인트 설정이 별도로 필요 없음
          • 퍼블릭 서브넷에 두면 보안 및 확장성 측면에서 좋지 않음
      3. 보안 그룹: 위에서 생성한 ALB를 고려해서 ECS를 위해 미리 만들어둔 보안 그룹이 없다면, 새로 생성하기
        1. 보안 그룹 이름: 여기에서도 sg를 이름에 추가해서 보안 그룹임을 명시하는 편
        2. 설명: 보통 어떤 목적의 보안 그룹인지 작성하는 편
        3. 인바운드 규칙
          1. 유형: 사용자 지정
          2. 포트 범위: 8080 (대상 그룹에서 입력한 포트와 동일하게)
          3. 소스: ALB를 위해 만들었던 보안그룹을 선택 (ALB를 통해서만 외부 트래픽이 들어올 수 있게 됨)
    6. 로드 밸런싱
      1. 로드 밸런싱 사용: 활성화
      2. VPC: 로드 밸런싱이 위치한 VPC로 선택
      3. 로드 밸런서 유형: ALB
      4. Application Load Balancer: 기존 로드 밸런서 사용
      5. 컨테이너: 기본적으로 잘 선택되어 있을 테니, 가만히 내버려 두거나 아래를 참고해서 틀렸다면 수정하기
        • 포트가 `8080:8080` 이렇게 되어 있을 텐데, 이런 의미다. `{컨테이너가 실행되는 호스트 머신의 포트}:{컨테이너 내부 포트}` → a:b 라면 a번 포트를 컨테이너의 b 포트로 연결하여 외부에서 a번 포트로 접근하면 컨테이너의 b번 포트로 연결됨(포트 포워딩)
      6. 로드 밸런서: 위에서 생성했던 로드 밸런서 선택
      7. 리스너: 8080-HTTP (대상 그룹에서 입력한 포트와 동일하게)
      8. 대상 그룹: 기존 대상 그룹 사용
      9. 대상 그룹 이름: 위에서 생성한 대상 그룹 선택
      10. 상태 확인 경로: 헬스 체크 API 있으면 작성
    7. 나머지는 기본값으로 놔두고 완료하기
  10. Private Link: 이대로 배포하면 ECR에서 이미지를 가져올 수 없다고 하는 통신/연결 에러가 발생할 것이다. 해결을 위해 다음 설정을 진행한다. 여기서는 3개의 VPC Endpoint(개당 0.01 USD / hour)와 S3 Gateway Endpoint(무료)를 생성한다.
    • VPC 엔드포인트
      1. VPC > PrivateLink 및 Lattice > 엔드포인트
      2. 엔드 포인트 생성 클릭
      3. 유형: AWS 서비스
      4. 서비스 > 검색창: `ecr`
        • 검색 시 `ecr.api`와 `ecr.dkr`이 나타남. 모두 필요하지만, 한 번에 여러 개 생성 불가능. 우선 둘 중 하나 선택하여 진행
      5. 네트워크 설정: ECS가 있는 VPC 선택
      6. 서브넷: ECS가 있는 서브넷
      7. 보안그룹: VPC 엔드포인트용 보안 그룹 생성 
        1. EC2 > 보안 그룹 > 보안 그룹 생성 - 인바운드 규칙만 추가
        2. 유형: HTTPS
        3. 소스 유형: 사용자 지정
        4. 소스: ECS가 속한 VPC의 IP 범위 (IPv4 CIDR)
      8. 정책: 전체 액세스
      9. 완료 (다음 셋 중 하나라도 안 하면 배포 실패)
        • 동일한 과정으로 총 3번 반복: `api`, `dkr`, `logs`
    • VPC Gateway
      1. VPC 엔드포인트의 3번까지 동일
      2. 서비스 > 검색창: `s3`
        • 유형이 `Gateway`인 항목으로 선택
      3. 네트워크 설정: ECS가 있는 VPC 선택
      4. 라우팅 테이블: ECS가 있는 서브넷과 연결된 라우팅 테이블 선택
      5. 정책: 전체 액세스
      6. 완료
  11. 드디어 모든 설정 끝!!! ECS 배포 상태를 확인해 보기
    • ECS > 클러스터 > 생성한 클러스터 클릭 > 서비스 탭 > 생성한 서비스 선택 > 배포 탭 클릭
    • 배포가 정해진 횟수만큼 실패하다 보면, 자동으로 배포가 실행되지 않는다. 이때는 서비스 업데이트를 클릭.
      • 배포 구성 > 새 배포 강제 적용: 활성화
      • 나머지는 손대지 말고 업데이트 완료하기
    • 이제 배포가 진행된다.
    • 배포가 성공했다면, ALB의 DNS를 통해 접근할 수 있다. (HTTPS 미적용 상태임을 잊지 말기~)
      • 선택된 서비스에서 구성 및 네트워킹 > DNS 이름이 해당 정보이다.

 

CoudWatch

별도로 설정을 안 했으면 기본 옵션으로 되어있다. 기본적으로 CloudWatch가 ECS에서 수집하는 지표는 ECS 클러스터 내 전체 자원의 평균 CPU 사용률, 평균 메모리 사용률 등 간단한 지표만 제공한다. 클러스터 수준의 지표만 수집하므로 세부 수준의 지표는 모니터링할 수 없다.

Container Insight를 사용하면 클러스터 내에서 더 세부적인 지표를 수집할 수 있다. 두 가지가 있다.

  • 일반 컨테이너 인사이트: ECS 클러스터 및 ECS 서비스 수준에 대해 지표를 수집
    • 일반 CloudWatch 지표 수집 비용과 동일. 수집한 지표 당 0.30 USD /month
  • 향상된 관찰 기능을 갖춘 컨테이너 인사이트: ECS 클러스터, ECS 서비스, ECS 태스크 정의, ECS 태스크, 실행 중인 컨테이너 수준에서 더 많은 지표를 수집
    • 수집한 지표 당 0.07 USD / month 

후자가 더 많은 지표를 수집하여 자세한 정보를 알 수 있긴 하지만, 지표 수가 많을수록 비용이 많이 부과되므로 잘 생각해 보고 선택해야 한다. 또한 서비스나 태스크는 트래픽 상황에 따라 얼마든지 증가할 수 있는데, 지표도 그만큼 많이 수집되므로 비용이 생각보다 많이 부과될 수도 있다. 주의하자!

 

 

 

 

 

 

🔖

Comments