솜이의 데브로그

Github Action 이용해서 Spring 프로젝트를 EC2에 배포하기 (ECR, ECS 이용) 본문

dev/etc

Github Action 이용해서 Spring 프로젝트를 EC2에 배포하기 (ECR, ECS 이용)

somsoming 2022. 12. 7. 00:00

Spring 프로젝트를 ecr, ecs를 이용해 배포해보자

 

내가 하고자하는 로직은 다음과 같다.

 

1. 스프링 프로젝트를 github action 이용해서 특정 브랜치에 머지할 때 배포되도록 하고자 함.

2. 배포는 먼저 ECR에 도커 이미지를 빌드해서 푸시한다.

3. ECS 를 이용해서 ECR에 있는 도커 이미지를 가지고 오고, EC2에 배포한다.

 

 

예제들이 보통 ECS를 사용하면 fargate를 사용하거나 스프링프로젝트가 아니었어서 대략적으로 작성해본다.

 

1. ECR 생성하기

AWS에서 Amazon Elastic Container Registry 를 생성한다.

ECR은 원하는 대로 private 또는 public으로 이름을 지정하여 생성한다. 나는 private으로 진행하였다.

여기서 생성만 하면 끝난다.

 

 

2. 작업정의 (Task Definition) 생성하기

 

task definition은 docker-compose 와 유사한 역할을 한다. 원하는 옵션들을 지정하여 컨테이너를 올려준다.

이 작업정의를 생성하기 전에, 먼저 Amazon ECS task execution IAM role 을 생성해야한다.

 

2-1. AWS IAM 생성

ecsTaskExecutionRole을 만들것입니다

Identity and Access Management(IAM) - 역할 - 역할만들기 클릭

아무것도 건들지말고  맨밑에 다른AWS 서비스의 사용 사례 에서 Elastic container Service 선택 - Elastic container Service Task 선택

 

AmazonECSTaskExecutionRolePolicy 검색 후 선택

역할 이름을 ecsTaskExecutionRole 로 설정하고 생성

 

2-2. 작업정의 생성

 

Amazon ECS - 작업정의 - 새 작업정의 생성 클릭

우리는 EC2로 만들것이니까 EC2 선택 (Fargate가 더 편하지만.. EC2가 프리티어를 지원해주기 때문에 ec2를 선택했다)

비교를 하고 싶다면 여기 참고

 

원하는 태스크정의 이름 입력, 태스크 역할과 작업 실행 역할은 아까 만든 ecsTaskExecutionRole을 선택하자

나는 그 밑에 작업 크기는 아무것도 지정하지 않았다.

 

컨테이너를 추가해주고, 이미지는 아까 만든 ecr 링크:latest 로 지정했다.

그래서 ecr에 도커 이미지가 푸시되면, 가장 최근에 푸시된 이미지를 사용하도록 했다.

나머지 설정은 원하는대로 설정

나는 포트매핑도 해줬다

 

그 외 설정은 다 default로 했고, 스토리지 및 로깅에도 Auto-configure CloudWatch Logs 체크를 했다.

이렇게 하면 CloudWatch에서 로그를 확인할 수 있다.

 

이렇게 컨테이너까지 추가하면 작업정의 생성 완료!

 

 

3. ECS  Cluster 생성하기

이제 ECS 클러스터를 생성해보자.

Amazon ECS - 클러스터 - 클러스터 생성 클릭

EC2로 만들거니까 EC2 Linux + 네트워킹 클릭 후 다음단계로 넘어가기

원하는 이름 입력, 온디맨드 인스턴스 클릭 (사용하는 만큼만 요금 지불하기 위해서 해당 옵션 선택)

EC2 인스턴스 유형은 원하는 유형으로 선택하면되는데, 나는 프리티어로 사용하고 싶어서 t2.micro 선택했다.

인스턴스 개수는 1개만 (이것도 원하는만큼 선택하면 되는데 일단 나는 한개만!)

EC2 AMI ID는 디폴트로 설정해주는게 권장값이라 그대로 두었고, 키페어는 SSH 접속하기 위해서 생성 후 지정해주었다. (사진에는 지정 안한 상태로 표시)

VPC 생성을 하면 Cloud Formation을 통해 자동으로 생성해준다.

그리고 아까 task definition 에서 포트를 8080으로 지정해줬기 때문에, 여기서 보안 그룹 인바운드 규칙에 8080을 추가해주었다.

(사진에는 역시 80번만 추가된 상태이므로 따로 추가해줘야함!)

나중에 확인했을 때 이런식으로

 

마지막으로 컨테이너 인스턴스 IAM 역할은 ecsInstanceRole 선택

그러면 클러스터 생성이 완료된다

 

 

4. ECS Service 생성하기

생성한 클러스터에서 서비스-생성 클릭

시작유형 EC2 선택

작업정의는 아까 생성한 작업정의

개정은 latest 최근꺼로

클러스터도 아까 생성한 클러스터 이름

서비스 이름은 원하는대로 지정

서비스 유형 : REPLICA

작업개수 1

나는 최소 정상 상태 백분율은 0, 최대 백분율은 200으로 지정했다.

 

 

작업 배치 옵션은 이렇게 선택

 

로드밸런서 없음 Auto Scaling 선택 안함

서비스 생성

(추후에 필요하면 따로 지정해서 변경하는걸로!)

 

5. 배포 스크립트 작성

자, 이제 AWS에서 필요한 것은 모두 생성했다!

그럼 github action에서 배포되는 스크립트를 작성해보자.

 

일단 기본적으로 ECR에 도커 이미지를 푸시하는것까지는 지난번에 올렸던 글과 동일하게 진행한다.

참고

https://somsoming9.tistory.com/143

 

Github Action 이용해서 AWS Lambda에 도커 이미지 자동 배포하기

AWS Lambda란? Lambda는 서버를 프로비저닝하거나 관리하지 않고도 코드를 실행할 수 있게 해주는 컴퓨팅 서비스입니다. Lambda는 고가용성 컴퓨팅 인프라에서 코드를 실행하고 서버와 운영 체제 유지

somsoming9.tistory.com

 

깃헙 레포가서 Actions 클릭

Deploy to Amazon ECS 선택

 

여기서 템플릿을 채우면 된다.

또는 그냥 직접 템플릿 작성. 나는 직접 작성했다.

여기서 주의할 점은 스프링 프로젝트를 빌드할것이기 때문에 JDK 나 gradle 명령어를 추가해준다!

 

먼저 프로젝트 루트 디렉토리에 Dockerfile을 추가한다.

내가 작성한 Dockerfile

#openjdk:11 image
FROM openjdk:11-jdk

#jar파일 생성 후 복사
ARG JAR_FILE=build/libs/*.jar
COPY ${JAR_FILE} app.jar

#컨테이너가 실행될 때 명령어 수행
CMD ["java","-jar","/app.jar"]

 

 

프로젝트 루트 디렉토리에 .github/workflows/deploy.yml 파일 생성

(.github/workflows 까지는 반드시 만들어야하는 디렉토리이고, 그 아래 파일명은 원하는대로 생성가능)

 

내가 작성한 deploy.yml 파일 템플릿

name: Deploy Backend to Amazon ECS
on:
  push:
    branches:
      - 'main'

jobs:
  deploy:
    name: Deploy
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v1

      - name: Set up JDK 11
        uses: actions/setup-java@v1
        with:
          java-version: 11

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ${{ secrets.AWS_REGION }}

      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v1

      - name: Grant execute permission for gradlew
        run: chmod +x ./gradlew
        shell: bash

      - name: Build with Gradle
        run: ./gradlew clean build
        shell: bash

      - name: Build, tag, and push image to Amazon ECR
        id: build-image
        env:
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
          ECR_REPOSITORY: {REPOSITORY_NAME}
          IMAGE_TAG: latest
        run: |
          docker buildx build --platform=linux/amd64 -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
          echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG"
      - name: Download task definition
        run: |
          aws ecs describe-task-definition --task-definition {TASK_DEFINITION_NAME} --query taskDefinition > task-definition.json
      - name: Fill in the new image ID in the Amazon ECS task definition
        id: task-def
        uses: aws-actions/amazon-ecs-render-task-definition@v1
        with:
          task-definition: task-definition.json
          container-name: {CONTAINER_NAME}
          image: ${{ steps.build-image.outputs.image }}

      - name: Deploy Amazon ECS task definition
        uses: aws-actions/amazon-ecs-deploy-task-definition@v1
        with:
          task-definition: ${{ steps.task-def.outputs.task-definition }}
          service: {SERVICE_NAME}
          cluster: {CLUSTER_NAME}
          wait-for-service-stability: true

여기에 {NAME} 입력하라고 되어있는 곳에만 해당 이름 입력하면 된다.

 

자 그럼 이제 github secrets 가서 AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION 을 각각 입력해주자.

액세스 키 id와 키는 IAM - 보안자격증명 - 액세스키 에서 발급 및 관리할 수 있다.

 

이렇게 설정하면 이제 main 브랜치에 푸시할때마다 github action이 자동으로 실행되면서 자바 파일을 빌드하고, 도커파일을 이용해 도커 이미지를 빌드 후 ECR에 이미지 푸시, 작업정의가 돌아가면서 ECS를 이용해 EC2 배포가 실행된다!

끝!

 

참고링크들

참고1

참고2