개발일지/돌픽

Docker + Github Actions로 SpringBoot CI/CD 구축하기

E-room 2023. 6. 8. 21:24
728x90

목표 : 깃허브 커밋을 하면 자동으로 EC2에 반영되도록 하는 CD/CD를 구축한다.

 

지난번에는 Docker를 이용하여 Spring boot 애플리케이션을 EC2에 배포를 했습니다.

이번에는 해당 과정을 로컬환경에서 깃허브 커밋&푸시가 이루어지면 Github Actions가 대신해 주도록 하여, CI/CD를 구축해 봅시다.

(자신이 Spring Boot 애플리케이션을 빌드하고 도커허브에 푸시하고 EC2에서 풀 받아서 실행시키도록 했던 과정을 Github Actions에게 모두 시킨다고 생각하시면 됩니다.)

 

깃허브 참조

 

GitHub - Ksiyeong/GithubAction-Docker-EC2

Contribute to Ksiyeong/GithubAction-Docker-EC2 development by creating an account on GitHub.

github.com

 

환경

  • Java 17
  • Spring Boot 3.1.0
  • gradle
  • 로컬 PC : M2 Mac os
  • EC2 : Ubuntu 22.04 프리티어

 

사전 작업

  • 깃허브 계정 & 사용할 레포지토리
  • 지난 글 과정까지 완료하기 (아래 링크 참조)
 

Docker로 spring-boot EC2에 배포하기

목표 : Docker를 사용해서 Spring-boot 애플리케이션을 EC2에 배포 사전 작업 로컬 PC 및 EC2에 Docker 설치 Spring-boot 프로젝트 Docker Hub 회원가입 환경 Java 17 Spring Boot 3.1.0 gradle 로컬 PC : M2 Mac os EC2 : Ubuntu 22.

e-room.tistory.com


1. CI 과정 해보기

이전글에서 했던 것들 중, Spring Boot 애플리케이션을 app.jar로 빌드하고 app.jar를 도커허브에 푸시하는 과정까지의 단계를 다루겠습니다.

 

 

1-1. Github Actions 환경변수 설정

깃허브 액션의 secrets에 도커허브의 username과 password를 등록해준다.

 

1-2. Actions의 gradle.yml 생성

이전글에서 했던 과정을 Guthub actions가 대신하도록 gradle.yml에 작성해 줍시다.

 

1-3. grdle.yml 수정

name: Java CI with Gradle

# 동작 조건 설정 : main 브랜치에 push 혹은 pull request가 발생할 경우 동작한다.
on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]

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. Spring Boot 애플리케이션 빌드
    - name: Build with Gradle
      uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1
      with:
        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

 

steps

  1. Java17을 사용하였으므로 Java17을 이용하라는 명령입니다.
  2. Spring boot를 Gradle을 이용하여 빌드하라는 명령입니다.
  3. Docker 이미지를 빌드합니다.
    • 1-1에서 설정했던 secrets들을 불러와서 사용합니다.
    • 이미지 이름은 적절하게 원하는 데로 수정하여 설정하도록 합니다.
  4. DockerHub에 로그인합니다.
  5. DockerHub에 이미지를 푸시합니다.

 

위와 같이 수정 후 저장한 뒤, Actions 탭에 들어가 보면 해당 과정이 진행되고 있음을 볼 수 있습니다.

최상단의 gradle.yml 수정이 진행중인 모습
과정이 진행되는 모습

각각의 과정이 진행되는 모습을 볼 수 있으며, 실패할 경우 어디서 실패했는지도 볼 수 있습니다.

 

1-4. Docker 허브 확인 및 EC2 배포

gradle.yml에 github-actions-demo 라는 이름으로 도커허브에 푸시하도록 명시해 놓았습니다.

정상적으로 업로드된 모습을 확인할 수 있습니다.

도커허브에 정상적으로 푸쉬된 모습

 

이제 EC2에서 실행시켜 보자

$ sudo docker run -p 8080:8080 philip2767/github-actions-demo

정상적으로 실행되는 모습

 

접속해 보면 정상적으로 응답되는 모습을 확인할 수 있습니다.

 


2. CD 과정 구축하기 (배포 자동화하기)

이제 app.jar를 도커허브에 푸시하는 데까지 자동화가 완료되었습니다.

이후의 과정인 (현 글에서는 1-4) 도커허브에 푸시(업로드)된 이미지를 EC2에서풀(다운로드) 받아서 서버를 실행시키는 부분을 자동화해보겠습니다.

 

해당 과정에서는 여러 방법이 존재하지만 self-hosted라는 방법을 이용해서 진행해 보도록 하겠습니다.

이유는 가장 쉽고 간단하다고 느꼈기 때문입니다.

 

2-1. Github Actions의 self-hosted 수신 준비하기

자세한 내용은 아래과정에서 Java를 설치하는 과정은 스킵하시고 github Actions에서 new self-hosted runner 연결을 하는 과정까지만 진행하시면 됩니다.

 

Spring-boot Github Actions를 이용한 자동배포

Github Actions를 이용하여 EC2, Linode 등 ubuntu 서버에 자동배포를 알아보겠습니다. 우선 본인의 서버 pc에 접속하여 기본적인 세팅을 해줍시다. sudo apt update # 각자 원하는 버전을 설치하시면 됩니다 su

e-room.tistory.com

 

2-2. gradle.yml 수정하기

도커허브에 올라가 있는 이미지를 pull 받아서 기존의 컨테이너를 중지시키고 새롭게 실행시키도록 하는 부분을 진행하겠습니다.

name: Java CI with Gradle

on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]

permissions:
  contents: read

jobs:
  # Spring Boot 애플리케이션을 빌드하여 도커허브에 푸시하는 과정
  build-docker-image:
    runs-on: ubuntu-latest

	... 생략

  # 위 과정에서 푸시한 이미지를 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 }}/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

살펴보자면

 

needs: build-docker-image

build-docker-image 과정의 완료가 필요한 실행조건입니다.

해당 부분이 없다면 동시에 실행이 되므로 정상적으로 최신 도커이미지가 실행되지 않습니다.

 

runs-on: self-hosted 를 통해 ec2에서 이후 명령이 동작하도록 합니다.

 

steps

  1. 최신 이미지를 풀 받도록 합니다.
  2. 기존의 컨테이너를 중지합니다.
    • $(sudo docker ps -q) 를 통해 현재 실행 중인 모든 컨테이너의 id를 인자로 받습니다.
    • sudo docker stop을 통해 인자로 받은 컨테이너를 종료시킵니다.
    • 실행 중인 컨이너가 없을 경우 sudo docker stop시 에러가 발생합니다.
      해당 에러를 방지하기 위해 2>/dev/null || true 를 사용했습니다.
  3. 최신 이미지를 컨테이너화하여 실행시킵니다.
    • --name 은 컨테이너의 이름을 설정해 줍니다. (ci/cd과정에서 컨테이너의 이름을 알아야 하는 경우는 없어서 굳이 안 하셔도 무방합니다. 다만, 추후에 여러 컨테이너가 사용될 경우 식별 편의를 위해 사용해 주었습니다.)
    • --rm 컨테이너 종료 시 해당 컨테이너가 자동으로 삭제되도록 합니다.
    • -d 백그라운드에서 실행하도록 합니다.
    • -p 포트를 설정해 줍니다.
  4. 미사용 이미지를 삭제합니다. (구버전이미지 = 기존에 실행 중이던 컨테이너 이미지)
    • 컨테이너 중지 후 삭제해 주어도 되지만 해당 부분을 뒤로 뺀 이유는
      기존 이미지에서 공유하여 사용하던 레이어 부분을 다시 다운로드하도록 하지 않기 위해서입니다.
      ex) demo 이미지가 a, b, c 로 구성되어 있을 경우 최신버전에서는 a만 변경되었을 경우 a만 새로 다운로드하게 됩니다.

 

2-3. 실행 결과 확인

Controller를 살짝 수정한 뒤 정상적으로 실행되는지 확인해 봅시다.

@GetMapping("/")
public ResponseEntity hello() {
    return ResponseEntity.ok("eroom 배포 자동화 테스트");
}

 

커밋&푸시해주면

 

gradle.yml에 명시한 데로 순차적으로 실행됩니다.

 

모든 Jobs가 완료된 뒤 실제로 서버에 GET요청을 해봅시다.

변경점이 서버에 정상적으로 반영된 모습

정상적으로 배포가 완료되었습니다.

이제 main 브랜치에 push 혹은 pull request 가 발생할 경우 자동적으로 서버가 최신화되어 배포됩니다.

 

감사합니다.


참고

self-hosted 대신 AWS IAM 사용한 방식

 

[Docker] GitHub Actions - Docker Image 자동 배포, run(CD) (2)

GitHub Actions - Docker Image 자동 배포 (CD) - info 이전 포스팅에서 GitHub Actions 를 사용하여 CI 파이프라인을 구축했었다. GitHub master 브랜치에 push 되었을 경우, jar빌드, docker image빌드, docker hub 푸시(퍼블

lucas-owner.tistory.com

 

728x90