Skip to content

fix: workflow 수정 (#168) #121

fix: workflow 수정 (#168)

fix: workflow 수정 (#168) #121

name: Deploy to Dev EC2 (Docker Compose)
on:
push:
branches: [ develop ]
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
environment: dev
permissions:
contents: read
packages: write
env:
IMAGE_REPO: ghcr.io/${{ github.repository }}
CONTAINER_NAME: saerok-dev
COMPOSE_FILE_REMOTE: docker-compose.dev.yml
steps:
- name: 🧾 Checkout
uses: actions/checkout@v4
- name: 🔧 Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: 🔐 Log in to GHCR
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ secrets.GHCR_USERNAME }}
password: ${{ secrets.GHCR_TOKEN }}
- name: 🏷️ Extract metadata (tags, labels)
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.IMAGE_REPO }}
tags: |
type=raw,value=dev-latest
type=sha,format=long,prefix=dev-,suffix=
- name: 🏗️ Build and push image
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=registry,ref=${{ env.IMAGE_REPO }}:buildcache
cache-to: type=registry,ref=${{ env.IMAGE_REPO }}:buildcache,mode=max
- name: 🚀 Deploy on EC2 via SSH
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.EC2_HOST }}
username: ubuntu
key: ${{ secrets.EC2_SSH_PRIVATE_KEY }}
script: |
set -euxo pipefail
banner () { echo "::notice::$1"; }
section () { echo "::group::$1"; }
endsection () { echo "::endgroup::"; }
section "0) Ensure Docker & Compose"
if ! command -v docker >/dev/null 2>&1; then
banner "Installing Docker..."
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER || true
fi
if ! docker compose version >/dev/null 2>&1; then
banner "Installing docker compose plugin..."
DOCKER_COMPOSE_VERSION="v2.29.7"
sudo mkdir -p /usr/local/lib/docker/cli-plugins
sudo curl -fsSL https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-linux-x86_64 \
-o /usr/local/lib/docker/cli-plugins/docker-compose
sudo chmod +x /usr/local/lib/docker/cli-plugins/docker-compose
fi
docker --version
docker compose version
endsection
section "1) Stop legacy raw JAR if running"
if pgrep -fa "java .* -jar" >/dev/null 2>&1; then
banner "Stopping old raw JAR process..."
pkill -f "java .* -jar" || true
for i in $(seq 1 20); do
if pgrep -fa "java .* -jar" >/dev/null 2>&1; then
echo "waiting old jar... ($i)"
sleep 1
else
break
fi
done
else
banner "No raw JAR process found."
fi
endsection
section "2) Prepare workspace"
mkdir -p ~/saerok
cd ~/saerok
pwd
endsection
section "3) Docker login (pull from GHCR)"
echo "${{ secrets.GHCR_TOKEN }}" | docker login ghcr.io -u "${{ secrets.GHCR_USERNAME }}" --password-stdin
endsection
section "4) Generate ${COMPOSE_FILE_REMOTE}"
cat > ${COMPOSE_FILE_REMOTE} <<'YAML'
services:
app:
image: ghcr.io/${{ github.repository }}:dev-latest
container_name: saerok-dev
restart: always
ports:
- "8080:8080"
environment:
SPRING_PROFILES_ACTIVE: "dev"
DB_URL: "${{ secrets.DB_URL }}"
DB_USERNAME: "${{ secrets.DB_USERNAME }}"
DB_PASSWORD: "${{ secrets.DB_PASSWORD }}"
IAM_ACCESS_KEY: "${{ secrets.IAM_ACCESS_KEY }}"
IAM_SECRET_KEY: "${{ secrets.IAM_SECRET_KEY }}"
UPLOAD_IMAGE_BUCKET_NAME: "${{ vars.UPLOAD_IMAGE_BUCKET_NAME }}"
UPLOAD_IMAGE_DOMAIN: "${{ vars.UPLOAD_IMAGE_DOMAIN }}"
DEX_IMAGE_BUCKET_NAME: "${{ vars.DEX_IMAGE_BUCKET_NAME }}"
DEX_IMAGE_DOMAIN: "${{ vars.DEX_IMAGE_DOMAIN }}"
APPLE_CLIENT_ID: "${{ secrets.APPLE_CLIENT_ID }}"
APPLE_TEAM_ID: "${{ secrets.APPLE_TEAM_ID }}"
APPLE_KEY_ID: "${{ secrets.APPLE_KEY_ID }}"
APPLE_PRIVATE_KEY: "${{ secrets.APPLE_PRIVATE_KEY }}"
JWT_SECRET: "${{ secrets.JWT_SECRET }}"
KAKAO_ADMIN_KEY: "${{ secrets.KAKAO_ADMIN_KEY }}"
KAKAO_CLIENT_ID: "${{ secrets.KAKAO_CLIENT_ID }}"
KAKAO_REDIRECT_URI: "${{ secrets.KAKAO_REDIRECT_URI }}"
KAKAO_CLIENT_SECRET: "${{ secrets.KAKAO_CLIENT_SECRET }}"
KMS_KEY_ID: "${{ secrets.KMS_KEY_ID }}"
FIREBASE_ADMIN_KEY: "${{ secrets.FIREBASE_ADMIN_KEY }}"
healthcheck:
test: ["CMD-SHELL", "curl -fsS http://localhost:8080/health >/dev/null || exit 1"]
interval: 10s
timeout: 3s
retries: 15
start_period: 60s
YAML
banner "Compose file written: ${COMPOSE_FILE_REMOTE}"
docker compose -f ${COMPOSE_FILE_REMOTE} config
endsection
section "5) Pull & Up (recreate)"
docker compose -f ${COMPOSE_FILE_REMOTE} pull
docker compose -f ${COMPOSE_FILE_REMOTE} up -d --force-recreate
docker compose -f ${COMPOSE_FILE_REMOTE} ps
endsection
section "6) Wait for health=healthy"
set +e
ATTEMPTS=40
for i in $(seq 1 ${ATTEMPTS}); do
STATUS=$(docker inspect -f '{{.State.Health.Status}}' ${{ env.CONTAINER_NAME }} 2>/dev/null || echo "unknown")
echo "[$i/${ATTEMPTS}] health: $STATUS"
if [ "$STATUS" = "healthy" ]; then
banner "Container is healthy."
OK=1
break
fi
sleep 2
done
if [ "${OK:-0}" != "1" ]; then
echo "::warning::Container did not reach healthy state in time."
docker logs --tail=200 ${{ env.CONTAINER_NAME }} || true
exit 1
fi
set -e
endsection
section "7) Tail last logs"
docker logs --tail=200 ${{ env.CONTAINER_NAME }} || true
endsection
banner "✅ Deploy done"