위 포스팅에 이어서, Github Actions 워크플로우를 실행하고 CodeDeploy, S3를 이용해 EC2 서버 내부에 배포를 수행하는 작업을 진행한다.
1. Github Actions 워크플로우 작성하기
Github Actions란?
Github 에서 제공하는 CI/CD (Continuous Integration/Continuous Deployment) 도구이다. 코드를 작성하였다면 이를 자동으로 빌드하거나 배포할 수 있는데, 이를 개발자가 직접 '워크플로우(workflows)'라는 이름의 자동화 코드를 작성하여 Github Actions가 개발자가 원하는 대로 순차적으로 작업(job)을 수행하게 된다.
나는 두 가지 워크플로우를 작성했는데, 하나는 dev 브랜치로 Pull Request를 올렸을 때 자동으로 빌드 및 테스트를 수행하는 워크플로우이고, 다른 하나는 dev 브랜치로 Merge하였을 때 (즉 dev 브랜치에서 변경사항이 생겼을 때) 자동으로 빌드 및 배포를 수행하는 워크플로우이다.
워크플로우는 프로젝트 최상단에 .github/workflows 경로에서 .yml 파일을 생성하는 것이 규칙이다. 이렇게 작성해야 Github Actions가 Pull Request 생성 이벤트, 혹은 Merge 이벤트 등을 감지해서 워크플로우를 실행할 수 있다.
직접 IDE에서 폴더와 .yml 파일을 생성해도 되고, 아래와 같이 Github 레포지토리에 들어가 Actions 탭 > Simple workflow의 Configure를 선택하여 생성할 수 있다.
이렇게 빈 공간에 코드를 작성한다.
빌드 및 테스트를 수행하는 워크플로우인 build.yml과, 배포를 수행하는 워크플로우인 deploy.yml 코드이다.
각자 프로젝트 워크플로우에 맞게 수정해서 사용하면 좋을 것 같다. : )
build.yml
name: build/test
on: # when the workflows should be triggered ?
pull_request: # Starting Build when pull request is created.
branches: [ "main", "dev"]
push:
branches: ["dev"]
permissions:
contents: read
checks: write
issues: write
jobs: # defining jobs, executed in this workflows
build:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3 # clone repository
# Caching Gradle
- name: Cache Gradle
uses: actions/cache@v3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-
# 프로젝트 세팅에 맞게 수정할 것 !
- name: Set up JDK 17
uses: actions/setup-java@v3 # set up the required java version
with:
java-version: '17'
distribution: 'temurin'
- name: Gradle Authorization
run: chmod +x gradlew
# Gradle run
# application-test.yml 환경설정으로 빌드하기 위해 -Dspring.profiles.active 옵션 추가
- name: Gradle Build Run
run: ./gradlew -Dspring.profiles.active=test build
# Gradle test
- name: Test with Gradle
run: ./gradlew -Dspring.profiles.active=test --info test
# Publish Unit Test Results
- name: Publish Unit Test Results
uses: EnricoMi/publish-unit-test-result-action@v1
if: ${{ always() }}
with:
files: "build/test-results/**/*.xml"
- name: Cleanup Gradle Cache
if: ${{ always() }}
run: |
rm -f ~/.gradle/caches/modules-2/modules-2.lock
rm -f ~/.gradle/caches/modules-2/gc.properties
deploy.yml
name: deploy
on:
push:
branches: ["dev"]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v3 # clone repository
# Caching Gradle
- name: Cache Gradle
uses: actions/cache@v3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*','**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-gradle-
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
- name: Gradle Authorization
run: chmod +x gradlew
- name: Gradle Build Run
run: ./gradlew build -x test
# $GITHUB_SHA는 기본 설정 된 Github 환경 변수이다. 랜덤으로 zip 파일의 이름을 지정한다.
- name: Create Zip files
run: zip -r ./$GITHUB_SHA.zip .
- name: Connecting to AWS
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 File to S3
run: |
aws s3 cp \
--region ap-northeast-2 \
./$GITHUB_SHA.zip s3://{S3버킷이름}
- name: Request to CodeDeploy
run: |
aws deploy create-deployment \
--application-name {CodeDeploy애플리케이션이름} \
--deployment-config-name CodeDeployDefault.AllAtOnce \
--deployment-group-name {CodeDeploy배포그룹이름} \
--s3-location bucket={S3버킷이름},bundleType=zip,key=$GITHUB_SHA.zip
이 deploy.yml이 Spring Boot 애플리케이션을 배포하는 핵심 워크플로우이다.
이 워크플로우가 실행되기 위해서는 github secrets에 AWS에 로그인하기 위한 IAM 사용자의 액세스 키와 비밀 키가 등록되어있어야 한다.
2. Github Secrets 등록하기
레포지토리의 Settings 탭에서 Secrets and variables > Actions 메뉴로 들어간다. New repository secrets 버튼을 누르고
아래와 같은 식으로 Name과 그에 해당하는 Secret 환경 변수 값을 기입하면, deploy.yml의 워크플로우에서 해당 시크릿 키를 가져다 쓸 수 있다.
IAM 사용자를 생성할 때 기록해두었던 두 개의 키를 활용해 Name, Secret으로 총 세개의 secrets를 등록해준다.
AWS_ACCESS_KEY_ID : 생성한 IAM 사용자의 액세스 키
AWS_SECRET_ACCESS_KEY : 생성한 IAM 사용자의 비밀 키
AWS_REGION : ap-northeast-2
이 과정을 거치면, dev 브랜치에 push 이벤트가 생기면 자동으로 deploy.yml 워크플로우가 실행된다. 워크플로우가 실행되면 작성해놓은 각 단계(step)에 맞추어 jar 파일이 빌드되고, 프로젝트 전체가 하나의 zip 파일로 합쳐져 S3에 저장된다. 그리고 CodeDeployAgent에게 배포를 수행하라는 요청을 보내면서, Code Deploy Agent 빌드 스크립트를 찾아 실행한다.
3. appspec.yml 작성하기
CodeDeploy Agent는 배포 요청을 받게 되면 EC2 서버에 저장된 프로젝트 경로에 접근하여 appspec.yml을 실행한다. 따라서 프로젝트의 루트에 appspec.yml 을 작성해야하고, 코드는 다음과 같다.
appspec.yml
version: 0.0
os: linux
files:
- source: /
destination: /home/ubuntu/app # 프로젝트 이름
overwrite: yes
file_exists_behavior: OVERWRITE
permissions:
- object: /
pattern: "**"
owner: ubuntu
group: ubuntu
hooks:
ApplicationStart:
- location: scripts/run_new_was.sh
timeout: 180
runas: ubuntu
- location: scripts/health_check.sh
timeout: 180
runas: ubuntu
- location: scripts/switch.sh
timeout: 180
runas: ubuntu
appspec.yml 코드에 의해서 S3에서 저장된 zip 파일이 /home/ubuntu/app 이라는 경로로 받아온다.
배포 스크립트는 다음 단계에서 무중단 배포와 관련된 설정을 하며 코드를 제시하고 설명하도록 하겠다.
여기까지 CodeDeploy Agent가 실행되고 배포 스크립트를 실행하는 appspec.yml 을 작성하는 것 까지 단계를 마쳤다. 다음 단계에서는 EC2 서버 내에서 Code Deploy Agent가 동작하고, Jar 파일 빌드, NginX 무중단 배포를 수행하기 위한 각종 패키지를 설치해보겠다.
4. EC2 서버 접속 후 패키지 설치
EC2 서버 접속
SSH 프로토콜로 Ubuntu EC2 서버에 접속하자.
이전에 인스턴스를 생성할 때 저장하였던 key가 있는 경로에서 아래 명령어를 입력하여 서버에 접속한다. 만약 SSH 접속이 처음이라면 친절하게 설명한 블로그를 첨부하니, 참고하길 바란다.
https://wlsvud84.tistory.com/12
나같은 경우에는 key 파일이 있는 .ssh 폴더에 config 파일을 생성하고 아래와 같이 접속 정보를 미리 입력해두어, 간단한 명령어로 접속할 수 있게 설정해놓았다.
vi config
## .ssh/config
Host {접속할 때 입력할 명칭}
HostName {탄력적IP주소}
User {유저이름}
IdentityFile {key파일의경로}
## 접속시
ssh {접속할 때 입력할 명칭}
CodeDeploy Agent 패키지 설치
1. 저장소 업데이트
sudo apt-get update
sudo apt-get upgrade
2. ruby 설치
CodeDeployAgent는 Ruby라는 언어로 구현되었기 때문에, 관련 패키지를 설치한다.
sudo apt-get install ruby
3. wget 설치
wget 명령어를 이용해 Agent 설치파일을 다운로드한다.
sudo apt-get install wget
4. CodeDeploy Agent 설치
# Agent 설치 파일 다운로드 경로
cd /home/ubuntu
# Seoul Region으로 Agent 를 다운로드한다.
wget https://aws-codedeploy-ap-northeast-2.s3.ap-northeast-2.amazonaws.com/latest/install
chmod +x ./install
sudo ./install auto
5. 서비스가 실행 중인지 확인
sudo service codedeploy-agent status # 상태 확인
sudo service codedeploy-agent start # 서비스 시작
sudo service codedeploy-agent restrat # 서비스 재시작
참고로, CodeDeploy Agent가 배포를 시작하고 발생한 로그들은 모두 /var/log/codedeploy-agent/codedeploy-agent.log에 찍힌다. 나중에 배포 상태로 개발하다보면 예상치 못한 에러가 많이 생기는데, 이 로그 파일을 잘 확인하면 좋다 !
JDK 설치
추후 배포 스크립트를 작성할 때 java -jar 명령어로 jar 파일을 빌드하게 되는데, 이 과정에서 JDK가 Ubuntu 서버 내에 설치되어있어야 한다.
나는 JDK 17 버전이기 때문에 17 버전을 기준으로 설명하겠다.
1. 저장소 업데이트
sudo apt-get update
sudo apt-get upgrade
2. openjdk-17 설치
sudo apt-get install openjdk-17-jdk
3. 설치 확인
java -version
# 아래와 같은 로그가 뜨면 성공
# openjdk version "17.0.3" 2022-04-19
# OpenJDK Runtime Environment (build 17.0.3+7-Ubuntu-0ubuntu0.20.04.1)
# OpenJDK 64-Bit Server VM (build 17.0.3+7-Ubuntu-0ubuntu0.20.04.1, mixed mode, sharing)
NginX 설치
1. 저장소 업데이트
sudo apt-get update
sudo apt-get upgrade
2. Nginx 설치
sudo apt-get install nginx
3. 서비스가 실행되는지 확인
sudo service start nginx
sudo service status nginx
이렇게 서버에 필요한 패키지까지 설치하고 나면, 배포를 할 준비가 끝났다.
다음 포스팅에서 무중단 배포와 관련된 내용을 포스팅하면서, 최종 배포 테스트를 해보겠다.
포스팅에 잘못 기입된 부분이 있다면 댓글로 알려주시면 감사하겠습니다 ! 😊
'Server > Architecture' 카테고리의 다른 글
Github Actions + Code Deploy + S3 + NginX 로 Spring Boot 블루/그린 무중단 배포 구현하기 (3) (0) | 2023.08.28 |
---|---|
Github Actions + Code Deploy + S3 + NginX 로 Spring Boot 블루/그린 무중단 배포 구현하기 (1) (0) | 2023.08.27 |
[MSA] 터빈 서버 (Turbine Server)로 Hystrix Client 메시지 수집하기 (0) | 2023.03.28 |
[MSA] Spring Cloud Config Server 구축 및 profiles 설정 (2) | 2023.03.27 |
[MSA] 유레카(Eureka)서버, 줄(Zuul) 서버 설정 및 구동하기 (0) | 2023.03.24 |