개발 환경
AWS EC2 Free tier - Operating System : Ubuntu 24.04 Server
Docker - Docker Hub
Spring Boot 3.3.1 - Gradle, JDK17
GitHub - Action
Name : DOCKERHUB_USERNAME | Your DockerHub Username
Name : DOCKERHUB_PASSWORD | Your DockerHub Password
Name : APPLICATION_YML | Your SpringBoot Project application.yml Content
📌 Secret 설정을 왜 하는가?
환경변수 관리 문제
github actions를 사용할 때 한가지 걸림돌이 있는데, 바로 환경변수 문제다. api키나, 각종 password 등의 민감한 데이터들은 보안을 이유로 github에 직접 업로드하지 않는 것이 일반적이다. 때문에 이런 데이터들은 .env와 같이 환경변수 파일을 만들고, 이 환경변수 파일을 .gitignore에 등록하여 github에 올라가지 못하도록 막게 된다.
github actions는 workflow를 가상머신 위에서 테스트하고 빌드하기 때문에 환경변수가 없는 상태에서는 제대로된 테스트와 빌드가 이루어질 수 없다. 하지만 그렇다고 .env파일을 그대로 github에 업로드하기에는 굳이 .env파일을 분리한 목적 자체가 불문명해진다. 이런 문제를 해결하기 위해 github은 secrets라는 기능을 제공하고 있다.
Secrets
api키나 password와 같이 숨기고자 하는 데이터를 관리해준다.
사용 방법은 github에서 secrets에 원하는 값을 입력하면, actions의 workflow가 실행될 때 이 secrets에 접근이 가능해진다. 그러면 이때 동적으로 secrets의 데이터를 취합해 .env파일을 새로 생성하면 되는 것이다.
➕ 추후 CI/CD 를 설정할 때 ${{ secrets.APPLICATION_YML }}형식의 코드로 Secrets에 등록한 데이터를 불러온다.
# Dockerfile
# jdk17 Image Start
FROM openjdk:17
ARG JAR_FILE=build/libs/book-0.0.1-SNAPSHOT.jar
ADD ${JAR_FILE} book_Backend.jar
ENTRYPOINT ["java","-jar","book_Backend.jar"]
baseImage : Docker 이미지 빌드 시 사용할 기본 이미지 지정JAR_FILE 변수를 정의해, 빌드 시 사용할 JAR 파일의 경로를 지정이제 이 Dockerfile을 사용하여 Docker 이미지를 빌드하고 실행하면, 컨테이너 내에서 Java 17 환경에서 Spring Boot 애플리케이션이 실행된다!
📌 자세한 설명FROM baseImage : Docker 이미지 빌드 시 사용할 기본 이미지 지정
ARG(Build Argument) : JAR_FILE 변수를 정의해, 빌드 시 사용할 JAR 파일의 경로(build/libs/book-0.0.1-SNAPSHOT.jar)를 지정
ADD(Add JAR File) : 지정된 JAR 파일을 이미지에 추가
build/libs/book-0.0.1-SNAPSHOT.jar 파일을 컨테이너 내부의 book_Backend.jar로 추가한다.ENTRYPOINT : 컨테이너가 시작될 때 실행할 명령을 지정
java -jar book_Backend.jar을 실행한다. 즉, 추가된 JAR 파일을 실행하여 Spring Boot 애플리케이션을 시작한다.💡Tip. Dockerfile을 작성할 때는 Layer 형태로 작성해주는 것이 좋다.
- 제일 빈번히 변경되는 파일일수록 제일 마지막에 작성해야 함
: 제일 빈번히 변경되는 파일을 제일 나중에 적으면 Layer에서 제일 위쪽에 배치되기 때문에, 이미지를 만들고 나중에 소스파일이 변경되어서 새로운 이미지를 만들어야 할 때 변경된 최상단의 Layer만 업데이트 해주고 나머지 Layer는 다시 만들지 않아도 된다!
그래서 이미지를 다시 만들 때, 변경되지 않은 Layer까지는 재사용(캐시된 걸 사용), 변경된 Layer부터 그 위의 Layer까지는 다시 빌드를 하기 때문에 이미지를 만드는 시간을 단축할 수 있고 효율성도 높아진다.
name: Java CI with Gradle
on:
push:
branches: [ "develop" ]
permissions:
contents: read
jobs:
# Spring Boot 애플리케이션을 빌드하여 도커허브에 푸시하는 과정
build-docker-image:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
# 1. Java 17 세팅
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'temurin'
# 2. application.yml 파일 생성
- name: Create application.yml
run: |
mkdir -p src/main/resources
echo "${{ secrets.APPLICATION_YML }}" > src/main/resources/application.yml
# 3. Spring Boot 애플리케이션 빌드
- name: Build with Gradle
uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1
with:
arguments: clean bootJar
# 4. Docker 이미지 빌드
- name: docker image build
run: docker build -t ${{ secrets.DOCKERHUB_USERNAME }}/book_cicd_action .
# 5. DockerHub 로그인
- name: docker login
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_PASSWORD }}
# 6. Docker Hub 이미지 푸시
- name: docker Hub push
run: docker push ${{ secrets.DOCKERHUB_USERNAME }}/book_cicd_action
on : 트리거 이벤트를 정의
push: branches: [ "develop" ] : 'develop' 브랜치에 push 이벤트가 발생할 때 workflow 실행permissions : workflow에서 사용할 권한을 설정
contents: read : workflow는 저장소의 콘텐츠를 읽을 수 있는 권한을 가짐jobs : 작업(job)을 정의 (여러 개 정의 가능)
runs-on: ubuntu-latest : 최신 버전의 Ubuntu를 사용하는 가상 환경에서 실행#1. 프로그램 설치 전 Ubuntu 시스템 패키지 업데이트
sudo apt-get update
#2. 필요한 패키지 설치
sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common
#3. Docker의 공식 GPG키 추가
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
#4. Docker의 공식 apt 저장소 추가
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
#5. 시스템 패키지 업데이트
sudo apt-get update
#6. Docker 설치
sudo apt-get install docker-ce docker-ce-cli containerd.io
#7. Docker 설치 확인
sudo systemctl status docker

Github Repository -> Settings -> Code and automation -> Actions -> Runners -> New self-hosted runner -> New self-hosted runner
Runner Image : Linux (Ubuntu를 사용하기 때문에) (+1서버에 N개 runner를 설치해도 잘 작동한다)
아래 Download / Configure 에 나와있는 코드를 본인의 운영 환경(EC2 서버)에 접속해서 순차적으로 실행시키면 된다.
마지막으로 아래 두 명령어를 실행한다.
sudo ./svc.sh install
sudo ./svc.sh start
📌 자세한 설명
GitHub Actions Runner : GitHub Actions workflow으로부터 job을 실행시켜주는 어플리케이션.
runner가 서버에서 대기 상태로 있다가 선언된 트리거가 작동되면 workflow를 실행한다.
Github Actions에는 크게 두 종류의 runner가 있는데 그 중 self-hosted runner는 사용자의 PC or 서버에 runner를 위치시켜 workflow를 실행하는 개념이다.
.github/workflows/gradle.yml 파일에 아래 코드를 입력한다.# 위 과정에서 푸시한 이미지를 ec2에서 풀받아서 실행시키는 과정
run-docker-image-on-ec2:
# build-docker-image (위)과정이 완료되어야 실행됩니다.
needs: build-docker-image
runs-on: self-hosted
steps:
# 1. 최신 이미지를 풀받습니다
- name: docker pull
run: sudo docker pull ${{ secrets.DOCKERHUB_USERNAME }}/book_cicd_action
# 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 }}/book_cicd_action
# 4. 미사용 이미지를 정리합니다
- name: delete old docker image
run: sudo docker system prune -f
초록색이 뜨면 성공!