자동배포(Github Action/AWS Codedeploy)

SaGo_MunGcci·2022년 10월 2일
0

실전 프로젝트

목록 보기
16/19

TIL

의사결정

배포 자동화 서비스

배경과 요구사항

  • private repository에 대해서 사용하는 데에 비용적인 문제가 크게 없어야 한다.
  • Python 런타임이 제공되어야 한다.
  • GitHub과 잘 연동되어야 한다.
  • AWS와 잘 접합되면 좋다.
  • 개발 조직이 Travis-CI를 써본 경험이 많이 있다.

선택지

  • Travis-CI
  • CircleCI
  • Amazon CodeBuild와 CodeDeploy를 함께 사용
  • Amazon CodeBuild만 사용

의사결정

Amazon CodeBuild만 사용하는 것을 선택하겠다. 그 이유는,

  • 개발 조직이 Travis-CI를 많이 써 봤지만, CircleCI나 Travis-CI나 private repository에 붙이려면 유료 플랜을 결제해야 하며 가격이 만만치 않다.
  • 관리 포인트가 여기저기에 분산되어 있으면 관리하기 불편하다. 되도록 AWS 내에서 모두 해결할 수 있도록 하기 위해서다.
  • CodeBuild는 private repository도 무료로 붙일 수 있게 되어 있다. 단지 빌드를 실행한 시간만큼만 지불하면 되는데, 월 100분까지는 무료로 제공되며 이를 넘더라도 과금이 그렇게 많지 않다. 메모리 3GB, 2개의 vCPU를 지원하는 build.general1.small 인스턴스 기준으로 하면 빌드 분당 0.005달러만 지불하면 된다.
  • CodeDeploy를 함께 사용하지 않는 이유는 바로 아래에서 더 설명한다.

CodeDeploy를 사용하지 않는 이유

zappa update라는 건 사실 우리의 웹 어플리케이션을 정말로 lambda에 새로 업데이트하는 배포의 과정이라, '코드 배포 자동화'라는 주제를 가진 CodeDeploy라는 서비스가 더 어울릴 것이라 생각할 수도 있다. 나도 그렇게 생각했어서 검토를 위해 조금 찾아봤더니, CodeDeploy는 정말 '배포 자체'에 대해 많은 지원을 하고 있었다. 무슨 뜻이냐면,

  • 우리가 그냥 zappa update 커맨드 하나로 패키징부터 업데이트까지 다 끝내니까 배포라는 게 정말 쉬워 보일 수 있겠지만, 배포 과정을 손수 정의하게 된다면 단일 작업이 많이 쪼개져 있어서 그리 쉬운 일이 아니다. 패키징도 해야 하고, 배포가 끝나면 어플리케이션 reload(서버 껐다 켜기)도 해줘야 하고, 서버가 다중화되어 있다면 그들도 함께 배포를 진행해야 한다. CodeDeploy는 일차적으로 '배포를 정의'하는 일을 많이 도와준다.
  • 어플리케이션을 배포하는 동안 가동 중지 시간을 최소화시키는 것도 배포에 있어서 매우 중요한 일이다. 그래서 구 버전과 새로운 버전의 코드를 함께 올려둔 채 트래픽을 나눠 전송하고, 새 버전의 어플리케이션으로 보내는 트래픽의 비율을 점진적으로 증가시키는 Canary 배포나, 구 버전과 새로운 버전의 코드를 함께 올려둔 채 트래픽을 이동시키고 구 버전의 코드를 제거하는 Blue/Green 배포같은 걸 쓰곤 한다. 에러가 생기면 롤백도 하고. 이러한 배포 프로세스들도 손수 정의하기 어려운 일이라 CodeDeploy가 도와준다.

엄청 좋아 보이지만 우리가 CodeDeploy를 사용하지 않는 이유는, CodeDeploy를 써서 얻을 수 있는 메리트가 그리 많지 않을 것이라고 생각했기 때문이다. 위에서도 말했듯 그냥 zappa update 커맨드가 패키징부터 배포까지 알아서 다 해주니 배포 정의에 대해 도움을 받을 이유가 딱히 없다. 게다가 가동 중지 시간 최소화는 lambda 자체에서 알아서 잘 챙겨준다. 현재로선 그냥 명령어를 대신 실행해 줄 주체가 필요할 뿐이다.

AWS CodeDeploy + Github Action + EC2 + S3 를 사용해 자동 배포를 구현한 경험을 공유하려고 합니다.

  • 먼저 깃 액션으로 서버를 자동 배포하기 위해서는  깃허브 Actions 탭을 눌러 준뒤 New workflows 를 눌러 workflows 파일을 생성해 줄 필요가 있다.

  • 다음과  같이 depoly.yml 파일을 만들어 주는데 코드는 아래와 같으며 주석을 통해 설명하겠다.
#main 브랜치에 푸시가 일어날때마다 동작
on:
  push:
    branches:
      - main

name: Deploy String boot to Amazon EC2
env:
  PROJECT_NAME: action_codedeploy

#실행되는 서버 사양은 우분투 18.04버전jobs:
  deploy:
    name: DEPLOY
    runs-on: ubuntu-18.04 (버전에 맞게 설정)
#작동확인
    steps:
      - name: Checkout
        uses: actions/checkout@v2

#프로젝트와 같은 jdk 17과 java17로 서버 내 설정 (버전에 맞게 설정)
      - name: Set up JDK 17
        uses: actions/setup-java@v1
        with:
          java-version: 17

#뒤에 일어날 작업을 위해 gradlew에 대한 권한 설정
      - name: Grant execute permission for gradlew
        run: chmod +x gradlew
        shell: bash

#깃 이그노어 처리되어 깃 레포지토리에 저장되지 않은 properties 파일 깃액션 서버내 생성
      - name: make application.properties
        run:
          mkdir ./src/main/resources |
          touch ./src/main/resources/application.properties
        shell: bash

#생성한 properties 파일에 깃 허브 내 secrets 경로에 환경변수로 저장한 properties 값을 저장
      - name: deliver application.properties
        run: echo "${{ secrets.PROPERTIES }}" > ./src/main/resources/application.properties
        shell: bash

#깃 레포지토리 파일 빌드
      - name: Build with Gradle
        run: ./gradlew build
        shell: bash

#zip 파일로 압축
      - name: Make zip file
        run: zip -qq -r ./$GITHUB_SHA.zip .
        shell: bash

#한국지역의 AWS에 접근하기 위한 ACCESS_KEY_ID와 SECRET_ACCESS_KEY를 secrets 경로에 환경변수로 저장한 각 키 값을 불러옴
      - 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

#aws s3버킷에 깃액션이 생성한 $GITHUB_SHA.zip파일 업로드. 이때 한국지역에서 S3버킷을 만들었으므로 --region ap-northeast-2로 설정, aws에 생성할 버킷명 sim-deploy을 다음 s3 주소에 추가. s3://버킷명(sim-deploy)/$PROJECT_NAME/$GITHUB_SHA.zip
      - name: Upload to S3
        run: aws s3 cp --region ap-northeast-2 ./$GITHUB_SHA.zip s3://sim-deploy/$PROJECT_NAME/$GITHUB_SHA.zip

#aws 에서 제공해주는 Code Deploy 서비스 사용. 이때 생성한 Code Depoly 어플리케이션 명 greenstep을 --application-name 뒤에 추가, 또한 Code Deploy가 받아올 S3 버킷명 sim-deploy를 --s3-location bucket= 뒤에 추가해준다.
      - name: Code Deploy
        run: aws deploy create-deployment --application-name greenstep --deployment-config-name CodeDeployDefault.OneAtATime --deployment-group-name dev --s3-location bucket=sim-deploy,bundleType=zip,key=$PROJECT_NAME/$GITHUB_SHA.zip
  • 위 코드를 통해 깃 레포지토리상의 파일을 깃액션상에서 자동으로 빌드, 압축 후 S3 버킷으로 보내주며, S3 버킷에 보내진 빌드 파일을 서버 배포를 도와주는 Code Deploy 애플리케이션에 저장시켜 주는게 이 deploy.yml의 핵심 기능이다.

  • 부가적으로 설명하자면 이 yml에서 사용되는 secrets 경로의 키 값들은 아래와 같은 방법으로 만들어준다.

  • Settings 탭을 누른뒤 Secrets 메뉴를 클릭, 서브 메뉴 중 Actions 메뉴를 누르면 Actions Secrets 이라는 페이지가 뜨는데, New Reposioty secret를 통해 시크릿 파일을 생성해 주면 된다.

  • 이때 파일명은 각각 PROPERTIES, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY로 만들어 주며 각각의 secret(환경변수) 값들을 넣어 파일을 생성해 주면 된다.

  • 이때 프로젝트의 properties 유형의 파일의 값을 그대로 집어넣으면 되는 PROPERTIES와 달리, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY의 경우 IAM의 값을 넣어줄 필요가 있는데 이에 대해서는 IAM 서비스 과정에서 서술하겠다.

  • 다음으로 위 사진과 같이 appspec.yml, beforeinstall.sh, deploy.sh 파일을 생성해 주면 깃 레포지토리 상에서의 서버 자동 배포 작업은 모두 끝이 난다.

  • 아래는 각 파일들을 생성할 때 사용된 코드들이다.

appspec.yml

#배포될 서버가 리눅스라 설정해줌
version: 0.0
os: linux

#아래 경로에서 실행
files:
  - source: /
    destination: /home/ubuntu/app
#실행 주체가 누구인지
permissions:
  - object: /home/ubuntu/app
    owner: ubuntu
    group: ubuntu
    mode: 755
hooks:
# 배포 이전 실행될 파일 beforeInstall.sh 파일은 이전에 배포된 파일을 삭제해줌
  BeforeInstall:
    - location: beforeInstall.sh
      timeout: 60
      runas: root
# 배포 시 실행될 파일, deploy.sh는 배포파일을 우분투 내에 실행시켜줌
  AfterInstall:
# location은 프로젝트의 root경로를 기준
    - location: deploy.sh
      timeout: 60
      runas: root

beforeinstall.sh

#!/usr/bin/env bash
#첫번째 줄 #!/usr/bin/env bash는 주석이 아니다 배쉬 경로 설정에 필요#해당 경로의 레포지토리들을 삭제해줌
REPOSITORY=/home/ubuntu/

if [ -d $REPOSITORY/myapp ]; then
    rm -rf $REPOSITORY/myapp
fi
mkdir -vp $REPOSITORY/myapp

deploy.sh

#!/usr/bin/env bash
#첫번째 줄 #!/usr/bin/env bash는 주석이 아니다 배쉬 경로 설정에 필요#해당 경로에 nohup으로 빌드 파일 강제실행
REPOSITORY=/home/ubuntu/app
cd $REPOSITORY

APP_NAME=greenstep
JAR_NAME=$(ls $REPOSITORY/build/libs/ | grep '.jar' | tail -n 1)
JAR_PATH=$REPOSITORY/build/libs/$JAR_NAME

CURRENT_PID=$(pgrep -f $APP_NAME)

if [ -z $CURRENT_PID ]
then
  echo "> 종료할것 없음."
else
  echo "> kill -9 $CURRENT_PID"
  kill -15 $CURRENT_PID
  sleep 5
fi

echo "> $JAR_PATH 배포"
nohup java -jar $JAR_PATH > /dev/null 2> /dev/null < /dev/null &
  • 다음으로 AWS의 설정들이다.

  • EC2 인스턴스를 우분투 18.04버전으로 설치하였고, 기본 포트인 80포트와 스프링 포트인 8080 포트를 포트포워딩 해주었다는 과정하에 설명을 이어가겠다.

  • 먼저 생성한 EC2 인스턴스에 태그를 하나 붙여 주어야 한다.

  • EC2 서비스로 들어가 인스턴스 메뉴를 누른뒤 태그 탭을 클릭하면 다음과 같은 화면을 볼 수 있다.

  • 태그관리를 눌러보자.

  • 키 종류와 키 값을 임의로 설정하여 설정한 인스터스를 불러올 수 있는 태그를 만들어보자.

  • 그 뒤 저장을 누르면 인스턴스에 태그가 붙여진 것을 볼 수 있을 것이다.

  • 다음으로 AWS에서 제공해주는 Identity and Access Management(IAM) 서비스에서 역할을 부여해 주어야 한다.

  • IAM 서비스에들어가 역할을 부여해 보자.

  • 역할 메뉴를 클릭, 역할 만들기 버튼을 누르면 다음과 같은 화면이 뜬다.

  • 신뢰할 수 있는 엔터티 유형을 AWS 서비스를 선택해 준뒤, 일반 사용 사례를 EC2를 선택, 이후 다음 버튼을 눌러주자.

  • CodeDeployFullAccess, S3FullAccess 을 각각 검색 후 체크해준다. 다음 정책이름을 검색하기 전에 이전 정책검색으로 인해 생성된 필터를 X버튼을 눌러 지워줘야한다.

  • 필터를 지워주지 않으면 다음 정책 이름이 검색되지 않으니 검색되지 않는다면 필터를 안 지운 것이 아닌지 다시 한번 확인해보자.

  • 각 정책들을 체크 한뒤에는 다음 버튼을 눌러준다.

  • 이제 해당 액세스들이 부여된 역할의 이름을 임의로 설정해주자(임의로 EC2-Deploy로 설정하였다)

  • 역할 생성 버튼을 누르면 역할이 생성된다.

  • 이 생성된 역할을 서버를 가동 시킬 EC2 인스터스와 연결해 줘야 한다.

  • 다시 EC2 서비스로 돌아가 인스턴스 메뉴를 클릭, 사용중인 인스턴스 id를 클릭해보자.

  • 작업 탭을 클릭, 보안을 누르고, IAM 역할 수정을 눌러준다.

  • 생성해 두었던 IAM 역할을 선택해준뒤, IAM 역할 업데이트를 눌러주면 역할과 인스턴스와의 연결 설정은 완료된다.

  • 이제 이 역할을 사용할 사용자를 추가해줘야 하다.

  • 다시 IAM 서비스로 돌아가보자.

  • 액세스 관리의 사용자 메뉴를 누르면 뜨는 화면의 사용자 추가 버튼을 누르면 아래와 같은 화면이 뜬다.

  • 사용자 이름은 임의의 값(임의로 service-deploy-user라 만들어 주었다. 사진의 끝에 붙은 숫자 2는 삭제)을 입력한 뒤 AWS 자격 증명 유형은 액세스 키로, 그뒤 다음:권한 버튼을 눌러 다음으로 넘어가 주자.

기존 정책 직접 연결을 선택해 준뒤 정책 필터를 통해

AmazonS3FullAccess,

AWSCodeDeployFullAccess

이 2개 필터를 체크해 주자.

그뒤 다시 다음:태그를 눌러 다음으로 넘어가자.

  • 인스턴스와 마찬가지로 키 종류와 값을 임의로 만들어 IAM 태그를 생성한뒤 다음:검토 버튼을 눌러보자.

  • 다시 사용자 만들기 버튼을 클릭하면 IAM 사용자가 추가된다.

  • 바로 닫지 말고 아래 화면이 뜰텐데 액세스 키 ID와 비밀 액세스 키를 복사해 따로 메모장 같은 곳에 저장해 놓자.

  • 비밀 액세스 키의 경우 표시 버튼을 누르면 나타나는 값을 복사해 주면된다.

  • 그뒤 다시 깃 레포지토리에 돌아가 앞서 깃허브의 시크릿 경로에 만들어 두었던 AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY에 각각 액세스 키 ID와 비밀 액세스 키의 값들을 넣주면 IAM에 대한 설정을 끝이난다.

  • 이제 jar 파일을 업로드할 배포용 S3 버킷을 만들어 보자.

  • AWS 에서 제공해주는 S3 서비스에 들어가 버킷 메뉴를 누르면 위 사진과 같은 화면을 볼 수 있다.

  • 버킷 만들기 버튼을 누른다.

  • 생성할 버킷 이름을 임의로 설정(임의로 sim-deploy로 설정)해주고 다른 설저들은 디폴트 값으로 건드리지 않았다.

  • 버킷 만들기 버튼을 눌러 버킷을 생성 해준다.

  • 이제 자동 배포의 핵심이 되는 CodeDeploy 어플리케이션을 만들어 보자.

  • AWS에서 제공하는 CodeDeploy서비스에 들어간다.

  • 애플리케이션 메뉴를 누른뒤 애플리케이션 생성버튼을 눌러준다.

  • 애플리케이션 이름을 임의로 설정(프로젝트명인 greenstep으로 임의로 설정함) 컴퓨팅 플랫폼은 EC2/온프레미스를 선택, 애플리케이션 생성 버튼을 눌러준다.

  • 다시 애플리케이션 화면으로 돌아가 생성한 애플리케이션 이름을 클릭해준다.

  • 배포 그룹 탭을 클릭, 배포 그룹 생성을 눌러준다.

  • 배포 그룹 명을 임의로 설정해주자.(임의로 dev로 설정)

  • 이후 서비스 역할 입력 부에 code-deploy를 선택해주자.

  • 배포유형은 아직 무중단 배포를 시도하는 것이 아니기에 현재위치로 선택.

  • 환경구성은 Amazon EC2 인스턴스를 선택해준다.

  • 태그 그룹은 인스턴스에 붙여넣은 태그 값을 넣어준다.

  • 배포 구성은 CodeDeployDefault.AllAtOnce를 선택해준다.

  • 로드 밸런싱 활성화는 아직 Http로 배포하기 때문에 비활성화 해주고 변경 사항 저장 버튼을 클릭한다.

  • 이제 깃배쉬를 통해 생성한 EC2 인스턴스에 접속해보자.

  • jdk를 프로젝트 버전에 맞게 설치하고, 방금 생성해둔 codedeploy를 사용하기 위해 codedeploy agent를 설치해주다.

  • aws 공식문서(Ubuntu Server용 CodeDeploy 에이전트 설치 - AWS CodeDeploy (amazon.com))에 들어가보면 설치방법에 대해 서술되어 있는데

  • 다음 순서에 맞게 설치해주면 된다.

  • 이때 한국리전을 사용하기 위해서는 wget https:// 다음에 나오는 bucket-name 부분을 aws-codedeploy-ap-northeast-2로 바꾸고, 그뒤 region-identifier를 ap-northeast-2로 바꿔줘야한다.

  • sudu service codedeploy-agent status를 사용해서 실행 유무를 확인해 주자.

  • 다음과 같이 running으로 active 상태가 표시되어 있으면 정상적으로 실행중인 상태이다.

  • 만약 실행중인 상태가 아니라면 sudo service codedeploy-agent start를 사용해서 실행해 주면 된다.

  • 이후 깃허브의 depoly.yml 로 돌아가 버킷 네임등을 생성한 값과 비교하여 맞추면 http 자동 배포가 완성된다.

  • 다음은 정상적으로 실행됐을때의 모습이다.

  • 깃허브의 액션을 눌러보면 다음과 같이 main 브랜치에 머지가 일어날때마다 머지 내역과 함께 체크 표시가 뜨는 것을 확인 할 수 있을것이다. 실패했을경우 X가 표시도니다.

  • 해당 머지 내역을 눌러보자.

  • 다음 페이지에서 Deploy를 눌러보면 아래 사진과 같이 빌드 후 파일 압축 S3버킷에 업로드 후 Code Deploy에 보내 주는 과정까지 정상적으로 작동되는 것을 확인 할 수 있다.

  • 다음으로 Code Deploy가 정상적을 작동되는지 확인해 보자.

  • CodeDeploy 서비스에서 배포 메뉴를 누르면 배포 성공 유무를 확인해 볼 수 있다.

  • 여기까지 완료되었다면 서버가 정상적으로 배포되는것을 확인 할 수 있다.

  • (자세한 해결 방법은 위 과정에 서술하였기 때문에 아래의 트러블 슈팅은 어떠한 문제들이 발생했고 어떻게 해결했는지 간략이 적었습니다.)

트러블 슈팅

깃액션 빌드 부분에서 계속해서 빌드에 실패하는 문제.

프로젝트를 깃 레포지토리에 저장시 properties 파일이 이그노어 처리되어 있어 레포지토리에 존재하지 않는 것이 문제.

그렇다고 주요 키값들을 깃허브내에 저장해서는 안되기 때문에 deploy.yml 파일에 시크릿 경로에서 properties 파일값을 불러와 레포지토리 밖에서 생성하는 방식을 추가.

문제점 해결

  1. 스파르타 코딩에서 스프링 기초 (남병관)님 꺼 5-4~5-6 까지 보고 인스턴스 세팅을 준비 후

    gitbash 또는 터미널을 이용해서 기초적인 배포 준비를 할 수 있다.

    주요 키워드 : 인스턴스 생성, 포트포워딩 , 파일질라 세팅, 노헙, 파일 디렉토리에 새로운 폴더 생성

    가. 인스턴스 생성은 스프링 기초 강좌를 참고 또는 추가 기록 내용에도 동일한 내용이 참조됨

    나. 포트포워딩

“sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 8080”

을 gitbash 또는 터미널에서 연결된 서버에 포트를 “8080”을 80으로 리다이렉트 하여 웹주소창에서 8080을 생략 가능토록 한다. // “80”번은 전세계 공통으로 디폴트 값이라 도메인 주소에 80이 안붙어도 자동으로 들어가진다.

다. 파일질라 세팅 : 기초 강의를 들으면서

1) 새 사이트 누르고 “프로젝트” 명을 임의적으로 정하면 된다 : 저는 final project로 정했습니다.

2) 프로토콜 타입은 SFTP로 설정

3) 호스트는 AWS인스턴스에서 “퍼블릭 IPv4 주소”라고 명시된 내용을 기입한다

4) 로그온 유형은 “키파일”로 설정

5) 사용자 : ubuntu로 기입

6) 키 파일 은 인스턴스 생성시에 만들어 놓은 pem타입의 키파일을 저장 위치를 찾아보기를 통해서

기입해주면 된다

7) 연결 버튼을 누른다.

라. 노헙 : 스프링 기초 강좌에서는 노헙을 해야하는 내용을 설명하지만, 자동배포 과정에서 git action을 통해 노헙이 될 수 있도록 조치를 하였다.

마. 디렉토리에 새로운 파일 생성 :

기존에 참고했던 블로그에서는 appspec.yml 에 “beforeinstall” 내용이 있었으나

code-deploy에서 지속적으로 beforeinstall 부분에서 에러가 발생 하여 관련내용을 검색해본 결과 appspec.yml에서 beforeinstall 에 이전에 있던 파일들을 삭제해주는 코드가 있어서, 부분을 삭제함.

바. 파일질라에서 home - ubuntu 밑 디렉토리에 “app”폴더 만들기

deploy.sh 가 실행되면서 자동적으로 우분투 서버에 home/ubuntu/app 의 경로에 빌드파일을 실행시켜야 하는데 파일질라에서 “app” 폴더가 자동생성 되어지지 않아서 에러가 지속적으로 발생 됨을 확인함.

IAM 설정 시

참고자료 :

https://isntyet.github.io/deploy/github-action과-aws-code-deploy를-이용하여-spring-boot-배포하기(1)/

https://isntyet.github.io/deploy/github-action과-aws-code-deploy를-이용하여-spring-boot-배포하기(2)/

https://isntyet.github.io/deploy/github-action과-aws-code-deploy를-이용하여-spring-boot-배포하기(3)/

https://isntyet.github.io/deploy/github-action과-aws-code-deploy를-이용하여-spring-boot-배포하기(4)/

https://kyuhyun7974.tistory.com/18

https://www.sunny-son.space/AWS/AWS%20CodeDeploy%EC%99%80%20ELB%EB%A5%BC%20%EC%9D%B4%EC%9A%A9%ED%95%9C%20%EB%AC%B4%EC%A4%91%EB%8B%A8%20%EB%B0%B0%ED%8F%AC%20-%202/

https://be-developer.tistory.com/51?category=1062619

서버 배포/Nohup/Nohup(키고끄기)

Git Action “Main Yml”

https://hanamon.kr/codestates-til-항해일지-70일차/



profile
이리저리 생각만 많은 사고뭉치입니다.

0개의 댓글