[AWS] ECS로 서버 배포 및 자동화하기
사용할 것들.
ECS + ECR + Docker + S3 + 로드밸런서 + Route53 + Github Action
서버환경
Nest.js (뭘로해도 상관없음)
ECS는 쿠버네티스까지 올리기는 뭐한데, 그렇다고 조촐하게 인스턴스를 직접 제어하고 싶지는 않을때, 그 중간점으로 적절한 선택이다.
내가 배포에 사용할 프로세스는 다음과 같다.
- 미리 작성해둔 기반 docker 이미지를 ECR에서 가져옴.
- 도커 빌드로 바로 실행시킬 수 있도록 처리 (종속성 설치, 컴파일, S3에서 환경변수 다운로드)
- 빌드한 이미지를 업로드
- ECS에 올라간 이미지로 작업정의 업데이트
꼭 이런 방식으로 해야하는건 아니고, 상황에 따라 변용하면 된다.
가령 내 경우에는 환경변수값을 비공개 S3에 저장해놓고 썼지만, 아예 다른 파일DB나 Key-Value DB 등에 저장해놓고 써도 무방하다.
ECR 생성 및 이미지 작업
먼저 ECR에 들어가서 배포용 이미지를 관리할 도커 레포지토리를 만들어준다.

이에 대한 자세한 내용은 다음 포스트를 참조하길 바란다.
https://blog.naver.com/sssang97/222459232906
그리고 우분투 베이스로 해서 "test-repo:base"의 형태로 기반 이미지 파일을 작성해 push해뒀다.
도커빌드 작성
배포 올라갈때 컴파일을 해도 되긴 되지만, 그러면 올라가는 속도가 느려지고 자원을 더 많이 먹게 된다.
그래서 웬만하면 빌드 떠놓은채로 이미지를 올리는게 낫다.
내 경우에는 다음과 같이 빌드파일을 작성해뒀다.
FROM ....dkr.ecr.ap-northeast-2.amazonaws.com/test-backend:base
ENV TZ=Asia/Seoul
ENV HOME=/home
WORKDIR $HOME/test-backend
RUN git branch master
RUN git checkout master
RUN git pull origin master
RUN aws s3 sync s3://test-env/test-backend . # 환경변수 다운로드
RUN npm i # 의존성 설치
RUN npm run build:prod # 컴파일
WORKDIR $HOME
EXPOSE 80
COPY ./run.sh ./run.sh # 실행파일 이동
CMD sh /home/run.sh # 실행
그리고 빌드해서 배포용 태그로 한번 올려준다.
내 경우에는 :latest 태그를 배포용으로 사용했다.
클러스터 생성
먼저 사용할 클러스터를 적절히 생성해준다.
기본값인 네트워킹 전용으로 고르고,
이름만 잘 지어준다.
작업 정의 생성
그럼 이번엔 실제로 클러스터에 올라갈 작업정의를 만들어주자.
웬만하면 Fargate로 하는게 정신건강에 이롭다.
이름 잘 지어주고
메모리와 CPU 양을 지정해준다.
보통 저정도면 충분할 것이다. 부하 늘면 스케일링하면 되고
컨테이너에 방금 만들었던 배포용 이미지를 지정해주고, 포트 매핑까지 해주면, 끝이다.
이대로 만들어주자.
대상 그룹 생성
서비스를 만들기 전에 로드밸런서부터 만들어둬야 하는데, 로드밸런서를 만들려면 대상그룹부터 만들어야 한다.
만드는 법은 어렵지 않다.
IP Address 모드로 선택해주고, 이름 잘 짓고, VPC를 옳게 넣어준다.
vpc는 그냥 이름으로 넣으면 된다.

그러고 생성만 해주면 된다.
로드밸런서 생성
이제 로드밸런서를 만들어주자.
어플리케이션 로드밸런서로 하고

이름 잘 짓고

늘 그렇듯이 가용영역 잘 박아주고

아까 만든 대상그룹을 리스너에 넣어주면 된다.

그리고 도메인 인증서도 있으면 잘 넣어준다.
이래야 HTTPS 연동이 잘 될 것이다.
클러스터에 서비스 생성
다음엔 클러스터에 방금 만든 작업정의를 기반으로 "서비스"를 생성하면, 이제 기본적인 세팅은 거의 다 된 것이다.
클러스터와 작업정의를 잘 넣어주고, 이름 잘 지어주고, 작업 개수 지정해주면 된다.
방금 만든 로드밸런서를 넣어준다.


그러면 서비스와 함께 작업목록이 뜰텐데, 아무거나 들어가서

링크로 접속 잘 되는지 보고

로드밸런서 엔트포인트도 잘 들어가지는지 보자.
다 잘 되면 된 것이다.
도메인 연동
이번엔 도메인을 붙여주자.
이미 route53에 도메인이 다 들어있다는 전제 하에 진행하겠다.
해당 도메인 항목에 들어가서 레코드 생성 클릭.
마법사 모드로 전환해서 단순 라우팅.

서브도메인 잘 지정해주고, 로드밸런서 찾아서 붙여주면 끝이다.

그렇게 해서 잘 호출되면 된다.

Github Action 연동
그럼 이제 저걸 push할때마다 자동으로 올라가게 해보자.
내가 사용한 action 로직은 다음과 같다.
# This workflow will build and push a new container image to Amazon ECR,
# and then will deploy a new task definition to Amazon ECS, when a release is created
#
# To use this workflow, you will need to complete the following set-up steps:
#
# 1. Create an ECR repository to store your images.
# For example: `aws ecr create-repository --repository-name my-ecr-repo --region us-east-2`.
# Replace the value of `ECR_REPOSITORY` in the workflow below with your repository's name.
# Replace the value of `aws-region` in the workflow below with your repository's region.
#
# 2. Create an ECS task definition, an ECS cluster, and an ECS service.
# For example, follow the Getting Started guide on the ECS console:
# https://us-east-2.console.aws.amazon.com/ecs/home?region=us-east-2#/firstRun
# Replace the values for `service` and `cluster` in the workflow below with your service and cluster names.
#
# 3. Store your ECS task definition as a JSON file in your repository.
# The format should follow the output of `aws ecs register-task-definition --generate-cli-skeleton`.
# Replace the value of `task-definition` in the workflow below with your JSON file's name.
# Replace the value of `container-name` in the workflow below with the name of the container
# in the `containerDefinitions` section of the task definition.
#
# 4. Store an IAM user access key in GitHub Actions secrets named `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY`.
# See the documentation for each action used below for the recommended IAM policies for this IAM user,
# and best practices on handling the access key credentials.
# Controls when the workflow will run
on:
# Triggers the workflow on push or pull request events but only for the main branch
push:
branches:
- master # master에 반응해 동작
workflow_dispatch:
name: Deploy Server to Amazon ECS (LIVE)
jobs:
deploy:
name: Deploy
runs-on: ubuntu-latest
environment: production
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v1
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} # S3 접근용 키 (github sercret으로 넣어둠)
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} # S3 접근용 키
aws-region: ap-northeast-2
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v1
- name: Build, tag, and push image to Amazon ECR
id: build-image
env:
ECR_REGISTRY: # ECR 엔드포인트
ECR_REPOSITORY: # ECR 레포지토리 이름
IMAGE_TAG: latest # 배포용 이미지 태그
run: |
# Build a docker container and
# push it to ECR so that it can
# be deployed to ECS.
docker image prune -a
docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG ./ecs/master # 여기에 도커파일 넣어둠
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG"
- name: Deploy Amazon ECS task definition
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
with:
task-definition: ./ecs/master/task-definition.json # 작업정의 설정파일
service: 서비스명
cluster: 클러스터명
wait-for-service-stability: true
그리고 저기서 task-definition.json 파일은 직접 작성해도 되긴 하는데, 이미 만들어둔거 긁어오는게 편하다.
작업 정의 들어가서 JSON 탭 누르고
복붙해오면 된다.
이렇게 해서 터지지 않고 잘 올라가면 끝이다.
참조
https://aws.amazon.com/ko/premiumsupport/knowledge-center/create-alb-auto-register/