프로젝트 전체 아키텍처.

신규 프로젝트를 진행하며, 더 이상 온프레미스 서버에서 관리하지 않고, 클라우드 컴퓨팅, 컨테이너 환경을 선택했다.

 

고가용성과 오토 스케일링, 또한 여러 컨테이너 환경을 첫 운영함에 있어서 쿠버네티스 , 도커 스웜, AWS ECS를 고려했다.

 

쿠버네티스와 도커 스웜 역시 강력한 컨테이너 오케스트레이션 도구였지만, AWS ECS 클러스터 인프라에서 배포 컴퓨팅 환경으로

 

서버리스 컴퓨팅 형태인 Fargate를 사용할 수 있다는 장점으로 인해 AWS ECS를 선택, 그에 맞는 인프라를 구축하기로 하였다.   

 

 

Route53

Amazon Route 53은 가용성과 확장성이 뛰어난 DNS 웹 서비스이며, 사용자 요청을

 

AWS 또는 온프레미스에서 실행되는 인터넷 애플리케이션에 연결한다.

 

위 그림과 같이 DNS로 도메인을 별도 구입하여 해당 도메인의 라우팅 경로를 VPC내에 있는 로드 밸런서의 ARN으로 연결 시켜주었다.


Application Load Balancer(ALB)

해당 로드 밸런서의 리스너는 두 가지 경우를 만들어 주었다.

 

HTTP:80

  • HTTP 프로토콜의 기본 포트인 80으로 접근 시, HTTPS:443(프로토콜:포트)를 리다이렉션 대상으로 삼아 주었다.

  • 이로써 http 프로토콜로 접속해도 보안 접속이 가능해졌다.

 

HTTPS:443

  • 리스너 규칙으로 접근하려는 호스트의 헤더에 api.도메인.com가 붙여져있다면 백엔드 대상 그룹으로 라우팅 경로를 지정 .

  •  그 외의 요청은 프론트엔드 대상 그룹으로 라우팅 경로를 지정
로드밸런서의 대상 그룹은 ECS에서 테스크 서비스가 배포되는 시점에서 선택을 할 수 있다.

예를 들어, 백엔드 서비스가 포함된 컨테이너 배포시, 기존에 생성한 로드 밸런서의 대상 그룹 A를 지정해준다면,

배포된 컨테이너 서비스가 자동으로 로드밸런서의 백엔드 대상 그룹으로 지정돼, 라우팅을 수신 할 수 있게 된다.
  • 추가로 트래픽 분산 알고리즘과, 각 대상 그룹에 등록된 서비스의 가중치 지정이 가능하다.

ECS Cluster

서버 자원에 대한 인력 리소스를 줄이기 위해, (ECS를 선택한 이유인) Fargate 컴퓨팅 유형으로 클러스터를 생성해주었고,

 

해당 클러스터에서 각각 프론트엔드 서비스 , 백엔드 서비스를 배포 하였다.

테스크 정의

테스크 정의의 규격을 vCPU 2, 메모리를 16GB로 리소스를 한정하고,

 

오토 스케일링 규칙을 해당 테스크가 로드밸런서의 트래픽 량에 따라

 

최소 3개, 최대 6개까지 유지 될 수 있도록 하여 트래픽 급증에 대비하여 유연하게 서비스를 운영할 수 있게 하였다.

 

cpu 아키텍처는  X86_64로 설정하였으며, 이는 곧 후에 기술하게 될 GitActions의 도커 이미지 빌드 아키텍처와 맞춰주기 위함이다.


또한 서비스 배포 옵션을 상단의 사진과 같이 최소 실행 작업 비율을 100% , 최대 실행 작업 비율을 200%로 하여

 

롤링 업데이트 방식으로 무중단 배포를 할 수 있었다.

 

(본래는 블루/그린 배포 방식으로 하려 했으나, 또 다른 서버 자원의 비용을 감내해야 했기 때문에 배포 속도가 좀 느리더라도 

 

롤링 업데이트 방식을 채택했다..흑)

 


  • 해당 테스크 스케줄러가 각 서비스 배포 서브넷은 로드 밸런서가 위치한 서브넷과 동일하게 맞춰 주었으며,

  • 로드밸런서도 미리 만들어둔 것으로 지정해주었다.
    -> 이 로드밸런서의 트래픽 량에 따라 테스크 실행 갯수가 조절이 된다.

GitActions를 통한 배포 자동화

배포 자동화를 구축하기 위해, 방법을 모색하던 중 이미 GitActions 배포 템플릿에서 ECS 배포용 yaml 템플릿이 있어 

 

해당 yml 파일을 입맛에 맞게 커스텀 해주었다.

 

각 블록을 살펴보자

 

name: Deploy to Amazon ECS

on:
  pull_request_target:
    types:
      - closed
      
  # 이 옵션을 통해 사용자가 직접 Actions를 통해 워크플로우 실행이 가능 !
  workflow_dispatch:
  
env:
  AWS_REGION: ap-northeast-2                  # set this to your preferred AWS region, e.g. us-west-1
  ECR_REPOSITORY: # set this to your Amazon ECR repository name
  ECS_SERVICE:  # set this to your Amazon ECS service name
  ECS_CLUSTER:  # set this to your Amazon ECS cluster name
  ECS_TASK_DEFINITION:  # set this to the path to your Amazon ECS task definition
                       # file, e.g. .aws/task-definition.json
  CONTAINER_NAME: backend # set this to the name of the container in the

name 블록은 워크 플로우 이름

 

on

 

PR이 머지 됐을 경우에만 배포가 될 수 있도록 설정.

 

workflow_dispatch

 

위에서 워크 플로우 배포를 실행 하기 위하여 반드시 PR을 머지시켰어야만 했는데, 

이를 생략하고 바로 실행할 수 있게 하기 위해 해당 옵션을 지정해주었다.

 

env

배포할 서비스 리전,
도커 이미지 프라이빗 레포지토리 ARN,
ECS 서비스 이름,
ECS 클러스터 이름,
ECS  테스크 정의 경로,
배포할 컨테이너 이름을 지정해주었다.

 

# 워크 플로우 종료 후, 배포 결과를 슬렉으로 알리기 위해 필요한 권한 설정
permissions:
  contents: read
  actions: read

jobs:
  deploy:
    if: |
      # 풀리퀘스트 머지시에만 job 실행
      github.event.pull_request.merged == true &&
      # 레포지토리가 fork된 레포지토리가 아닌, 원본 레포지토리일 경우에만
      github.repository == ${{ secretes.REPOSITORY_NAME }} &&
      github.event.pull_request.base.ref == 'main'
    
    # job 이름 설정
    name: Deploy
    # job 실행 환경 설정
    runs-on: ubuntu-latest
    # 배포 환경
    environment: production

    steps:
    - name: Checkout
      uses: actions/checkout@v3
      
    # GitActions에 ECS 서비스 배포 권한 및 ECR에 푸쉬 할 수 있는 권한을 가진
    # IAM 유저의 액세스 키와, 시크릿 키 설정을 해준다.
    - 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
      
    # 도커 이미지 빌드 시, 필요한 환경변수는 이미 .gitignore로 제외 되었기 때문에
    # 이미지 빌드 전, repository Secrets에 애플리케이션 환경 변수를 저장 후 생성해준다. 
    - name: make application.yml
      if: contains(github.ref, 'main')
      run: |
        cd ./src/main/resources
        touch ./application.yml
        echo "${{ secrets.ENVIRONMENT_MAIN }}" > ./application.yml
      shell: bash
      
    # 프로젝트 루트 경로의 도커파일에 맞게 이미지 빌드 후, ECR에 푸쉬
    - 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: |
        '''
        도커 이미지 빌드 명령어
        도커 이미지 ECR 푸쉬 명령어
        '''
	
    # 배포될 테스크 정의 파일 경로 지정
    - 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 }}
	
    # ECS 테스크 정의 배포
    - 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
        
    # 배포 결과 슬렉 전송
    - name: action-slack
      uses: 8398a7/action-slack@v3
      with:
      	# 프론트엔드와 백엔드 레포지토리가 분리 되어있기 때문에 따로 설정해준다.
        status: ${{ job.status }}
        author_name: 백엔드 배포 결과
        fields: repo,message,commit,author,action,eventName,workflow
      env:
        SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} # required
      if: always()

 

위와 같이 yml 파일로 배포 자동화를 설정 후에 배포 자동화가 무사히 잘 이뤄진 것 까지 확인해보았다.

 

문제점

GitActions에서는 배포 때 마다, 매번 새로운 실행환경을 생성하니 도커 빌드의 캐시를 제대로 활용하지 못하고 있었음

 

이는 곧 매 배포 시마다 새롭게 이미지 빌드를 하며 배포 시간이 늘어남

 

해결방안 : GitActions에서의 도커 이미지 레이어 캐시 활용

레이어 캐시를 사용하는 step을 추가해주면 같은 레이어를 다시 빌드하는데 드는 시간을 줄일 수 잇다.

 

이전 빌드의 캐시를 복원하는 동시에 (커밋마다) 새 캐시를 저장하게 된다.

- name: Cache Docker layers
      uses: actions/cache@v2
      with:
        path: /tmp/.buildx-cache
        key: ${{ runner.os }}-buildx-${{ github.sha }}
        restore-keys: |
            ${{ runner.os }}-buildx-

 

 

path 블록

캐시할 디렉토리를 지정하며, '/tmp/.buildx-cache'는 Docker Buildx가 이미지 레이어를 저장하는 임시 경로이다.

 

key 블록

캐시의 고유한 키를 설정한다. 캐시 키 ${{ runner.os }}-buildx-${{ github.sha }}와 같이 지정된다.

여기서 runner.os는 GitHub Actions 러너의 운영 체제를 나타내고, github.sha는 현재 커밋의 SHA를 나타낸다.

이렇게 하면 각 커밋마다 새로운 캐시가 생성되므로, 도커 레이어가 변경될 때마다 새로운 레이어가 캐시에 저장된다.

 

restore-keys 블록

이전 캐시를 찾을 때 사용되는 키의 패턴, key 값으로 캐시를 찾지 못할 경우 해당 블록에서 지정한 패턴에 맞는 가장 최근의 캐시를 사용한다.

위의 경우(${{ runner.os }}-buildx-)에는 이전에 빌드한 모든 Docker 레이어 캐시를 검색하는 데 사용된다.

'AWS' 카테고리의 다른 글

IAM  (0) 2024.03.30
AWS Cloud Support Associate 1차 면접 후기  (10) 2023.12.12

+ Recent posts