name: Web UI CI/CD on: push: branches: - master paths: # 仅当构建产物 dist 目录变化时触发部署 # 修改源码不会触发,需要先在本地构建后推送 dist 目录 - 'apps/web-antd/dist/**' - 'apps/web-antd/nginx.conf' - 'Dockerfile.deploy' - '.gitea/workflows/deploy-web.yaml' jobs: build-and-deploy: runs-on: xw-runner # 使用包含 Docker 客户端的镜像,这样我们可以在容器内构建镜像 (Docker-in-Docker 模式) container: image: catthehacker/ubuntu:act-latest # 这里的 options 很重要,有时候 Runner 需要特权才能操作宿主机的 Docker # 如果遇到 permission denied,尝试取消注释下一行: # options: --privileged --user root steps: # 1. 检出代码 - name: Checkout Code run: | # 清理当前目录,防止旧文件干扰 ls -A1 | xargs rm -rf # 拼接 Clone URL (支持 http 和 https) SERVER_DOMAIN=$(echo "${{ gitea.server_url }}" | sed -E 's|https?://||') PROTO="http" if [[ "${{ gitea.server_url }}" == https* ]]; then PROTO="https"; fi # 使用 Gitea Token 进行认证 GIT_URL="${PROTO}://${{ gitea.actor }}:${{ gitea.token }}@${SERVER_DOMAIN}/${{ gitea.repository }}.git" echo "Cloning..." git clone --depth 1 "$GIT_URL" . git log -1 --format='%h - %s' # 2. 准备 Docker 网络 # 使用 1Panel 的默认网络,确保所有服务在同一个网络下,方便互相访问 - name: Check Docker Network run: | # 检查 1panel-network 是否存在,如果不存在则创建 docker network inspect 1panel-network > /dev/null 2>&1 || docker network create 1panel-network || true # 3. 检查构建产物(必须存在) - name: Check Build Artifacts run: | if [ ! -d "apps/web-antd/dist" ] || [ -z "$(ls -A apps/web-antd/dist 2>/dev/null)" ]; then echo "❌ Error: Build artifacts not found in apps/web-antd/dist" echo "Please build locally first: pnpm build:antd" echo "Then run: ./scripts/deploy/build-and-push.sh" exit 1 fi echo "✅ Build artifacts found" BUILD_SIZE=$(du -sh apps/web-antd/dist | cut -f1) echo "📊 Build size: $BUILD_SIZE" # 4. 构建并部署(只打包,不构建) - name: Build & Deploy Web UI env: # 镜像名称 IMAGE_NAME: 'aiot-web-antd' # 容器名称 CONTAINER_NAME: aiot-web-antd # 宿主机端口 HOST_PORT: 9090 run: | SHORT_SHA=$(git log -1 --format='%h') FULL_IMAGE_NAME="${IMAGE_NAME}:${SHORT_SHA}" echo "🚀 Building Docker Image (deploy only, no build): $FULL_IMAGE_NAME..." # 使用 Dockerfile.deploy,只复制构建产物,不进行构建 # 这样可以避免服务器资源占用 DOCKER_BUILDKIT=1 docker build -t "$FULL_IMAGE_NAME" -f Dockerfile.deploy . # 打上 latest 标签 docker tag "$FULL_IMAGE_NAME" "${IMAGE_NAME}:latest" # --- 部署阶段 --- echo "Deploying Container: $CONTAINER_NAME..." # 停止并删除旧容器 docker stop $CONTAINER_NAME || true docker rm $CONTAINER_NAME || true # 检查端口占用,如果有其他容器占用,先停止它 PORT_CONTAINER=$(docker ps --filter "publish=${HOST_PORT}" --format "{{.Names}}" | head -1) if [ ! -z "$PORT_CONTAINER" ]; then echo "⚠️ Port ${HOST_PORT} is occupied by container: $PORT_CONTAINER" echo "Stopping conflicting container..." docker stop $PORT_CONTAINER || true fi # 启动新容器 # -d: 后台运行 # --restart always: 开机自启 # -p: 端口映射 宿主机:容器 docker run -d \ --name $CONTAINER_NAME \ --network 1panel-network \ --restart always \ -p ${HOST_PORT}:80 \ "${IMAGE_NAME}:latest" echo "✅ Deployment Successful! Access at port ${HOST_PORT}"