
be/dev 로 PR Merge 시 Spring Boot 프로젝트를 도커 이미지로 빌드 후 Docker Hub private repo 에 배포


개발 서버에서 빌드한 이미지와 docker-compose.yaml 다운로드 후 변경이 필요한 컨테이너만 재시작

우테코에서 제공받은 EC2 는 모든 외부 IP 에서 SSH 접속이 불가능 합니다.
따라서 EC2 에 self-hosted runner 를 설치하여 Github 에 Polling 방식으로 명령을 수행해야하는지 지속적으로 물어보며 트리거가 될 경우 작업을 실행하는 구성을 해야합니다.

Setting > Actions > Runner 에서 New self-hosted runner 버튼을 클릭하여 운영체제와 아키텍쳐를 선택 후 알려주는 명령어 대로 실행합니다.

.github/workflows/be-cd-dev.yaml 파일 생성
각 job 의 설명을 아래와 같아서 프로젝트 상황 별 필요한 부분만 가져다 사용하면 됩니다!
Checkout Repository 코드 가져오기Set up JDK 21 자바 설치Cache Gradle 그래들 캐싱Add execute permissions 그래들 실행 권한 부여Build 스프링 빌드Test and Create OAS 테스트 및 API Spec 생성Create bootJar 실행 가능한 jar 파일 생성Build Docker image 도커 이미지 빌드Login to Docker Hub 도커 허브 로그인Push Docker image 도커 허브로 업로드Upload docker-compose 깃헙 액션 저장소에 컴포즈 파일 업로드Set up environment variables 중요 변수 추출Download docker-compose 깃헙 액션 저장소에서 컴포즈 파일 다운로드Rename downloaded file 파일명에 -dev 제거Login to Docker Hub 도커 허브 로그인Pull latest Docker images 도커 이미지 다운로드Restart docker compose 컴포즈 재시작 (무중단 배포 필요)Clean up unused Docker images 이전 도커 이미지 제거name: Backend CD Develop
on:
push:
branches:
- be/dev
concurrency:
group: ${{ github.ref }}
cancel-in-progress: true
jobs:
build:
runs-on: ubuntu-latest
environment: test
steps:
- name: Checkout Repository
uses: actions/checkout@v4
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
java-version: 21
distribution: temurin
cache: gradle
- name: Cache Gradle
uses: actions/cache@v4
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/build.gradle') }}
restore-keys: |
${{ runner.os }}-gradle-
- name: Add execute permissions
working-directory: ./backend
run: chmod +x ./gradlew
- name: Build
working-directory: ./backend
run: ./gradlew build -x test -x bootJar
- name: Test and Create OAS
env:
JASYPT_PASSWORD: ${{ secrets.JASYPT_PASSWORD }}
working-directory: ./backend
run: ./gradlew copyOasToSwagger
- name: Create bootJar
working-directory: ./backend
run: ./gradlew bootJar
- name: Build Docker image
working-directory: ./backend
run: |
docker build \
-f Dockerfile-dev \
-t ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_IMAGE_NAME }}:dev \
.
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Push Docker image
run: docker push ${{ secrets.DOCKERHUB_USERNAME }}/${{ secrets.DOCKERHUB_IMAGE_NAME }}:dev
- name: Upload docker compose
uses: actions/upload-artifact@v4
with:
name: docker-compose
path: ./backend/src/main/resources/docker-compose-dev.yaml
if-no-files-found: error
deploy:
needs: build
runs-on: [self-hosted, dev]
environment: dev
steps:
- name: Set up environment variables
run: |
cd ~/${{ secrets.DOCKERHUB_IMAGE_NAME }}
echo "MYSQL_DATABASE=${{ secrets.MYSQL_DATABASE }}" > .env
echo "MYSQL_ROOT_PASSWORD=${{ secrets.MYSQL_ROOT_PASSWORD }}" >> .env
echo "JASYPT_PASSWORD=${{ secrets.JASYPT_PASSWORD }}" >> .env
- name: Download docker compose
uses: actions/download-artifact@v4
with:
name: docker-compose
path: ~/${{ secrets.DOCKERHUB_IMAGE_NAME }}
- name: Rename downloaded file
run: |
cd ~/${{ secrets.DOCKERHUB_IMAGE_NAME }}
mv docker-compose-dev.yaml docker-compose.yaml
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Pull latest Docker images
run: docker compose -f ~/${{ secrets.DOCKERHUB_IMAGE_NAME }}/docker-compose.yaml pull
- name: Restart docker compose
run: |
cd ~/${{ secrets.DOCKERHUB_IMAGE_NAME }}
docker compose up -d
- name: Clean up unused Docker images
run: docker image prune -af
CD 스크립트는 default branch 를 변경할 필요가 없으며 on > push > branches 에 현재 작업 중인 브랜치 be/feat/000 을 추가하여 Push 할 때 마다 스크립트가 잘 작동하는지 Github 홈페이지 Actions 탭에서 확인하는 식으로 반복하는 것이 좋습니다.
테스트가 모두 잘 되어 배포가 될 경우 on > push > branches 에 feat 브랜치를 제거하여 PR 을 작성합니다!