name: Deploy on: push: branches: [main] workflow_dispatch: # 同一分支只保留最新一次部署,避免并发发布互相覆盖容器 concurrency: group: deploy-main cancel-in-progress: true env: IMAGE: demo CONTAINER: demo HOST_PORT: "9121" jobs: deploy: runs-on: ubuntu-latest steps: - name: 检出代码 uses: actions/checkout@v4 - name: 构建镜像 run: | docker build \ --label "org.opencontainers.image.revision=${{ github.sha }}" \ -t "$IMAGE:latest" \ -t "$IMAGE:${{ github.sha }}" \ . - name: 滚动重启容器 run: | docker rm -f "$CONTAINER" 2>/dev/null || true docker run -d \ --name "$CONTAINER" \ --restart unless-stopped \ -p "127.0.0.1:${HOST_PORT}:80" \ "$IMAGE:latest" - name: 健康检查 run: | # 作业跑在独立的 job 容器里,127.0.0.1 不是宿主机, # 因此进应用容器内部自检(nginx:alpine 自带 busybox wget) for i in $(seq 1 15); do if docker exec "$CONTAINER" wget -q -O /dev/null http://127.0.0.1/; then echo "容器已就绪(第 ${i} 次探测)" exit 0 fi sleep 2 done echo "健康检查失败" docker logs --tail 50 "$CONTAINER" || true exit 1 - name: 清理旧镜像 run: | # 保留 latest 与当前提交的镜像,其余同仓库的悬空/历史镜像清掉 docker image prune -f || true