CodeDeploy 설치 및 GitHub Actions 워크플로우 작성

이제 EC2 인스턴스에 CodeDeploy를 설치하고 GitHub Actions 워크플로우를 작성할것이다.

GitHub Actions 워크플로우를 요약하면 아래와 같다.

  1. GitHub Actions로 jar 파일을 빌드하고 jar파일, appspec.yml, 배포 스크립트들을 zip로 압축한다.
  2. GitHub의 Secret에 저장한 AWS IAM 사용자 정보를 이용하여 S3, CodeDeploy 접근 권한을 얻는다.
  3. 1에서 압축한 zip 파일을 S3에 저장하고, CodeDeploy 배포 프로세스를 실행한다.
  4. EC2의 CodeDeploy Agent는 S3에 저장된 zip 파일을 압축 해제하여 appspec.yml을 참고하여 배포 프로세스를 진행한다.

AWS IAM 사용자 설정은 이쪽 글을 참고하도록 하자.

Secret은 아래와 같은 변수명으로 설정해주었다.

Secret에 변수를 저장하는 방법은 이 글을 참고하자.

 


1. EC2에 CodeDeploy 설치

아래 명령어로 EC2 인스턴스에 CodeDeploy를 설치해준다.

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

 

위 명령어를 순서대로 입력하고, 가장 아래 명령어를 입력했을 때 아래처럼 뜨면 CodeDeploy가 제대로 설치된 것이다.


2. GitHub Actions 워크플로우 작성

아래 워크 플로우는 테스트하기 편하게 main 브랜치에 PR을 올릴 때 동작하게끔 했다.

실제로는 PR이 제대로 머지된 후에 동작하게끔 바꾸도록 하자.

name: CI/CD with S3 and CodeDeploy

on:
  pull_request:
    branches: [ "main" ]

env:
  AWS_REGION: ap-northeast-2
  S3_BUCKET_NAME: midcondria-cicd
  CODE_DEPLOY_APPLICATION_NAME: midcon-codedeploy-app
  CODE_DEPLOY_DEPLOYMENT_GROUP_NAME: midcon-codedeploy-deploy-group

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v4
    - name: Set up JDK 17
      uses: actions/setup-java@v4
      with:
        java-version: '17'
        distribution: 'temurin'  

    ## application.yml 파일 생성
    - name: make application.yml
      run: |
        echo ">> mkdir & touch"
        mkdir -p ./src/main/resources
        cd ./src/main/resources
        touch ./application.yml
        echo ">> copy application.yml"
        echo "${{ secrets.PROPERTIES }}" >> ./application.yml
        
    - name: Grant execute permission for gradlew
      run: chmod +x gradlew
      shell: bash

    - name: Build with Gradle Wrapper
      run: ./gradlew build -x test  // 여기서는 편의성을 위해 테스트를 안하기로 했음
      shell: bash

    - name: Make zip file
      run: zip -r ./myapplication.zip appspec.yml scripts/* ./build/libs/team-0.0.1-SNAPSHOT.jar
      shell: bash

    - name: Configure AWS credentials
      uses: aws-actions/configure-aws-credentials@v1
      with:
        aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY }}
        aws-secret-access-key: ${{ secrets.AWS_SECRET_KEY }}
        aws-region: ${{ env.AWS_REGION }}

    - name: Upload to AWS S3
      run: |
        aws s3 cp \
          --region $AWS_REGION ./myapplication.zip s3://$S3_BUCKET_NAME/$GITHUB_SHA.zip

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

3. 결과 확인

3-1. PR 시 GitHub Actions 동작 확인

3-2. CodeDeploy 동작 확인

아래처럼 배포 세부 정보를 확인할 수 있다.

 

배포 이벤트 별로 확인할 수 있으니 실패 시 어디서 실패했는지 참고할 수 있다.

 

아래 명령어로 CodeDeploy Agent의 로그를 확인할 수 있다.

본인은 대부분 appspec.yml을 대문자로 써서 못찾는 이슈 때문에 보긴 했지만 여러 로그가 남으니 참고하자.

vim /var/log/aws/codedeploy-agent/codedeploy-agent.log

 

3-3. EC2 인스턴스 확인

EC2 인스턴스의 /home/ubuntu/app 경로를 확인하면 아래와 같다.

S3 버킷에 저장된 zip 파일에 담긴 appspec.yml, jar파일, 배포 스크립트 파일들이 이 경로에 있고, 이들을 사용함을 알 수 있다.

 

아래처럼 접속도 잘 된다.

배포 스크립트 작성 및 Nginx 설정

이번 글에서는 무중단 배포를 3가지 스탭으로 나눠서 배포용 쉘 스크립트를 작성하고,

CodeDeploy에서 배포를 위해 참고할 AppSpec 파일을 작성할 것이다.

배포 스크립트는 아래와 같이 세가지 스탭으로 나눈다.

  1. 서비스 중인 WAS와 다른 포트에 새로운 버전의 WAS를 띄운다.
  2. 1번의 과정이 정상 동작 했는지 해당 포트로 HTTP 요청을 보내 확인한다.
  3. 1, 2가 정상 동작한다면 Nginx가 새로운 버전의 WAS를 바라보도록 변경하고 기존의 WAS를 종료한다.

1. 배포 스크립트 작성

이제 배포 시 실행할 쉘 스크립트를 작성할 것이다.

기존에 리버스 프록시로 이용하고 있던 Nginx를 여기서도 써먹어서 무중단 배포를 구현한다.

배포 스크립트의 각 스탭에 주석을 달아두었으니 리눅스 커맨드를 어느정도 알고 있다면 쉽게 이해할 수 있을 것이다.

1-1. run_new_was

업데이트 된 버전의 새로운 WAS를 띄운다.

# run_new_was.sh

#!/bin/bash

# 환경 변수 설정
PROJECT_ROOT="/home/ubuntu/app" # 프로젝트 루트
JAR_FILE="$PROJECT_ROOT/build/libs/team-0.0.1-SNAPSHOT.jar" # 빌드해서 생성된 jar 파일명

# service_url.inc 에서 현재 서비스 중인 WAS의 포트 번호 확인
CURRENT_PORT=$(cat /home/ubuntu/service_url.inc | grep -Po '[0-9]+' | tail -1)
TARGET_PORT=0

echo "> Current port of running WAS is ${CURRENT_PORT}."

# 서비스 중인 포트가 8081이면 8082 포트로 배포
# 서비스 중인 포트가 8082이면 8081 포트로 배포
if [ ${CURRENT_PORT} -eq 8081 ]; then
  TARGET_PORT=8082
elif [ ${CURRENT_PORT} -eq 8082 ]; then
  TARGET_PORT=8081
else
  echo "> Any WAS is connected to nginx" # 애플리케이션이 실행되고 있지 않음
fi

# 타겟 포트 번호로 실행 중인 프로세스가 있는지 확인
TARGET_PID=$(lsof -Fp -i TCP:${TARGET_PORT} | grep -Po 'p[0-9]+' | grep -Po '[0-9]+')

# PID를 이용해 타겟 포트로 실행 중인 프로세스 Kill
if [ ! -z ${TARGET_PID} ]; then
  echo "> Kill ${TARGET_PORT}."
  sudo kill ${TARGET_PID}
fi

# 타켓 포트로 업데이트 된 버전의 새로운 서버 실행
nohup java -jar -Dserver.port=${TARGET_PORT} ${JAR_FILE} > /home/ubuntu/nohup.out 2>&1 &
echo "> Now new WAS runs at ${TARGET_PORT}."
exit 0

1-2. health_check

새로 띄운 WAS가 정상 동작하는지 헬스 체크한다.

# health_check.sh

#!/bin/bash

# 환경 변수 설정
# service_url.inc에서 현재 서비스 중인 WAS의 포트 번호 확인
# 해당 포트 번호로 health_check 실행
CURRENT_PORT=$(cat /home/ubuntu/service_url.inc | grep -Po '[0-9]+' | tail -1)
TARGET_PORT=0

if [ ${CURRENT_PORT} -eq 8081 ]; then
    TARGET_PORT=8082
elif [ ${CURRENT_PORT} -eq 8082 ]; then
    TARGET_PORT=8081
else
    echo "> Any WAS is connected to nginx"  # 헬스체크 시 Nginx에 어떤 WAS도 연결돼있지 않으면 에러 코드
    exit 1
fi

echo "> Start health check of WAS at 'http://127.0.0.1:${TARGET_PORT}' ..."

# "/" 경로로 헬스 체크하여 응답 코드를 보고 서버가 정상적으로 작동하는지 확인
# 최대 10번까지 테스트 해서 그 안에 성공하면 통과(WAS가 늦게 뜨는 경우를 대비한 안전 장치)
for RETRY_COUNT in 1 2 3 4 5 6 7 8 9 10
do
    echo "> #${RETRY_COUNT} trying..."
    # 테스트할 API 주소를 통해 http 상태 코드 확인
    RESPONSE_CODE=$(curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:${TARGET_PORT})

	  # RESPONSE_CODE의 http 상태가 200번인 경우 성공
    if [ ${RESPONSE_CODE} -eq 200 ]; then
        echo "> New WAS successfully running"
        exit 0
    elif [ ${RETRY_COUNT} -eq 10 ]; then
        echo "> Health check failed."
        exit 1
    fi
    sleep 5  # 각 시도 마다 5초간 대기
done

 

이 때, 본인은 "/"  경로로 헬스 체크를 수행하였다.

따라서 "/" 경로로 GET 요청 시 상태코드 200을 반환하는 컨트롤러를 하나 만들어줘야 한다.

포트번호까지 확인하고 싶어서 아래처럼 해주었다.

@Slf4j
@RestController
public class HealthChecktController implements ApplicationListener<WebServerInitializedEvent> {

    private int serverPort;

    @Override
    public void onApplicationEvent(WebServerInitializedEvent event) {
        this.serverPort = event.getWebServer().getPort();
    }

    @GetMapping
    public String health() {
        log.info("[헬스체크] 포트번호: {} 호출", serverPort);
        return "hi" + serverPort;
    }
}

1-3. switch

위 두 단계가 정상적으로 진행됐다면 Nginx가 바라보는 애플리케이션을 스위칭한다.

그리고 이전 버전의 WAS는 종료한다.

# switch.sh

#!/bin/bash

# service_url.inc에서 현재 서비스 중인 WAS의 포트 번호 확인
CURRENT_PORT=$(cat /home/ubuntu/service_url.inc  | grep -Po '[0-9]+' | tail -1)
TARGET_PORT=0

echo "> Nginx currently proxies to ${CURRENT_PORT}."

if [ ${CURRENT_PORT} -eq 8081 ]; then
    TARGET_PORT=8082
elif [ ${CURRENT_PORT} -eq 8082 ]; then
    TARGET_PORT=8081
else
    echo "> No WAS is connected to nginx"
    exit 1
fi

# service_url.inc 파일에 적힌 서비스 주소를 새로 띄운 서버의 주소로 변경
echo "set \$service_url http://127.0.0.1:${TARGET_PORT};" | tee /home/ubuntu/service_url.inc

echo "> Now Nginx proxies to ${TARGET_PORT}."

# service_url이 변경됐으므로 nginx를 reload 해줌
sudo service nginx reload

echo "> Nginx reloaded."

# -9 SIGKILL 은 서버를 바로 종료하므로
# -15 SIGTERM  안전 종료인 SIGTERM을 사용하여 이전 포트 프로세스를 제거한다.
CURRENT_PID=$(lsof -Fp -i TCP:${CURRENT_PORT} | grep -Po 'p[0-9]+' | grep -Po '[0-9]+')

if [ -z "$CURRENT_PID" ]; then
    echo "> No process found on port ${CURRENT_PORT}."
else
    echo "> Killing process ${CURRENT_PID} on port ${CURRENT_PORT}."
    sudo kill -15 ${CURRENT_PID}

    # kill 명령이 실패했는지 확인
    if [ $? -eq 0 ]; then
        echo "> Process ${CURRENT_PID} successfully terminated."
    else
        echo "> Failed to terminate process ${CURRENT_PID}."
        exit 1
    fi
fi

2. 무중단 배포를 위한 Nginx 설정

8081, 8082 두개의 포트를 이용하여 애플리케이션을 띄우는 방식으로 무중단 배포를 구현한다.

기존 서비스가 8081이면 8082 포트로 새로운 버전의 애플리케이션을 띄우고, 정상 동작 시 기존 8081 포트를 내린다.

Nginx로 도메인으로의 요청을 포트포워딩 해주고 있으므로 Nginx 설정을 배포 시에 자동으로 수정하도록 변경해줘야 한다.

 

1에서 배포 스크립트를 작성하면서 service_url.inc 를 보았을 것이다.

service_url.inc의 내용은 아래와 같다.

# service_url.inc
set $service_url http://127.0.0.1:8081;

 

배포 시 매번 $service_url이 변경되면서 Nginx가 바라볼 포트 번호를 지정해준다.

/etc/nginx/sites-available/default 파일이 service_url.inc의 $service_url를 이용할 수 있도록 아래처럼 수정해주자.

include /home/ubuntu/service_url.inc; 구문으로 /home/ubuntu/service_url.inc 를 참조할 수 있게 해준다.

다른 포트로 접근 시 막히거나 리다이렉트 되기 때문에 443 포트로 접근할 때만 설정해주면 된다.


3. AppSpec 파일 작성

CodeDeploy Agent는 배포 시 appspec.yml 파일을 참고하여 배포 프로세스를 진행한다.

(참고로 파일 이름은 꼭 appspec.yml 이어야 한다!)

 

본인은 EC2의 /home/ubuntu/app 폴더에서 배포를 진행할 것이다.

아래처럼 설정하면 CodeDeploy Agent가 동작할 때 S3 버킷의 zip 파일을 /home/ubuntu/app 로 압축해제한다.

AppSpec 파일은 기본적으로 배포를 실행할 폴더의 루트 디렉터리 에 위치해야 하기 때문에

압축 시 루트 디렉터리에 위치시켜주면 된다.

appspec.yml

files의 overwrite: yes 로 설정하면 /home/ubunut/app 경로가 없을 시 자동으로 생성한다.

해당 옵션이 없을 때 /home/ubunut/app 경로가 없으면 배포에 실패하므로 참고하자.

version: 0.0
os: linux

files:
  - source: /
    destination: /home/ubuntu/app
    overwrite: yes  # /home/ubuntu/app 경로가 없을 시 생성함

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

hooks:
  ApplicationStart:
    - location: scripts/run_new_was.sh
      timeout: 60
      runas: ubuntu
    - location: scripts/health_check.sh
      timeout: 60
      runas: ubuntu
    - location: scripts/switch.sh
      timeout: 60
      runas: ubuntu

AWS S3

자동화 된 배포를 위해서는 배포 파일을 저장할 수 있는 저장소가 필요한데, 이 저장소를 S3로 선택했다.

이전 글에서 이미지 저장소를 만들 때도 썼던 그 S3인데, CI/CD 용 버킷을 새로 만들어서 사용한다.

S3를 선택한 이유는 자동 배포를 위해 AWS CodeDeploy를 사용할 예정이라 같은 AWS 서비스라서 연동하기 편하기 때문이다.


1. EC2에 적용할 IAM 역할 설정

CI/CD 과정에서 EC2 인스턴스에서 실행 중인 CodeDeploy를 통해 S3 버킷의 배포용 파일들에 접근한다.

따라서 EC2의 IAM 역할을 설정해줘야 문제 없이 동작한다.

1-1. IAM 역할 생성 페이지로 이동

1-2. 신뢰할 수 있는 엔티티 선택

1-3. 권한 추가

1-4. 역할 이름 지정

역할 이름 지정 후 생성을 완료한다.

1-5. EC2 인스턴스에 IAM 역할 연결

EC2 인스턴스로 이동해서 IAM을 연결한다.


2. S3 버킷 생성

CI/CD 용으로 버킷을 새로 만들것이다.

깃헙 액션에서 IAM 사용자 정보로 이 S3 버킷에 저장한다.

따라서 퍼블릭 엑세스가 필요 없으므로 최대한 private 하게 생성한다.

2-1. S3 버킷 생성 페이지로 이동

2-2. 버킷 만들기

아래처럼 리전과 이름만 설정하면 나머지는 기본값으로 생성하면 된다.

2-3. 버킷 생성 확인

 

CodeDeploy

CodeDeploy는 EC2, ECS 등의 서비스로의 애플리케이션 배포를 자동화하 해주는 배포 서비스이다.

S3에 저장된 배포 파일들을 이 CodeDeploy가 자동으로 배포하도록 설정할 수 있다.


1. CodeDeploy에 적용할 IAM 역할 설정

CodeDeploy 애플리케이션을 생성하고 이를 이용해 EC2에 배포할 것이다.

이 때, CodeDeploy가 EC2에 접근하여 배포 과정을 실행하기 위해 IAM 역할을 설정해줘야 한다.

1-1. IAM 역할 생성 페이지로 이동

1-2. 신뢰할 수 있는 엔티티 선택

CodeDeploy로 선택해주면 권한은 자동으로 추가되므로 이후는 기본값으로 설정한다.

1-3. 역할 이름 지정

역할 이름 지정 후 생성을 완료한다.


2. CodeDeploy 애플리케이션 생성

2-1. 애플리케이션 생성 페이지로 이동

2-2. 애플리케이션 생성

아래 사진처럼 앱 이름과 컴퓨팅 플랫폼을 설정해준다.

컴퓨팅 플랫폼은 EC2/온프레미스로 선택하고 애플리케이션을 생성한다.


3. CodeDeploy 배포 그룹 설정

3-1. 배포 그룹 생성 페이지로 이동

3-2. 배포 그룹 설정

배포 그룹 설정을 해준다.

역할은 위 1 에서 생성한 역할을 선택해준다.

3-3. 환경 구성

3-2에서 아래로 내려오면 환경 구성이 나온다.

EC2 인스턴스를 선택하고, 태그 그룹을 선택해준다.

이 글에서 생성한대로 EC2를 생성했다면 아래처럼 선택할 수 있다.

EC2 설정에서 태그를 따로 생성할 수도 있다.

태그를 선택하면 맨 아래 박스처럼 일치하는 인스턴스를 확인할 수 있다.

3-3. 설정 완료

AWS Systems Manager 설정은 적당히 넘기고

배포 설정을 확인하면 아래처럼 돼 있으면 넘어간다.

로드 밸런서는 사용하지 않으니 설정을 완료하고 배포 그룹을 생성한다.

CI/CD

지금까지 EC2 인스턴스를 만들고 서버를 띄워서 배포도 했고, RDS 인스턴스를 만들어서 DB도 연동했다.

버전 업데이트 시 일일이 테스트 및 빌드 하던 것도 Github Actions로 자동화했으니 CI 까지는 진행하였다.

이제 배포의 틀은 어느정도 갖춰지긴 했지만, 아직까지 수작업으로 매번 scp 커맨드를 써서 최신 버전으로 배포하고 있다.

결국 이런 단순 반복 작업은 사람이 하다보면 언젠가 꼭 실수가 나오기 마련이고, 이는 곧 장애로 이어질 수 있다.

따라서 이번엔 GitHub에 PR을 올리고 머지 시 배포되는것 까지 자동화(CD) 해보려 한다.

 

보통 이 두가지를 합쳐서 CI/CD라고 한다.

자동 빌드 및 테스트(CI, Continuous Integration)

업데이트 한 버전을 자동으로 빌드 및 테스트 하는 것

배포 자동화(CD, Continuous Deploy)

빌드 및 테스트를 마치고 성공적으로 업데이트 한 버전의 애플리케이션을 자동으로 배포 하는 것


CI/CD & 무중단 배포

애플리케이션의 버전을 업데이트하면 자동으로 빌드 및 테스트하고, 자동으로 배포까지 해보려 한다.

하지만 현재 배포 중인 서비스를 종료하고, 새로운 버전의 서비스를 띄우면 서버가 죽어있는 시간이 존재하지 않을까?

만약 별 다른 공지 없이 이렇게 서버가 내려가 있으면 사용자에게 나쁜 경험을 줄 수 있다.

따라서 새로운 버전을 배포해도 서버가 죽어있는 시간이 거의 없는 자동화 과정을 만들어보려 한다.

그림으로 나타내자면 아래와 같다.

 

 

참고자료

 

Github Actions CD: AWS EC2 에 Spring Boot 배포하기

Overview 애플리케이션을 개발하면 외부에서도 접근 가능하도록 클라우드 환경에 배포합니다. 이전에 포스팅 했던 AWS 1편에서는 마지막에 scp 명령어로 로컬에 존재하는 빌드 파일을 EC2 인스턴스

bcp0109.tistory.com

 

 

IAM

IAM은  AWS 리소스에 대한 액세스를 안전하게 제어하게 해주는 웹 서비스이다. 

이 서비스를 이용하여 AWS 서비스에 접근할 수 있는 권한을 설정할 수 있다.

IAM 사용자를 생성하고, 생성한 사용자에게 권한을 부여해보자.


1. IAM 사용자 생성

Github Actions나 우리의 스프링부트 애플리케이션 같이 외부에서 AWS 서비스에 접근하기 위해서는 

해당 서비스에 대한 권한을 가진 사용자의 accessKey와 secretKey가 필요하다.

스프링부트 애플리케이션에서 AWS SDK로 S3 버킷에 이미지를 저장할 때도 이 IAM 사용자를 만들어서 사용한다.

이번 글에서는 CI/CD에 쓸 수 있도록 Github Actions에서 S3, CodeDeploy 이 두 서비스에 대한 권한을 가진 사용자를 만들어 본다.

1-1. 사용자 생성 페이지로 이동

1-2. 사용자 이름 설정

1-3. 사용자 권한 설정

Github Actions에서 AWS 서비스를 이용하기 위해서는 S3, Code Deploy에 대한 권한이 필요하다.

따라서 권한 정책에서 아래 두개를 선택하고 사용자 생성을 완료한다.

  • AmazonS3FullAccess
  • AWSCodeDeployFullAccess

1-4. 사용자 생성 확인

2. IAM 사용자 액세스 키 생성

2-1. 액세스 키 생성

2-2. 액세스 키 사용 사례 선택

2-3. 액세스 키 생성 및 확인

액세스 키를 생성 완료하면 아래와 같은 창을 확인할 수 있다.

시크릿 키  생성 시에만 확인할 수 있으므로 따로 저장해두고 분실 시 재발급해야 한다.

자동 빌드 및 테스트(CI, Continuous Integration)

업데이트 한 버전을 자동으로 빌드 및 테스트 하는 것 CI라고 한다.

 

협업 시 대부분 Git, GitHub을 통해 버전 관리를 할텐데, GitHub에 올리는 버전은 모든 팀원이 공유를 한다.

버전 업데이트 시 제대로 테스트가 통과하는지 확인하고 GitHub에 올려야 팀원들이 Pull 받고 오류가 발생하지 않을것이다.

따라서 GitHub에 푸시 전에 일일이 빌드도 해보고 테스트도 제대로 통과하는지 확인하고 버전을 업데이트 해야 한다.

하지만 사람이 하는 작업인지라 아무래도 빠르게 처리하고 다른거 하고싶다는 생각도 들기도 하고,

버전 업데이트마다 매번 해야하는 반복적인 작업이므로 깜빡 잊어버리고 테스트를 생략하고 PR을 올릴 수가 있다.

이런 반복적인 작업을 자동화하면 휴먼 에러를 방지할 수 있지 않을까?


1. Github Actions로 자동 빌드 및 테스트

우선은 간단한 CI부터 진행해보자.

CI를 지원하는 툴은 GitHub Actions, Jenkins, Travis CI 등 여러가지가 있다.

이 중에서 본인은 깃헙 액션을 이용하려고 한다.

프로젝트 버전 관리는 GitHub으로 관리하기 때문에 깃헙 액션을 이용한다면 워크 플로우를 작성하면 CI를 지원해준다.

 

PR을 올리면 자동으로 빌드 및 테스트가 되는 깃헙액션 워크 플로우를 작성해보자.

1-1. Secret 작성

application.yml 파일에는 민감한 환경 변수들이 담겨있을 수 있다.

따라서 깃헙 레포에는 애플리케이션에 필요한 yml 파일을 올리지 않는다.

하지만 빌드나 테스트를 할때는 이 application.yml 파일이 필요하다.

따라서 레포에는 드러나지 않지만 내부적으로 환경변수를 설정해주는 Secret을 사용한다.

아래 사진처럼 Secret에 application.yml 파일을 설정한다.

본인은 PROPERTIES 라는 이름으로 application.yml 내용을 Secret에 설정해뒀다.

이제 아래 깃헙액션 워크플로우에서 여기서 설정한 Secret을 바탕으로 빌드 시 application.yml 파일을 생성한다.

1-2. yml파일로 워크플로우 작성

아래처럼 yml로 워크플로우를 작성한다.

이 때 디렉토리 경로는 아래처럼 .github/workflows 여야 한다.yml 파일명은 뭘로 하든 상관 없다.

본인이 작성한 main.yml 파일은 아래와 같다.

name: Java CI with Gradle

on:
  pull_request:
    branches: [ "main" ]    # main 브랜치에 PR 했을때 실행(PR이 merge 될 때는 동작하지 않음)

jobs:
  build:

    runs-on: ubuntu-latest  # ubuntu 환경에서 실행

    steps:
    - uses: actions/checkout@v4
    
    ## Java 17 사용
    - name: Set up JDK 17
      uses: actions/setup-java@v4
      with:
        java-version: '17'
        distribution: 'temurin'  

    ## application.yml 파일 생성
    - name: make application.yml
      run: |
        echo ">> mkdir & touch"
        mkdir -p ./src/main/resources
        cd ./src/main/resources
        touch ./application.yml
        echo ">> copy application.yml"
        echo "${{ secrets.PROPERTIES }}" >> ./application.yml
        
    ## Gradle에 권한 부여
    - name: Grant execute permission for gradlew
      run: chmod +x gradlew
      shell: bash

    ## Gradle build 실행(gradle의 build 과정에 test가 포함돼 있음)
    - name: Build with Gradle Wrapper
      run: ./gradlew build
      shell: bash

2. 결과 확인

아래처럼 다른 브랜치에서 main 브랜치에 PR을 올리면 빌드 테스트를 하는걸 확인할 수 있다.

+ Recent posts