Amazon ECS 실습하기 - 서비스 배포하기

Jaewoong2·2024년 10월 13일
post-thumbnail

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

  1. 태스크 안에 2개의 컨테이너를 넣고 1개의 서비스로 배포 하고, API 통신 하는 방법
  2. 2개의 컨테이너를 각각의 태스크로 생성하고 2개 서비스로 배고, API 통신 하는 방법

ECS 란?

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

ECS는 본질적으로 컨테이너 오케스트레이션 서비스이므로, 애플리케이션을 Docker 컨테이너에서 실행할 수 있도록 설정해야 합니다.

ECS 배포 실습하기

ECS 들어가기

먼저 AWS ECS 로 접속 합니다.

ECS 클러스터 생성하기

클러스터를 생성하러 갑시다.

클러스터 란❗️❓

Amazon ECS 클러스터는 작업 또는 서비스의 논리적 그룹입니다. 클러스터는 작업 및 서비스 외에도 다음과 같은 리소스로 구성됩니다.
[인스턴스, Fargate, 네트워크, 네임스페이스 등]

ECS 클러스터는 여러 ECS 태스크(Task)서비스(Service)가 실행되는 논리적인 그룹입니다.

클러스터는 VPC와 서브넷을 사용해 네트워크 구성을 제어하며, 애플리케이션의 확장성, 가용성, 보안을 제공하는 역할을 합니다.

클러스터 구성 - 이름 및 인프라 설정

이름은 테스트 용이기 때문에 ECS-TEST-CLUSTER 로 작성 하였구요, 네임스페이스도 동일하게 지어주도록 하고 생성 하도록 하겠습니다.

태스크 안에 컨테이너 2개 실행 하고, 통신 테스트 하기

태스크 정의 생성 하기

✅ 태스크 정의 생성 하기 전에 ECR에 컨테이너 이미지를 올려 놔야 합니다.
ECR 에 Docker Image 를 Build & Push 하는 방법을 알고 싶다면
링크로 가셔서 Image를 Push 하고 오시면 좋아요 👍
AWS ECR Docker Image Push 하기

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

즉, 테스크 정의는 컨테이너들 을 띄울 서버의 유형/자원 등을 설정 하는 것 입니다. (ECS 에서 서비스를 배포하기 위한 최소 단위)

  • 태스크 정의 당 하나 이상의 컨테이너 정의 가능 (최대 10)

  • 테스크 정의 패밀리의 이름 설정 및 인프라 유형 설정을 합니다. 저는 Fargate로 시작 하도록 하겠습니다.

  • 또한, OS 및 네트워크 모드 (Fargate는 awsvpc 모드 고정 입니다)

  • 태스크 역할 및 태스크 실행 역할을 설정 합니다.

태스크 실행 역할의 예:
컨테이너를 실행 할 때, 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 노드 서버를 실행 시킵니다. (프론트엔드 역할)
    해당 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)

이렇게 설정 후 서비스를 생성 하면, 아래와 같이 서비스가 생성되고 태스크를 확인하러 갈 수 있습니다.

태스크 에서 NextJS 확인하기

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

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

컨테이너당 태스크 및 서비스 생성하고 API 테스트 하기

태스크 정의 생성 하기

백엔드 태스크 정의 구성

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

프론트엔드 태스크 정의 구성

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

서비스 생성 하기

프론트엔드 서비스, 백엔드 서비스 각각 생성하기


  • 프론트엔드 서비스 생성


  • 백엔드 서비스 생성

위와 같이 프론트엔드 / 백엔드 서비스를 각각 생성 합니다.

여기서 보안그룹은 이전 과 같이 3000번 포트만 접근 가능 하도록 설정 을 하였습니다. 또한, 백엔드 서비스에서도 관리 차원에서 관리하기 쉽게 동일한 보안그룹을 설정 하도록 하겠습니다.

상황에 맞게 다른 보안 그룹을 설정하는 것이 좋습니다.

그 후, 앞서 확인 한 방법과 동일한 방법을 거쳐서 서비스를 배포하고 태스크를 실행 하고 Pulic IP를 통해 프론트엔드에 접근을 하게 되면,

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

fetch failed , 127.0.0.1 인 로컬로의 통신 오류가 나는 것으로 확인 되었습니다.

이를 해결 하기 위해서 서비스 연결 이라는 서비스를 사용 할 것 입니다.

서비스 연결이란❓
Amazon ECS Service Connect는 ECS 클러스터 내 서비스 간 통신을 간소화하고 AWS Cloud Map을 통해 서비스 검색과 서비스 메시 기능을 제공합니다.

이를 통해 VPC 및 DNS 구성을 따로 관리하지 않고 네임스페이스 내에서 쉽게 서비스 간 연결을 설정할 수 있으며, 서비스 프록시를 사용해 높은 가용성과 복원력을 갖춘 네트워크 통신을 지원할 수 있습니다.

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

그리고, 아래과 같이 구성을 합니다.

    1. 클라이언트 및 서버 클릭
    1. 서비스 연결 서비스 에서 백엔드 포트 별칭을 누르고, 검색 및 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 포트 로 접근 할 수 있도록 인바운드 규칙을 열어두고 프론트엔드 화면을 확인 하게 되면

정상적으로 화면에서 백엔드와의 통신이 이뤄지는 것을 확인 할 수 있었습니다.

profile
DFF (Development For Fun)

2개의 댓글

comment-user-thumbnail
2024년 10월 15일

제가 찾고있던 내용인데 정말 정리를 잘 해주셨군요ㅠㅠ 감사합니다

1개의 답글