Skip to content

Multi-Module Deployment to AWS ECR and EC2 #258

Multi-Module Deployment to AWS ECR and EC2

Multi-Module Deployment to AWS ECR and EC2 #258

Workflow file for this run

name: Multi-Module Deployment to AWS ECR and EC2
on:
workflow_dispatch:
inputs:
profile:
description: '프로파일을 선택하세요 (dev 또는 prod)'
required: true
default: 'dev'
type: choice
options:
- dev
- prod
package:
description: '배포할 패키지를 선택하세요'
required: true
default: 'peauty-customer-api'
type: choice
options:
- customer
- designer
permissions:
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
# 1. 코드 체크아웃
- name: Checkout code
uses: actions/checkout@v3
# 2. 환경 변수 설정
- name: Set environment variables
run: |
echo "DEPLOY_PROFILE=${{ github.event.inputs.profile }}" >> $GITHUB_ENV
echo "DEPLOY_DOMAIN=${{ github.event.inputs.package }}" >> $GITHUB_ENV
echo "TARGET_PACKAGE=peauty-${{ github.event.inputs.package }}-api" >> $GITHUB_ENV
# 프로파일과 패키지에 따라 호스트와 사용자 설정
if [[ "${{ github.event.inputs.profile }}" == "prod" && "${{ github.event.inputs.package }}" == "customer" ]]; then
echo "HOST_SECRET=EC2_CUSTOMER_PROD" >> $GITHUB_ENV
elif [[ "${{ github.event.inputs.profile }}" == "prod" && "${{ github.event.inputs.package }}" == "designer" ]]; then
echo "HOST_SECRET=EC2_DESIGNER_PROD" >> $GITHUB_ENV
elif [[ "${{ github.event.inputs.profile }}" == "dev" && "${{ github.event.inputs.package }}" == "customer" ]]; then
echo "HOST_SECRET=EC2_CUSTOMER_DEV" >> $GITHUB_ENV
elif [[ "${{ github.event.inputs.profile }}" == "dev" && "${{ github.event.inputs.package }}" == "designer" ]]; then
echo "HOST_SECRET=EC2_DESIGNER_DEV" >> $GITHUB_ENV
else
echo "Invalid profile or package selection"
exit 1
fi
# 환경 변수 검증
- name: Debug environment variables
run: |
echo "DEPLOY_PROFILE: $DEPLOY_PROFILE"
echo "DEPLOY_DOMAIN: $DEPLOY_DOMAIN"
echo "TARGET_PACKAGE: $TARGET_PACKAGE"
echo "HOST_SECRET: $HOST_SECRET"
# 2. Java 17 설치
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
distribution: 'corretto'
package: 'jdk'
jdk-version: '17.0.12'
# 3. 선택된 패키지 빌드 (로컬에서 JAR 생성)
- name: Build Selected Package
run: |
echo "Building $TARGET_PACKAGE with profile $DEPLOY_PROFILE..."
# 선택한 패키지 디렉토리로 이동 후 Gradle 빌드
# $TARGET_PACKAGE-$DEPLOY_PROFILE => profile 이름이 customer-prod라서
./gradlew clean build -Pspring.profiles.active=$TARGET_DOMAIN-$DEPLOY_PROFILE -p $TARGET_PACKAGE
# 빌드 완료 확인
if [ ! -f $TARGET_PACKAGE/build/libs/*SNAPSHOT.jar ]; then
echo "Build failed: JAR file not found in $TARGET_PACKAGE/build/libs/"
exit 1
fi
echo "Build successful. JAR file located at $TARGET_PACKAGE/build/libs/"
# 4-1. ECR 자격 증명
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v3
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-2
# 4-2. ECR 로그인
- name: Log in to Amazon ECR
id: ecr-login
uses: aws-actions/amazon-ecr-login@v2
# 5. 하루 이전에 푸시된 이미지 삭제
- name: Delete Images Older Than 1 Day
env:
ECR_REGISTRY: ${{ steps.ecr-login.outputs.registry }}
ECR_REPOSITORY: peauty/server
run: |
echo "Fetching and deleting images older than 1 day..."
# 현재 시간에서 1일 전 날짜 계산
ONE_DAY_AGO=$(date -d '1 day ago' +%Y-%m-%dT%H:%M:%S)
# 하루 이전에 푸시된 이미지 조회 및 삭제
aws ecr describe-images \
--repository-name $ECR_REPOSITORY \
--query 'imageDetails[?imagePushedAt<`'$ONE_DAY_AGO'`].[imageDigest]' \
--output text | while read DIGEST; do
echo "Deleting image with digest: $DIGEST"
aws ecr batch-delete-image \
--repository-name $ECR_REPOSITORY \
--image-ids imageDigest=$DIGEST
done
echo "Old images deleted successfully!"
# 5. Docker 이미지 빌드 및 푸시
- name: Build and Push Docker Image to ECR
env:
ECR_REGISTRY: ${{ steps.ecr-login.outputs.registry }}
ECR_REPOSITORY: peauty/server
IMAGE_TAG: ${{env.DEPLOY_DOMAIN}}-${{ env.DEPLOY_PROFILE }}
run: |
echo "Building Docker image for $TARGET_PACKAGE with profile $DEPLOY_PROFILE..."
docker build -t $ECR_REPOSITORY:$IMAGE_TAG -f $TARGET_PACKAGE/Dockerfile $TARGET_PACKAGE
docker tag $ECR_REPOSITORY:$IMAGE_TAG $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
docker push $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
# 6. EC2 서버에 배포
- name: Deploy to EC2 Server
uses: appleboy/[email protected]
env:
DEPLOY_PROFILE: ${{ github.event.inputs.profile }}
DEPLOY_DOMAIN: ${{ github.event.inputs.package }}
TARGET_PACKAGE: peauty-${{ github.event.inputs.package }}-api
ECR_REGISTRY: ${{ steps.ecr-login.outputs.registry }}
ECR_REPOSITORY: peauty/server
IMAGE_TAG: ${{ github.event.inputs.package }}-${{ github.event.inputs.profile }}
with:
host: ${{ secrets[env.HOST_SECRET] }}
username: ${{ secrets.EC2_USER }}
key: ${{ secrets.EC2_SSH_KEY }}
envs: DEPLOY_PROFILE,DEPLOY_DOMAIN,TARGET_PACKAGE,ECR_REGISTRY,ECR_REPOSITORY,IMAGE_TAG
script: |
echo "Deploying to EC2 for $TARGET_PACKAGE with profile $DEPLOY_PROFILE"
# AWS CLI 설정
aws configure set aws_access_key_id ${{ secrets.AWS_ACCESS_KEY_ID }}
aws configure set aws_secret_access_key ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws configure set region ap-northeast-2
# 기존 컨테이너 중지 및 삭제
echo "Docker Container Status"
docker ps
echo "STOP $DEPLOY_DOMAIN-$DEPLOY_PROFILE"
docker stop $DEPLOY_DOMAIN-$DEPLOY_PROFILE || { echo "Failed to stop container"; }
docker rm $DEPLOY_DOMAIN-$DEPLOY_PROFILE || { echo "Failed to remove container"; }
# 사용하지 않는 이전 도커 이미지 삭제
echo "=== Cleaning up unused Docker images ==="
docker image prune -af || { echo "Failed to prune Docker images"; }
# .env 파일 생성
echo "Generating .env file..."
rm -f .env
echo "${{ secrets.ALL_SECRET }}" > .env
echo ".env file generated:"
# Docker 이미지 Pull
aws ecr get-login-password --region ap-northeast-2 | docker login --username AWS --password-stdin $ECR_REGISTRY
docker pull $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
# 새로운 컨테이너 실행
docker run --env-file ./.env -d -p 8080:8080 --name $DEPLOY_DOMAIN-$DEPLOY_PROFILE \
--env SPRING_PROFILES_ACTIVE=$DEPLOY_DOMAIN-$DEPLOY_PROFILE \
$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
# 새로운 컨테이너 상태 확인
echo "=== Verifying the new container ==="
sleep 10 # 컨테이너 초기화를 위한 대기 시간
if ! docker ps --filter "name=$DEPLOY_DOMAIN-$DEPLOY_PROFILE" --filter "status=running" | grep $DEPLOY_DOMAIN-$DEPLOY_PROFILE; then
echo "새로운 컨테이너가 실행 중이지 않습니다. 로그를 확인하세요."
docker logs --tail 50 $DEPLOY_DOMAIN-$DEPLOY_PROFILE
exit 1
fi
# 컨테이너 상태 확인
docker ps
# 7. Gradle 빌드 및 Docker 이미지 빌드/푸시
# - name: Gradle Build and Docker Image Push
# run: |
# echo "=== Starting Gradle Build and Docker Push ==="
#
# - name: Login to Docker Hub
# env:
# DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
# DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
# IMAGE_TAG: ${{env.DEPLOY_DOMAIN}}-${{ env.DEPLOY_PROFILE }}
# run: |
# echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin
#
# - name: Build and Push Docker Image
# run: |
# # echo "Using Dockerfile in $TARGET_PACKAGE with build context $TARGET_PACKAGE"
# docker build -t 93ed43223fb8/docker-peauty:$IMAGE_TAG .
#
# # echo "Pushing Docker image to ECR..."
# docker push 93ed43223fb8/docker-peauty:$IMAGE_TAG
# # Docker 빌드 컨텍스트 설정
# echo "Using Dockerfile in $TARGET_PACKAGE with build context $TARGET_PACKAGE"
#
# # Docker 이미지 빌드
# echo "Building Docker image..."
# docker build -t 93ed43223fb8/docker-peauty:$IMAGE_TAG .
#
# # Docker 이미지 태그 및 푸시
# echo "Pushing Docker image to ECR..."
# docker push 93ed43223fb8/docker-peauty:$IMAGE_TAG
#
# echo "=== Gradle Build and Docker Image Push Completed ==="