리눅스

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

변군이글루 2025. 1. 14. 21:00
반응형

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
반응형