본문 바로가기

카테고리 없음

git action + docker를 이용한 spring boot ci/cd 구성하기

컴퓨터에 도커가 설치되어 있다는 것과 스프링 부트 프로젝트가 존재한다는 가정 하에 진행한다. 

 

Dockerfile 을 통해 이미지 및 컨테이너 생성

우선 프로젝트 디렉토리 최상단에 다음과 같이 Dockerfile을 작성한다.

Dockerfile의 내용은 아래와 같다.

FROM openjdk:11

ENV APP_HOME=/usr/app/

WORKDIR $APP_HOME

COPY build/libs/*.jar application.jar

EXPOSE 8080

CMD ["java", "-jar", "application.jar"]

FROM openjdk:11:  openjdk의 11버전을 기본 도커 이미지로 사용한다.

 

ENV APP_HOME=/usr/app/ : 만들어진 도커 컨테이너 내부 /usr/app이라는 경로를 APP_HOME으로 등록한다.

 

WORKDIR $APP_HOME : 위에서 만든 경로 APP_HOME을 도커 컨테이너 내부 작업용 디렉토리로 등록한다.

 

COPY build/libs/*.jar application.jar : 해당 도커 파일이 있는 디렉토리를 기준으로 build/libs/*.jar 파일을 도커 내부에 application.jar파일로 복사한다. 이 때 위에서 지정한 경로(APP_HOME)로 파일이 복사되게 된다.

 

EXPOSE 8080 : 도커 파일의 포트 번호를 지정한다.

 

CMD ["java", "-jar", "application.jar"] : 도커 컨테이너가 실행될 때 실행할 명령어이다. jar파일을 실행시키기 위한 커맨드를 작성하였다. 

 

 

이 파일이 잘 작동하는지 확인해보자.

 

우선 -plain.jar  파일이 생성되지 않도록 build.gradle 파일에 다음과 같은 설정을 추가한다.

 

다음으로 DockerFile이 있는 디렉토리(프로젝트 최상단 디렉토리)에서 jar파일을 생성한다.

./gradlew clean build

jar파일이 생성 되었다면 아래의 명령어를 실행한다.

docker build -t docker:test .

DockerFile을 읽어 이미지로 만드는 명령어이다. -t 옵션을 통해 이미지의 이름(docker) 및 버전(test)을 작성해 주었다.

 

다음 명령어를 통해 이미지가 생성되었는지 확인한다.

docker images

잘 생성된 것을 알 수 있다.

이제 이 이미지를 실행시켜 컨테이너를 만들어보자.

다음 명령어를 수행한다.

docker run --name docker -p 8080:8080 docker:test

--name 옵션 : 컨테이너의 이름 지정

-p : {호스트 컴퓨터 포트}:{도커 컨테이너 포트} 를 통해 호스트 컴퓨터(도커가 설치되어 있는 컴퓨터)의 포트와 도커 내부의 application.jar 파일의 포트를 연결한다.

이 명령어를 실행하면 스프링부트 어플리케이션이 실행되는 것을 볼 수 있다. 

어플리케이션 종료 후 다음의 명령어를 통해 컨테이너가 존재하는지 확인해 보자.(사실 스프링 부트 어플리케이션이 실행된것 자체가 컨테이너가 정상적으로 생성된것이긴 하다.)

docker ps -a

-a 옵션 : 기본적으로 docker ps는 현재 구동되고 있는 컨테이너만을 보여주는데 우리는 컨테이너를 종료한 후 확인했으므로 -a옵션을 통해 모든 컨테이너를 확인한다.

사진과 같이 정상적으로 컨테이너가 생긴것을 알 수 있다.

 

깃허브 SECRET에 비밀파일(properties) 추가하기

설정 파일들과 같은 비밀 정보들이 깃허브에 올라가지 않도록 gitignore에 작성해논 경우가 많을 것이다. 

우리는 깃허브 파일을 빌드해서 배포하는 시스템이므로 빌드할 때 설정 파일이 없으면 빌드가 되질 않는다.

이를 해결하기 위해서 깃허브 SECRET에 설정 파일을 작성해 놓는다.

 

github 레포지토리에 Settings -> Secrets -> Actions에 들어가 New repository secret을 클릭하여 

NAME에 원하는 이름을 작성하고 VALUE에 내용을 작성한 후 ADD SECRET을 눌러 저장한다.

 

깃 액션을 이용한 CI 설정하기

깃허브의 Actions에 들어오면 친절하게도 자신의 레포지토리에 맞는 액션들을 찾아준다. 

본인은 Gradle기반 스프링 부트 어플리케이션이므로 Java with Gradle을 클릭하였다.

다음과 같이 기본적인 틀이 잡혀져 있는 yml파일을 얻게 된다. 

이 파일은 깃헙 레포지토리의 /github/workflows/에 작성된다. 

이제 프로젝트에 맞춰 커스텀해보자. 

# 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://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle

name: Java CI with Gradle

on:
  pull_request:
    branches: [ "prod" ]

permissions:
  contents: read

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3
    - name: Set up JDK 11
      uses: actions/setup-java@v3
      with:
        java-version: '11'
        distribution: 'temurin'
        
    - name: make main properties
      run: |
        cd ./src/main/resources
        touch ./application.properties
        echo "${{ secrets.PROPERTIES }}" > ./application.properties
      shell: bash    
    
    - name: Build with Gradle
      uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1
      with:
        arguments: build

다음과 같이 수정하였다. 

 

name : 이 액션의 이름을 지정한다.

on: 이 액션이 언제 수행될지 지정한다. 여기서는 prod 브랜치에 pull request가 요청될 때 실행되게 작성하였다.

jobs: 액션이 할 일을 지정한다. 

runs-on : 이 작업을 어떤 OS에서 작업할지 정한다.

steps: 해당 jobs을 아래 적힌 순서대로 실행하겠다는 의미이다.

-uses: 이미 정의된 작업들을 실행한다는 것이다. (actions/checkout@V3, actions/setup-java@v3 등등 다른 사람들이 이미 작성해논 파일들을 실행하겠다는 의미이다. 사용자가 일일히 작성할 필요 없이 이미 잘 만들어진 파일을 실행하기만 하면 된다.)

-name: 실행되는 작업의 이름을 지정한다.

run : 때에 따라 이미 작성된 파일들을 실행하기보다는 직접 해야할 일을 작성할 필요가 있다. 그 때 어떤 일을 할건지 작성한다. 여기서는 위에서 지정한 시크릿파일(properties)를 가져와 만들어주는 작업을 한다. 시크릿 파일은 ${{ secrets.시크릿파일이름 }}을 통해 접근할 수 있다.

 

위와 같이 작성 후 prod 브랜치로 pull request를 열어보면 다음과 같은 화면이 뜬다.

우측에 Details를 눌러보며 작업별 진행상황을 알 수 있다.

정상적으로 빌드해보며 CI가 동작하는 것을 알 수 있다.

 

깃액션을 이용한 CD 설정하기

CD는 위와 같은 과정으로 만들어진 jar파일을 도커 이미지에 넣어 도커 허브에 올린 후 배포서버에서 도커 이미지를 다운받아 실행할 예정이다. 

도커 아이디와 비밀번호, 배포 서버에 접속을 위한 host주소 및 pem키와 같은 비밀 내용을 github secret에 저장하자.

이제 CI 파일과 비슷하게 CD 파일을 만든다. 

CI 파일을 그대로 복사하여 필요한 내용을 덧붙여 커스터마이징한다.

# 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://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle

name: Java CD with Gradle, Docker, Aws

on:
  push:
    branches: [ "prod" ]

permissions:
  contents: read

jobs:
  build:

    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v3
    - name: Set up JDK 11
      uses: actions/setup-java@v3
      with:
        java-version: '11'
        distribution: 'temurin'
        
    - name: make main properties
      run: |
        cd ./src/main/resources
        touch ./application.properties
        echo "${{ secrets.PROPERTIES }}" > ./application.properties
      shell: bash    
    
    - name: Build with Gradle
      uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1
      with:
        arguments: build
        
    - name: Docker build and push
      run: |
        docker login -u ${{ secrets.DOCKER_ID }} -p ${{ secrets.DOCKER_PWD }}
        docker build -t ppyooy336/docker:${GITHUB_SHA::7} .
        docker push ppyooy336/docker:${GITHUB_SHA::7}
        
    - name: SSH Remote Commands
      uses: appleboy/ssh-action@v0.1.4
      with:
        host: ${{ secrets.SERVER_HOST }}
        username: ec2-user
        key: ${{ secrets.SERVER_KEY }}
        envs: GITHUB_SHA
        script: |
          docker pull ppyooy336/docker:${GITHUB_SHA::7}
          docker tag ppyooy336/docker:${GITHUB_SHA::7} docker
          docker stop server
          docker run -d --rm --name server -p 8080:8080 docker

CI파일에서 pull request가 아닌 push될 때 실행되게 변경한 후 

Docker build and push와 SSH Remote Command가 추가한 것이다. 

 

${GITHUB_SHA::7} 은 현재 커밋 버전을 의미한다. 이렇게 함으로서 커밋 별 버전 관리가 가능해진다.

 

여기서는 pem키로 배포 서버에 접속하므로 SSH Remote Commands에 key를 등록해준다. 

script는 접속 후 실행할 명령어들을 적어주는 것인데 도커허브에 있는 이미지를 다운받아 실행하는 명령어이다.

 

prod 브랜치로 푸쉬하여 잘 동작하는지 확인해보자. 

모든 작업이 정상적으로 수행되었다.

서버컴퓨터에 접속해서 컨테이너를 확인해보니 잘 동작하고 있음을 알 수 있다.