본문 바로가기
카테고리 없음

[SPRING BOOT] AWS EC2, RDS, github actions, docker 사용해서 자동배포 하기(5) - 깃허브 파일 설정

by sum_mit45 2023. 9. 20.
728x90
반응형

목표: github main branch에 push 할때 ec2에서 스프링부트가 자동으로 실행되도록 하기

1. github actions 스크립트 파일 생성하기

(1) Github repository - Actions - Java with Gradle을 선택한다. 

Github repository - Actions - Java with Gradle

 자동 배포를 원하는 github repository에서 상단의 Actions을 선택한 후에 Java with Gradle을 선택한다. 

 

 

(2) repsitory이름 / .github / workflows / gradle.yml 의 경로로 파일이 생성된다. 

기본적으로는 아래와 같은 내용의 파일이 생성된다. 

name: Java CI with Gradle

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

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: Build with Gradle
      uses: gradle/gradle-build-action@bd5760595778326ba7f1441bcf7e88b49de61a25 # v2.6.0
      with:
        arguments: build

코드 분석

name: Java CI with Gradle

이 부분은 워크플로우의 이름을 정의하는 부분을, 워크플로우가 어떤 작업을 수행하는지 간략하게 설명한다. 

 

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

GitHub Actions 워크플로우를 언제 실행할지를 정의하는 부분이다. 여기서는 main 브랜치로의 push와 pull request가 main 브랜치로의 변경 사항에 대해 워크플로우를 실행하도록 설정되어 있다.

 

permissions:
  contents: read

Github Actions 워크프롤우가 저장소 내의 내용을 읽을 수 있는 권한을 부여하는 부분이다. 

 

jobs:
  build:
    runs-on: ubuntu-latest

'build'라는 작업을 정의하고, 이 작업을 Ubuntu 환경에서 실행하도록 설정한다. 

 

steps:
- uses: actions/checkout@v3

Github Actions에서 레포지토리를 체크아웃 하는 단계이다. 소스 코드를 가져오기 위해서 사용된다. 

- name: Set up JDK 11
  uses: actions/setup-java@v3
  with:
    java-version: '11'
    distribution: 'temurin'

Java 11을 설치하고 설정하는 스텝이다. 현재 내 프로젝트에서 자바 11을 사용중이기 때문에 자동으로 만들어진 듯 하다.

- name: Build with Gradle
  uses: gradle/gradle-build-action@bd5760595778326ba7f1441bcf7e88b49de61a25 # v2.6.0
  with:
    arguments: build

여기는 Github Actions가 자동으로 프로젝트를 빌드하고 결과를 표시하는 단계이다. Gradle 빌드 스크립트에서 정의한 빌드 작업을 수행하고, 빌드에 필요한 의존성을 자동으로 가져온다.

 

(name: 스텝의 이름을 설정,

 uses: Github Actions 워크플로우에서 사용할 액션 지정,

 with: 액션에 전달할 추가적인 매개변수 설정)

 

(3) gradle.yml 코드를 수정하기

# 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://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-gradle

name: Java CI with Gradle

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

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 application-prod.yml
      run: |
        cd ./src/main/resources
        touch ./application-prod.yml
        echo "${{ secrets.APPLICATION_PROD }}" > ./application-prod.yml
        
    - name: Grant execute permission for gradlew
      run: chmod +x gradlew

    - name: Build with Gradle
      run: ./gradlew build -x test

    - name: Docker build
      run: |
        docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }}
        docker build -t app .
        docker tag app ${{ secrets.DOCKER_USERNAME }}/gomaoom:latest
        docker push ${{ secrets.DOCKER_USERNAME }}/gomaoom:latest

    - name: Deploy
      uses: appleboy/ssh-action@master
      with:
        host: ${{ secrets.HOST }} # EC2 인스턴스 퍼블릭 DNS
        username: ec2-user
        key: ${{ secrets.PRIVATE_KEY }} # pem 키
        # 도커 작업
        script: |
          docker pull ${{ secrets.DOCKER_USERNAME }}/gomaoom:latest
          docker stop $(docker ps -a -q)
          docker run -d --log-driver=syslog -p 8080:8080 -e SPRING_PROFILES_ACTIVE=prod ${{ secrets.DOCKER_USERNAME }}/gomaoom:latest
          docker rm $(docker ps --filter 'status=exited' -a -q)
          docker image prune -a -f

나는 steps 부분의 코드를 더 수정하여, 도커에서 자동으로 최근 프로젝트를 받아올 수 있도로 하였다. 

구체적인 코드 설명은 아래에 있다.

코드 분석

- name: make application-prod.yml
  run: |
    cd ./src/main/resources
    touch ./application-prod.yml
    echo "${{ secrets.APPLICATION_PROD }}" > ./application-prod.yml

application-prod.yml 파일을 생성하는 부분이다. src/main/resources 디렉토리로 이동한 다음, application-prod.yml 파일을 만들고 GitHub Actions의 시크릿 (secrets.APPLICATION_PROD)에서 가져온 값을 이 파일에 쓰기 위한 작업을 수행한다.

보안상의 이유로 GitHub에 올릴 수 없는 데이터베이스 URL, USERNAME, PASSWORD 및 타 프로그램 API KEY 등을 저장한 application-prod.yml 파일이다. 이 파일을 .gitignore 되어 있어서 repository에 없기 때문에 따로 파일을 만들어 주었다.

- name: Grant execute permission for gradlew
  run: chmod +x gradlew

Gradle 실행 권한 부여하는 단계이다. gradlew 파일에 실행 권한을 부여한다.

- name: Build with Gradle
  run: ./gradlew build -x test

Gradle로 빌드하는 단계이다. Gradle을 사용하여 프로젝트를 빌드하는데,  -x test 옵션을 사용하여 테스트를 실행하지 않도록 설정했다.

- name: Docker build
  run: |
    docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }}
    docker build -t app .
    docker tag app ${{ secrets.DOCKER_USERNAME }}/gomaoom:latest
    docker push ${{ secrets.DOCKER_USERNAME }}/gomaoom:latest

Docker 이미지를 빌드하고 푸시하는 단계이다. Docker Hub에 로그인한 다음, 현재 디렉토리의 Dockerfile을 사용하여 Docker 이미지를 빌드했다. 이미지의 이름은 "app"으로 지정했다. 빌드된 이미지에 태그를 지정하고 Docker Hub에 푸시한다. 이미지 이름은 Docker Hub에서의 사용자명(secrets.DOCKER_USERNAME)으로 지정된다. 마찬가지로 Docker Hub에 로그인하기 위해 사용해야 하는 아이디와 패스워드는 github secrets에 올려두었다.

- name: Deploy
  uses: appleboy/ssh-action@master
  with:
    host: ${{ secrets.HOST }} # EC2 인스턴스 퍼블릭 DNS
    username: ec2-user
    key: ${{ secrets.PRIVATE_KEY }} # pem 키
    # 도커 작업
    script: |
      docker pull ${{ secrets.DOCKER_USERNAME }}/gomaoom:latest
      docker stop $(docker ps -a -q)
      docker run -d --log-driver=syslog -p 8080:8080 -e SPRING_PROFILES_ACTIVE=prod ${{ secrets.DOCKER_USERNAME }}/gomaoom:latest
      docker rm $(docker ps --filter 'status=exited' -a -q)
      docker image prune -a -f

 배포하는 단계이고, AWS EC2 인스턴스에 접속하여 Docker 이미지를 배포한다. AWS EC2에 접속하기 위해서 EC2 인스턴스 퍼블릭 DNS, username, pem key가 필요하다. 이 중에서 공개되면 안되는 내용은 secret key를 통해 설정해 두었다. 

(pem 파일을 열기 위해 vsCode를 사용했다.) 

 이후에 scirpt 부분은 원격 서버에 실행할 스크립트를 정의하는 부분이다. Docker Hub에서 최신 이미지를 다운로드한다. 현재 실행 중인 모든 Docker 컨테이너를 중지한다. docker run 명령어를 사용하여 Spring Boot 애플리케이션을 Docker 컨테이너로 실행한다. 이 때 -e SPRING_PROFILES_ACTIVE=prod를 사용하여 로컬에서와 다른, Github Secrets에 올려둔 파일로 application.yml파일을 대체한다. 중지된 Docker 컨테이너를 제거하고, 사용하지 않는 Docker 이미지는 정리한다. 

 즉, Github Actions 워크플로우가 실행될 때 Spring Boot 애플리케이션을 Docker 이미지로 빌드하고 배포하여 EC2 인스턴스에서 실행하는 것이다. 

2. Dockerfile 코드 생성하기

(1) repsitory이름 / Dockerfile 의 경로로 파일을 생성한다.

파일명은 꼭 Dockerfile로 해주어야한다. Dockerfile 코드는 아래와 같다.

FROM openjdk:11-jdk
ARG JAR_FILE=build/libs/gomaoom_server-0.0.1-SNAPSHOT.jar
COPY ${JAR_FILE} /gomaoom.jar

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

이 Dockerfile은 OpenJDK 11을 기반으로 Spring Boot 애플리케이션을 실행하기 위한 것으로, Spring Boot 애플리케이션의 JAR 파일을 Docker Image로 복사하고 실행하는 데 사용된다. 이 Dockerfile을 사용하면 Spring Boot 애플리케이션을 Docker 이미지로 빌드하고, 해당 이미지를 컨테이너로 실행할 수 있다. Docker 이미지는 Java 11과 Spring Boot 애플리케이션 JAR 파일을 포함하며, 애플리케이션은 컨테이너 내에서 실행된다.

 

(2) 코드 분석

FROM openjdk:11-jdk

Docker 이미지를 빌드할 때 사용할 베이스 이미지를 정의하는데, OpenJDK 11베이스의 이미지를 사용하고 있으며 Java 11 실행환경을 제공한다는 의미이다.

ARG JAR_FILE=build/libs/gomaoom_server-0.0.1-SNAPSHOT.jar

Docker 빌드 시에 인자로 전달할 JAR_FILE 변수를 정의한다. 이 경로는 Docker 이미지에 복사될 Spring Boot 애플리케이션 JAR 파일의 경로를 나타낸다.

COPY ${JAR_FILE} /gomaoom.jar

로컬 파일 시스템에서 Spring Boot 애플리케이션 JAR 파일을 Docker 이미지 내부로 복사한다. 

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

Docker 컨테이너가 실행될 때 시작되는 명령어를 정의한다.

3. Github Action 비밀키 생성하기

(1) Github repository - Settings - Secrets and variables - Actions 을 선택한다. 

New Repository Secret 버튼을 통해 새로운 키를 생성 가능하다.

Github repository - Settings - Secrets and variables - Actions

4. 배포 완료 확인하기

github actions를 통해 배포가 완료된 것을 확인할 수 있다.

AWS에서 제공받은 {퍼블릭 IPv4주소}:8080/ 을 통해 확인 해볼 수도 있다.

*혹시 오류가 난다면 보안그룹에서 8080 포트를 열었는지 확인해보기

728x90
반응형