저번에는 ec2를 이용한 수동배포만을 해봤으니, 이제
github actions를 이용한 CI/CD를 진행해보려고 한다. Github프로젝트가 있다는 것을 전제로 시작하고, 전체적인 그림을 우선 파악할 필요가 있다. 먼저 큰그림을 파악하지 못해서 나도 삽질을 오래 했다.

위와 같은 과정을 거치는 것이고, Github에서 merge만 하면 나머지 과정들을 실행시킬 수 있는 파이프라인(일종의 script)를 짜서 쉽게 서버 배포를 하는 것이다.
우선 Docker와 Docker Desktop를 로컬(노트북)에 설치해주고, Spring Boot 프로젝트에서
Dockerfile이라는 파일을 만든다. 그 후 아래와 같은 내용을 써넣는다. 아마도 이 파일은 스프링 부트 프로젝트에서.jar을 빌드하라 라는 뜻인 것 같다.
# Dockerfile
# jdk17 Image Start
FROM openjdk:11
# 인자 설정 - JAR_File
ARG JAR_FILE=build/libs/*.jar
# jar 파일 복제
COPY ${JAR_FILE} app.jar
# 인자 설정 부분과 jar 파일 복제 부분 합쳐서 진행해도 무방
#COPY build/libs/*.jar app.jar
# 실행 명령어
ENTRYPOINT ["java", "-jar", "app.jar"]
우선 Github 프로젝트에서 해당 repository에 접속한 후,
Actions탭에서New Workflow를 클릭하고Java with Gradle을 선택하여gradle.yml파일을 생성한다. 자동으로 생성된 이 파일을 그대로 저장하고 로컬 스프링부트에서 pull하여 이 파일이 생성된 것을 확인한다. 이 파일에는 아래와 같이 작성한다.
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
# This workflow will build a Java project with Gradle and cache/restore any dependencies to improve the workflow execution time
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-gradle
name: project cicd flow
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
permissions:
contents: read
jobs:
# build:
build-docker-image:
runs-on: ubuntu-latest
steps:
# 1. Java 세팅
- uses: actions/checkout@v3
- name: Set up JDK 11
uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'temurin'
# 2. Spring Boot 애플리케이션 빌드
- name: Build with Gradle
uses: gradle/gradle-build-action@bd5760595778326ba7f1441bcf7e88b49de61a25 # v2.6.0
with:
# arguments: build
arguments: clean bootJar
# 3. Docker 이미지 빌드
- name: docker image build
run: docker build -t ${{ secrets.DOCKERHUB_USERNAME }}/github-actions-demo .
# 4. DockerHub 로그인
- name: docker login
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
# 5. Docker Hub 이미지 푸시
- name: docker Hub push
run: docker push ${{ secrets.DOCKERHUB_USERNAME }}/github-actions-demo
# 위 과정에서 푸시한 이미지를 ec2에서 풀받아서 실행시키는 과정
run-docker-image-on-ec2:
# build-docker-image (위)과정이 완료되어야 실행됩니다.
needs: build-docker-image
# runs-on: self-hosted
runs-on: ubuntu-latest
steps:
- name: login to ec2
uses: appleboy/ssh-action@v0.1.6
with:
host: ${{ secrets.SERVER_HOST }}
username: ${{ secrets.SERVER_USERNAME }}
key: ${{ secrets.SERVER_PRIVATE_KEY }}
envs: GITHUB_SHA
port: 22
script : |
sudo docker pull ${{ secrets.DOCKERHUB_USERNAME }}/github-actions-demo
sudo docker stop $(sudo docker ps -q) 2>/dev/null || true
sudo docker run --name github-actions-demo --rm -d -p 8080:8080 ${{ secrets.DOCKERHUB_USERNAME }}/github-actions-demo
sudo docker system prune -f
## 아래 과정들을 ec2 접속 후 한 번에 진행
# # 0. ec2 접속
# - name: login to ec2
# uses: appleboy/ssh-action@v0.1.6
# # 1. 최신 이미지를 풀받습니다
# - name: docker pull
# run: sudo docker pull ${{ secrets.DOCKERHUB_USERNAME }}/github-actions-demo
#
# # 2. 기존의 컨테이너를 중지시킵니다
# - name: docker stop container
# run: sudo docker stop $(sudo docker ps -q) 2>/dev/null || true
#
# # 3. 최신 이미지를 컨테이너화하여 실행시킵니다
# - name: docker run new container
# run: sudo docker run --name github-actions-demo --rm -d -p 8080:8080 ${{ secrets.DOCKERHUB_USERNAME }}/github-actions-demo
#
# # 4. 미사용 이미지를 정리합니다
# - name: delete old docker image
# run: sudo docker system prune -f
이 파일이 위에서 얘기했던 파이프라인, 즉 스크립트가 된다.
jobs부분만 간단하게 살펴보면build-docker-image:이라는 이름을 가진1~5번이 제일 위의 그림에서 왼쪽 부분(파란색)에 해당되는 것이고, 밑의run-docker-image-on-ec2:이라는 이름을 가진 부분이 오른쪽 부분(노란색)에 해당 되는 것이다.
바로 위의
gradle.yml파일에서 보면${{ secrets.DOCKERHUB_USERNAME }}이런 부분들이 있다. 이 부분은 보통 접속 주소나 아이디/비밀번호 등을 그대로 스크립트에 쓰기 좀 그러니까 이런식으로 써두고, 실제 정보는 Github에 저장해 놓는 느낌이다. 다시 Github에서 해당 repository에 Settings탭으로 이동한 다음, 비밀번호나 username등을 추가한다. 이렇게 하면gradle.yml파일에서secrets.을 통해 접근할 수 있나 보다.
참고
DOCKER_USERNAME,DOCKER_PASSWORD는 도커허브 ID 및 비밀번호이고,
SERVER_HOST는 ec2에서 할당받은 주소,
SERVER_USERNAME은 보통 다른 블로그들을 많이 참고했다면ubuntu일 것이고,SERVER_PRIVATE_KEY는 해당 ec2의.pem파일 내용을 메모장으로 연 다음 전부 복붙하면 된다.
이제 로컬에서 Github의 main(또는 master)브랜치에 push해보면
이런식으로 배포가 성공했음을 알 수 있다.
많이 삽질하고 고민했던.. 트러블 슈팅