티스토리 뷰

Github Action, ECR, S3, CodeDeploy를 활용해 Blue/Green 방식의 무중단 배포를 해보려 합니다. 아래는 모든 과정이 끝난 후의 아키텍처입니다.

 

배포 시나리오


1. Github에 코드 push하면 Github Action 동작

2. ECR에 Docker image push

3. S3에 CodeDeploy script 업로드

4. CodeDeploy 실행해 EC2 배포

 

Github Action을 통해 2,3,4 과정이 실행됩니다. ECR에는 Spring Boot docker image를 push하고, S3에는 CodeDeploy에 필요한 스크립트를 압축해 업로드 합니다. CodeDeploy에서는 S3의 스크립트를 실행해 EC2 배포를 진행합니다. 스크립트에는 ECR로부터 docker image를 pull 받고 컨테이너를 실행하는 명령이 들어있습니다.

 

1. IAM 생성


IAM은  AWS 리소스에 대한 액세스를 안전하게 제어할 수 있는 웹 서비스입니다. 이를 통해 특정 인스턴스나 그룹 혹은 계정에 특정 권한을 부여할 수 있습니다. CI/CD를 위해서 첫번째로, EC2가 S3, ECR에 접근할 수 있도록 IAM 역할을 생성해야 합니다. 두번째로, CodeDeploy가 AutoScalingGroup에 접근하기 위한 IAM 역할을 생성해야 합니다. 

 

[ 1.  EC2 IAM 역할 생성 ]

AmazonS3FullAccess, AmazonEC2ContainerRegistryFullAccess 정책을 연결합니다.

 

 

[ 2.  CodeDeploy IAM 역할 생성 ]

CodeDeploy IAM 역할을 생성한 뒤, AutoScalingGroup에 접근하기 위한 정책을 연결해줄 예정입니다.

1. 우선 기본적인 CodeDeploy IAM 역할을 생성합니다.

 

2. CodeDeploy 배포 그룹에서 사용될 정책으로, CodeDeploy가 AutoScalingGroup에 접근할 수 있도록 정책을 생성합니다. JSON을 클릭하고 아래 JSON 코드를 붙여넣습니다.

 

 

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
                "iam:PassRole",
                "ec2:CreateTags",
                "ec2:RunInstances"
            ],
            "Resource": "*"
        }
    ]
}

3. 첫번째로 생성한 CodeDeploy 역할에 위에서 생성한 정책을 연결해줍니다.

 

 

2. S3, ECR 생성


codeDeploy 스크립트를 업로드할 S3 bucket을 생성합니다. 이름과 리전 설정 후 나머지는 기본값으로 두면 됩니다.

 

docker image 레지스트리인 ECR Repository를 생성합니다. Repository 이름만 설정해 생성하면 됩니다.

 

 

3. AMI 생성


AMI는 Amazon Machine Image로, AWS 인스턴스를 생성할 때 base가 되는 이미지입니다. AWS에서 기본으로 제공해주는 AMI에는 ubuntu, centos 등이 있으며, 필요한 운영체제, 소프트웨어가 세팅되어 있는 AMI를 직접 구성할 수도 있습니다. 

 

[ 3-1. EC2 인스턴스 생성 ]

AutoScaling에 의해 생성되는 EC2의 AMI를 생성하기 위해 인스턴스를 생성합니다. 해당 인스턴스에는 Docker, Docker-compose, CodeDeploy Agent를 설치할 예정입니다.

 

인스턴스 이름 설정 후 AMI는 ubuntu를 선택해줍니다. 나머지는 기본값으로 간단하게 EC2를 생성해줍니다. 추후 생성할 시작템플릿에서 인스턴스의 용량, 보안그룹 등을 다시 설정할 예정입니다.

 

 

[ 2-2. CodeDeploy Agent, Docker, AWS CLI 설치 ]

위에서 생성한 EC2 인스턴스에 들어가 연결을 클릭하고, 오른쪽 하단의 주황색 연결 버튼을 클릭합니다.

 

EC2에 접속이 되셨다면, 아래의 명령어를 차례대로 입력해 Docker, Docker-compose, CodeDeploy Agent, AWS CLI, redis-server를 설치합니다.

-- docker 설치
$ sudo apt update
$ sudo apt install apt-transport-https ca-certificates curl software-properties-common
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
$ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu focal stable"
$ sudo apt update
$ sudo apt install docker-ce
$ sudo usermod -aG docker ubuntu

-- docker-compose 설치
$ sudo curl -L https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose
$ sudo chmod +x /usr/local/bin/docker-compose
-- CodeDeploy Agent 설치
$ sudo apt update
$ sudo apt install ruby-full
$ sudo apt install wget
$ cd /home/ubuntu
$ wget https://aws-codedeploy-ap-northeast-2.s3.ap-northeast-2.amazonaws.com/latest/install
$ chmod +x ./install
$ sudo ./install auto > /tmp/logfile
$ sudo service codedeploy-agent status
-- AWS CLI 설치
$ sudo apt install curl unzip
$ curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
$ unzip awscliv2.zip
$ sudo ./aws/install
$ sudo apt-get update
$ sudo apt-get install redis-server

정상적으로 설치가 되었다면, 아래와 같은 응답이 나와야합니다.

 

[ 3-3. AMI 생성 ]

해당 인스턴스에서 작업 - 이미지 및 템플릿 - 이미지 생성 버튼을 클릭합니다. 

 

4. 시작템플릿 생성


시작템플릿은 인스턴스 시작에 필요한 구성 정보를 모아둔 템플릿입니다. 시작템플릿을 만들어두면, 시작 템플릿의 내용대로 바로 인스턴스를 생성할 수 있습니다. 여기서는 Auto Scaling Group에서 사용할 시작템플릿을 생성해보겠습니다.

 

위에서 생성한 AMI를 선택합니다. 이를 통해 docker, docker-compose, codeDeploy agent가 설치된 환경의 인스턴스를 바로 생성할 수 있습니다.

 

인스턴스 유형은 프리티어로 제공해주는 t2.micro를 사용하겠습니다. (t2.micro는 가용영역 2a, 2c에서만 사용할 수 있습니다. 다른 가용영역을 사용해야하는 경우 t3.micro를 선택하시기 바랍니다.)

 

키페어를 생성합니다. 이 키페어는 앞으로 Auto Scaling Group으로 설정되어 생성될 ec2 그룹들에 접속하기 위해 사용됩니다.

 

보안 그룹은 기존의 보안그룹을 사용해도 되고, 생성하셔도 됩니다. 저는 Spring Boot를 배포할 것이기에 인바운드로 8080, 22 포트를 허용해주었습니다. 

 

Auto Scaling으로 인해 생성되는 EC2에 public IP를 부여하고 싶은 경우, 네트워크 인터페이스를 추가해 아래와 같이 설정해주면 됩니다. 

 

IAM 인스턴스 프로파일로 위에서 생성한 IAM 역할을 연결해줍니다. 해당 역할은 EC2에 S3, ECR FullAccess 권한을 부여합니다. (실제 운영에서는 FullAccess 권한을 주면 안됩니다! 정책 생성을 통해 꼭 필요한 권한만 부여해야합니다.) 이 역할을 통해 EC2에 설치되어 있는 CodeDeploy Agent가 S3 버켓의 스크립트를 읽어오고, ECR에 있는 docker image를 pull 받을 수 있게 됩니다.

 

 

5. Target Group(대상 그룹) 생성


대상 그룹은 지정한 프로토콜과 포트 번호를 사용하여 등록된 대상(EC2 인스턴스)으로 요청을 라우팅합니다. 대상 그룹들은 로드밸런서에 의해 로드밸런싱 됩니다. 아래에서 생성한 대상 그룹은 추후 Auto Scaling Group을 연결할 예정입니다. (즉, 로드밸런서는 Auto Scaling Group에서 생성된 EC2들에 트래픽을 분산하게 됩니다.)

 

Spring Boot의 기본 포트인 8080을 매핑해줍니다. 추가로, 대상 그룹에 포함할 인스턴스가 있는 VPC를 선택해주어야 합니다.

 

대상 그룹은 특정 엔드포인트에 대해 health check를 실행합니다. 상태 코드 200을 반환하는 health check api 경로를 지정해줍니다. 개인적으로는, health check를 위한 endpoint를 만들어 사용하는 것을 권장합니다. health check는 몇 초에 한번씩 이뤄지기 때문에 기존 api 경로를 사용하는 경우 성능에 지장이 가거나 로그 및 메트릭이 오염될 수 있습니다.

 

- 정상 임계값: 연속으로 몇 번 정상 응답을 해야만 정상 상태로 볼 것인지 지정하는 항목

- 비정상 임계값: 연속으로 몇 번 비정상 응답을 해야만 정상 상태로 볼 것인지 지정하는 항목

- 제한 시간: 타임아웃 시간으로 응답이 몇 초 이내로 오지 않을 경우 비정상 응답으로 판단할지 지정하는 항목

- 간격: 몇 초 간격으로 인스턴스의 상태를 물어볼지 지정하는 항목

 

값을 작게 설정 해주어야 CodeDeploy 배포 과정인 AllowTraffic 구간에서 빠르게 진행될 수 있습니다.

(현재 설정에서는 배포 시 한 인스턴스당 90초 (30초 * 3회) + a 가 소요됩니다. 인스턴스의 개수가 많을 경우 몇십분의 시간이 소요될 수 있으므로, 헬스체크 간격과 정상 임계값을 적절하게 설정하는 것이 좋습니다)

 

그리고 다음 대상 등록에서는 인스턴스를 지금 등록하지 않고 Auto Scaling Group을 대상그룹으로 연결할 예정이니 넘어가겠습니다.

 

6. 로드밸런서 생성


인스턴스들에게 트래픽을 분산하기 위해 로드밸런서를 생성합니다.

 

VPC는 위의 대상그룹과 동일한 VPC를 선택해주어야 합니다. 그리고, ALB가 트래픽을 분산할 가용영역을 선택해줍니다. 각 가용영역에서는 외부와 연결된 public 서브넷을 선택해야 합니다. 저는 2a, 2c 가용영역의 public 서브넷을 선택했습니다.

 

보안 그룹은 80 포트에 대해 인바운드를 허용해주고, 아웃바운드는 대상그룹의 포트인 8080포트에 대해 허용해줬습니다.

 

리스너는 위에서 생성한 대상그룹에 80포트를 연결해줍니다. 즉, 로드밸런서의 80포트로 들어오는 요청은 해당 대상그룹으로 전달됩니다.

 

 

7. Auto Scaling Group 생성


Auto Scaling Group은 트래픽 혹은 하드웨어 사용량에 따라 인스턴스의 개수를 줄이거나 늘릴 수 있게 해주는 서비스입니다.

시작 템플릿은 위에서 생성한 시작템플릿을 선택해줍니다. AutoScaling 시 해당 시작템플릿 내용으로 EC2가 생성됩니다.

 

Auto Scaling에 의해 생성될 EC2를 배치할 VPC와 가용영역을 선택합니다. private 서브넷도 선택가능합니다. (private 서브넷에 EC2를 배치하고, ALB를 통해 트래픽 분산 가능) 저는 2a, 2c 가용영역을 선택했습니다.

 

위에서 Load Balancer와 대상그룹을 생성했으므로, 해당 대상 그룹과 Auto Scaling Group을 연결해주었습니다.

 

해당 옵션은 Elastic Load Balancer의 health check를 반영해 Auto Scaling하겠다는 의미입니다. Auto Scaling Group은 인스턴스의 상태를 기준으로 health check를 합니다. 즉, 인스턴스가 실행 중이면 실제 WAS가 작동하지 않는 경우에도 정상이라고 판단합니다. 이에 반해, Elastic Load Balancer는 health check endpoint로 요청을 보내 상태를 확인하기 때문에 WAS가 작동하지 않는 경우도 탐지할 수 있습니다. 따라서, Elastic Load Balancer의 상태를 반영해 WAS가 작동하지 않는 경우에도 Auto Scaling하기 위해 해당 옵션을 활성화했습니다.

 

Auto Scaling Group에 의해 생성될 인스턴스들의 최소 값, 최대 값, 평상시 원하는 값을 설정해야합니다. 저는 각 가용영역에 1개씩 분배하기 위해 원하는 용량 2, 최소 용량 2를 지정하였고, 트래픽이 더 들어올 시 최대 4개까지 인스턴스가 생성되도록 설정했습니다.

 

Auto Scaling Group - 인스턴스 관리 에 들어가면 Auto Scaling Group에 의해 관리되는 인스턴스들을 확인할 수 있습니다. 

 

8. CodeDeploy 생성


CodeDeploy는 appspec.yml 이라는 yml 파일에 의해 작동하는 도구로, 원하는 스크립트를 실행하거나 동작 시킬 수 있습니다. CodeDeploy를 통해 S3에 업로드한 script를 EC2 인스턴스에 다운받아 실행시킬 예정입니다. 

 

먼저 CodeDeploy 애플리케이션을 생성합니다. 간단하게 이름, 컴퓨팅 플랫폼을 선택한 뒤 생성해줍니다.

 

위에서 생성한 CodeDeploy 애플리케이션에 들어가 배포 그룹 생성을 클릭합니다.

 

CodeDeploy 역할은 맨 위에서 생성한 CodeDeploy IAM 역할을 연결해줍니다.

 

배포 유형은 무중단 배포 및 Rollback이 가능한 블루/그린 배포 유형을 선택합니다. 환경 구성은 Auto Scaling 그룹 자동 복사를 선택합니다. 인스턴스 수동 프로비저닝을 선택하면 직접 새로운 Auto Scaling Group을 만들어야 하지만, 그룹 자동 복사를 선택하면 자동으로 Auto Scaling Group (Green 그룹)이 생성되고, Blue Group 삭제까지 진행됩니다.

 

배포 성공시 트래픽을 Green Group으로 라우팅할 수 있도록, 트래픽 재 라우팅은 즉시 라우팅으로 설정해줍니다. 그리고, 원본 인스턴스(Blue Group) 종료 시간을 설정해줍니다. 필요한 경우 Blue Group으로 롤백할 수 있도록, 적절한 시간을 설정해줍니다. 아래에서는 Green Group 배포 후 1시간이 지난 뒤 원본 인스턴스들이 종료됩니다.

 

로드 밸런서는 위에서 생성한 대상그룹으로 연결해줍니다. 배포에 성공해 Green Group으로 트래픽 라우팅이 가능해지면 대상 그룹으로 인스턴스들을 자동 등록해줍니다.

 

 

9. IAM 사용자


Github Action에서 AWS 리소스에 접근하기 위해 IAM 사용자를 생성해야 합니다. 사용자 생성 후 발급받은 access key, secret key로 AWS 리소스에 접근할 수 있습니다.

 

AWS 외부에서 실행되는 애플리케이션을 선택 후, 적절히 사용자 이름을 설정해주고 ECR, S3, CodeDeploy에 대한 FullAccess 권한을 부여합니다.

 

IAM 사용자를 생성했으면, 생성한 IAM 사용자에 들어가 access key, secret key 를 발급받습니다. 이 key들은 한번 발급 후 다시 조회할 수 없으니 꼭 로컬에 저장해두시는 것을 추천드립니다.

 

 

10. Github Action CI/CD


Github Action CI/CD를 위해선 Dockerfile, CodeDeploy 배포를 위한 스크립트 파일이 필요합니다. 먼저 필요한 파일들을 생성한 뒤, Github Action CI/CD workflow에 대해 살펴보겠습니다.

[ 10-1. Dockerfile 작성 ]

아래와 같이 Spring Boot Dockerfile을 작성합니다. 저는 멀티모듈을 사용하고 있습니다. Dockerfile은 자신의 환경에 맞게 작성해주시면 됩니다. 해당 Dockerfile은 Github Action을 통해 build해 docker image를 생성하고, ECR에 push합니다.

FROM openjdk:17-ea-11-jdk-slim AS BUILDER
RUN mkdir /app_source
COPY .. /app_source
WORKDIR /app_source
RUN chmod +x ./gradlew
RUN ./gradlew :api:bootJar

FROM openjdk:17-ea-11-jdk-slim AS RUNNER
RUN mkdir /app
COPY --from=BUILDER /app_source/api/build/libs /app
WORKDIR /app
ENV TZ=Asia/Seoul
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app/api-0.0.1-SNAPSHOT.jar"]

저는 EC2에 redis, spring boot 컨테이너를 띄울 것이기 때문에 다수의 컨테이너를 실행하기 위한 docker-compose 파일도 작성했습니다.docker-compose 파일은 S3에 업로드 후, codeDeploy에 의해 실행될 예정입니다. (codeDeploy가 S3로 부터 파일을 가져와 EC2에 압축을 해제한 뒤, appspec.yml에 정의된 스크립트를 실행시켜 docker-compose에 정의된 컨테이너 실행)

version: '3.7'

services:
  redis:
    image: redis:latest
    command: redis-server
    container_name: tago-redis
    ports:
      - "6379:6379"
  spring:
    # ECR로부터 Spring Boot 이미지를 pull 받아 컨테이너 실행
    image: 121284569119.dkr.ecr.ap-northeast-2.amazonaws.com/tago-dev:latest
    restart: always
    depends_on:
      - redis
    ports:
      - "8080:8080"
    container_name: tago-spring
    environment:
      DATABASE_URL: ${DATABASE_URL}
      DATABASE_USERNAME: ${DATABASE_USERNAME}
      DATABASE_PASSWORD: ${DATABASE_PASSWORD}
      REDIS_HOST: ${REDIS_HOST}
      REDIS_PORT: ${REDIS_PORT}

 

[ 9-4. CodeDeploy script 작성 ]

CodeDeploy는 S3에 업로드한 압축파일을 EC2로 가져와 압축을 해제한 뒤, appspec.yml에 정의되어 있는 스크립트를 실행합니다. CodeDeploy 배포에 필요한 파일의 구조는 아래와 같습니다.

1. afterInstall.yml

ECR에 로그인 후, ECR로 부터 docker image를 pull 받은 뒤, 컨테이너를 실행하는 스크립트입니다.

#!/bin/bash
REPOSITORY=/home/ubuntu/tago
CONTAINER_NAME=tago-spring
ECR_REGISTRY=121284569119.dkr.ecr.ap-northeast-2.amazonaws.com

cd $REPOSITORY

echo "> 🔵 PULL DOCKER IMAGE FROM ECR"
aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin $ECR_REGISTRY

echo "> 🔵 RUN APPLICATION CONTAINER"
docker-compose pull spring
docker-compose up -d

2. appspec.yml

위에서 정의한 스크립트를 S3로 부터 가져오고 스크립트의 실행권한과, 실행 시기를 정의해놓은 파일입니다.

version: 0.0
os: linux
files:
  - source: /
    destination: /home/ubuntu/tago
    overwrite: yes

permissions:
  - object: /
    pattern: "**"
    owner: ubuntu
    group: ubuntu
    mode: 755

hooks:
  AfterInstall:
    - location: scripts/afterInstall.sh
      timeout: 60
      runas: ubuntu

간단하게 살펴보면 appspec.yml은 3가지 작업을 수행합니다. 

- files : S3에 업로드된 zip 파일을 EC2에 다운받아 압축 해제 후 /home/ubuntu/tago 경로로 옮긴다

- permissions : 옮기기 전 파일들의 권한을 설정한다. (shell script 실행을 위한 권한 부여)

- hooks : 압축 해제한 스크립트 파일을 실행한다.

 

hooks에서 해당 스크립트 파일에 정의된 명령들을 실행한다. 여기서는 afterInstall.sh 스크립트 내 docker-compose up 명령에 의해 EC2에 Spring boot, redis 컨테이너가 실행된다.

 

[ 9-2. Github Action ]

name: cd-dev

on:
  pull_request:
    branches: [ develop ]
    types: [ closed ]

env:
  AWS_REGION: ap-northeast-2
  S3_BUCKET_NAME: S3 버켓 이름
  CODE_DEPLOY_APPLICATION_NAME: CodeDeploy 애플리케이션 이름
  CODE_DEPLOY_DEPLOYMENT_GROUP_NAME: CodeDeploy 배포 그룹 이름

permissions:
  contents: read

jobs:
  build:
    runs-on: ubuntu-latest
    if: github.event.pull_request.merged
    steps:
      - uses: actions/checkout@v3
      - name: Set up JDK 17
        uses: actions/setup-java@v2
        with:
          java-version: '17'
          distribution: 'temurin'

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

      - name: Create .env file
        env:
          ENV_PATH: .env
        run: |
          touch $ENV_PATH
          echo DATABASE_URL=${{ secrets.DEV_DATABASE_URL }} >> $ENV_PATH
          echo DATABASE_USERNAME=${{ secrets.DEV_DATABASE_USERNAME }} >> $ENV_PATH
          echo DATABASE_PASSWORD=${{ secrets.DEV_DATABASE_PASSWORD }} >> $ENV_PATH
          echo REDIS_HOST=${{ secrets.DEV_REDIS_HOST }} >> $ENV_PATH
          echo REDIS_PORT=${{ secrets.DEV_REDIS_PORT }} >> $ENV_PATH

      - 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: 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
        env:
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
          ECR_REPOSITORY: tago-dev
          IMAGE_TAG: latest
        run: |
          docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
          docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG

      - name: Upload to S3
        run: |
          zip -r ./$GITHUB_SHA.zip ./scripts appspec.yml docker-compose.yml .env
          aws s3 cp --region ap-northeast-2 ./$GITHUB_SHA.zip s3://$S3_BUCKET_NAME

      - name: Deploy to EC2 with CodeDeploy
        run: |
          aws deploy create-deployment \
          --application-name ${{ env.CODE_DEPLOY_APPLICATION_NAME }} \
          --deployment-config-name CodeDeployDefault.AllAtOnce \
          --deployment-group-name ${{ env.CODE_DEPLOY_DEPLOYMENT_GROUP_NAME }} \
          --s3-location bucket=$S3_BUCKET_NAME,key=$GITHUB_SHA.zip,bundleType=zip

Github Action의 과정을 간단하게 소개하면 아래와 같습니다.

- 1. docker-compose 환경변수 파일 세팅

- 2. AWS IAM 로그인

- 3. ECR에 docker image push

- 4. CodeDeploy에 필요한 스크립트 압축해 S3에 업로드

- 5. CodeDeploy 실행해 배포 시작

 

2단계는 위에서 생성한 IAM 사용자의 access key, secret key를 github secret 변수로 등록해 AWS에 로그인했습니다. 이를 통해 Github Action은 ECR, S3, CodeDeploy에 접근할 수 있게 됩니다. 3단계부터는 좀 더 자세히 살펴보겠습니다.

 

- ECR에 docker image push

정의한 Dockerfile을 build해 docker image 생성한 뒤, 해당 docker image를 ECR에 push합니다.

  - name: Build, tag, and push image to Amazon ECR
    env:
      ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
      ECR_REPOSITORY: tago-dev
      IMAGE_TAG: latest
    run: |
      docker build -t $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG .
      docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG

 

- CodeDeploy에 필요한 스크립트 압축해 S3에 업로드

appspec.yml 파일과 스크립트, docker-compose 파일을 압축해 S3에 업로드합니다.

  - name: Upload to S3
    run: |
      zip -r ./$GITHUB_SHA.zip ./scripts appspec.yml docker-compose.yml .env
      aws s3 cp --region ap-northeast-2 ./$GITHUB_SHA.zip s3://$S3_BUCKET_NAME

- CodeDeploy 실행해 배포 시작

해당 S3 버켓으로 부터 zip 파일을 가져오고, CodeDeploy 애플리케이션의 특정 배포그룹에 배포를 진행합니다. 

- name: Deploy to EC2 with CodeDeploy
  run: |
    aws deploy create-deployment \
    --application-name ${{ env.CODE_DEPLOY_APPLICATION_NAME }} \
    --deployment-config-name CodeDeployDefault.AllAtOnce \
    --deployment-group-name ${{ env.CODE_DEPLOY_DEPLOYMENT_GROUP_NAME }} \
    --s3-location bucket=$S3_BUCKET_NAME,key=$GITHUB_SHA.zip,bundleType=zip

 

11. CI/CD 결과 확인


Github Action이 정상동작 했다면, 아래와 같이 CodeDeploy의 Blue/Green 배포가 실행될 것입니다. 3단계까지 완료가 되었다면, Green Group의 AutoScaling Group이 생성되고, 대상 그룹에 Auto Scaling에 의해 생성된 인스턴스(green)가 등록됩니다.

 

4단계까지 완료가 되면, 원본 인스턴스(Blue)가 종료됩니다. 저는 CodeDeploy 애플리케이션 생성 시 원본 인스턴스를 1시간 뒤에 삭제한다고 설정했기 때문에, 1시간 뒤 원본 인스턴스가 종료되고, 원본 Auto Scaling Group도 삭제됩니다. 아래와 같이 원본 AutoScaling Group(Blue Group)이 삭제 중인 것을 확인할 수 있습니다.

 

대상 그룹에도 새로 생성된 인스턴스(Green Group)만 등록되어 있는 것을 확인할 수 있습니다.

 

 

마지막으로! 제대로 배포가 되었는지 확인해봅시다. ELB DNS로 접속하면 아래와 같이 응답이 정상적으로 오는 것을 확인할 수 있습니다.

 

삽질 Log .....

ELB의 아웃바운드 규칙으로 8080포트를 허용하지 않아서 트래픽이 EC2로 전달되지 않았다. 대상 그룹의 health check도 당연히 실패했고, codeDeploy 배포도 실패했다. codeDeploy의 AllowTraffic 단계에서 계속 실패했는데, 이는 대상 그룹의 health check가 비정상인 경우 실패처리 된다고 한다. 보안 그룹을 제대로 확인하자!

 

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
글 보관함