본문 바로가기
Docker

[Docker] Github Actions을 활용한 Spring 자동 빌드, Docker Image push(CI) (1)

by 도전하는 린치핀 2024. 4. 9.

0. GitHub Actions 를 사용하기 전 Spring 프로젝트 CI/CD

이전 포스팅에서 프로젝트 자체 빌드, 또는 Docker를 사용하여  프로젝트를 배포하는 프로세스 플로우에 대해서 알아봤다. 실제로 CI/CD 배포 프로세스는 매우 다양한 방법으로 진행할 수 있고 복잡한 프로세스를 통해 진행되기 때문에 설정을 제대로 하지 않거나, 프로세스 Flow를 제대로 이해하지 않는다면 굉장한 장애를 발생시킬 수 있다.

 

따라서 실제로 배포 프로세스를 잘 파악하고 있다면 배포 자동화 프로세스(CI/CD 프로세스)를 통해서 처음에 설정을 통해 편하게 배포를 할 수 있다.

이러한 배포 자동화를 CI/CD(Continuous Integration, Continuous Deployment) 라고 한다. 

  • CI (Continuous Integration)
    • 지속적 통합 : 여러 개발자들이 협업을 하고 있는 경우 발생하는 '불일치'를 최소화 해주는 개념.
    • 예를들어 master 브랜치에 PR 요청이 왔을때, 빌드, 테스트를 수행하여 코드 Qulity를 체크 할 수 있다. 
    • CI System 종류 : Jenkins, Travis CI, GitHub Actions 가 대표적으로 유명하다.
  • CD (Continuous Deployment)
    • 지속적 배포 : 프로젝트의 변경사항을 가상 환경(AWS, IDC)에 배포하는것이다.
    • 배포의 자동화가 이루어지는 환경으로, 수동으로 배포해야하는 번거로움을 줄일 수 있고, 더 나아가 무중단 배포 환경까지 구성할 수있다. 

 

- 이번 포스팅에서는 CI 프로세스를 Github Actions을 통해 자동화 하는 것을 다루며, Docker 이미지를 통한 배포를 진행할 것이다.

 

이전 포스팅에서 작성한 프로세스 중 Jar 빌드 -> Docker Image 생성 -> Docker Hub를 자동화 하는것이다.

 

만약 아직 배포 프로세스에 대해서 아직 파악하지 못했다면 아래 포스팅을 통해 프로세스 플로우를 제대로 확인하고 이번 포스팅을 읽어야 한다.

Docker 개념 정리 및 Spring 프로젝트 배포 프로세스

 

[ASAC_04/Docker] Docker 개념 정리 및 Spring 환경 배포 프로세스

0. Docker 의 개념과 역할 먼저 Docker의 자세한 개념과 설명은 이전 포스팅에서 다루었기 때문에 이번 포스팅에서는 간단하게만 다루도록 하자. [ASAC_04/Docker] Docker의 기본 개념 Docker 사용 이유 : Consi

rnclf1005.tistory.com

 

1. Github Actions 란?

- GitHub Actions란?

GitHub에서 제공하는 CI/CD tool 이다. 특정 branch에 이벤트(push, pull Request)가 발생 했을때, 미리 지정 해둔 work flow가 실행된다. 

 

  • Main 브랜치(따로 원하는 브랜치를 설정할 수 있다) push, PR 발생시
  • JAR빌드, Docker 이미지 빌드, Docker Hub push 까지 다룰 예정이다. 

해당 작업을 통해 Test를 수행하여 코드 품질또한 체크할 수 있지만 해당 포스팅에서는 Test를 수행하지 않고 JAR파일을 빌드할 것이다.

  • Test를 제외하는 이유는 보통 프로젝트에서 DB와 연결을 통해서 Test를 수행하지만 보통 DB는 프로젝트 외부에서 프로젝트와 연결되어 있기 때문에 동작하지 않는 경우가 많다.

 

(1) GitHub Actions 설정 

- 해당 프로젝트의 GitHub Repository -> Actions -> gradle 검색 -> Java With Gradle Configure 선택

(2) gradle.yml 파일 생성 및 수정 

 

  • Configure를 클릭하면 위와 같은 화면이 나오게 된다.
  • 해당 화면은 어떤 이벤트가 발생 했을때, 어떤 작업을 수행할 것인지 명시하는 파일로 기본적으로 주어지는 것이다.
  • 우리는 아래의 코드로 수정하여 gradle.yml 파일을 수정할 것이다.
name: Java CI with Gradle

# master 브랜치에 push, PR 이벤트 발생시 동작.
on:
  push:
    branches: [ "main" ]
  pull_request:
    branches: [ "main" ]

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      # Java 및 Docker 빌드를 위한 환경 설정
      - uses: actions/checkout@v3
      - name: Set up JDK 17
        uses: actions/setup-java@v3
        with:
          java-version: '17'
          distribution: 'temurin'

      # Java 빌드를 위한 ./gradlew 파일 권한 변경
      - name: Run chmod to make gradlew executable
        run: chmod +x ./gradlew

      # Java 빌드
      - name: Spring Boot Build
        run: ./gradlew clean build

      # DockerFile 을 기반으로 Docker Image 빌드
      - name: docker image build
        run: docker build -t ${{ secrets.DOCKERHUB_USERNAME }}/github-actions-demo .

      # Docker Hub 에 Login
      - name: docker login
        uses: docker/login-action@v2
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_PW }}

      # Docker Hub 에 빌드된 이미지 push
      - name: docker Hub push
        run: docker push ${{ secrets.DOCKERHUB_USERNAME }}/github-actions-demo

 

  • 위의 코드가 우리가 사용할 수정 파일이다.
  • on 부분의 수정을 통해, 어떤 이벤트에 동작할것인지 명시 할 수 있고, 
  • jobs 부분의 수정을 통해, 상세 설정을 할 수 있다. 
  • 추가적인 Github Actions에서 gradle.yml 파일 작성 방법은 추후 다른 포스팅에서 다루기로 하자.

 ++ Github Actions gradle.yml 파일에서 Steps Flow 확인

  1. 가장 먼저 Java Build가 일어날 환경을 설정하는 것이다. 쉽게 생각하면 Java의 버전을 맞추는 행위라고 생각할 수 있다.
  2. 그 다음 Java Build를 진행하기 위해 ./gradlew 파일의 설정 권한을 변경하는 것이다.
  3. 그 후 Spring 프로젝트에 있는 .java 파일들을 JAR파일로 빌드하는 것이다.
  4. 프로젝트에 있는 JAR파일과 Docker File을 통해 Docker Build를 진행하는 것이다.(이 과정을 통해 Docker Image가 생성된다.)
  5. 그 후 Docker Registory에 Docker Image를 Push 하기 위해 Docker Hub에 로그인하는 과정이다.
  6. 로그인 한 Docker Registory에 Docker Image를 Push 하는 과정이다.

+++ 프로젝트 내 존재해야하는 Docker File

FROM amazoncorretto:17-alpine

ARG JAR_FILE=build/libs/*.jar

COPY ${JAR_FILE} app.jar

ENTRYPOINT ["java", "-jar", "/app.jar"]

 

++++ 추가적으로 확인해야 하는 점

  • 위의 Steps의 Flow를 확인할 때 Docker Login을 진행하는 과정에서 with 부분을 보면 Docker hub의 username, password 가 존재하는데,
  • 이는 GitHub Actions의 Secret Key를 설정해줘야 한다. 해당 항목이 존재하지 않는다면, Actions = Fail 상태가 될것이다. 
  • 이처럼 외부에 공개되면 안되는 ID/Password(추후 AWS 계정 관련된 내용)은 Secret key로 생성하여 외부에 노출되지 않게 해야한다.

 

(3) GitHub Actions Secret Key 생성

 

  1. repository 의 Settings - Security - Secrets and Variable - Actions 
  2. New repository secret 클릭 후 이름과 내용 작성 및 저장
  3. 저장이 되었다면 생성한 List가 생성되고, gradle.yml 에서 사용할 수 있게된다.
  4. 이때, 위의 사진과 다르게 USERNAME과 PW만 설정하면 된다.
  5. USERNAME의 경우 Docker에 로그인하여 My Profile을 클릭하면 나오는 이름이다.
  6. PW의 경우 Docker에 로그인할 때 사용하는 패스워드를 등록하면 된다.

2. 설정한 이벤트를 통한 Actions flow 실행 및 동작 확인

이제 Github Actions를 사용하기 위한 설정은 끝났으니 실제 "on: " 부분에 설정한 이벤트를 동작시켜서 Github Actions가 동작하는지 확인해보자.

 

나의 경우에는 main branch에서  push, pull request가 발생시 동작하도록 설정하였다. 

 

2-1. Github Actions 동작 실패할 경우

  • 해당 flow 상세페이지에 들어가서, 어떤부분에서 실패했는지 확인 할 수 있고, 해당 flow를 재시작 할 수도 있다.
  • 실패했을 경우 name 부분에 설정한 step마다 성공했는지 실패했는지 알수 있기 때문에 어느 부분에서 잘못되었는지 확인하자.
  • 따라서 name을 설정하고 step을 나누는 것은 매우 중요한 과정이라고 할 수 있다.

 

2-2 Github Actions 동작 성공했을 경우

  • 동작이 성공했을 경우 설정한 모든 것을 끝냈다고 할 수 있으니 이제 Docker Image가 생성되어 Docker Hub에 Push 되었다고 할 수 있다.

3. Docker Hub에서 Docker Image 확인

  • 바로 위에서 설명했다시피 Github Actions의 동작이 성공했으니 Spring 프로젝트를 java 빌드를 통해 JAR 파일을 생성하고,
  • Docker File과 JAR파일을 Docker Build를 통해 Docker Image를 생성하고,
  • 생성된 Docker Image를 Docker Hub에 Push한 것이라고 할 수 있다.
  • 이제 Docker Hub에 이미지가 잘 등록되어 있는지 확인해보자.

  • gradle.yml 에 설정했던 이미지명으로 Image가 만들어져 푸시된것을 확인 할 수있다. 

 

4. EC2에서 Docker Engine / Image 다운로드 후 동작

 

4-1. Docker Image 구동을 위한 EC2 설정

  • 이름 및 태그는 확인하기 쉬운 이름으로 설정하면 된다.
  • 인스턴스 유형 또한 간단한 구동 확인을 위함이니 프리티어로 설정하면 된다.
  • 키 페어의 경우 Local 터미널에서 ssh로 접근하려면 설정하면 되지만 해당 포스팅에서는 EC2 인스턴스 연결을 통해서 할 예정이지 설정하지 않는다.
  • EC2 인스턴스 연결을 위해 퍼블리 IP 설정의 경우 활성화로 해야한다.
  • 보안 그룹의 경우 기존 22번 포트 외에 "8080 포트의 모든 IP" 인바운드 규칙을 추가해줘야 한다.

  • EC2 인스턴스 연결을 통해 접속하면 위의 사진과 같다.

4-2. EC2 내 Docker Engine 설치 

 

(1) EC2 내 인스턴스에 있는 모든 패키지 업데이트

  • "sudo yum update -y" 를 통해 패키지 업데이트를 진행한다.

 

(2) EC2 인스턴스 내 Docker Engine 설치 후 구동

  • "sudo yum install docker -y" 명령어를 통해 EC2 내 Docker Engine을 설치해준다.
  • "sudo service docker start" 명령어를 통해 EC2 내 Docker Engine을 구동시킨다.

 

(3) EC2 인스턴스 내 Docker Login

  • "docker login" 명령어를 통해 Docker Hub에 있는 Docker Image를 Pull 받기 위해 Docker Login을 진행한다.
  • 이때, USERNAME과 Password는 GithubActions의 Secret Key에 설정한 것을 입력하면 된다.

 

(4) Docker Hub 내 Image  Pull 후 확인

  • "docker pull hyeonjjun/github-actions-demo" 명령어를 통해 Docker Hub에 있는 Docker Image를 다운로드 받는다.
  • "docker images" 명령어를 통해 Pull 이 성공적으로 진행되었는지 확인한다.

(5) EC2 내에서 Docker Run을 통한 Docker Container 구동 및 서버 확인

  • "docker run -p 8080:8080 hyeonjjun/github-actions-demo" 명령어를 통해 Docker Image를 구동시켜 Docker Containe를 구동시킨다.
  • 추가적으로 docker run을 진행할 때 -d 옵션을 추가하면 EC2 연결을 끊어도 EC2가 자동으로 서버를 구동시키고 있다고 한다.
  • 또한, -d 옵션은 spring 서버가 구동되면서도 다른 커맨드를 입력하게 daemon으로 돌아가게 하는 것 같다.
  • docker 컨테이너 정상 동작 및 "EC2 퍼블릭IP : 8080"로 접속해보면 실제로 서버가 구동중인 것을 확인할 수 있다.

 


 

 

해당 글을 마치면서 CI 프로세스에 관해서는 나름 쉽게 해결되었지만 다음 포스팅에서 진행될 CD 자동화는 매우매우 복잡한 과정으로 진행될 예정이다.

따라서 다음 포스팅에 들어가기 전에 한번 더 배포 프로세스 및 Docker에 관한 개념을 다잡고 가야할 것 같다.