spring boot 프로젝트를 github actions, docker를 활용하여 EC2에 배포하는 과정을 담았다. AWS EC2 인스턴스 생성(Ubuntu 22.04), EC2에 docker설치, Docker hub 계정이 있다는 가정하에 진행한다.
기존 배포 방법의 문제점
기존에 CI/CD 를 구축하지 않고 배포를 진행할 때, 우리는 spring boot 프로젝트를 직접 build 해서 jar 파일을 EC2에 Filezila 등으로 옮기고, java -jar 명령어를 실행하여 프로젝트를 실행했다. 프로젝트를 진행하면서 코드의 수정이 빈번하게 일어날 텐데, 매번 이런 과정을 거치는 것은 매우 비효율 적이다. CI/CD를 구축해 두면 이 과정을 자동화할 수 있어 개발 생산성을 높일 수 있다.
Github Actions vs Jenkins
Github Actions는 Jenkins와 비교하면 CI 서버가 따로 필요하지 않다. Github 자체의 서버 인프라를 CI 서버로 활용할 수 있어서 따로 서버 설정을 해주지 않아도 되어 매우 편리하다.
CI / CD 구축하기
개발 환경은 spring boot v3.2.4, Java17 이다. 잘 배포가 되었는지 확인하기 위해 TestController를 하나 작성했다. 버전을 변경하고 배포를 진행하여 배포가 잘 되었는지 확인하기 위함이다.

Dockerfile 작성
도커 이미지로 빌드할 도커 파일을 작성한다.
FROM bellsoft/liberica-openjdk-alpine:17
ARG JAR_FILE=build/libs/*.jar
COPY ${JAR_FILE} app.jar
# 도커 컨테이너를 시작할 때 실행할 명령어
ENTRYPOINT ["java","-jar","/app.jar"]
Github Actions workflow 파일 작성
workflow를 작성하기 위해, 레포지토리를 하나 만들고 Actions 탭에 들어가서 파일을 작성한다. workflow의 순서는 다음과 같다.
- main 브랜치 이벤트 발생시 작성한 workflow 실행
- spring boot 프로젝트 build
- workflow에 따라 docker 이미지 빌드
- docker hub에 이미지 push
- EC2에서 docker hub의 이미지 pull
- 이미지 실행

name: CI/CD using github actions & docker
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
# Configure Gradle for optimal use in GiHub Actions, including caching of downloaded dependencies.
# See: https://github.com/gradle/actions/blob/main/setup-gradle/README.md
- name: Setup Gradle
uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0
- name: Build with Gradle Wrapper
run: ./gradlew build
# Docker build & Push
- name: Docker build & push to Docker hub
run: |
docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }}
docker build -t ${{ secrets.DOCKER_USERNAME }}/docker-test .
docker push ${{ secrets.DOCKER_USERNAME }}/docker-test
# EC2 배포
- name: Docker image pull & Deploy to EC2
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.EC2_HOST }} # EC2 인스턴스 퍼블릭 DNS
username: ubuntu
key: ${{ secrets.EC2_PRIVATE_KEY }} # pem 키
# 도커 작업
script: |
sudo docker pull ${{ secrets.DOCKER_USERNAME }}/docker-test:latest
sudo docker stop $(sudo docker ps -a -q)
sudo docker run -d --log-driver=syslog -p 8080:8080 ${{ secrets.DOCKER_USERNAME }}/docker-test:latest
sudo docker rm $(sudo docker ps --filter 'status=exited' -a -q)
sudo docker image prune -a -f

workflows 디렉토리에 방금 작성한 파일이 저장된다.
Github secrets 변수 설정
workflow에서 사용할 민감한 정보들을 Secrets 환경 변수로 등록하여 사용할 수 있다. EC2 퍼블릭 IP와 생성 시 얻은 pem 키를 등록한다. pem 키는 '-----BEGIN RSA PRIVATE KEY-----' 와 '-----END RSA PRIVATE KEY-----' 부분까지 포함해서 넣으면 된다.



테스트
controller의 version을 수정하고 github 레포지토리 main에 push 해본다.


성공한 모습을 볼 수 있다. 배포한 EC2 퍼블릭 ip로 접속해보자.

배포 성공!
spring boot 프로젝트를 github actions, docker를 활용하여 EC2에 배포하는 과정을 담았다. AWS EC2 인스턴스 생성(Ubuntu 22.04), EC2에 docker설치, Docker hub 계정이 있다는 가정하에 진행한다.
기존 배포 방법의 문제점
기존에 CI/CD 를 구축하지 않고 배포를 진행할 때, 우리는 spring boot 프로젝트를 직접 build 해서 jar 파일을 EC2에 Filezila 등으로 옮기고, java -jar 명령어를 실행하여 프로젝트를 실행했다. 프로젝트를 진행하면서 코드의 수정이 빈번하게 일어날 텐데, 매번 이런 과정을 거치는 것은 매우 비효율 적이다. CI/CD를 구축해 두면 이 과정을 자동화할 수 있어 개발 생산성을 높일 수 있다.
Github Actions vs Jenkins
Github Actions는 Jenkins와 비교하면 CI 서버가 따로 필요하지 않다. Github 자체의 서버 인프라를 CI 서버로 활용할 수 있어서 따로 서버 설정을 해주지 않아도 되어 매우 편리하다.
CI / CD 구축하기
개발 환경은 spring boot v3.2.4, Java17 이다. 잘 배포가 되었는지 확인하기 위해 TestController를 하나 작성했다. 버전을 변경하고 배포를 진행하여 배포가 잘 되었는지 확인하기 위함이다.

Dockerfile 작성
도커 이미지로 빌드할 도커 파일을 작성한다.
FROM bellsoft/liberica-openjdk-alpine:17
ARG JAR_FILE=build/libs/*.jar
COPY ${JAR_FILE} app.jar
# 도커 컨테이너를 시작할 때 실행할 명령어
ENTRYPOINT ["java","-jar","/app.jar"]
Github Actions workflow 파일 작성
workflow를 작성하기 위해, 레포지토리를 하나 만들고 Actions 탭에 들어가서 파일을 작성한다. workflow의 순서는 다음과 같다.
- main 브랜치 이벤트 발생시 작성한 workflow 실행
- spring boot 프로젝트 build
- workflow에 따라 docker 이미지 빌드
- docker hub에 이미지 push
- EC2에서 docker hub의 이미지 pull
- 이미지 실행

name: CI/CD using github actions & docker
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: '17'
distribution: 'temurin'
# Configure Gradle for optimal use in GiHub Actions, including caching of downloaded dependencies.
# See: https://github.com/gradle/actions/blob/main/setup-gradle/README.md
- name: Setup Gradle
uses: gradle/actions/setup-gradle@417ae3ccd767c252f5661f1ace9f835f9654f2b5 # v3.1.0
- name: Build with Gradle Wrapper
run: ./gradlew build
# Docker build & Push
- name: Docker build & push to Docker hub
run: |
docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }}
docker build -t ${{ secrets.DOCKER_USERNAME }}/docker-test .
docker push ${{ secrets.DOCKER_USERNAME }}/docker-test
# EC2 배포
- name: Docker image pull & Deploy to EC2
uses: appleboy/ssh-action@master
with:
host: ${{ secrets.EC2_HOST }} # EC2 인스턴스 퍼블릭 DNS
username: ubuntu
key: ${{ secrets.EC2_PRIVATE_KEY }} # pem 키
# 도커 작업
script: |
sudo docker pull ${{ secrets.DOCKER_USERNAME }}/docker-test:latest
sudo docker stop $(sudo docker ps -a -q)
sudo docker run -d --log-driver=syslog -p 8080:8080 ${{ secrets.DOCKER_USERNAME }}/docker-test:latest
sudo docker rm $(sudo docker ps --filter 'status=exited' -a -q)
sudo docker image prune -a -f

workflows 디렉토리에 방금 작성한 파일이 저장된다.
Github secrets 변수 설정
workflow에서 사용할 민감한 정보들을 Secrets 환경 변수로 등록하여 사용할 수 있다. EC2 퍼블릭 IP와 생성 시 얻은 pem 키를 등록한다. pem 키는 '-----BEGIN RSA PRIVATE KEY-----' 와 '-----END RSA PRIVATE KEY-----' 부분까지 포함해서 넣으면 된다.



테스트
controller의 version을 수정하고 github 레포지토리 main에 push 해본다.


성공한 모습을 볼 수 있다. 배포한 EC2 퍼블릭 ip로 접속해보자.

배포 성공!