본문 바로가기

퍼블릭 클라우드

Spring Boot 애플리케이션을 Docker 이미지로 빌드하고 Docker Hub에 배포한 뒤 AWS EC2에 배포하는 방법

반응형

Spring Boot 애플리케이션을 Docker 이미지로 빌드하고 Docker Hub에 배포한 뒤 AWS EC2에 배포하는 방법

이 GitHub Actions 워크플로는 Spring Boot 애플리케이션을 Docker 이미지로 빌드하고 Docker Hub에 배포한 뒤 AWS EC2에 배포하고 헬스 체크를 수행합니다.

주요 작업

  • Build: Docker 이미지 빌드 및 Docker Hub 푸시
  • Deploy: AWS EC2 서버에 Docker 이미지 배포
  • Health Check: 배포된 애플리케이션의 상태 확인

전체 워크플로

더보기

---

vim deploy.yml
name: Deploy Spring Boot Application

on:
  push:
    branches:
      - main

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

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

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set Docker Tag
        id: set_docker_tag
        run: echo "DOCKER_TAG=$(echo $GITHUB_SHA | cut -c 1-7)" >> $GITHUB_ENV

      - name: Login to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ vars.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}
      
      - name: Set up QEMU
        uses: docker/setup-qemu-action@v3

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Build and Push Docker Image
        uses: docker/build-push-action@v6
        with:
          platforms: linux/amd64,linux/arm64
          push: true
          tags: |
          	${{ env.DOCKER_REPO }}/${{ env.DOCKER_NAMESPACE }}:${{ env.DOCKER_IMAGE_NAME }}-${{ env.DOCKER_TAG }}
            ${{ env.DOCKER_REPO }}/${{ env.DOCKER_NAMESPACE }}:latest


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

    steps:
      - name: Get GitHub Runner Public IP
        id: ip
        uses: haythem/public-ip@v1.3

      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ${{ env.AWS_REGION }}

      - name: Authorize Runner IP in Security Group
        run: |
          aws ec2 authorize-security-group-ingress \
            --group-id ${{ env.SECURITY_GROUP_ID }} \
            --protocol tcp \
            --port 22 \
            --cidr ${{ steps.ip.outputs.ipv4 }}/32 || echo "IP already exists"

      - name: Set Docker Tag
        id: set_docker_tag
        run: echo "DOCKER_TAG=$(echo $GITHUB_SHA | cut -c 1-7)" >> $GITHUB_ENV

      - 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
            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"

      - name: Revoke Runner IP from Security Group
        run: |
          aws ec2 revoke-security-group-ingress \
            --group-id ${{ env.SECURITY_GROUP_ID }} \
            --protocol tcp \
            --port 22 \
            --cidr ${{ steps.ip.outputs.ipv4 }}/32 || echo "Failed to remove IP"

  health_check:
    runs-on: ubuntu-latest
    needs: deploy

    steps:
      - name: Get GitHub Runner Public IP
        id: ip
        uses: haythem/public-ip@v1.3

      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ${{ env.AWS_REGION }}

      - name: Authorize Runner IP in Security Group
        run: |
          aws ec2 authorize-security-group-ingress \
            --group-id ${{ env.SECURITY_GROUP_ID }} \
            --protocol tcp \
            --port 22 \
            --cidr ${{ steps.ip.outputs.ipv4 }}/32 || echo "IP already exists"

      - 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: |
            APP_URL="http://localhost:${{ env.APPLICATION_PORT }}/test"
            curl -fsSL $APP_URL

      - name: Revoke Runner IP from Security Group
        run: |
          aws ec2 revoke-security-group-ingress \
            --group-id ${{ env.SECURITY_GROUP_ID }} \
            --protocol tcp \
            --port 22 \
            --cidr ${{ steps.ip.outputs.ipv4 }}/32 || echo "Failed to remove IP"

---

코드 블록 설명

Set Docker Tag : 커밋 해시의 처음 7자를 추출해 DOCKER_TAG로 설정합니다.

- name: Set Docker Tag
  id: set_docker_tag
  run: echo "DOCKER_TAG=$(echo $GITHUB_SHA | cut -c 1-7)" >> $GITHUB_ENV

Login to Docker Hub : Docker Hub에 로그인합니다.

- name: Login to Docker Hub
  uses: docker/login-action@v3
  with:
    username: ${{ vars.DOCKERHUB_USERNAME }}
    password: ${{ secrets.DOCKERHUB_TOKEN }}

Set up QEMU : 멀티플랫폼 빌드를 위한 QEMU 설정

- name: Set up QEMU
  uses: docker/setup-qemu-action@v3

Set up Docker Buildx : Docker Buildx 빌더 설정

- name: Set up Docker Buildx
  uses: docker/setup-buildx-action@v3

Build and Push Docker Image : Docker 이미지를 빌드하고 Docker Hub에 푸시합니다.

  • 확장 가능성 : 멀티플랫폼 Docker 빌드 지원 (linux/amd64, linux/arm64)
- name: Build and Push Docker Image
  uses: docker/build-push-action@v6
  with:
    platforms: linux/amd64,linux/arm64
    push: true
    tags: |
      ${{ env.DOCKER_REPO }}/${{ env.DOCKER_NAMESPACE }}:latest
      ${{ env.DOCKER_REPO }}/${{ env.DOCKER_NAMESPACE }}:${{ env.DOCKER_IMAGE_NAME }}-${{ env.DOCKER_TAG }}

Deploy Docker Image : EC2 서버에서 Docker Compose로 이미지를 배포합니다.

- 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
      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"

Check Application Health: curl로 애플리케이션 상태를 확인합니다. HTTP 200 상태를 기대합니다.

- 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: |
      APP_URL="http://localhost:${{ env.APPLICATION_PORT }}/test"
      curl -fsSL $APP_URL

dockerhub

dockerhub

 

728x90
반응형