Add GitHub staging deployment workflow

This commit is contained in:
2026-06-02 20:45:05 -07:00
parent 87ebfa1fac
commit 3df59ef345
3 changed files with 199 additions and 2 deletions
+171
View File
@@ -0,0 +1,171 @@
name: Deploy Staging
on:
push:
branches:
- main
- internal
workflow_dispatch:
permissions:
contents: read
packages: write
env:
IMAGE_NAME: ghcr.io/tawcorp/hifast-server
DEPLOY_HOST: 154.12.35.103
DEPLOY_PATH: /opt/hifast-server
HEALTHCHECK_URL: http://127.0.0.1:8080/v1/common/heartbeat
jobs:
build-and-deploy:
name: Build image and deploy to staging
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GitHub Container Registry
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push image
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile
platforms: linux/amd64
push: true
build-args: |
TARGETARCH=amd64
VERSION=${{ github.sha }}
tags: |
${{ env.IMAGE_NAME }}:${{ github.sha }}
${{ env.IMAGE_NAME }}:staging
- name: Copy compose file
uses: appleboy/scp-action@v0.1.7
with:
host: ${{ env.DEPLOY_HOST }}
username: ${{ secrets.STAGING_SSH_USER }}
key: ${{ secrets.STAGING_SSH_KEY }}
port: ${{ secrets.STAGING_SSH_PORT || 22 }}
source: docker-compose.cloud.yml
target: /tmp/hifast-server-deploy/
- name: Deploy on staging server
uses: appleboy/ssh-action@v1.0.3
env:
GHCR_USERNAME: ${{ secrets.GHCR_USERNAME }}
GHCR_TOKEN: ${{ secrets.GHCR_TOKEN }}
with:
host: ${{ env.DEPLOY_HOST }}
username: ${{ secrets.STAGING_SSH_USER }}
key: ${{ secrets.STAGING_SSH_KEY }}
port: ${{ secrets.STAGING_SSH_PORT || 22 }}
timeout: 300s
command_timeout: 600s
envs: GHCR_USERNAME,GHCR_TOKEN
script: |
set -euo pipefail
IMAGE_NAME="${{ env.IMAGE_NAME }}"
NEW_TAG="${{ github.sha }}"
DEPLOY_PATH="${{ env.DEPLOY_PATH }}"
HEALTHCHECK_URL="${{ env.HEALTHCHECK_URL }}"
ROLLBACK_TAG="rollback-${NEW_TAG}"
if command -v sudo >/dev/null 2>&1 && ! docker ps >/dev/null 2>&1; then
SUDO="sudo"
else
SUDO=""
fi
docker_cmd() {
if [ -n "$SUDO" ]; then
sudo docker "$@"
else
docker "$@"
fi
}
compose_cmd() {
tag="$1"
shift
if docker compose version >/dev/null 2>&1; then
if [ -n "$SUDO" ]; then
sudo env PPANEL_SERVER_IMAGE="$IMAGE_NAME" PPANEL_SERVER_TAG="$tag" docker compose -f docker-compose.cloud.yml "$@"
else
PPANEL_SERVER_IMAGE="$IMAGE_NAME" PPANEL_SERVER_TAG="$tag" docker compose -f docker-compose.cloud.yml "$@"
fi
else
if [ -n "$SUDO" ]; then
sudo env PPANEL_SERVER_IMAGE="$IMAGE_NAME" PPANEL_SERVER_TAG="$tag" docker-compose -f docker-compose.cloud.yml "$@"
else
PPANEL_SERVER_IMAGE="$IMAGE_NAME" PPANEL_SERVER_TAG="$tag" docker-compose -f docker-compose.cloud.yml "$@"
fi
fi
}
health_check() {
attempt=1
while [ "$attempt" -le 6 ]; do
if curl -fsS "$HEALTHCHECK_URL"; then
echo
return 0
fi
echo "Health check ${attempt}/6 failed; retrying in 10s..."
attempt=$((attempt + 1))
sleep 10
done
return 1
}
if [ -n "${GHCR_USERNAME:-}" ] && [ -n "${GHCR_TOKEN:-}" ]; then
echo "$GHCR_TOKEN" | docker_cmd login ghcr.io -u "$GHCR_USERNAME" --password-stdin
fi
if [ -n "$SUDO" ]; then
sudo mkdir -p "$DEPLOY_PATH"
sudo cp /tmp/hifast-server-deploy/docker-compose.cloud.yml "$DEPLOY_PATH/docker-compose.cloud.yml"
else
mkdir -p "$DEPLOY_PATH"
cp /tmp/hifast-server-deploy/docker-compose.cloud.yml "$DEPLOY_PATH/docker-compose.cloud.yml"
fi
cd "$DEPLOY_PATH"
PREVIOUS_IMAGE_ID="$(docker_cmd inspect --format '{{.Image}}' ppanel-server 2>/dev/null || true)"
echo "Previous image ID: ${PREVIOUS_IMAGE_ID:-none}"
echo "Pulling ${IMAGE_NAME}:${NEW_TAG}"
compose_cmd "$NEW_TAG" pull ppanel-server
echo "Starting ppanel-server"
compose_cmd "$NEW_TAG" up -d ppanel-server
echo "Checking ${HEALTHCHECK_URL}"
if health_check; then
docker_cmd image prune -f || true
echo "Staging deployment succeeded"
exit 0
fi
echo "Health check failed; attempting rollback"
if [ -n "$PREVIOUS_IMAGE_ID" ]; then
docker_cmd tag "$PREVIOUS_IMAGE_ID" "${IMAGE_NAME}:${ROLLBACK_TAG}"
compose_cmd "$ROLLBACK_TAG" up -d ppanel-server
health_check || true
else
echo "No previous image found; rollback skipped"
fi
docker_cmd image prune -f || true
exit 1