AWS

[AWS] 아키텍쳐 구현(2): Github Action으로 AWS ECS CI / CD 자동화

ShinySinee 2024. 8. 14. 22:42

 

https://2hy2on.tistory.com/17

 

[AWS] 아키텍쳐 구현(1) : HTTPS 및 로드밸런서 적용

현재 내가 완성시키고자 하는 아키택쳐는 아래와 같다.사전 준비 상태1) VPC 생성 완료2) private subnet 2개, public subnet 2개 ig와 연결 완료3) kafka용 ec2 설치 완료4) public 도메인 구매 완료 이번 포스팅

2hy2on.tistory.com

지난 시간에 이어서 ecs와 lb 연결 및 배포 테스트를 진행해보겠다.

 

1. ECR 생성

Private registory > Repositories > 리포지토리 생성 클릭

2. Task 생성

ECS > 테스크 정의 >y > Repositories > 새 테스크 정의 생성 클릭

 

 

아까 생성한 ecr에 들어가 푸시 명령어 보기에 있는 이미지 URL을 복사해온다.

컨테이너 포트는 8080으로 설정해준다.

정상적으로 task가 생성된 것을 확인할 수 있다.

 

3. Cluster 생성

ECS > 클러스터 > 클러스터 생성 클릭

4. Service 생성

클러스터 > 생성한 클러스터 > 서비스 삭제 옆 생성 클릭

 

패밀리에는 아까 생성한 task를 선택해준다.

보안 그룹은 HTTPS, HTTP가 아닌 8080으로 해준다!!!! (아래 이슈 참고)

 

이전에 만들었던 로드밸런서를 설정해준다.

상태확인은 HTTP로 설정한다. 스프링 부트 애플리케이션이 동작할 때 기본적으로 HTTP 프로토콜을 사용하게 설정했기 때문이다.

5. IAM 설정

IAM > 사용자 > 사용자 이름 > 권한 > 권한 추가 > 직접 정책 연결하기 

AmazonEC2ContainerRegistryFullAccessAmazonECS_FullAccess 를 추가해준다.

엑세스 키2 밑에 엑세스 키 만들기를 눌러주었다.

CLI를 선택해 생성해주었다.

 

6. github action yml 작성

1) yml 파일

name: Deploy to Amazon ECS CI/CD

on:
  push:
    branches: [ "main" ]

env:
  AWS_REGION: 				                  # AWS region, e.g. us-west-1
  ECR_REPOSITORY: 			                  # Amazon ECR repository name
  ECS_SERVICE:					              # Amazon ECS service name
  ECS_CLUSTER: 			     		          # Amazon ECS cluster name
  ECS_TASK_DEFINITION: 						# Amazon ECS task definition 경로 (json 파일경로)
  CONTAINER_NAME:				           # container name

jobs:

  deploy:
    name: Deploy
    runs-on: ubuntu-latest
    environment: production

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

      - name: Set up JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'temurin'

      - name: Grant execute permission for gradlew
        run: chmod +x gradlew

      #      - name: Copy Secret
      #        env:
      #          CREATE_SECRET: ${{secrets.APPLICATION_YML}}
      #          CREATE_SECRET_DIR: src/main/resources
      #          CREATE_SECRET_DIR_FILE_NAME: application.yml
      #        run: echo $CREATE_SECRET | base64 --decode > $CREATE_SECRET_DIR/$CREATE_SECRET_DIR_FILE_NAME

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

      - 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: ${{ env.AWS_REGION }}

      - 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: ${{ steps.login-ecr.outputs.registry }}
          IMAGE_TAG: ${{ github.sha }}
        run: |
          docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
          echo "image=$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG" >> $GITHUB_OUTPUT

      - 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: ${{ env.ECS_TASK_DEFINITION }}
          container-name: ${{ env.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: ${{ env.ECS_SERVICE }}
          cluster: ${{ env.ECS_CLUSTER }}
          wait-for-service-stability: true

 

2) JSON 파일 생성

아까 만든 task에서  JSON > AWS CLI 입력 다운로드 클릭

 

경로는 루트에 넣어주면 된다.

 

7. 배포 성공

 

 

 

public 도메인 이름으로 했을 때와 lb DNS로 접속했을 때 둘 다 잘 실행되는 것을 확인할 수 있다.


이슈!!!!

ecs 배포를 진행하면서 이슈가 정말 많았다... 그 중 몇개만 요약해보겠다.

 

1. target group 포트를 HTTPS 로 설정해준 점이다.

 

ECS에서 배포한 애플리케이션의 Target Group 포트를 HTTPS로 설정한 것이 문제였다. CloudWatch 로그를 살펴보니 아래와 같은 에러가 발생했다.

--- [apigateway-service] [nio-8080-exec-1] o.apache.coyote.http11.Http11Processor : Error parsing HTTP request header ecs

이 에러의 원인은 HTTP 요청이 HTTPS 포트로 전달되면서 발생한 문제였다.

스프링 부트 애플리케이션이 동작할 때 기본적으로 HTTP, HTTPS 프로토콜을 사용하지만 나는 HTTP 프로토콜을 사용했다.(HTTPS를 사용하려면 ssl 추가설정 필요)

따라서, Target Group 포트를 HTTP로 설정해야 하지만, 이를 HTTPS로 설정하면서 요청이 잘못된 포트로 전달되었고, 이로 인해 HTTP 요청 헤더를 파싱하는 과정에서 오류가 발생한 것이다.

 

2. Security 인바운드 규칙

위와 같은 에러는 현재 접근하고 싶은 service security 인바운드 규칙에 해당 container포트, 즉 8080을 추가 안해줘서 생긴일이다.