diff --git a/.drone.yml b/.drone.yml index bd7fc85..7567669 100644 --- a/.drone.yml +++ b/.drone.yml @@ -1,96 +1,350 @@ +--- kind: pipeline type: docker -name: build - -steps: - - name: maven-package - image: maven:3-eclipse-temurin-21-alpine - volumes: - - name: maven-cache - path: /root/.m2 - commands: - - mvn clean package -DskipTests -B +name: par-build volumes: - name: maven-cache host: - path: /tmp/drone/cache/maven + path: /tmp/drone-maven-cache + - name: npm-cache + host: + path: /tmp/drone-npm-cache + - name: dockersock + host: + path: /var/run/docker.sock trigger: - branch: - - dev - - test - - main - event: - - push + event: [push] + branch: [dev, test, main] + exclude: + commit: + - ^\[skip ci\] + - ^\[ci skip\] ---- +platform: + os: linux + arch: amd64 -kind: pipeline -type: docker -name: docker-build-test +workspace: + path: /drone/src -depends_on: - - build +environment: + # 仓库配置 + LOCAL_HARBOR_REG: "192.168.31.253" + LOCAL_HARBOR_PROJ: "yescent" + + # 镜像/容器通用 + IMAGE_NAME: "${DRONE_REPO_NAME}" + CONTAINER_NAME: "par-server" + + # 部署配置 + SERVER_PORT: "8080" + APP_PORT: "9012" + TZ: "Asia/Shanghai" steps: - - name: docker-build-and-push-test - image: plugins/docker - settings: - registry: 192.168.31.253 - repo: 192.168.31.253/yescent/par - tags: test - dockerfile: par-api/Dockerfile - username: - from_secret: harbor_username - password: - from_secret: harbor_password + # ===================== 调试信息 ===================== + - name: print-drone-vars + image: 192.168.31.253/library/alpine:latest + commands: + - echo "===== ALL DRONE ENV VARIABLES =====" + - env | grep -i drone | sort -trigger: - branch: - - test - event: - - push + # ===================== 准备 Maven 缓存 ===================== + - name: prepare-cache + image: 192.168.31.253/library/maven-java21:3.9.9-alpine + volumes: + - name: maven-cache + path: /host-cache + commands: + - | + echo "正在准备Maven缓存目录..." + mkdir -p /host-cache/repository + if [ "$(ls -A /host-cache/repository 2>/dev/null)" ]; then + CACHE_SIZE=$(du -sh /host-cache/repository | cut -f1) + echo "检测到现有缓存,大小: $CACHE_SIZE" + echo "CACHE_EXISTS=true" > /drone/src/.cache_info + else + echo "未发现现有缓存,将初始化新缓存。" + echo "CACHE_EXISTS=false" > /drone/src/.cache_info + fi ---- + # ===================== 前端构建(npm) ===================== + - name: frontend-build + image: 192.168.31.253/library/node:22-alpine + volumes: + - name: npm-cache + path: /root/.npm + commands: + - | + echo "====== 开始前端构建 ======" + cd web + npm ci --prefer-offline --ignore-scripts 2>/dev/null || npm install --prefer-offline --ignore-scripts + # 确保 rollup 原生绑定可用 + if [ -f node_modules/@rollup/rollup-linux-x64-musl/package.json ]; then + node -e "require('@rollup/rollup-linux-x64-musl/package.json')" 2>/dev/null || npm install @rollup/rollup-linux-x64-musl --ignore-scripts --force + fi + npm run build + echo "前端构建完成,产物列表:" + ls -la dist/ + echo "====== 前端构建结束 ======" -kind: pipeline -type: docker -name: docker-build-and-deploy + # ===================== Maven 构建(含前端静态资源) ===================== + - name: maven-build + image: 192.168.31.253/library/maven-java21:3.9.9-alpine + pull: if-not-exists + environment: + MAVEN_OPTS: "-Dmaven.repo.local=/root/.m2/repository -Xms256m -Xmx512m" + volumes: + - name: maven-cache + path: /root/.m2 + commands: + - | + set -e + echo "====== 开始 Maven 构建 ======" -depends_on: - - build + # 将前端构建产物复制到 static 目录 + FRONTEND_DIST="/drone/src/web/dist" + STATIC_DIR="/drone/src/par-api/src/main/resources/static" + if [ -d "$FRONTEND_DIST" ]; then + mkdir -p "$STATIC_DIR" + cp -r "$FRONTEND_DIST"/* "$STATIC_DIR"/ + echo "前端产物已复制到 $STATIC_DIR" + ls -la "$STATIC_DIR" + else + echo "警告:未找到前端构建产物 $FRONTEND_DIST,将仅构建后端" + fi -steps: - - name: docker-build-and-push - image: plugins/docker - settings: - registry: 192.168.31.253 - repo: 192.168.31.253/yescent/par - tags: latest - dockerfile: par-api/Dockerfile - username: - from_secret: harbor_username - password: - from_secret: harbor_password + # 生成版本标签 + RELEASE_VERSION="v1.0.0" + BUILD_VERSION="v1.0.0.${DRONE_BUILD_NUMBER}" + echo "RELEASE_VERSION=$RELEASE_VERSION" > /drone/src/.version.env + echo "BUILD_VERSION=$BUILD_VERSION" >> /drone/src/.version.env + echo "BUILD_DATE=$(TZ=Asia/Shanghai date +%Y%m%d)" >> /drone/src/.version.env + echo "发布版本: $RELEASE_VERSION, 构建版本: $BUILD_VERSION" - - name: deploy - image: appleboy/drone-ssh - settings: - host: 192.168.31.252 - username: - from_secret: ssh_username - password: - from_secret: ssh_password - port: 22 - script: - - cd /data/par - - ./deploy.sh - command_timeout: 2m - timeout: 2m + # Maven 打包 + mvn -B clean package \ + -DskipTests \ + -T 1C \ + --no-transfer-progress -trigger: - branch: - - main - event: - - push + JAR_FILE=$(ls par-api/target/*.jar | head -1) + echo "构建成功!产物: $JAR_FILE ($(du -sh $JAR_FILE | cut -f1))" + depends_on: + - prepare-cache + - frontend-build + + # ===================== Docker 镜像构建 ===================== + - name: build-docker-image + image: 192.168.31.253/library/docker:cli + volumes: + - name: dockersock + path: /var/run/docker.sock + commands: + - | + echo "====== 开始构建 Docker 镜像 ======" + source /drone/src/.version.env + # main 分支用干净版本号,test 带 pipeline 号 + if [ "$DRONE_BRANCH" = "main" ]; then + APP_VERSION="$RELEASE_VERSION" + else + APP_VERSION="$BUILD_VERSION" + fi + echo "版本: $APP_VERSION" + + docker build \ + -t "$IMAGE_NAME:$BUILD_VERSION" \ + -t "$IMAGE_NAME:latest" \ + --build-arg VERSION="$APP_VERSION" \ + --build-arg BUILD_TIME="$(TZ=Asia/Shanghai date '+%Y-%m-%d %H:%M')" \ + -f par-api/Dockerfile \ + . + + echo "Docker 镜像构建完成。" + docker images | grep "$IMAGE_NAME" + depends_on: + - maven-build + when: + branch: [test, main] + + # ===================== Test:推本地 Harbor ===================== + - name: push-to-harbor + image: 192.168.31.253/library/docker:cli + network_mode: host + volumes: + - name: dockersock + path: /var/run/docker.sock + environment: + LOCAL_HARBOR_REG: "192.168.31.253" + LOCAL_HARBOR_PROJ: "yescent" + LOCAL_REGISTRY_USER: + from_secret: local_registry_user + LOCAL_REGISTRY_PASSWORD: + from_secret: local_registry_password + commands: + - | + echo "====== 推送镜像到本地 Harbor ======" + source /drone/src/.version.env + LOCAL_IMAGE_FULL="$LOCAL_HARBOR_REG/$LOCAL_HARBOR_PROJ/$IMAGE_NAME" + LOCAL_IMAGE_TAG="$LOCAL_IMAGE_FULL:$BUILD_VERSION" + LOCAL_IMAGE_LATEST="$LOCAL_IMAGE_FULL:latest" + + docker tag "$IMAGE_NAME:$BUILD_VERSION" "$LOCAL_IMAGE_TAG" + docker tag "$IMAGE_NAME:latest" "$LOCAL_IMAGE_LATEST" + + echo "$LOCAL_REGISTRY_PASSWORD" | docker login -u "$LOCAL_REGISTRY_USER" --password-stdin $LOCAL_HARBOR_REG + docker push "$LOCAL_IMAGE_TAG" + docker push "$LOCAL_IMAGE_LATEST" + + docker rmi "$LOCAL_IMAGE_TAG" "$LOCAL_IMAGE_LATEST" || true + echo "====== Harbor 推送完成 ======" + depends_on: + - build-docker-image + when: + status: success + branch: [test] + + # ===================== Test:部署到测试服务器 ===================== + - name: deploy-test + image: 192.168.31.253/library/alpine-openssh:latest + environment: + DEPLOY_IMAGE: "192.168.31.253/yescent/${DRONE_REPO_NAME}" + APP_PORT: "9012" + SSH_USER: + from_secret: test_ssh_user + SSH_HOST: + from_secret: test_ssh_host + SSH_KEY: + from_secret: test_ssh_key + commands: + - | + echo "====== 部署测试环境 ======" + source /drone/src/.version.env + + mkdir -p ~/.ssh + echo "$SSH_KEY" > ~/.ssh/id_rsa + chmod 600 ~/.ssh/id_rsa + + export IMG="$DEPLOY_IMAGE:$BUILD_VERSION" + ssh -o StrictHostKeyChecking=no $SSH_USER@$SSH_HOST " + docker pull $IMG + docker stop par-server 2>/dev/null || true + docker rm -f par-server 2>/dev/null || true + docker run -d --name par-server --restart always \\ + --env-file /data/par/db.env \\ + -p \${APP_PORT:-9012}:8080 \\ + -v /data/par/logs:/app/logs \\ + -v /data/par/static:/app/static \\ + $IMG + sleep 10 + curl -s http://localhost:\${APP_PORT:-9012}/health && echo OK || echo FAIL + " + echo "====== 部署完成 ======" + depends_on: + - push-to-harbor + when: + status: success + branch: [test] + + # ===================== Main:推本地 Harbor 并部署 ===================== + - name: push-to-harbor-main + image: 192.168.31.253/library/docker:cli + network_mode: host + volumes: + - name: dockersock + path: /var/run/docker.sock + environment: + LOCAL_HARBOR_REG: "192.168.31.253" + LOCAL_HARBOR_PROJ: "yescent" + LOCAL_REGISTRY_USER: + from_secret: local_registry_user + LOCAL_REGISTRY_PASSWORD: + from_secret: local_registry_password + commands: + - | + echo "====== 推送镜像到本地 Harbor (main) ======" + source /drone/src/.version.env + LOCAL_IMAGE_FULL="$LOCAL_HARBOR_REG/$LOCAL_HARBOR_PROJ/$IMAGE_NAME" + LOCAL_IMAGE_TAG="$LOCAL_IMAGE_FULL:$BUILD_VERSION" + LOCAL_IMAGE_LATEST="$LOCAL_IMAGE_FULL:latest" + + docker tag "$IMAGE_NAME:$BUILD_VERSION" "$LOCAL_IMAGE_TAG" + docker tag "$IMAGE_NAME:latest" "$LOCAL_IMAGE_LATEST" + + echo "$LOCAL_REGISTRY_PASSWORD" | docker login -u "$LOCAL_REGISTRY_USER" --password-stdin $LOCAL_HARBOR_REG + docker push "$LOCAL_IMAGE_TAG" + docker push "$LOCAL_IMAGE_LATEST" + + docker rmi "$LOCAL_IMAGE_TAG" "$LOCAL_IMAGE_LATEST" || true + echo "====== Harbor 推送完成 ======" + depends_on: + - build-docker-image + when: + status: success + branch: [main] + + - name: deploy-main + image: 192.168.31.253/library/alpine-openssh:latest + environment: + DEPLOY_IMAGE: "192.168.31.253/yescent/${DRONE_REPO_NAME}" + APP_PORT: "9012" + SSH_USER: + from_secret: prod_ssh_user + SSH_HOST: + from_secret: prod_ssh_host + SSH_KEY: + from_secret: prod_ssh_key + commands: + - | + echo "====== 部署生产环境 ======" + source /drone/src/.version.env + + mkdir -p ~/.ssh + echo "$SSH_KEY" > ~/.ssh/id_rsa + chmod 600 ~/.ssh/id_rsa + + export IMG="$DEPLOY_IMAGE:$BUILD_VERSION" + ssh -o StrictHostKeyChecking=no $SSH_USER@$SSH_HOST " + docker pull $IMG + docker stop par-server 2>/dev/null || true + docker rm -f par-server 2>/dev/null || true + docker run -d --name par-server --restart always \\ + --env-file /data/par/db.env \\ + -p \${APP_PORT:-9012}:8080 \\ + -v /data/par/logs:/app/logs \\ + -v /data/par/static:/app/static \\ + $IMG + sleep 10 + curl -s http://localhost:\${APP_PORT:-9012}/health && echo OK || echo FAIL + " + echo "====== 部署完成 ======" + depends_on: + - push-to-harbor-main + when: + status: success + branch: [main] + + # ===================== 构建报告 ===================== + - name: cache-report + image: 192.168.31.253/library/alpine:latest + volumes: + - name: maven-cache + path: /host-cache + commands: + - | + echo "====== 构建流程结束 ======" + if [ -d "/host-cache/repository" ]; then + CACHE_SIZE=$(du -sh /host-cache/repository 2>/dev/null | cut -f1 || echo "计算失败") + echo "Maven缓存大小: $CACHE_SIZE" + fi + source /drone/src/.version.env 2>/dev/null + if [ -n "$BUILD_VERSION" ]; then + echo "构建版本: $BUILD_VERSION" + fi + echo "==============================" + when: + status: [success, failure] + depends_on: + - maven-build