DevOps/AWS

[AWS] Github Actions, CodeDeploy, Nginx 로 무중단 배포하기 - 2

샤아이인 2022. 5. 31.

 

총 4개의 시리즈 글로 진행될 것입니다.

 

1) Github Actions과 AWS S3 연동 

2) EC2 설정과 CodeDeploy 적용 (이번 글)

3) EC2와 RDS

4) Nginx 설치와 배포 스크립트

 

▶ 전체 흐름도

우선 전반적인 흐름은 다음과 같습니다!

과정을 진행하면서 막힐 때, 다음 그림을 보면서 생각해보시면 어떤 부분에서 막히고 있는지 이해하기 쉬우실 거예요!

 

2. EC2 설정과 CodeDeploy 적용

이번 글에서는 Github Actions에서 CodeDeploy에게 S3에 있는 jar 파일을 EC2로 가져가서 담당한 배포 그룹의 EC2에 배포하는 과정을 진행하게 됩니다.

 

CodeDeploy는 AWS에서 지원하는 배포 자동화 서비스입니다.

자세한 설명은 다음 레퍼런스를 참고해보시길 권장드립니다!

 

CodeDeploy란 무엇인가요? - AWS CodeDeploy

또한 일반적으로 기존 환경의 인스턴스에서 실행되는 애플리케이션 수정이 있지만, 블루/그린 배포의 경우 반드시 이럴 필요는 없습니다.

docs.aws.amazon.com

 

CodeDeploy의 배포 과정은 다음과 같습니다.

  • 우리의 애플리케이션 최상단 경로에 AppSpec.yml이라는 yml파일을 추가합니다.
    • AppSpec.yml 은 배포에 필요한 모든 절차를 적어둔 파일입니다.
  • CodeDeploy에 프로젝트의 특정 버전을 배포해 달라고 요청하면, CodeDeploy는 우리의 EC2 인스턴스에 미리 설치된 CodeDeploy Agent와 통신하며 Agent에게 요청받은 버전을 배포하라 명령합니다.
  • 요청받은 CodeDeploy Agent는 S3에서 프로젝트 전체를 서버에 내려받고, AppSpec.yml 파일을 읽어 해당 파일에 적힌 절차대로 배포를 진행합니다.
  • CodeDeploy Agent는 배포를 진행한 후 CodeDeploy에게 성공/실패 등의 결과를 알려줍니다.

CodeDeploy Agent는 EC2 인스턴스에 설치되어 CodeDeploy의 명령을 기다립니다.
실제로 배포를 수행하는 것은 Agent이기 때문에 반드시 EC2 인스턴스에 설치되어 있어야 합니다.

 

참고로 Agent는 Ruby라는 언어로 만들어졌기 때문에 EC2 상에서 Ruby를 먼저 설치해줘야 합니다. 이는 뒤에서 알아봅시다.

 

1. VPC 와 Subnet 만들기

우선 EC2를 만들기 전에 VPC를 생성하고, VPC 안에 각각 Public Subnet 과 Private Subnet 2개를 만들게 될 것 입니다.

다음 그림을 살펴 보시죠!

위 그림처럼 VPC 네트워크 망 안에다가 Subnet을 2개 생성하는것이 목적 입니다.

다음과 같이 VPC 로 이동하여 VPC 생성을 눌러줍시다.

 

이후 설정페이지 에서 다음과 같이 CIDR 값을 설정해 줍니다.

이전에도 말했듯 VPC 는 10.51.0.0/16 으로 지정해 줬습니다.  CIDR 방식인데 자세한 내용은 다른 글을 참고해보시길 권장합니다.

태그는 꼭 지정해 주시길 권장합니다!! 저는 저의 별칭인 shine으로 지정했는데, 원하시는 이름으로 설정하시면 됩니다!

이후 생성 버튼을 누르면 성공적으로 VPC가 생성됩니다.

 

이제 Subnet을 2개 생성 해봅시다! 서브넷은 VPC 바로 아래에 버튼이 보이실 겁니다!

누른후에 서브넷 생성을 눌러줍니다.

 

생성단계에서 VPC 를 선택해줘야 하는데, 직전에 만든 shine-vpc를 선택해 줍니다!

 

이어서 밑으로 이어지는 하단부분에서 Public Subnet에 대한 설정을 진행해 줍니다.

 

다음으로는 Private Subnet에 대한 설정을 동일하게 진행하는데, RDS는 Subnet Group이 필요합니다!

즉, Private Subnet 이 2개 이상인 Group이 필요하다는 것 이죠!

따라서 Private Subnet 을 2개 더 생성할것 입니다.

 

각각 서로 다른 가용영역을 지정해주셔야 합니다.

저는 b 와 d를 선택하였습니다. 

 

이후 생성하기 버튼을 누르면 정상적으로 다음과 같이 생성되게 됩니다!

이제 VPC 작업이 다 끝났습니다! EC2를 만들러 가봅시다!

 

2. EC2 생성하기

EC2에 설치할 OS로는 Amazon Linux를 선택할 것입니다.

이는 향후 Nat Instance를 직접 만들어 보기 위해 고려한 설정입니다.

 

자세한 EC2 설치 과정은 예전에 글로 미리 작성해 두었습니다. 

 

[AWS] EC2 인스턴스 만들기

다른 여타 어느 블로그의 글 보다 자세하게 설명 하였습니다. 도움이 될 수 있길!!! 총 3개의 글 시리즈로 작성할 것 입니다!! 1. EC2 인스턴스 만들기 (현재 글) 2. AWS의 EC2에 MySQL을 설치하고, Sequal A

blogshine.tistory.com

위 글에서는 Ubuntu를 사용하기는 했는데, 크게 다른 점은 없을 것입니다.

EC2를 생성할때 subnet은 꼭 직전에 만든 public subnet을 선택해주셔야 합니다!

 

위 전체 흐름도 에서도 알 수 있듯, EC2 는 public subnet에 위치하고 있습니다.

직전 글에서 전체 VPC는 10.51.0.0/16 으로 할당 했고,

public subnet 은 10.51.1.0/24 (EC2 용)

private subnet 은 10.51.11.0/24. 10.51.21.0/24 (RDS용) 로 할당 하였습니다.

 

이렇게 subnet을 나누는 이유는 RDS 같은 경우 public subnet 안의 EC2 에서만 접근하도록 하고 싶기 때문입니다.

외부에서는 우리의 RDS에 직접적으로 접근할수가 없습니다!

 

이후 EC2 -> 보안그룹 -> 인바운드 규칙 -> 인바운드 규칙 편집 에 들어가 다음과 같이 해주셔야 합니다.

ssh 접속을 위해 22번 포트로는 현재 내 IP를 허용하였습니다.

또한 웹 애플리케이션 서버이기 때문에 HTTP, HTTPS의 well known 포트인 80, 443에 대해서 허용하였습니다.

마지막으로 RDS 와의 소통을 위한 3306 포트 또한 열어두었습니다.

 

이후 발급받은 pem key를 이용하여 ssh로 접속하면 다음과 같이 성공적으로 접속할 수 있다.

 

3. EC2에 Java 11 설치

기본적으로 2022/5/31 현 기점으로 아직 Amazon Linux에서는 Java-11을 지원하지 않고 있다.

yum list java*

위 명령어를 통해 설치 가능한 Java의 버전들을 확인해 보면

java-11-amazon-corretto-javadoc.x86_64 가 ec2에서 설치할 수 있는 jdk11 버전 이다.

 

Amazon-corretto 는 무료로 사용할 수 있는 Open JDK의 의 프로덕션 용 멀티플렛폼 배포판 입니다.

다음 명령어를 통해 설치할 수 있습니다.

sudo yum install java-11-amazon-corretto-javadoc.x86_64

설치 후 버전을 확인해보면 다음과 같다.

 

4. EC2에 CodeDeploy Agent 설치

설치하는 과정은 다음 레퍼런스를 참고하였습니다.

 

Amazon Linux 또는 RHEL용 CodeDeploy 에이전트 설치 - AWS CodeDeploy

네 번째 명령에서 /home/ec2-user는 Amazon Linux 또는 RHEL Amazon EC2 인스턴스의 기본 사용자 이름을 나타냅니다. 사용자 지정 AMI를 사용하여 인스턴스를 만든 경우 AMI 소유자가 다른 기본 사용자 이름을

docs.aws.amazon.com

요약하면 다음과 같이 진행하시면 됩니다.

# 패키지 매니저 업데이트, ruby 설치
sudo yum update
sudo yum install ruby
sudo yum install wget

# 서울 리전에 있는 CodeDeploy 리소스 키트 파일 다운로드
cd /home/ec2-user
wget https://aws-codedeploy-ap-northeast-2.s3.ap-northeast-2.amazonaws.com/latest/install

# 설치 파일에 실행 권한 부여
chmod +x ./install

# 설치 진행 및 Agent 상태 확인
sudo ./install auto
sudo service codedeploy-agent status

Agent의 상태를 확인해보면 다음과 같이 실행중임을 확인하게 됩니다.

만약 실행상태가 아니라면 다음 명령어를 통해 실행해 줍니다.

sudo service codedeploy-agent start

 

5. EC2에 IAM Role 부여하기

EC2 에서 S3, CodeDeploy 에 접근할 수 있는 IAM Role을 부여해 보겠습니다.

IAM Role은 AWS 서비스 에서 다른 계정의 IAM 사용자, 혹은 다른 AWS 서비스에 접근할 수 있는 역할 권한을 부여하는 것 입니다.

 

이전 글에서 만들었던 IAM User와는 어떤점이 다를까요?

IAM Role IAM User
AWS 서비스에만 할당할 수 있는 권한 AWS 서비스 외에 사용할 수 있는 권한
EC2, CodeDeploy, SQS 등... 로컬 PC, IDC 서버, Github 등...

 

지금 만들 권한은 EC2에서 사용할 것 이기 때문에 User가 아닌 Role로 처리하게 됩니다.

 

우선 IAM으로 이동하여 다음과 같이 역할 만들기를 눌러줍니다.

 

이후 신뢰할 수 있는 엔티티 유형(접근할 대상)으로 AWS 서비스를 선택해 주고,

사용 사례로(리소스에 접근하려는 주체) 는 EC2 를 선택해 줍니다.

다음으로 넘어가 정책을 선택하는 부분에서

AWSCodeDeployFullAccess 와 AmazonS3FullAccess 를 선택해 줍니다.

 

이후 검토 부분에서 다음과 같이 확인할 수 있습니다.

 

이후 EC2 인스턴스로 이동하여 선택한 후, IAM 역할 수정을 눌러줍니다.

 

이후 역할을 선택하는 부분에서 직전에 만든 S3-CodeDeploy-FullAccess-Role을 지정해주고 저장합니다.

 

6. CodeDeploy를 위한 IAM Role 생성하기

CodeDeploy 서비스를 생성하기 전에, 이전 EC2와 마찬가지로 CodeDeploy를 위한 IAM Role이 필요합니다.

CodeDeploy 또한 EC2에 접근하려면 마찬가지로 IAM Role이 필요한 상황입니다.


다시 IAM - 역할 - 역할 만들기 로 이동하여, 신뢰할 수 있는 엔티티는 동일하게 AWS 서비스를, 사용 사례도 CodeDeploy를 선택하고 다음으로 넘어갑니다.

 

이후 권한 정책을 선택하는 페이지 에서 검색을 하면 CodeDeploy 관련 권한이 하나 뿐이라 바로 선택해주시면 됩니다.

AWSCodeDeployRole을 선택해주시면 됩니다.

(ps. CodeDeploy가 EC2에 접근할 때 필요한 Role이니까 정책 이름이 AWSec2FullAccessRole일것 같지만 그냥 AWSCodeDeployRole을 선택해주시면 됩니다.)

 

이후 검토페이지는 다음과 같습니다.

 

7. CodeDeploy 생성과 IAM Role 부여하기

CodeDeploy 는 AWS의 배포 삼형제중 하나 입니다. 이에 대해 간단하게 설명하면

 

  1. Code Commit
    • Github와 같은 코드 저장소
  2. Code Build
    • Travic CI, Github Actions 와 같은 빌드용 서비스 입니다.
  3. Code Deploy
    • AWS의 배포 서비스 입니다.
    • 오토 스케일링 그룹 배포, 블루/그린 배포, 롤링 배포, EC2 단독 배포 등 많은 기능을 지원합니다.

 

 

CodeDeploy 서비스를 실행하기 위해, 이동하여 애플리케이션 생성 을 눌러줍니다.

 

애플리케이션 이름을 선택하고, 플랫폼을 지정하여 애플리케이션 생성을 눌러줍니다.

 

이후 배포 그룹을 선택해 줘야 합니다.

 

배포 그룹 생성 화면에서 이름과, 방금 만들었던 IAM Role을 연결합니다.

 

우리는 최소 단위의 무중단 배포를 CodeDeploy가 아닌 Nginx를 통해 구현할 것이기 때문에, 지금은 일단 현재 위치 배포를 선택합니다.

만약 본인이 배포할 서비스가 2대 이상이라면 블루/그린 을 선택해주시면 됩니다!

 

환경 구성은 EC2를 선택하고,

태그 그룹에서는 EC2의 태그(EC2 이름)를 입력해 줍니다.

배포 설정은 여러 대의 서버를 어떤 단계에 따라 순차적으로 배포할 것인지를 선택하는 설정이다.


우리는 단일 EC2로 배포를 끝내는 CodeDeployDefault.AllAtOnce 를 선택할 것 입니다.

사진에는 잘렸는데, 로드밸런서는 없기 때문에 활성화를 해제합니다.

 

8. CodeDeploy 스크립트 작성

이제 CodeDeploy를 위한 설정작업이 끝났습니다.

다음으로는 배포에 CodeDeploy가 수행할 스크립트 파일을 작성해 줍시다!

 

먼저 프로젝트의 최상단에 appspec.yml을 생성합니다.


appspec.yml은 CodeDeploy Agent가 참조하면서 배포를 진행하는 스크립트 입니다.

 

우선 다음과 같이 일부분을 적고, 나머지는 이후 Nginx를 이용할때 작성하겠습니다.

# appspec.yml

version: 0.0
os: linux
files:
  - source: /
    destination: /home/ec2-user/airbnb-deploy/ # 프로젝트 이름
    overwrite: yes

permissions:
  - object: /
    pattern: "**"
    owner: ec2-user
    group: ec2-user
  1. version: 0.0
    • CodeDeploy의 버전입니다.
    • 프로젝트 버전이 아니라 0.0 외에 다른 버전을 지정하면 오류가 발생합니다 (주의!)
  2. source
    • CodeDepoly에서 전달해 준 파일 중에서 destination으로 이동시킬 대상을 지정합니다.
    • 루트 경로(/)를 지정하면 전체 파일을 이동시키게 됩니다.
  3. destination
    • source 에서 지정된 파일을 받을 디렉토리 위치 입니다.
  4. overwrite
    • 기존의 파일들을 덮어쓸지 결정합니다.
    • yes로 설정했으니 덮어쓰게 됩니다.

 

또한 Githun Actions 의 스크립트 에도 CodeDeploy 작업에 대한 부분을 작성해 줍니다.

새롭게 추가된 부분을 주석으로 명시하였습니다.

# airbnb-deploy.yml

name: test-deploy

on:
  push:
    branches: [test-deploy]
    
permissions:
  contents: read
  
env: 
  S3_BUCKET_NAME: build-jar-shine-deploy
  PROJECT_NAME: test-deploy
  
jobs:
  build:
    runs-on: ubuntu-latest
    env:
      working-directory: ./BE

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

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

      - name: Grant execute permission for gradlew
        run: chmod +x gradlew
        shell: bash
        working-directory: ${{env.working-directory}}

      - name: Build with Gradle
        run: ./gradlew bootjar
        shell: bash
        working-directory: ${{env.working-directory}}
        
      - name: Make zip file
        run: zip -r ./$GITHUB_SHA.zip .
        shell: bash
        working-directory: ${{env.working-directory}}

      - 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: Upload to S3
        run: aws s3 cp --region ap-northeast-2 ./$GITHUB_SHA.zip s3://$S3_BUCKET_NAME/$PROJECT_NAME/$GITHUB_SHA.zip
        working-directory: ${{env.working-directory}}
        
      # 새로 추가한 부분!!!!!!
      - name: Code Deploy
        run: aws deploy create-deployment --application-name airbnb-deploy --deployment-config-name CodeDeployDefault.AllAtOnce --deployment-group-name airbnb-code-deploy --s3-location bucket=$S3_BUCKET_NAME,bundleType=zip,key=$PROJECT_NAME/$GITHUB_SHA.zip
        working-directory: ${{env.working-directory}}
  • application-name
    • CodeDeploy 애플리케이션의 이름을 지정합니다.
  • deployment-config-name
    • 배포 그룹 설정에서 선택했던 배포 방식을 지정합니다.
  • deployment-group-name
    • 배포 그룹의 이름입니다.
  • s3-location
    • jar를 S3에서 가지고 오기 위해 차례로 bucket 이름, 파일 타입, 파일 경로를 입력합니다.

 

Github Actions에서 배포를 실행하기 전에 한 가지 진행해야 하는 부분이 있습니다!
지금까지의 과정 순서를 똑같이 따라하셨다면, CodeDeploy Agent를 시작한 후에 IAM Role을 EC2에 부여했기 때문에 아마 Agent가 IAM Role을 가지고 있지 않아 배포가 실패할 것입니다.

 

EC2에 접속해서 다음 커맨드로 Agent를 재시작해주세요!

sudo service codedeploy-agent restart

 

이후 우리의 test-deploy의 branch에 push 하게 되면 배포가 성공하게 됩니다.

 

EC2에 접속해 목록을 확인해 보면 다음과 같이 성공적으로 받아온것을 확인하게 됩니다.

 

user의 home 디렉토리에 S3로부터 받아온 airbnb-deploy 라는 디렉토리가 생성된것을 확인할수 있습니다.

 

다음 단계에서는 RDS와 연동을 한 후, 그 다음글에서 배포 스크립트를 통해 배포를 진행하겠습니다.

 

 

참고

https://jojoldu.tistory.com/267

 

7) 스프링부트로 웹 서비스 출시하기 - 7. Nginx를 활용한 무중단 배포 구축하기

이번 시간엔 무중단 배포 환경을 구축하겠습니다. (모든 코드는 Github에 있습니다.) 7-1. 이전 시간의 문제점? 이전 시간에 저희는 스프링부트 프로젝트를 Travis CI를 활용하여 배포 자동화 환경을

jojoldu.tistory.com

https://wbluke.tistory.com/40?category=418851 

 

Github Actions + CodeDeploy + Nginx 로 무중단 배포하기 (2)

CodeDeploy 소개 전 시간에 이어 다음으로는 Github Actions 에서 CodeDeploy 에게 S3에 있는 jar 파일을 가져가서 담당한 배포 그룹의 EC2에 배포해 줘! 라는 명령을 내릴 수 있도록 구성해 보겠습니다. 먼저

wbluke.tistory.com

 

댓글