※ 기존에 기록해둔 노션 글을 옮겨적은 것으로, 노션 템플릿에 맞게 적게된 글이라 해당 링크를 통해 더 가독성있게 보실 수 있습니다.
https://www.notion.so/ECS-EC2-Fargate-EC2-2690661ce6288002b649e41cce173d12
ECS(EC2, Fargate)로 백엔드 애플리케이션 배포하기 + 기본 EC2배포까지 | Notion
1. 각각에 넣을 보안그룹 생성하기( ALB, Gateway Server, ECS )
pleasant-sand-55a.notion.site
4. ALB 생성하기
4-1) alb 생성하기






[ 정책 이름 ] :
최신 TLS 1.2/1.3 지원하는 ELBSecurityPolicy-TLS13-1-2-Res-2021-06 추천 (보안성 가장 좋음)
⇒ 현업에서도 많이 쓰이는 모던 보안 정책입니다.
[ 클라이언트 인증서 처리 → 상호 인증(m TLS) ] :
- 일반적인 웹사이트나 API 통신에서는 클라이언트 인증서는 필요 X
- Mutual TLS는 금융권/내부망에서만 특수하게 사용합니다.

4-2) 80으로 들어갔을 때 443으로 바로 리디렉션하는 설정하기





5. Route 53에서 A 레코드 생성 (api.reciping.kr → ALB)




+) 게이트웨이 서버를 기본 EC2에 배포하기
⇒ 그 다음 절차는 gateway server를 EC2에 띄우는 것인데 그 과정은 다른 페이지에 따로 담았습니다.
기본 EC2 배포하기(Gateway Server) | Notion
1. EC2 키페어 만들기
pleasant-sand-55a.notion.site
6. ECS 클러스터 생성하기


+) 네임스페이스 설정하기
✅ [ 기본 네임스페이스 ] :
선택사항이긴 하지만, 클러스터 내부에서 서비스들을 논리적으로 그룹화하고 싶을 때 사용합니다.
향후 Prometheus, CloudWatch, Service Connect 등을 고려하면 reciping-ns 같은 네임스페이스를 만들어 두는 것도 나쁘지 않기에 만들어두겠습니다.
+) 네임스페이스의 다른 좋은 점 정리
| 기능 | 네임스페이스 사용 시 효과 |
| 서비스 격리 | reciping-user-service 와 reciping-recommend-service 를 분리해서 관리 가능 |
| Cloud Map 연동 | 서비스 디스커버리 이름이 recommend.reciping.local 이런 식으로 구조화 가능 |
| Observability 향상 | CloudWatch, X-Ray, Prometheus 연동 시 태깅 기준으로 분석 용이 |
| Multi-tenant 운영 대비 | 나중에 하나의 클러스터에 여러 팀/서비스를 운영할 때 구조적으로 구분 가능 |

[ 네임스페이스 이름 ] :
[프로젝트명].local 도메인은 VPC 내부 전용 용도로 AWS가 자동 인식해서 설정해줍니다.
⇒ 내부 DNS에서 user.reciping.local, event.reciping.local처럼 사용
[ 인스턴스 검색 ] :
| 옵션 | 설명 | 권장 여부 |
| API 호출 | 서비스 디스커버리 이름으로 ECS에서 호출할 때 Cloud Map을 API 통해 조회함 | 기본 + 요금 없음 |
| VPC에서 API 호출 및 DNS 쿼리 | DNS 기반 + API 호출을 모두 지원함 (비용 발생) | 외부 서비스가 DNS로 호출해야 할 때만 사용 |
| 퍼블릭 DNS 쿼리 포함 | 퍼블릭 DNS로도 외부에서 접근 가능 (비용 발생) | 지금 상황에서는 불필요 |

[ Auto Scaling 그룹(ASG) ]
: 클러스터에 EC2 Capacity Provider로 사용할 Auto Scaling Group을 설정
⬇️ 여기서 EC2 Capacity Provider란?
- EC2 인스턴스를 ECS에서 자동으로 사용할 수 있게 해주는 중개자 매개체
- 즉, Auto Scaling Group(ASG) 기반의 EC2 인스턴스를 ECS가 자동으로 관리하게끔 연결해주는 "다리”
- ECS가 태스크를 실행해야 할 때 ASG의 용량을 보고 자동으로 EC2 인스턴스를 띄움
- 예) 태스크 수 증가 → Capacity 부족하면 → ASG 스케일 아웃 유도
# 구성 요소 흐름도
Auto Scaling Group (EC2 인스턴스 묶음)
↓ 연결
EC2 Capacity Provider
↓ 연결
ECS 클러스터 내 서비스
결론 : 일단 새 ASG 생성으로 자동생성
→ 이후 세밀 조절을 위해 EC2 > Auto Scaling > 생성된 그룹으로 이동해서 정책을 추가해야 합니다.
→ 예) CPU 60% 이상이면 EC2 한 대 더 생성 등
→ fargate는 ECS 서비스 > Auto Scaling 설정에서 task수를 자동 증가 정책 필요
→ 예) 예: CPU 평균 60% 이상이면 Task 수를 2 → 3으로 자동 증가
[ 컨테이너 인스턴스 AMI ]
: Amazon Linux 2 그대로 두면 ECS Agent 포함된 최적화된 AMI로 자동 선택됨
[ EC2 인스턴스 역할 ]
: 기본값 ecsInstanceRole 선택 ⇒ ECS 에이전트가 동작하고 CloudWatch, ECR 등에 접근할 권한을 가짐
[ 시작 인스턴스 수 ]
: 기본값 최소가 0으로 되어있는데 그대로 두면 ‘최초 배포 안 해도 된다’ 는 표시이니 최소 1 / 최대 2로 초기 세팅
[ SSH 키 페어 ]
: EC2 인스턴스에 접속해서 디버깅하고 싶다면 꼭 필요 ⇒ reciping-prod-ec2-key 선택
[ 루트 EBS 볼륨 크기 ]
- EC2 인스턴스의 기본 디스크 공간(운영체제, 로그, 컨테이너 캐시 등 저장)
- ECS에서 컨테이너를 EC2에서 실행할 경우, 도커 이미지/로그도 이 루트 볼륨에 저장됨
⇒ 대부분의 AMI에서 기본값은 30 GiB인데, 지금 MSA 서비스 여러 개 구성 예정이니 넉넉하게 50GiB로 세팅

[ 퍼블릭 IP 자동 할당 ]
: 프라이빗 서브넷에서 동작할 것이므로 끄기 선택

7. ECR 생성하기


[ 이미지 태그 변경 가능성 ]
| 옵션 | 설명 | 구분 기준 |
| Mutable (기본값) | 같은 태그로 이미지를 덮어쓰기 가능 (예: latest) |
개발/테스트 환경에서 많이 씀 |
| Immutable | 같은 태그로는 한 번만 푸시 가능 (덮어쓰기 불가) | 실운영 배포 환경에서 선호 (보안 및 추적성 확보) |
[ 암호화 설정 ]
| 옵션 | 설명 | 구분 기준 |
| AES-256 (기본값) | AWS가 자동으로 암호화 관리 | 대부분 이걸 씀 |
| AWS KMS | 직접 생성한 KMS 키로 암호화 | 보안이 매우 민감한 조직에서 사용 (예: 금융, 의료) |
[ 이미지 스캔 설정 ] - 푸쉬된 이미지 취약점 검사해주는 옵션
⇒ 저희는 현재 리포지토리 단위에서 구성되므로, 신경 쓰지 말고 그냥 꺼두면 됩니다.

8. Dockerfile 작성하기
멀티 스테이지 빌드를 이용하겠습니다. & 경량 베이스 이미지도 사용
# 1단계 : Build Stage
# 빠른 빌드에 최적화된 이미지인 openjdk:17-jdk-slim 사용, Builder 단계에서만 사용
FROM openjdk:17-jdk-slim AS builder
WORKDIR /app
# gradle 설정 복사
COPY gradlew build.gradle settings.gradle ./
COPY gradle ./gradle
# 소스 복사
COPY src ./src
# 실행 권한 부여 + 빌드
# bootJar만 빌드하여 build 전체 안 쓰고 필요한 아티팩트만 생성해서 빠르게 함
# --no-daemon 사용하여 도커 환경에서 데몬 프로세스 오류 방지
RUN chmod +x ./gradlew && ./gradlew bootJar --no-daemon
# 2단계: Runtime Stage (이 또한 경량 이미지)
# 런타임은 경량 + AWS 친화적 (ECS, EC2 AMI와 일관성 유지)
FROM amazoncorretto:17-alpine
WORKDIR /app
# 빌드된 JAR 복사
COPY --from=builder /app/build/libs/*.jar app.jar
# 도커 컨테이너 내부에서 사용하는 헬스체크용 포트 노출
EXPOSE 8080
# Spring Boot 실행
ENTRYPOINT ["java", "-jar", "app.jar"]
+) MacOS에 AWS CLI 설치
curl "https://awscli.amazonaws.com/AWSCLIV2.pkg" -o "AWSCLIV2.pkg"
sudo installer -pkg AWSCLIV2.pkg -target /
# 설치 끝나면 아래로 확인
# 예시 출력: aws-cli/2.x.x 이런 식이면 성공
aws --version

# ECR에 로그인하기 위해 인증 정보 입력해야 함
aws configure
# 그 뒤에는 아랫 내용 입력하면 됩니다.
+) IAM에서 내 계정(내 사용자) 엑세스 키 만들기


| 항목 | 설명 | 입력값 |
| AWS Access Key ID | IAM 사용자로 받은 키 | AKIA... |
| AWS Secret Access Key | IAM 사용자 시크릿 | xxyyzz... |
| Default region name | 서울 리전 | ap-northeast-2 |
| Default output format | 그대로 엔터 쳐도 됨 | json 혹은 그냥 엔터 |

🚨 docker desktop 실행 중인 상태로 아랫 명령어 쭉 진행합니다.
# 일단 user-service 기준으로 문서 남겨둡니다.
# 892117097999.dkr.ecr.ap-northeast-2.amazonaws.com => ecr에서 유저 서비스 url 그대로 가져오면 됩니다.
aws ecr get-login-password --region ap-northeast-2 | \
docker login --username AWS --password-stdin 892117097999.dkr.ecr.ap-northeast-2.amazonaws.com

저희는 이미지 버전을 mutable하게 가져가지 않고(lastest ❌) Immutable하게 v1.0.0 형식으로 버전관리할 예정입니다.
<주의할 점> : 과정 중에 이후의 하나의 과정이라도 실패하면 그냥 해당 ECR 삭제하고 다시 만드는 것 추천
docker build -t reciping-user-service:v1.0.0 .

# 빌드한 도커 이미지'reciping-user-service:v1.0.0'를 태깅 후, ECR에 푸쉬
docker tag reciping-user-service:v1.0.0 \
892117097999.dkr.ecr.ap-northeast-2.amazonaws.com/reciping-user-service:v1.0.0
docker push 892117097999.dkr.ecr.ap-northeast-2.amazonaws.com/reciping-user-service:v1.0.0

+) 나머지 서비스들도 다 똑같은 과정으로 진행하세요.
# 1. 디렉토리 이동 (예: reciping-recipe-service-BE)
cd ~/Desktop/dev_sini/reciping-recipe-service-BE
# 2. jar 빌드
./gradlew clean bootJar --no-daemon
# 3. 도커 이미지 빌드 (캐시 없이)
docker build --no-cache --platform linux/amd64 -t reciping-recipe-service:v1.0.0 .
# 4. 태깅
docker tag reciping-recipe-service:v1.0.0 \
892117097999.dkr.ecr.ap-northeast-2.amazonaws.com/reciping-recipe-service:v1.0.0
# 5. 푸시
docker push 892117097999.dkr.ecr.ap-northeast-2.amazonaws.com/reciping-recipe-service:v1.0.0
8. 태스크 정의 생성하기
8-1) fargate 태스크 정의 예시 (reciping-user-service)


[ 운영 체제/아키텍처 ]
: Linux/X86_64 대부분 기본 설정.(ARM 기반 컨테이너가 맞을 때는 다른거 사용)
[ 태스크 크기 ]
: fargate는 EC2와 달리 조합을 미리 정해둡니다.
현업에서는 웹 서비스: 0.5 vCPU + 1GB ~ 1 vCPU + 3GB, 검색, 머신러닝 등 고성능: 2~4 vCPU + 8GB~
[ 태스크 역할 ]
: 컨테이너 내 애플리케이션이 AWS 리소스에 접근할 수 있도록 부여된 IAM Role
현업에서는 ecsTaskExecutionRole 또는 서비스 전용 Role 따로 생성해서 사용한다고 합니다.

[ 프라이빗 레지스트리 ]
: 프라이빗 레지스트리 인증을 켜면, Docker 이미지의 사용자명/비밀번호가 필요할 수 있습니다.
ECR이 아닌 타사 프라이빗 레지스트리(ex. DockerHub Pro, GitHub Container Registry 등)일 경우는 Secrets Manager를 통해 자격 증명을 받아야 하는데 ECR 사용하고 있으니 켜놓긴 하되, Secrets Manager 설정은 빈칸으로 두세요.
[ 포트 매핑 ]
: ECS에서 유저 서비스는 포트 8080로 스프링부트가 구동되고 있습니다.
[ 읽기 전용 루트 파일 시스템 ]
: 컨테이너 내의 루트 파일 시스템을 읽기 전용으로 설정할지 선택 ⇒ 스프링 부트 앱이면 읽기 전용은 체크 X
[ 리소스 할당 제한 ]
| 목적 | CPU | Memory |
| 소규모 API 서비스 (트래픽 적음) | 0.5 vCPU | 1~2 GiB |
| 일반 SpringBoot 서비스 (유저 로그인/조회 등) | 1 vCPU | 2~3 GiB |
| 대용량 또는 병렬 처리 서비스 | 2 vCPU | 4 GiB 이상 |
[ 환경 변수 ]
배포 자동화 환경(Jenkins)에서 환경 변수를 주입할 거면 ECS 환경변수 설정은 생략해도 됩니다.


8-2) EC2 태스크 정의 예시 (reciping-search-service)

[ 네트워크 모드 ]
: awsvpc : ECS Task가 ENI(IP)를 직접 받아서 통신함 → 보안 그룹, IAM 관리도 쉬움
[ 작업 배치 ]
추가 X
[ 결함 주입 ]
: AWS Fault Injection Simulator (FIS)와 연동하여 장애 유도 테스트 수행 옵션이며, 보통 장애 대응 훈련, 복원력 테스트 시 QA 환경에서 사용 가능하며 현재 프로덕션 환경에선 사용 안 하므로 체크 X

9. 서비스 생성하기
9-1) fargate일 경우(예 : user-service)


[ 태스크 정의 개정 ]
: 최신 개정 선택(예: :1, :2 등) → 수동 선택 가능, 일반적으로 최신 개정 선택 (기본값 유지 OK)
[ 서비스 이름 ]
: 자동으로 reciping-user-task-service-<랜덤>처럼 생성될텐데 이건 직접 reciping-user-service로 수정해야 팀 기준으로 서비스명 일관성이 유지가 되니 꼭 바꾸기
[ 컴퓨팅 구성(고급) ]
: 어떤 인스턴스에 태스크를 띄울지 ECS가 알아서 선택하는 방식 → 용량 공급자 전략 선택
( 시작 유형은 예전 방식이며, 간단하지만 오토 스케일링과 스팟 연동 등 제한)
[ 용량 공급자 전략 ]
- fargate의 경우, 사용자 지정 사용(고급) 선택 ( EC2의 경우, 클러스터 기본값 사용 선택)
[ 용량 공급자 ]
- 메인 컨테이너를 정규 fargate에서 실행한다는 의미로 FARGATE 선택
- 가중치는 1 기본값 유지 (FARGATE_SPOT을 추가하려면 전략적으로 FARGATE: 1, FARGATE_SPOT: 1 같이 구성해서 비용 최적화도 가능)
- ⇒ 하지만 user-service처럼 항상 켜져야 하는 서비스는 FARGATE 단독이 안정적
[ 플랫폼 버전 ]
: LATEST 선택 (보안 정책상 고정 버전 사용하는 금융/대겹은 1.4.0 사용하기도 한다고 합니다.)

[ 서비스 유형 ]
: 원하는 태스크 수만큼 ECS가 유지하는 구조 (MSA 대부분이 여기에 해당) → 복제본 선택
[ 원하는 태스크 ]
: 초기에는 1개로 시작, 필요 시 오토 스케일링 설정하면 되는데 저희는 나중에 설정할 것입니다.
(실무에서는 초기 서비스에서는 1~2개 선택하고 트래픽 증가에 따라 조정한다고 합니다.)
[ 가용 영역 리밸런싱 ]
: Fargate가 AZ 불균형 발생 시 자동으로 리밸런싱 해줌 (현업에서 반드시 켜놓음)
[ 상태 검사 유예 기간 ]
: 스프링 부트 서버의 경우, 기동이 20~30초 걸린다 생각하면 30으로 설정해두기
[ 배포 유형 ]
- 롤링 업데이트 : 한 번에 일부 태스크를 교체하며 무중단 배포 → 규모 작을 때 적합합니다. 이거 선택
- 블루/그린 : 테스트 후 승인 방식 배포 → 서버가 많이 떠있으면 가능(지금은 필요X / 나중에 고려)
[ 최소 실행 작업 비율 ]
: 업데이트 도중 기존 태스크는 100% 유지, 새 태스크 배포 후 교체
[ 최대 실행 작업 비율 ]
: 최대 몇 개까지 동시 실행 가능한지 (기존 + 신규) → 기본값 200% 적용(오토 스케일링 대응 포함됨)
[ 배포 실패 감지 ]
| 옵션 | 설명 | |
| Amazon ECS 배포 회로 차단기 사용 | 배포 중 태스크가 unhealthy 상태에 도달하면 즉시 배포 중단 | 항상 ON(기본 보호 메커니즘) |
| 실패 시 롤백 | 새 배포가 실패하면 이전 정상 상태로 자동 롤백 | ON (중단 없는 운영을 위해) |
| CloudWatch 경보 사용 | CloudWatch Alarm이 발생하면 배포 중단 | 알람 연동된 모니터링 세팅이 있는 경우만 사용 (없으면 꺼두는 게 맞습니다) |


'Project > reciping' 카테고리의 다른 글
| [reciping 2차] minikube로 로컬 쿠버네티스 테스트하기 (0) | 2025.11.05 |
|---|---|
| [reciping] 프론트단의 Route53 + S3 + CloudFront 설정하기 (0) | 2025.11.05 |
| [reciping] ECS(EC2, Fargate)로 백엔드 애플리케이션 배포하기 + 기본 EC2배포까지 (1) (0) | 2025.11.05 |
| [reciping] 베스천 서버 세팅하기 (0) | 2025.11.05 |
| [reciping] 기본 EC2 배포하기(Gateway Server) (0) | 2025.11.05 |