ci: gate image push and add deploy health rollback
Build docker and publish / build (20.15.1) (pull_request) Successful in 8m3s
Build docker and publish / build (20.15.1) (pull_request) Successful in 8m3s
Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
+118
-24
@@ -115,24 +115,37 @@ jobs:
|
||||
docker version || true
|
||||
echo "客户端 API 版本:" $(docker version --format '{{.Client.APIVersion}}')
|
||||
|
||||
# 步骤4: 构建并发布到镜像仓库
|
||||
- name: 📤 构建并发布到镜像仓库
|
||||
# 步骤4: 构建镜像
|
||||
- name: 🏗️ 构建镜像
|
||||
run: |
|
||||
echo "开始构建并推送镜像..."
|
||||
echo "开始构建镜像..."
|
||||
echo "仓库: ${{ env.REPO }}"
|
||||
echo "版本标签: ${{ env.VERSION }}"
|
||||
echo "分支标签: ${{ env.DOCKER_TAG_SUFFIX }}"
|
||||
|
||||
# 构建镜像,同时打上版本和分支两个标签
|
||||
BUILD_TAG_ARGS="-t ${{ env.REPO }}:${{ env.VERSION }}"
|
||||
if [ "${{ github.event_name }}" = "push" ]; then
|
||||
BUILD_TAG_ARGS="$BUILD_TAG_ARGS -t ${{ env.REPO }}:${{ env.DOCKER_TAG_SUFFIX }}"
|
||||
else
|
||||
echo "PR事件仅构建版本标签,不推送镜像、不部署"
|
||||
fi
|
||||
|
||||
docker build -f Dockerfile \
|
||||
--platform linux/amd64 \
|
||||
--build-arg TARGETARCH=amd64 \
|
||||
--build-arg VERSION=${{ env.VERSION }} \
|
||||
--build-arg BUILDTIME=${{ env.BUILDTIME }} \
|
||||
-t ${{ env.REPO }}:${{ env.VERSION }} \
|
||||
-t ${{ env.REPO }}:${{ env.DOCKER_TAG_SUFFIX }} \
|
||||
$BUILD_TAG_ARGS \
|
||||
.
|
||||
|
||||
echo "镜像构建完成"
|
||||
|
||||
# 步骤5: 发布到镜像仓库
|
||||
- name: 📤 发布到镜像仓库
|
||||
if: github.event_name == 'push'
|
||||
run: |
|
||||
echo "开始推送镜像..."
|
||||
|
||||
echo "推送版本标签镜像: ${{ env.REPO }}:${{ env.VERSION }}"
|
||||
docker push ${{ env.REPO }}:${{ env.VERSION }}
|
||||
|
||||
@@ -141,8 +154,9 @@ jobs:
|
||||
|
||||
echo "镜像推送完成"
|
||||
|
||||
# 步骤5: 调试 - 打印部署目标(不输出敏感信息)
|
||||
# 步骤6: 调试 - 打印部署目标(不输出敏感信息)
|
||||
- name: 🔍 调试 - 打印部署目标
|
||||
if: github.event_name == 'push'
|
||||
run: |
|
||||
echo "========== 部署目标调试 =========="
|
||||
echo "当前分支: ${{ github.ref_name }}"
|
||||
@@ -153,7 +167,7 @@ jobs:
|
||||
echo "DEPLOY_PATH: ${{ env.DEPLOY_PATH }}"
|
||||
echo "====================================="
|
||||
|
||||
# 步骤6: 传输配置文件
|
||||
# 步骤7: 传输配置文件
|
||||
- name: 📂 传输配置文件
|
||||
if: github.event_name == 'push'
|
||||
uses: appleboy/scp-action@v0.1.7
|
||||
@@ -165,7 +179,7 @@ jobs:
|
||||
source: "docker-compose.cloud.yml"
|
||||
target: "/tmp/ppanel-deploy/"
|
||||
|
||||
# 步骤7: 连接服务器更新并启动
|
||||
# 步骤8: 连接服务器更新、健康检查并按需回滚
|
||||
- name: 🚀 连接服务器更新并启动
|
||||
if: github.event_name == 'push'
|
||||
uses: appleboy/ssh-action@v1.0.3
|
||||
@@ -177,34 +191,112 @@ jobs:
|
||||
timeout: 300s
|
||||
command_timeout: 600s
|
||||
script: |
|
||||
set -e
|
||||
|
||||
echo "连接服务器成功,开始部署..."
|
||||
echo "部署目录: ${{ env.DEPLOY_PATH }}"
|
||||
echo "部署标签: ${{ env.DOCKER_TAG_SUFFIX }}"
|
||||
echo "登录用户: ${{ env.SSH_USER }}"
|
||||
|
||||
HEALTHCHECK_URL="http://127.0.0.1:8080/v1/common/heartbeat"
|
||||
NEW_TAG="${{ env.DOCKER_TAG_SUFFIX }}"
|
||||
ROLLBACK_TAG="rollback-${{ env.VERSION }}"
|
||||
SUDO=""
|
||||
if [ "${{ github.ref_name }}" = "main" ]; then
|
||||
SUDO="sudo"
|
||||
fi
|
||||
|
||||
docker_cmd() {
|
||||
if [ -n "$SUDO" ]; then
|
||||
sudo docker "$@"
|
||||
else
|
||||
docker "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
compose_with_tag() {
|
||||
tag="$1"
|
||||
shift
|
||||
if [ -n "$SUDO" ]; then
|
||||
sudo env PPANEL_SERVER_TAG="$tag" docker-compose -f docker-compose.cloud.yml "$@"
|
||||
else
|
||||
PPANEL_SERVER_TAG="$tag" docker-compose -f docker-compose.cloud.yml "$@"
|
||||
fi
|
||||
}
|
||||
|
||||
write_previous_tag() {
|
||||
if [ -n "$SUDO" ]; then
|
||||
printf '%s\n' "${PREVIOUS_IMAGE_TAG:-}" | sudo tee .previous-ppanel-image-tag >/dev/null
|
||||
else
|
||||
printf '%s\n' "${PREVIOUS_IMAGE_TAG:-}" > .previous-ppanel-image-tag
|
||||
fi
|
||||
}
|
||||
|
||||
health_check() {
|
||||
attempt=1
|
||||
while [ "$attempt" -le 3 ]; do
|
||||
if curl -sf "$HEALTHCHECK_URL"; then
|
||||
echo
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "健康检查第 ${attempt}/3 次失败,10s 后重试..."
|
||||
attempt=$((attempt + 1))
|
||||
sleep 10
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
if [ "${{ github.ref_name }}" = "main" ]; then
|
||||
sudo mkdir -p ${{ env.DEPLOY_PATH }}
|
||||
sudo cp /tmp/ppanel-deploy/docker-compose.cloud.yml ${{ env.DEPLOY_PATH }}/docker-compose.cloud.yml
|
||||
cd ${{ env.DEPLOY_PATH }}
|
||||
echo "📥 拉取镜像..."
|
||||
sudo docker-compose -f docker-compose.cloud.yml pull ppanel-server
|
||||
echo "🚀 启动服务..."
|
||||
sudo docker-compose -f docker-compose.cloud.yml up -d ppanel-server
|
||||
sudo docker image prune -f || true
|
||||
else
|
||||
mkdir -p ${{ env.DEPLOY_PATH }}
|
||||
cp /tmp/ppanel-deploy/docker-compose.cloud.yml ${{ env.DEPLOY_PATH }}/docker-compose.cloud.yml
|
||||
cd ${{ env.DEPLOY_PATH }}
|
||||
echo "📥 拉取镜像..."
|
||||
docker-compose -f docker-compose.cloud.yml pull ppanel-server
|
||||
echo "🚀 启动服务..."
|
||||
docker-compose -f docker-compose.cloud.yml up -d ppanel-server
|
||||
docker image prune -f || true
|
||||
fi
|
||||
|
||||
echo "✅ 部署命令执行完成"
|
||||
cd ${{ env.DEPLOY_PATH }}
|
||||
|
||||
# 步骤8: TG通知 (成功)
|
||||
PREVIOUS_IMAGE_TAG="$(docker_cmd inspect --format '{{.Config.Image}}' ppanel-server 2>/dev/null || true)"
|
||||
PREVIOUS_IMAGE_ID="$(docker_cmd inspect --format '{{.Image}}' ppanel-server 2>/dev/null || true)"
|
||||
echo "上一版本镜像tag: ${PREVIOUS_IMAGE_TAG:-未发现}"
|
||||
echo "上一版本镜像ID: ${PREVIOUS_IMAGE_ID:-未发现}"
|
||||
write_previous_tag
|
||||
|
||||
echo "📥 拉取镜像: ${{ env.REPO }}:${NEW_TAG}"
|
||||
compose_with_tag "$NEW_TAG" pull ppanel-server
|
||||
echo "🚀 启动服务..."
|
||||
compose_with_tag "$NEW_TAG" up -d ppanel-server
|
||||
|
||||
echo "🩺 部署后健康检查: ${HEALTHCHECK_URL}"
|
||||
if health_check; then
|
||||
docker_cmd image prune -f || true
|
||||
echo "✅ 部署后健康检查通过"
|
||||
echo "✅ 部署命令执行完成"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "❌ 部署后健康检查连续 3 次失败,开始回滚..."
|
||||
if [ -n "$PREVIOUS_IMAGE_ID" ]; then
|
||||
docker_cmd tag "$PREVIOUS_IMAGE_ID" "${{ env.REPO }}:${ROLLBACK_TAG}"
|
||||
echo "回滚镜像tag: ${{ env.REPO }}:${ROLLBACK_TAG}"
|
||||
compose_with_tag "$ROLLBACK_TAG" up -d ppanel-server
|
||||
|
||||
echo "🩺 回滚后健康检查: ${HEALTHCHECK_URL}"
|
||||
if health_check; then
|
||||
echo "✅ 回滚后健康检查通过"
|
||||
else
|
||||
echo "❌ 回滚后健康检查仍失败"
|
||||
fi
|
||||
else
|
||||
echo "未找到上一版本镜像ID,无法自动回滚"
|
||||
fi
|
||||
|
||||
docker_cmd image prune -f || true
|
||||
exit 1
|
||||
|
||||
# 步骤9: TG通知 (成功)
|
||||
- name: 📱 发送成功通知到Telegram
|
||||
if: success() && github.event_name == 'push'
|
||||
uses: appleboy/telegram-action@master
|
||||
@@ -221,9 +313,10 @@ jobs:
|
||||
🕐 时间: ${{ github.event.head_commit.timestamp }}
|
||||
|
||||
${{ env.DEPLOY_ENV_LABEL }}
|
||||
🩺 健康检查: 通过 (http://127.0.0.1:8080/v1/common/heartbeat)
|
||||
parse_mode: Markdown
|
||||
|
||||
# 步骤9: TG通知 (失败)
|
||||
# 步骤10: TG通知 (失败)
|
||||
- name: 📱 发送失败通知到Telegram
|
||||
if: failure() && github.event_name == 'push'
|
||||
uses: appleboy/telegram-action@master
|
||||
@@ -239,5 +332,6 @@ jobs:
|
||||
👤 提交者: ${{ github.actor }}
|
||||
🕐 时间: ${{ github.event.head_commit.timestamp }}
|
||||
|
||||
🩺 健康检查: 失败或未完成;若新版本健康检查连续 3 次失败,已自动尝试回滚并重新检查
|
||||
⚠️ 请检查构建日志获取详细信息
|
||||
parse_mode: Markdown
|
||||
|
||||
Reference in New Issue
Block a user