407 lines
14 KiB
YAML
407 lines
14 KiB
YAML
---
|
||
kind: pipeline
|
||
type: docker
|
||
name: par-build
|
||
|
||
volumes:
|
||
- name: maven-cache
|
||
host:
|
||
path: /tmp/drone-maven-cache
|
||
- name: npm-cache
|
||
host:
|
||
path: /tmp/drone-npm-cache
|
||
- name: dockersock
|
||
host:
|
||
path: /var/run/docker.sock
|
||
|
||
trigger:
|
||
event: [push]
|
||
branch: [dev, test, main]
|
||
exclude:
|
||
commit:
|
||
- ^\[skip ci\]
|
||
- ^\[ci skip\]
|
||
|
||
platform:
|
||
os: linux
|
||
arch: amd64
|
||
|
||
workspace:
|
||
path: /drone/src
|
||
|
||
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: print-drone-vars
|
||
image: 192.168.31.253/library/alpine:latest
|
||
commands:
|
||
- echo "===== ALL DRONE ENV VARIABLES ====="
|
||
- env | grep -i drone | sort
|
||
|
||
# ===================== 准备 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
|
||
environment:
|
||
NPM_CONFIG_REGISTRY: "https://registry.npmmirror.com"
|
||
commands:
|
||
- |
|
||
echo "====== 开始前端构建 ======"
|
||
npm config set registry https://registry.npmmirror.com
|
||
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 "====== 前端构建结束 ======"
|
||
|
||
# ===================== 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 -Xms512m -Xmx1024m -Djava.awt.headless=true -Dmaven.compiler.forceJavacCompilerUse=true"
|
||
volumes:
|
||
- name: maven-cache
|
||
path: /root/.m2
|
||
commands:
|
||
- |
|
||
set -e
|
||
echo "====== 开始 Maven 构建 ======"
|
||
|
||
# 配置阿里云 Maven 镜像加速
|
||
mkdir -p /root/.m2
|
||
cat > /root/.m2/settings.xml << 'EOF'
|
||
<settings>
|
||
<mirrors>
|
||
<mirror>
|
||
<id>aliyunmaven</id>
|
||
<name>阿里云公共仓库</name>
|
||
<url>https://maven.aliyun.com/repository/public</url>
|
||
<mirrorOf>central</mirrorOf>
|
||
</mirror>
|
||
</mirrors>
|
||
</settings>
|
||
EOF
|
||
echo "已配置阿里云 Maven 镜像"
|
||
|
||
# 将前端构建产物复制到 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
|
||
|
||
# 生成版本标签
|
||
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"
|
||
|
||
# 检测可用 CPU 核数,动态设置 Maven 并行度
|
||
CPU_CORES=$(nproc 2>/dev/null || echo 4)
|
||
echo "检测到 $CPU_CORES 个 CPU 核心"
|
||
if [ "$CPU_CORES" -ge 4 ]; then
|
||
MVN_THREADS="2C"
|
||
else
|
||
MVN_THREADS="1C"
|
||
fi
|
||
echo "Maven 并行度: -T $MVN_THREADS"
|
||
|
||
# Maven 打包(使用阿里云镜像 + 多线程并行编译 + 跳过测试 + 离线优先)
|
||
mvn -B clean package \
|
||
-s /root/.m2/settings.xml \
|
||
-DskipTests \
|
||
-Dmaven.test.skip=true \
|
||
-T "$MVN_THREADS" \
|
||
--no-transfer-progress \
|
||
--fail-at-end
|
||
|
||
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 镜像构建 =====================
|
||
# 参考 mediabot 优化:Drone 已在前序步骤完成编译(frontend-build + maven-build),
|
||
# 此处使用 CI 精简 Dockerfile,仅将预构建 jar 打包进 JRE 镜像,无需在 Docker 内重新编译。
|
||
- name: build-docker-image
|
||
image: 192.168.31.253/library/docker:cli
|
||
volumes:
|
||
- name: dockersock
|
||
path: /var/run/docker.sock
|
||
environment:
|
||
DOCKER_BUILDKIT: "1"
|
||
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"
|
||
|
||
# 验证 jar 产物存在
|
||
JAR_FILE=$(ls par-api/target/*.jar 2>/dev/null | head -1)
|
||
if [ -z "$JAR_FILE" ]; then
|
||
echo "错误:未找到 jar 产物,maven-build 可能失败"
|
||
exit 1
|
||
fi
|
||
echo "jar 产物: $JAR_FILE ($(du -sh $JAR_FILE | cut -f1))"
|
||
|
||
# 使用 CI 精简 Dockerfile:仅 COPY jar + 设置运行环境,秒级完成
|
||
docker build \
|
||
--build-arg BUILDKIT_INLINE_CACHE=1 \
|
||
--build-arg VERSION="$APP_VERSION" \
|
||
--build-arg BUILD_TIME="$(TZ=Asia/Shanghai date '+%Y-%m-%d %H:%M')" \
|
||
-t "$IMAGE_NAME:$BUILD_VERSION" \
|
||
-t "$IMAGE_NAME:latest" \
|
||
-f 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
|
||
chmod 700 ~/.ssh
|
||
# 使用 printf 确保换行符正确写入
|
||
printf '%s\n' "$SSH_KEY" > ~/.ssh/id_rsa
|
||
chmod 600 ~/.ssh/id_rsa
|
||
|
||
# 如果私钥是 OpenSSH 新格式,尝试转换为 PEM 格式
|
||
ssh-keygen -p -m PEM -N "" -f ~/.ssh/id_rsa 2>/dev/null || true
|
||
|
||
export IMG="$DEPLOY_IMAGE:$BUILD_VERSION"
|
||
ssh -o StrictHostKeyChecking=no -o IdentitiesOnly=yes -i ~/.ssh/id_rsa $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
|
||
chmod 700 ~/.ssh
|
||
# 使用 printf 确保换行符正确写入
|
||
printf '%s\n' "$SSH_KEY" > ~/.ssh/id_rsa
|
||
chmod 600 ~/.ssh/id_rsa
|
||
|
||
# 如果私钥是 OpenSSH 新格式,尝试转换为 PEM 格式
|
||
ssh-keygen -p -m PEM -N "" -f ~/.ssh/id_rsa 2>/dev/null || true
|
||
|
||
export IMG="$DEPLOY_IMAGE:$BUILD_VERSION"
|
||
ssh -o StrictHostKeyChecking=no -o IdentitiesOnly=yes -i ~/.ssh/id_rsa $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
|