fix: workflow 수정 (#168) #121
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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" |