이번에는, ECS를 통해 서비스를 배포하는 방법을 알아보도록 하려고 합니다.

ECS(Elastic Container Service)는 AWS에서 제공하는 컨테이너 오케스트레이션 서비스로, 다양한 애플리케이션 컨테이너를 손쉽게 실행하고, 컨테이너를 효율적으로 분배하며 확장 또는 축소할 수 있도록 도와줍니다.
ECS는 본질적으로 컨테이너 오케스트레이션 서비스이므로, 애플리케이션을 Docker 컨테이너에서 실행할 수 있도록 설정해야 합니다.

먼저 AWS ECS 로 접속 합니다.

클러스터를 생성하러 갑시다.
클러스터 란❗️❓
Amazon ECS 클러스터는 작업 또는 서비스의 논리적 그룹입니다. 클러스터는 작업 및 서비스 외에도 다음과 같은 리소스로 구성됩니다.
[인스턴스, Fargate, 네트워크, 네임스페이스 등]ECS 클러스터는 여러 ECS 태스크(Task)와 서비스(Service)가 실행되는 논리적인 그룹입니다.
클러스터는 VPC와 서브넷을 사용해 네트워크 구성을 제어하며, 애플리케이션의 확장성, 가용성, 보안을 제공하는 역할을 합니다.

이름은 테스트 용이기 때문에 ECS-TEST-CLUSTER 로 작성 하였구요, 네임스페이스도 동일하게 지어주도록 하고 생성 하도록 하겠습니다.
✅ 태스크 정의 생성 하기 전에 ECR에 컨테이너 이미지를 올려 놔야 합니다.
ECR 에 Docker Image 를 Build & Push 하는 방법을 알고 싶다면
링크로 가셔서 Image를 Push 하고 오시면 좋아요 👍
AWS ECR Docker Image Push 하기

테스크 정의를 생성 하러갑시다. ECS 에서 테스크 정의(Task Definition)란,태스크(컨테이너의 묶음 등을) 를 실행 할때 어떤 유형 (Fargate, EC2) 으로 실행시킬지, 어떤 OS 로 실행 할지, 컴퓨팅 자원 (CPU, 메모리) 을 어떻게 사용 할 것인지 등을 선택 하는 것 입니다.
즉, 테스크 정의는 컨테이너들 을 띄울 서버의 유형/자원 등을 설정 하는 것 입니다. (ECS 에서 서비스를 배포하기 위한 최소 단위)



태스크 실행 역할의 예:
컨테이너를 실행 할 때, ECS에서 AWS 에 접근 할 때 사용 됩니다.
- ECR 및 S3 접근 등
태스크 작업 역할 의 예
실제 코드가 실행될 때 해당 IAM 역할을 통해 권한 설정이 됩니다.
// 태스크 실행 역할을 아래와 같이 설정 합니다.
// IAM > 역할 > 아래와 같은 값으로 역할 생성
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "EcsTaskExecution",
"Effect": "Allow",
"Action": [
"ecr:GetAuthorizationToken",
"ecr:BatchCheckLayerAvailability",
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": [
"*"
]
}
]
}
위와 같이 세팅 한 후, 해당 테스크 안에 컨테이너를 2개를 실행 할 예정 입니다.

백엔드 서버를 실행 시킬 컨테이너 입니다.
fastify 노드 서버를 실행 시킵니다. /hello 엔드포인트 접속시 "Hello World" 를 Return 해주는 노드 서버 입니다.fastify.get("/hello", async function (request, reply) {
return {
data: "hello world",
status: 200,
};
});

Nextjs 노드 서버를 실행 시킵니다. (프론트엔드 역할)const fetcher = () =>
fetch("http://localhost:3001/hello", { cache: "no-cache" }).then((res) => {
try {
const data = res.json();
return data;
} catch (err) {
return res.text();
}
});
export default async function Home() {
const result = await fetcher();
return (
<main className="flex min-h-screen flex-col items-center justify-between p-24">
<div className="text-xl font-bold">
{result.data} From {'"http://localhost:3001/hello"'}
</div>
// 중략
<main/>
);
}
각각의 vCPU 와 메모리는 원하는 만큼 설정 해주고, 태스크 정의를 생성 해줍니다.
✅ 서비스를 생성 하기 전에 VPC 및 Subnet에 대해서 알아가면 좋습니다.
링크로 가셔서 VPC 네트워크에 대해서 한번 확인하고 가시는 건 어떨까요?
AWS-시리즈-VPC-생성-및-구성-하기 | 배스천 호스트 구성 실습 + NAT - Private Subnet, Public

다시, 생성한 클러스트 로 가서 서비스를 생성 해줍니다.
서비스란 ❗️❓
Task의 상위의 있는 부분입니다.
- Task를 Cluster에 몇 개나 어떻게 배포할 것인지 결정하는 역할
- 로드밸런서 및 네트워크 등을 설정 하는 역할
- Task가 문제가 생기면 자동으로 새로운 Task를 생성하는 역할
- K8S의 Deployment 또는 Service와 비슷한 역할



복잡한 설정을 하지 않기 위해 네트워크는, Public Subnet으로 설정 하였습니다. 또한, 보안그룹은 3000번 포트로 들어 오는 Inbound 규칙만 열어두도록 합시다. (3)
이렇게 설정 후 서비스를 생성 하면, 아래와 같이 서비스가 생성되고 태스크를 확인하러 갈 수 있습니다.


태스크에서 구성을 찾고 퍼블릭 IP를 확인 합시다. 이 주소의 3000번 포트로 접속하게 되면,

NextJS 어플리케이션이 잘 생성 된것을 확인 할 수 있습니다. 또한, 3001번 포트로 열어둔 백엔드로의 통신이 잘 됨을 확인 할 수 있습니다.


위와 같이 백엔드 컨테이너를 띄울 태스크를 정의 합시다.


위와 같이 프론트엔드 태스크 정의를 구성 합니다.




위와 같이 프론트엔드 / 백엔드 서비스를 각각 생성 합니다.
여기서 보안그룹은 이전 과 같이 3000번 포트만 접근 가능 하도록 설정 을 하였습니다. 또한, 백엔드 서비스에서도 관리 차원에서 관리하기 쉽게 동일한 보안그룹을 설정 하도록 하겠습니다.
상황에 맞게 다른 보안 그룹을 설정하는 것이 좋습니다.
그 후, 앞서 확인 한 방법과 동일한 방법을 거쳐서 서비스를 배포하고 태스크를 실행 하고 Pulic IP를 통해 프론트엔드에 접근을 하게 되면,

당연스럽게 오류가 나옵니다. 오류 로그를 확인 하기위해 태스크의 로그를 확인 하게 되면

fetch failed , 127.0.0.1 인 로컬로의 통신 오류가 나는 것으로 확인 되었습니다.
이를 해결 하기 위해서 서비스 연결 이라는 서비스를 사용 할 것 입니다.
서비스 연결이란❓
Amazon ECS Service Connect는 ECS 클러스터 내 서비스 간 통신을 간소화하고 AWS Cloud Map을 통해 서비스 검색과 서비스 메시 기능을 제공합니다.이를 통해 VPC 및 DNS 구성을 따로 관리하지 않고 네임스페이스 내에서 쉽게 서비스 간 연결을 설정할 수 있으며, 서비스 프록시를 사용해 높은 가용성과 복원력을 갖춘 네트워크 통신을 지원할 수 있습니다.


백엔드 서비스의 구성 및 네트워킹 탭을 찾아 검색 이름의 구성을 클릭합니다.

그리고, 아래과 같이 구성을 합니다.
backend로 설정 합니다.구성을 완료하면 서비스가 재배포 됩니다.
const fetcher = () =>
fetch("http://backend:3001/hello", { cache: "no-cache" }).then((res) => {
try {
const data = res.json();
return data;
} catch (err) {
return res.text();
}
});

fetch 하는 함수를 http://backend:3001 로 통신하도록 코드를 변경하고, 새 배포 강제 구성을 통해서 새 코드를 가진 컨테이너로 강제로 변경 합니다.
그 후, 다시 프론트엔드로 접근을 하게되면

또다시 오류가 나오고, 로그를 봐도 이전과 동일하게 fetch 에 대한 오류가 나왔음을 확인 할 수 있었습니다.
프론트엔드 또한 서비스 연결 구성을 합시다.

서버로의 요청을 할 수 있게, 클라이언트 측만 해당을 통해 프론트엔드 서비스 또한 서비스를 연결 할 수 있도록 설정 합시다.
그러고, 다시 확인 하게 되면 아래와 같은 에러 로그를 확인 할 수 있습니다

fetch 에러와 다른 에러가 나왔음을 확인 할 수 있었습니다.또한, 프론트엔드에 접근 하게되면 오류 화면 대신 화면 뜨기까지 시간이 오래 걸리는 것을 확인 할 수 있습니다.
이를 통해 보안그룹 문제라는 것을 알 수 있습니다.

현재 VPC에서 3001 포트 로 접근 할 수 있도록 인바운드 규칙을 열어두고 프론트엔드 화면을 확인 하게 되면

정상적으로 화면에서 백엔드와의 통신이 이뤄지는 것을 확인 할 수 있었습니다.
제가 찾고있던 내용인데 정말 정리를 잘 해주셨군요ㅠㅠ 감사합니다