140 lines
5.3 KiB
YAML
140 lines
5.3 KiB
YAML
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 "Waiting for container to start..."
|
||
sleep 3
|
||
|
||
# 检查容器状态
|
||
CONTAINER_STATUS=$(docker ps -a --filter "name=$CONTAINER_NAME" --format "{{.Status}}" | head -1)
|
||
if [ -z "$CONTAINER_STATUS" ]; then
|
||
echo "❌ Error: Container failed to start"
|
||
exit 1
|
||
fi
|
||
|
||
# 检查容器是否正在运行
|
||
if docker ps --filter "name=$CONTAINER_NAME" --format "{{.Names}}" | grep -q "$CONTAINER_NAME"; then
|
||
echo "✅ Container is running"
|
||
else
|
||
echo "❌ Error: Container is not running"
|
||
echo "Container status: $CONTAINER_STATUS"
|
||
echo "Container logs:"
|
||
docker logs $CONTAINER_NAME --tail 50
|
||
exit 1
|
||
fi
|
||
|
||
# 显示容器信息
|
||
echo "Container info:"
|
||
docker ps --filter "name=$CONTAINER_NAME" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}"
|
||
|
||
echo "✅ Deployment Successful! Access at port ${HOST_PORT}"
|
||
|