Skip to content

Merge pull request #138 from finpik/develop #57

Merge pull request #138 from finpik/develop

Merge pull request #138 from finpik/develop #57

Workflow file for this run

name: Build & Deploy
on:
push:
branches: [ "main" ]
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }} # org/repo
IMAGE_REPO: ghcr.io/${{ github.repository }} # ghcr.io/org/repo
jobs:
build-and-push:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
outputs:
sha_short: ${{ steps.vars.outputs.sha_short }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
distribution: temurin
java-version: '21'
- name: Login to GHCR (runner)
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract short SHA
id: vars
run: echo "sha_short=${GITHUB_SHA::7}" >> $GITHUB_OUTPUT
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile
push: true
tags: |
${{ env.IMAGE_REPO }}:${{ steps.vars.outputs.sha_short }}
${{ env.IMAGE_REPO }}:latest
deploy:
needs: build-and-push
runs-on: ubuntu-latest
steps:
- name: SSH & Deploy (stop-first)
uses: appleboy/ssh-action@v1.2.0
with:
host: ${{ secrets.SSH_HOST }} # EC2 퍼블릭 IP/도메인
username: ${{ secrets.SSH_USER }} # ec2-user
key: ${{ secrets.SSH_KEY }} # pem 내용
script: |
set -Eeuo pipefail
IMAGE_REPO="${{ env.IMAGE_REPO }}"
IMAGE_TAG="${{ needs.build-and-push.outputs.sha_short }}"
APP_NAME="finpik-app"
PORT="8080"
ENV_FILE="/srv/app/.env"
RESTART_POLICY="no"
JAVA_OPTS="-Xms1g -Xmx1g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:+ExitOnOutOfMemoryError"
# (선택) GHCR private이면 EC2에서 로그인 필요: packages:read 권한 PAT를 GHCR_TOKEN/USERNAME로 넣어두기
if [ -n "${{ secrets.GHCR_TOKEN || '' }}" ]; then
echo "${{ secrets.GHCR_TOKEN }}" | docker login ghcr.io -u "${{ secrets.GHCR_USERNAME }}" --password-stdin
fi
# .env 존재 확인(최초 1회 수동 생성 가정)
if [ ! -f "${ENV_FILE}" ]; then
echo "ERROR: ${ENV_FILE} not found"; exit 1
fi
echo "== Pull image =="
docker pull "${IMAGE_REPO}:${IMAGE_TAG}"
echo "== Stop & remove old =="
docker ps -a --filter "name=^/${APP_NAME}$" -q | xargs -r docker stop
docker ps -a --filter "name=^/${APP_NAME}$" -q | xargs -r docker rm
echo "== Run new container =="
docker run -d \
--name "${APP_NAME}" \
-p "${PORT}:8080" \
--env-file "${ENV_FILE}" \
-e SPRING_PROFILES_ACTIVE=prod \
-e JAVA_TOOL_OPTIONS="${JAVA_OPTS}" \
--restart "${RESTART_POLICY}" \
"${IMAGE_REPO}:${IMAGE_TAG}"
echo "== Wait for health (up to 60s) =="
# 호스트에서 외부 헬스체크(컨테이너 안에 curl/wget 없어도 OK)
command -v curl >/dev/null 2>&1 || sudo yum -y install -q curl || true
ok=""
for i in {1..12}; do
if curl -fsS "http://127.0.0.1:${PORT}/actuator/health" >/dev/null; then
ok="yes"; echo "healthy"; break
fi
sleep 5
done
if [ -z "$ok" ]; then
echo "!! app not healthy. recent logs:"
docker logs --tail=200 "${APP_NAME}" || true
exit 1
fi
echo "== OK: ${APP_NAME} is healthy on :${PORT}"