본문 바로가기

리눅스

GitHub Actions를 사용해 Spring Boot 애플리케이션을 빌드하고 Docker 이미지를 생성하여 Docker Hub에 업로드하는 방법

반응형

GitHub Actions를 사용해 Spring Boot 애플리케이션을 빌드하고 Docker 이미지를 생성하여 Docker Hub에 업로드하는 방법

GitHub Actions 워크플로우

전체 워크플로우

더보기

---

name: Deploy Spring Boot Application

on:
  push:
    branches:
      - main

env:
  AWS_REGION: us-east-1
  SECURITY_GROUP_ID: sg-07f3
  CONTAINER_BASE_DIR: "/app/docker-container"
  CONTAINER_LOG_DIR: "$CONTAINER_BASE_DIR/logs"
  APPLICATION_PORT: 8080
  DOCKER_REPO: ${{ vars.DOCKER_REPO }}
  DOCKER_NAMESPACE: playground
  DOCKER_IMAGE_NAME: springboot-app

jobs:
  build:
    name: Build and Push Docker Image
    runs-on: ubuntu-latest

    steps:
      # 코드 체크아웃
      - name: Checkout code
        uses: actions/checkout@v4

      # Java 21 설정
      - name: Set up JDK 21
        uses: actions/setup-java@v4
        with:
          java-version: '21'
          distribution: 'temurin'

      # Gradle 빌드
      - name: Build with Gradle
        run: |
          chmod +x gradlew
          ./gradlew clean build

      # Docker 이미지 태그 생성
      - name: Set Docker Tag
        id: set_docker_tag
        run: echo "DOCKER_TAG=$(echo $GITHUB_SHA | cut -c 1-7)" >> $GITHUB_ENV

      # Docker 이미지 빌드
      - name: Build Docker Image
        run: |
          docker build -t ${{ vars.DOCKER_REPO }}/${{ env.DOCKER_IMAGE_NAME }}:latest .

      # Docker Hub에 이미지 푸시
      - name: Push Docker Image to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ vars.DOCKER_REPO }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
      - run: |
          docker tag ${{ env.DOCKER_REPO }}/${{ env.DOCKER_IMAGE_NAME }}:latest \
            ${{ env.DOCKER_REPO }}/${{ env.DOCKER_NAMESPACE }}:${{ env.DOCKER_IMAGE_NAME }}-$DOCKER_TAG
          docker push ${{ env.DOCKER_REPO }}/${{ env.DOCKER_NAMESPACE }}:${{ env.DOCKER_IMAGE_NAME }}-$DOCKER_TAG
          echo "Docker Image: ${{ env.DOCKER_REPO }}/${{ env.DOCKER_NAMESPACE }}:${{ env.DOCKER_IMAGE_NAME }}-$DOCKER_TAG"

      # 빌드 아티팩트 업로드
      - name: Upload build artifacts
        uses: actions/upload-artifact@v4
        with:
          name: build-artifacts
          path: build/libs/*-SNAPSHOT.jar
          overwrite: true

  deploy:
    name: Deploy Application
    runs-on: ubuntu-latest
    needs: build

    steps:
      # 애플리케이션 배포
      - name: Deploy Docker Image
        uses: appleboy/ssh-action@v1.2.0
        with:
          host: ${{ vars.AWS_EC2_HOST }}
          username: ${{ vars.AWS_EC2_USER }}
          key: ${{ secrets.AWS_EC2_SSH_KEY }}
          script: |
            FQ_IMAGE=${{ env.DOCKER_REPO }}/${{ env.DOCKER_NAMESPACE }}:${{ env.DOCKER_IMAGE_NAME }}-${{ env.DOCKER_TAG }}
            mkdir -p ${{ env.CONTAINER_BASE_DIR }}
            cd ${{ env.CONTAINER_BASE_DIR }}
            docker compose down -v || true
            docker rmi -f $(docker images | grep ${{ env.DOCKER_IMAGE_NAME }}  | awk '{print $3}' | uniq) || true
            docker pull $FQ_IMAGE
            cat <<EOF > ${{ env.CONTAINER_BASE_DIR }}/docker-compose.yml
            services:
              ${{ env.DOCKER_IMAGE_NAME }}:
                image: $FQ_IMAGE
                container_name: ${{ env.DOCKER_IMAGE_NAME }}
                restart: unless-stopped
                ports:
                  - "${{ env.APPLICATION_PORT }}:${{ env.APPLICATION_PORT }}"
            EOF
            docker compose up -d || echo "Failed to start the container"

  status:
    name: Health Check
    runs-on: ubuntu-latest
    needs: deploy

    steps:
      # 애플리케이션 헬스 체크
      - name: Check Application Health
        uses: appleboy/ssh-action@v1.2.0
        with:
          host: ${{ vars.AWS_EC2_HOST }}
          username: ${{ vars.AWS_EC2_USER }}
          key: ${{ secrets.AWS_EC2_SSH_KEY }}
          script: |
            curl -fsSL http://localhost:${{ env.APPLICATION_PORT }} || echo "Health check failed"

---

1. 트리거

name: Deploy Spring Boot Application

on:
  push:
    branches:
      - main

2. 환경 변수

env:
  AWS_REGION: us-east-1
  SECURITY_GROUP_ID: sg-07f3
  CONTAINER_BASE_DIR: "/app/docker-container"
  CONTAINER_LOG_DIR: "$CONTAINER_BASE_DIR/logs"
  APPLICATION_PORT: 8080
  DOCKER_REPO: ${{ vars.DOCKER_REPO }}
  DOCKER_NAMESPACE: playground
  DOCKER_IMAGE_NAME: springboot-app

3. Build Job

코드 체크아웃

  • GitHub 저장소에서 코드를 가져옵니다.
# 코드 체크아웃
- name: Checkout code
  uses: actions/checkout@v4

Java 21 설치

  • JDK(Java)를 설치합니다
# Java 21 설정
- name: Set up JDK 21
  uses: actions/setup-java@v4
  with:
    java-version: '21'
    distribution: 'temurin'

Gradle 빌드

  • 애플리케이션을 빌드합니다.
# Gradle 빌드
- name: Build with Gradle
  run: |
    chmod +x gradlew
    ./gradlew clean build

Docker 태그 생성

  • 현재 Git 커밋 SHA의 처음 7자로 DOCKER_TAG 환경 변수를 생성합니다.
# Docker 이미지 태그 생성
- name: Set Docker Tag
  id: set_docker_tag
  run: echo "DOCKER_TAG=$(echo $GITHUB_SHA | cut -c 1-7)" >> $GITHUB_ENV
  • Dockerfile 코드
FROM openjdk:21-jdk-slim

ARG JAR_FILE=build/libs/*-SNAPSHOT.jar

WORKDIR /app

COPY ${JAR_FILE} /app/app.jar

EXPOSE 8080

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

Docker 이미지 빌드 및 푸시

  • Docker 이미지를 빌드하고 Docker Hub에 이미지를 푸시합니다.
# Docker 이미지 빌드
- name: Build Docker Image
  run: |
    docker build -t ${{ vars.DOCKER_REPO }}/${{ env.DOCKER_IMAGE_NAME }}:latest .

# Docker Hub에 이미지 푸시
- name: Push Docker Image to Docker Hub
  uses: docker/login-action@v3
  with:
    username: ${{ vars.DOCKER_REPO }}
    password: ${{ secrets.DOCKERHUB_TOKEN }}
- run: |
    docker tag ${{ env.DOCKER_REPO }}/${{ env.DOCKER_IMAGE_NAME }}:latest \
      ${{ env.DOCKER_REPO }}/${{ env.DOCKER_NAMESPACE }}:${{ env.DOCKER_IMAGE_NAME }}-$DOCKER_TAG
    docker push ${{ env.DOCKER_REPO }}/${{ env.DOCKER_NAMESPACE }}:${{ env.DOCKER_IMAGE_NAME }}-$DOCKER_TAG
    echo "Docker Image: ${{ env.DOCKER_REPO }}/${{ env.DOCKER_NAMESPACE }}:${{ env.DOCKER_IMAGE_NAME }}-$DOCKER_TAG"
728x90

빌드 아티팩트 업로드(선택 사항)

  • 빌드된 JAR 파일을 결과물로 업로드합니다.
# 빌드 아티팩트 업로드
- name: Upload build artifacts
  uses: actions/upload-artifact@v4
  with:
    name: build-artifacts
    path: build/libs/*-SNAPSHOT.jar
    overwrite: true

4. Deploy Job

Docker 이미지 배포 및 도커 컴포즈 실행

  • 기존 컨테이너를 중지 및 제거하고 새로운 이미지를 가져와 도커 컴포즈를 이용하여 애플리케이션을 실행합니다.
# 애플리케이션 배포
- name: Deploy Docker Image
  uses: appleboy/ssh-action@v1.2.0
  with:
    host: ${{ vars.AWS_EC2_HOST }}
    username: ${{ vars.AWS_EC2_USER }}
    key: ${{ secrets.AWS_EC2_SSH_KEY }}
    script: |
      FQ_IMAGE=${{ env.DOCKER_REPO }}/${{ env.DOCKER_NAMESPACE }}:${{ env.DOCKER_IMAGE_NAME }}-${{ env.DOCKER_TAG }}
      mkdir -p ${{ env.CONTAINER_BASE_DIR }}
      cd ${{ env.CONTAINER_BASE_DIR }}
      docker compose down -v || true
      docker rmi -f $(docker images | grep ${{ env.DOCKER_IMAGE_NAME }}  | awk '{print $3}' | uniq) || true
      docker pull $FQ_IMAGE
      cat <<EOF > ${{ env.CONTAINER_BASE_DIR }}/docker-compose.yml
      services:
        ${{ env.DOCKER_IMAGE_NAME }}:
          image: $FQ_IMAGE
          container_name: ${{ env.DOCKER_IMAGE_NAME }}
          restart: unless-stopped
          ports:
            - "${{ env.APPLICATION_PORT }}:${{ env.APPLICATION_PORT }}"
      EOF
      docker compose up -d || echo "Failed to start the container"

5. Status Job

애플리케이션 헬스 체크

  • cURL 명령어로 애플리케이션이 올바르게 실행 중인지 확인합니다.
# 애플리케이션 헬스 체크
- name: Check Application Health
  uses: appleboy/ssh-action@v1.2.0
  with:
    host: ${{ vars.AWS_EC2_HOST }}
    username: ${{ vars.AWS_EC2_USER }}
    key: ${{ secrets.AWS_EC2_SSH_KEY }}
    script: |
      curl -fsSL http://localhost:${{ env.APPLICATION_PORT }} || echo "Health check failed"

 

728x90
반응형