ECS Cluster 생성

Cluster란?
ECS 클러스터는 Docker Container를 실행할 수 있는 논리적인 공간이다.
ECR에 등록한 Docker Image를 가지고 컨테이너를 구성하려면 이 클러스터를 생성 및 사용해야 한다.

클러스터 이름을 sample-cluster로 짓고, 나머지 설정은 그대로 둔 후 생성한다.

인프라 탭에서 주로 Fargate와 EC2 인스턴스 둘을 사용한다.
간략하게 두 인프라의 차이점을 살펴보면 아래와 같다.


EC2인스턴스
EC2는 AWS에 대표적인 서비스 중 하나이다. 주로 서버로 사용하며, 비용을 지불하고 가상의 서버를 대여 받을 수 있다.

ECS 서비스를 구축할 때 EC2 인스턴스를 인프라로 선택하면 서비스에 속한 EC2 인스턴스 서버와 클러스터를 직접 관리해주어야 한다.

Fargate
EC2 인스턴스와 다르게 서버 인스턴스를 관리할 필요가 없는 컨테이너 서비스이며 사용량에 따라 요금이 부과되는 종량제 형식으로 제공된다.
(서버리스란 서버가 없다는 것이 아니다. 서버가 필요한 순간이 왔을 때 잠시 서버를 깨워 기능을 수행하고 다시 잠든다. 이렇게 종량제 서비스가 되는 것이다.)

EC2 인스턴스와 Fargate는 상황에 맞게 잘 고려해서 선택하면 될 것 같다.


Task 정의 생성

다시 본론으로 돌아와서 클러스터를 생성했다면, 이제 Task 정의를 생성한다.

클러스터를 생성할 때 인프라를 Fargate로 생성했으니 시작 유형을 AWS Fargate로 설정한다.
태스크 크기는 CPU : 0.25vCPU, 메모리 : 0.5GB 으로 설정한다. (캡처와 다르니 참고)

컨테이너 이름은 sample로 지었다.
이미지 URI는 지난번 ECR에 등록된 이미지 URI를 복사해서 사용한다.
여기서 주의할 점이 있는데, 레포지토리 URI가 아닌 이미지 URI를 복사해야한다.
(그래야 sample:${version}까지 복사된다.)


다음, 포트 매핑에서는 컨테이너 포트를 7000으로 설정한다.
Docker File에서 Port를 7000으로 설정했기 때문에 여기서도 맞춰준다.

이후에는 기본 값으로 두고 작업을 생성한다.


서비스 생성

앞서 클러스터와 Task를 정의 한 것은 바로 서비스를 생성하기 위함이다.
이제 대망의 서비스를 올려보자!

생성한 ECS 클러스터를 클릭하면 서비스 생성이 가능하다.


컴퓨팅 옵션 : 시작 유형
시작 유형 : Fargate
플랫폼 버전 : LATEST



태스크 : 2 (Fargate 인스턴스가 2개 생성된다.)



네트워킹은 별도로 건들지 않았다.
로드밸런서 및 대상 그룹은 서비스를 생성하며 함께 생성해준다.


서비스가 정상적으로 생성되고 활성화가 되었다.

이제서야 비로소 개인 프로젝트가 모든 서버 인스턴스에 Docker를 통한 동일한 서비스 환경을 구축한 것이다.

아래 로드밸런서 DNS 이름의 주소를 가지고 웹에서 나의 프로젝트를 확인할 수 있다.

결과 화면


마무리하며

포스팅을 하면서 서버와 네트워크에 대해 점점 친숙해지는 기분이다.
사실 여기까지의 과정에서 우여곡절이 많았지만 시간이 걸려도 해내면 그만이다.

다음 포스팅에서는 Git을 통한 ECS 서비스 자동 생성을 구현해볼 예정이다.

글을 읽으시는 모든 분들께 알량한 나의 지식이 도움이 되었으면 한다.

Docker란 무엇인가?

Docker는 컨테이너화 기술을 사용하여 애플리케이션을 개발, 배포 및 실행하는 데 사용되는 오픈 소스 플랫폼 및 생태계이다. Docker를 사용하면 애플리케이션과 그 종속성을 컨테이너라고 하는 경량 가상 환경에 패키징할 수 있으며, 이러한 컨테이너는 호스트 시스템과 독립적으로 실행다.

Docker의 주요 특징과 개념

  1. 컨테이너: Docker 컨테이너는 애플리케이션, 라이브러리 및 종속성을 패키징하는 데 사용되는 경량 환경이다. 각 컨테이너는 격리된 환경에서 실행되며 호스트 시스템과 공유 커널을 사용한다.

  2. 이미지: Docker 컨테이너를 생성하기 위한 템플릿으로서, 이미지는 애플리케이션과 해당 종속성을 포함한다. 이미지는 컨테이너를 여러 환경에서 생성하고 실행하는 데 사용된다.

  3. 도커 엔진: Docker 엔진은 컨테이너를 관리하고 실행하는 핵심 구성 요소이다. Docker 엔진은 Docker 데몬 및 Docker CLI(Command Line Interface)를 포함하며 컨테이너 작업을 제어한다.

  4. 이식성: Docker 컨테이너는 호스트 환경과 독립적이므로 어디에서나 실행할 수 있다. 이는 개발 환경에서 프로덕션 환경으로 애플리케이션을 이동할 때 매우 유용하다.

  5. 자동화: Docker를 사용하면 애플리케이션의 빌드, 배포 및 스케일링을 자동화할 수 있다. Docker Compose 및 Kubernetes와 같은 도구를 통해 애플리케이션 스택을 정의하고 관리하는 데 도움을 준다.

  6. 확장성: Docker 컨테이너는 가벼우면서 확장 가능하므로 대규모 애플리케이션 배포 및 관리에 적합하다.

Docker는 개발자, 운영팀 및 DevOps 엔지니어 등에게 애플리케이션 배포 및 관리를 단순화하고 효율적으로 관리할 수 있는 강력한 도구이다. 컨테이너화 기술은 애플리케이션의 일관성, 이식성 및 확장성을 향상시키는 데 도움이 된다.


Docker 사용법

Docker의 동작 순서

DockerFile : Container를 어떻게 만들어야 하는지에 대한 설명서 느낌이다.

Image : Docker 파일을 가지고 만들 수 있다.

Container : Image를 고립된 환경(개별적인 FileSystem 안에서) 에서 실행할 수 있는 단위


주요 인스트럭션

FROM : base image를 지정. 주로 OS 이미지나 런타임 이미지를 지정

RUN : 이미지를 빌드할 때 사용되는 커맨드를 설정할 때 사용

ADD : 이미지에 호스트의 파일이나 폴더를 추가하기 위해 사용.
만약 이미지에 복사하려는 디렉토리가 존재하지 않으면 docker가 자동으로 생성

COPY : 호스트 환경의 파일이나 폴더를 이미지 안으로 복사하기 위해 사용
'ADD'와 동일하게 동작하지만 가장 확실한 차이점은
URL을 지정하거나, 압축파일을 자동으로 풀지 않음

EXPOSE : 이미지가 통신에 사용할 포트를 지정할 때 사용

ENV : 환경 변수를 지정할 때 사용
여기서 설정한 변수는 $name, ${name}의 형태로 사용 가능
추가로 아래와 같은 문법으로 사용할 수 있음
- ${name:-else} : name이 정의가 안되어 있다면 'else'가 사용됨

CMD : 도커 컨테이너가 실행될 때 실행할 커맨드를 지정
'RUN'과 유사하지만 CMD는 도커 이미지를 빌드할 때 실행되는 것이 아니라
컨테이너를 시작할 때 실행된다는 것이 다름

ENTRYPOINT : 도커 이미지가 실행될 때 사용되는 기본 커맨드를 지정 (강제)

WORKDIR : RUN, CMD, ENTRYPOINT 등을 사용한 커맨드를 실행하는 디렉토리를 지정
-w 옵션으로 오버라이딩 할 수 있음

VOLUME : 퍼시스턴스 데이터를 저장할 경로를 지정할 때 사용
호스트의 디렉토리를 도커 컨테이너에 연결
주로 휘발성으로 사용되면 안되는 데이터를 저장할 때 사용

DockerFile 생성

FROM node:18-alpine

WORKDIR / app

COPY package.json package-lock.json ./

RUN npm ci

COPY routes/index.js .

ENTRYPOINT [ "node", "index.js" ]

DockerFile 설명

코드 설명 하기 전에 알아둘 점
도커는 레이어 시스템을 차용했기 때문에 빈번하게 발생하는 작업은 아래쪽에 작성해준다.
그러면 가장 빈번한 작업은 레이어의 제일 위쪽에 위치하게 된다.
이미지를 만들 때 변경된 사항부터 이후 단계들에 대해서만 새로 만들고 변경이 없는 레이어는 캐시된 데이터를 그대로 사용한다.
이게 무슨 말인가 하면, 위 코드 맨 첫 줄부터 Layer0 ~ Layer5가 되며, index.js 파일이 변경 되면 이미지를 만들 때 Layer4, 5만 새로 작성한다는 의미이다.
따라서 Docker File을 잘 작성하면 이미지 생성시 불필요한 작업을 줄여 성능을 개선시킬 수 있다.

  • FROM node:18-alpine
    => 베이스 이미지를 설정한다. node의 경우는 전용 베이스 이미지를 지원하기 때문에 node:[version] 형식으로 설정한다.

  • WORKDIR / app
    => root 경로에 있는 app이라는 디렉토리에 우리 프로젝트에 관련된 모든 파일들을 copy해오겠다라는 뜻.

  • COPY package.json package-lock.json ./
    => 프로젝트에 필요한 모듈들에 대한 정보가 들어 있는 package 파일을 copy한다.

  • RUN npm install or ci
    => package.json / package-lock.json에 설정된 모듈을 설치한다.
    => npm install을 사용할 경우 특정 라이브러리에서 ‘버전 몇 이상은 다 괜찮다’ 라고 명시를 해주면 최신 버전이 나올 때마다 해당 버전을 새로 설치한다. 그러나 ci를 사용하면 package-lock.json에 설정된 버전 그대로 설치한다.

  • COPY index.js
    => index.js 파일을 copy한다.

  • ENTRYPOINT [”node”, “index.js”]
    => node를 실행하고, index.js를 실행한다.

Docker File로 Image 및 Container 만들기

Docker build

$docker build -f Dokcerfile -t today-lunch .

위 명령어를 해석하면 아래와 같다.
docker build - 말 그대로 도커를 빌드한다는 뜻.
-f Dockerfile - Dockerfile이라는 파일명을 가진 DockerFile을 명시한다.

만약 도커파일명이 다르다면 -f [도커파일명]을 작성한다.
-t image name - 도커이미지의 이름을 부여
위 명령어가 제대로 실행되면 도커 이미지가 생성된다.

Docker Image 생성

docker images

이미지에 대한 정보를 확인할 수 있다.

Docker Container 실행

docker run -d -p 8080:8080 today-lunch

-d (detached) - 컨테이너를 백그라운드에서 실행하겠다는 의미
-p (port 지정) - host machine의 포트 8080과 container의 포트 8080을 연결해주는 작업

컨테이너 정보 확인

docker ps

Next.js 샘플 프로젝트를 Git Workflow / Action을 통해 AWS ECS로 자동 배포하는 시스템을 구축해보려 한다.


자동 배포 sequence

아래와 같은 순서를 거쳐 최종적으로 AWS ECS에 프로젝트가 자동 배포되는 과정을 경험해보고자 한다.

  1. Next.js 프로젝트 생성 및 배포
  2. Git workflow 작성
  3. AWS ECS 서비스에 연동

uml diagram

선행되어야 할 학습 내용

  • Next.js 설치 및 프로젝트 생성
  • Git / Github - workflow 설정과 Git Action
  • AWS
    • Route53 - 도메인 호스팅
    • EC2 - 클라우드 인스턴스
    • Load Balancer - 인스턴스에 접근할 트래픽 분산 처리
    • ECR - Docker Image의 저장소
    • ECS - ECR에 저장된 Docker Image를 기반으로 인스턴스를 생성하는 서비스
  • Docker - 배포한 시스템이 모든 환경에서 동일할 수 있도록 컨테이너라는 청사진 역할을 하는 시스템 구축 환경 제공

+ Recent posts