[AWS] ECR + ECS(Fargate)로 웹 앱 배포하기 (Windows 환경 기준)
1. 준비 과정 (Windows 기준)
1-1. AWS 계정 생성 및 기본 설정
- AWS IAM 사용자 생성, AdministratorAccess 정책 부여
- Access Key ID / Secret Key 발급





1-2. AWS CLI 설치
- Windows용 AWS CLI v2 설치:
👉 다운로드 링크 - 설치 후 PowerShell에서 확인:
aws --version
1-3. AWS CLI 설정
aws configure
- AWS Access Key ID: IAM에서 발급받은 키
- Default region name: 예) ap-northeast-2 (서울)
- Default output format: : json
1-4. Docker 설치 (Docker Desktop + WSL2)
- Docker for Windows 설치
- WSL2 활성화 필요 (Windows 10 이상):
wsl --install
docker --version

2. Docker 이미지 만들기 및 ECR 푸시
2-1. Dockerfile 작성
# Dockerfile
FROM nginx:alpine
COPY ./index.html /usr/share/nginx/html/index.html
| FROM nginx:alpine | nginx 웹서버가 설치된 경량 alpine 리눅스를 기반 이미지로 사용 |
| COPY | 내가 만든 index.html 파일을 nginx의 웹 루트로 복사 |
2-2. index.html 작성
<!-- index.html -->
<h1>Hello</h1>
2-3. ECR Repository 생성
aws ecr create-repository --repository-name my-web-app
AWS에 이미지를 저장할 저장소(버킷) 을 만듬
출력되는 repositoryUri 는 나중에 Docker 이미지에 태그를 붙일 때 필요함.
2-4. ECR 로그인
aws ecr get-login-password | docker login --username AWS --password-stdin <<2-3에서 얻은 repositoryUri 값>>
🔗 저장소 주소 구성 방식
<계정 ID>.dkr.ecr.<리전>.amazonaws.com/<저장소 이름>
| 계정 ID | 계정아이디 |
| 리전 | ap-northeast-2 (서울) |
| 저장소 이름 | my-web-app |
| 저장소 URI | 계정아이디.dkr.ecr.ap-northeast-2.amazonaws.com/my-web-app |
💡 AWS 계정 ID 확인하는 법:
aws sts get-caller-identity
2-5. 이미지 빌드 & 태깅 & 푸시
이미지 빌드
docker build -t my-web-app .
이미지 태깅
docker tag my-web-app:latest <계정 ID>.dkr.ecr.<리전>.amazonaws.com/my-web-app:latest
태깅은 "ECR 저장소 주소를 Docker 이미지에 붙여주는 작업
Docker 이미지 푸시 (업로드)
docker push <계정 ID>.dkr.ecr.<리전>.amazonaws.com/my-web-app:latest

3. ECS 설정 (Fargate)
🧠 ECS 관련 핵심 개념 정리
| ECS (Elastic Container Service) |
AWS에서 도커 컨테이너를 실행할 수 있게 도와주는 서비스 |
| 클러스터 (Cluster) | 컨테이너들이 모여 있는 공간 (하나의 ECS 프로젝트라고 생각하면 돼) |
| 태스크 정의 (Task Definition) | 어떤 Docker 이미지를, 어떤 설정(CPU, 포트 등)으로 실행할지 작성한 설정파일 |
| 태스크 (Task) | Task Definition을 실제로 실행한 인스턴스 (하나의 컨테이너) |
| 서비스 (Service) | 태스크(Task)를 몇 개 실행하고, 꺼지면 다시 켜주고, ALB랑 연결도 해주는 자동 관리자 |
| Fargate | AWS가 서버를 알아서 관리해주는 컨테이너 실행 방식 서버 설치/관리 필요 없음! |
3단계 흐름
(1) 클러스터 생성 → 컨테이너가 실행될 공간 만들기
(2) 태스크 정의 작성 → 어떤 이미지로 컨테이너 만들지 정의
(3) 서비스 만들기 → 그걸 몇 개 돌릴지, 퍼블릭으로 공개할지 설정
(4) ALB 연결 → URL로 접속 가능하게 만들기
✅ 3-1. 클러스터 생성 (PowerShell)
aws ecs create-cluster --cluster-name my-cluster
하나의 프로젝트 공간이라고 생각하면 됨. 나중에 서비스나 태스크는 여기서 관리됨.
✅ 3-2. IAM 역할 만들기 (ECS가 ECR 접근할 수 있도록)
아래 JSON을 trust-policy.json 이라는 이름으로 저장
{
"Version": "2012-10-17", // 정책 버전 (항상 이 값 사용)
"Statement": [{
"Effect": "Allow", // 허용(Allow) 정책
"Principal": {
"Service": "ecs-tasks.amazonaws.com" // 이 역할을 누가 사용할 수 있냐? → ECS 태스크!
},
"Action": "sts:AssumeRole" // 이 역할을 사용할 수 있는 권한 (역할 위임 허용)
}]
}
powerShell에서 실행
aws iam create-role \
--role-name ecsTaskExecutionRole \ # 역할 이름 설정
--assume-role-policy-document file://trust-policy.json # 위에서 만든 신뢰 정책 파일 지정
aws iam attach-role-policy \
--role-name ecsTaskExecutionRole \ # 방금 만든 역할
--policy-arn arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
한줄로 실행
aws iam create-role --role-name ecsTaskExecutionRole --assume-role-policy-document file://trust-policy.json
aws iam attach-role-policy --role-name ecsTaskExecutionRole --policy-arn arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy
✅ 3-3. 태스크 정의 만들기
태스크 정의(Task Definition) 은 ECS에게
👉 “이 이미지로 컨테이너를 실행해줘”
👉 “CPU, 메모리, 포트는 이렇게 설정해줘”
같은 실행 방법을 알려주는 설정 파일(JSON)
🧱 태스크 정의가 포함하는 내용들
| 항목 | 설명 |
| containerDefinitions | 어떤 컨테이너를 쓸지, 이미지 경로, 포트 등 |
| cpu / memory | 실행할 때 쓸 리소스 |
| executionRoleArn | ECR에서 이미지 가져오고 로그 쓰기 위한 IAM 역할 |
| networkMode | 네트워크 방식 (Fargate는 awsvpc 고정) |
| requiresCompatibilities | Fargate로 실행한다는 뜻 |
task-def.json
{
"family": "web-task", // 태스크 이름 (자유롭게 지정)
"networkMode": "awsvpc", // Fargate에서 꼭 필요한 네트워크 모드
"requiresCompatibilities": ["FARGATE"], // 실행 방식: EC2 아님, Fargate임
"cpu": "256", // CPU 할당량 (0.25 vCPU)
"memory": "512", // 메모리 할당량 (512 MiB)
"executionRoleArn": "arn:aws:iam::<계정ID>:role/ecsTaskExecutionRole", // ECR 접근용 IAM 역할
"containerDefinitions": [
{
"name": "web", // 컨테이너 이름 (원하는 대로)
"image": "<계정ID>.dkr.ecr.ap-northeast-2.amazonaws.com/my-web-app:latest", // ECR 이미지 주소
"portMappings": [
{
"containerPort": 80 // 컨테이너 내부에서 열리는 포트 (nginx는 80 기본)
}
]<계정ID>
}
]
}
powershell 에서 실행
aws ecs register-task-definition --cli-input-json file://task-def.json
4. 퍼블릭 배포를 위한 VPC, 서브넷, 보안그룹, ALB, ECS 서비스 만들기
이 단계에서 만들 것
| VPC | 네트워크 공간 |
| 퍼블릭 서브넷 2개 | Fargate 컨테이너가 실행될 네트워크 (서로 다른 AZ에 있어야 함) |
| 보안 그룹 | 80포트 오픈 (인터넷 접속 허용) |
| ALB (Application Load Balancer) | 사용자 요청을 컨테이너로 전달 |
| ECS 서비스 | 실제로 Fargate에 태스크를 실행시킴 |
🧭 전체 흐름
[사용자 브라우저]
↓
[ALB - 80 포트]
↓
[보안 그룹 - 80 허용]
↓
[퍼블릭 서브넷에 있는 ECS 태스크 (Fargate)]
↓
[내가 만든 Docker 컨테이너 실행됨]
4-1. 퍼블릭 VPC + 서브넷 만들기
▶ 1) VPC 생성
- AWS 콘솔 → VPC 서비스 이동
- 좌측 메뉴 VPC 대시보드 > VPC 만들기
- VPC 및 추가 리소스 선택
- 아래처럼 입력:
| 이름 태그 | my-vpc |
| IPv4 CIDR 블록 | 10.0.0.0/16 |
| 퍼블릭 서브넷 개수 | 2 (서울 리전이면 2개 AZ 자동 분배됨) |
| NAT 게이트웨이 | 없음 |
| 탄력적 IP | 체크 X |
| Auto-assign public IP | 체크 (중요!) |

4-2. 보안 그룹 만들기 (80포트 오픈)
- VPC > 보안 그룹 > 생성
- 이름: ecs-web-sg
- VPC: 위에서 만든 my-vpc
- 인바운드 규칙 추가
- 유형: HTTP
- 포트 범위: 80
- 소스: 0.0.0.0/0 (모든 외부에서 허용)

4-3. ALB (Application Load Balancer) 생성
- EC2 → 로드 밸런서 > 생성 > ALB
- 이름: ecs-web-alb
- 유형: Application Load Balancer
- 리스너: HTTP (포트 80)
- VPC: my-vpc
- 서브넷: 위에서 만든 2개 퍼블릭 서브넷 선택



대상 그룹을 선택해줘야 하니
대상 그룹을 생성 한다.
- “대상 그룹 생성” 버튼 클릭 (리스너 아래쪽에 있어)
- 아래처럼 설정:
| 대상 그룹 이름 | ecs-web-tg |
| 대상 유형 | IP 주소 (중요) |
| 프로토콜 | HTTP |
| 포트 | 80 |
| VPC | my-vpc-vpc 선택 |
| 헬스 체크 경로 | / (또는 /health 라우터가 있다면 그것도 가능) |
5. ECS 서비스 생성 (Fargate + ALB 연결)
콘솔에서 ECS 서비스 생성
📍 경로:
AWS 콘솔 → ECS > 클러스터 > my-cluster 클릭 > 서비스 생성

▶️ 1. 기본 구성
| 런타입 | FARGATE |
| 태스크 정의 | web-task:1 (버전은 1일 수도 있고 더 높을 수도 있음) |
| 플랫폼 | Fargate 그대로 |
| 서비스 이름 | web-service |
| 태스크 수 | 1 (기본 1개 실행) |
▶️ 2. 네트워킹 설정
| 클러스터 VPC | my-vpc-vpc |
| 서브넷 2개 선택 | ap-northeast-2a, ap-northeast-2b 퍼블릭 서브넷 |
| 보안 그룹 | ecs-web-sg (ALB와 동일한 보안 그룹) |
| 퍼블릭 IP 자동 할당 | ✅ 활성화(ENABLED) (중요!) |
▶️ 3. 로드 밸런싱
| 로드 밸런서 유형 | Application Load Balancer |
| 로드 밸런서 이름 | ecs-web-alb |
| 리스너 | HTTP:80 선택됨 |
| 대상 그룹 | ecs-web-tg 선택 |
최종 확인
1. ECS 서비스 > 태스크(Task)가 실행 중인지 확인
- AWS 콘솔 → ECS > 클러스터 > my-cluster > 서비스 클릭
- 아래쪽 태스크 탭 → 실행 중인지 확인

2. ALB 대상 그룹 → 대상 상태 확인 (본인이 해당됨 )
- AWS 콘솔 → EC2 > 대상 그룹
- → ecs-web-tg 클릭
- → 대상 탭으로 이동

✅ 해결 방법 (단계별 정리)
ECS 서비스 새로 생성하면서 ALB 대상 그룹 연결
- AWS 콘솔 → ECS → 클러스터 → my-cluster → 서비스 삭제 (선택)
- 서비스 생성 버튼 클릭
- 중간에 로드 밸런싱 설정 단계에서 꼭 아래 항목 확인:
| 로드 밸런서 유형 | Application Load Balancer |
| 로드 밸런서 | ecs-web-alb 선택 |
| 리스너 포트 | HTTP:80 |
| 대상 그룹 | ecs-web-tg 선택 |
| 컨테이너 이름 | web |
| 컨테이너 포트 | 80 |
이 단계에서 연결만 제대로 하면 ECS가 자동으로 컨테이너의 IP를 ALB 대상 그룹에 등록필요!!
서비스 생성 단계에서
네트워킹 , 로드 밸런싱 세팅을 하지 않았음 ..



3. 보안 그룹 확인(본인이 해당됨 )

클러스터 태스크 보안 그룹은 위와 같이 되어 있는데 ,
ALB 보안 그룹 (ecs-web-sg) 로 되어 있음
❗ 문제 요약
| 항목 | 현재 상태 | 설명 |
| ALB 보안 그룹 (ecs-web-sg) | ✅ 80포트, 0.0.0.0/0 허용 | 외부에서 접근 가능함 |
| ECS 태스크 보안 그룹 (sg-08e5b873e825321b2) | ❌ ALB 소스를 허용 안 함 | ALB → ECS 접근 차단됨 |
즉,
ALB가 ECS 컨테이너에 헬스 체크 보내는데, 방화벽에서 막힘 → timeout 발생 → Unhealthy 뜸
해결 방법
🔧 sg-08e5b873e825321b2 (ECS 태스크 보안 그룹) 에 다음 인바운드 규칙 추가:
| HTTP | TCP | 80 | sg-0b18c75d615f44300 (ALB 보안 그룹) |
마지막 으로 서비스 업데이트
