chore: migrate from Jenkins to GitHub Actions

- Add GitHub Actions workflow for multi-arch Docker builds
  * Supports automatic builds on push/tag/PR
  * Manual workflow trigger with component selection
  * Multi-architecture support (linux/amd64, linux/arm64)
  * Integrated GitHub Actions cache for faster builds

- Remove Jenkins CI/CD infrastructure
  * Delete all Jenkins-related scripts and configurations
  * Remove Jenkins Docker Compose files and directories
  * Clean up old CI/CD documentation (133 files removed)

- Update documentation
  * Resolve README.md merge conflict
  * Add GitHub Actions usage instructions
  * Update CLAUDE.md with new CI/CD workflow
  * Remove Jenkins references from project docs

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-12-14 20:02:53 +08:00
co-authored by Claude
parent ace426898e
commit a2a80c1de1
144 changed files with 7153 additions and 23450 deletions
+192
View File
@@ -0,0 +1,192 @@
name: Build and Push Docker Images
on:
push:
branches:
- main
- develop
tags:
- 'v*'
pull_request:
branches:
- main
- develop
workflow_dispatch:
inputs:
component:
description: 'Component to build (all/ljwx-boot/ljwx-admin/ljwx-bigscreen/ljwx-mysql/ljwx-redis)'
required: false
default: 'all'
version:
description: 'Version tag (default: use VERSION from .env or branch name)'
required: false
env:
DOCKER_BUILDKIT: 1
COMPOSE_DOCKER_CLI_BUILD: 1
jobs:
prepare:
name: Prepare Build Information
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
registry: ${{ steps.config.outputs.registry }}
components: ${{ steps.components.outputs.matrix }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Load .env configuration
id: config
run: |
if [ -f .env ]; then
source .env
echo "registry=${REGISTRY}" >> $GITHUB_OUTPUT
echo "harbor_host=${HARBOR_HOST}" >> $GITHUB_OUTPUT
echo "harbor_project=${HARBOR_PROJECT}" >> $GITHUB_OUTPUT
else
echo "registry=harbor.omniverseai.net/health" >> $GITHUB_OUTPUT
fi
- name: Determine version
id: version
run: |
if [ -n "${{ github.event.inputs.version }}" ]; then
VERSION="${{ github.event.inputs.version }}"
elif [[ "${{ github.ref }}" == refs/tags/v* ]]; then
VERSION="${GITHUB_REF#refs/tags/v}"
elif [ -f .env ]; then
source .env
VERSION="${LJWX_VERSION}"
else
VERSION="latest"
fi
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "Build version: ${VERSION}"
- name: Determine components to build
id: components
run: |
COMPONENT="${{ github.event.inputs.component }}"
if [ -z "$COMPONENT" ] || [ "$COMPONENT" = "all" ]; then
COMPONENTS='["ljwx-boot", "ljwx-admin", "ljwx-bigscreen", "ljwx-mysql", "ljwx-redis"]'
else
COMPONENTS='["'$COMPONENT'"]'
fi
echo "matrix=${COMPONENTS}" >> $GITHUB_OUTPUT
echo "Components to build: ${COMPONENTS}"
build-and-push:
name: Build and Push ${{ matrix.component }}
needs: prepare
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
component: ${{ fromJson(needs.prepare.outputs.components) }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
platforms: linux/amd64,linux/arm64
- name: Log in to Harbor
uses: docker/login-action@v3
with:
registry: ${{ secrets.HARBOR_HOST || 'harbor.omniverseai.net' }}
username: ${{ secrets.HARBOR_USERNAME }}
password: ${{ secrets.HARBOR_PASSWORD }}
- name: Prepare build context
id: context
run: |
COMPONENT="${{ matrix.component }}"
VERSION="${{ needs.prepare.outputs.version }}"
REGISTRY="${{ needs.prepare.outputs.registry }}"
case "$COMPONENT" in
ljwx-mysql)
DOCKERFILE="docker/mysql/Dockerfile"
CONTEXT="."
;;
ljwx-redis)
DOCKERFILE="docker/redis/Dockerfile"
CONTEXT="."
;;
ljwx-boot)
DOCKERFILE="ljwx-boot/ljwx-boot-admin/Dockerfile.prod"
CONTEXT="."
;;
ljwx-bigscreen)
DOCKERFILE="ljwx-bigscreen/bigscreen/Dockerfile.prod"
CONTEXT="ljwx-bigscreen/bigscreen"
;;
ljwx-admin)
DOCKERFILE="ljwx-admin/Dockerfile"
CONTEXT="ljwx-admin"
;;
*)
echo "Unknown component: $COMPONENT"
exit 1
;;
esac
echo "dockerfile=${DOCKERFILE}" >> $GITHUB_OUTPUT
echo "context=${CONTEXT}" >> $GITHUB_OUTPUT
echo "image_name=${REGISTRY}/${COMPONENT}" >> $GITHUB_OUTPUT
echo "version=${VERSION}" >> $GITHUB_OUTPUT
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ steps.context.outputs.image_name }}
tags: |
type=raw,value=${{ steps.context.outputs.version }}
type=raw,value=latest
type=sha,prefix={{branch}}-
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: ${{ steps.context.outputs.context }}
file: ${{ steps.context.outputs.dockerfile }}
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
BUILD_DATE=${{ github.event.head_commit.timestamp }}
GIT_COMMIT=${{ github.sha }}
VERSION=${{ steps.context.outputs.version }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Image digest
run: echo "Image pushed successfully"
summary:
name: Build Summary
needs: [prepare, build-and-push]
runs-on: ubuntu-latest
if: always()
steps:
- name: Check build status
run: |
echo "## Build Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Version:** ${{ needs.prepare.outputs.version }}" >> $GITHUB_STEP_SUMMARY
echo "**Registry:** ${{ needs.prepare.outputs.registry }}" >> $GITHUB_STEP_SUMMARY
echo "**Components:** ${{ needs.prepare.outputs.components }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ "${{ needs.build-and-push.result }}" == "success" ]; then
echo "✅ All images built and pushed successfully!" >> $GITHUB_STEP_SUMMARY
else
echo "❌ Some builds failed. Check the logs above." >> $GITHUB_STEP_SUMMARY
fi
-156
View File
@@ -1,156 +0,0 @@
# 构建部署快速指南
## 🎯 简洁用法(推荐)
### 三阶段操作
```bash
# 1️⃣ 构建镜像(仅构建,不推送)
./build-and-push.sh -b bigscreen
# 2️⃣ 推送镜像到 Registry
./build-and-push.sh -p bigscreen
# 3️⃣ 部署服务
./build-and-push.sh -d # Docker Compose 部署所有服务
./build-and-push.sh -d bigscreen # K8s 部署单个组件
```
## 📦 完整流程示例
### 场景一:开发测试(仅本地构建)
```bash
# 仅构建,不推送到 Registry
./build-and-push.sh -b bigscreen
./build-and-push.sh -b boot
./build-and-push.sh -b admin
```
### 场景二:生产发布(构建+推送+部署)
```bash
# 步骤1: 构建所有应用镜像
./build-and-push.sh -b mysql redis boot bigscreen admin
# 步骤2: 推送到 Registry
./build-and-push.sh -p mysql redis boot bigscreen admin
# 步骤3: Docker Compose 部署
./build-and-push.sh -d
```
### 场景三:快速部署(默认行为)
```bash
# 一步完成:构建+推送
./build-and-push.sh bigscreen
# 然后部署
./build-and-push.sh -d
```
## 🐳 Docker Compose 管理
```bash
# 启动所有服务
./build-and-push.sh -d
./build-and-push.sh compose-up
# 停止所有服务
./build-and-push.sh compose-down
# 重启服务
./build-and-push.sh compose-restart
# 查看日志
./build-and-push.sh compose-logs
# 查看状态
./build-and-push.sh compose-ps
```
## ☸️ Kubernetes 部署
```bash
# 部署单个组件
./build-and-push.sh -d bigscreen # 使用 -d 选项
./build-and-push.sh deploy bigscreen # 完整命令
# 部署所有服务
./build-and-push.sh deploy-all
# 指定命名空间
K8S_NAMESPACE=production ./build-and-push.sh -d bigscreen
```
## 🔧 选项对比
| 操作 | 简洁方式 | 完整方式 | 说明 |
|------|----------|----------|------|
| 仅构建 | `-b bigscreen` | `PUSH_TO_REGISTRY=false bigscreen` | 不推送到 Registry |
| 仅推送 | `-p bigscreen` | `push bigscreen` | 推送已构建的镜像 |
| Docker Compose 部署 | `-d` | `compose-up` | 部署所有服务 |
| K8s 部署 | `-d bigscreen` | `deploy bigscreen` | 部署到 K8s |
## 💡 常用命令速查
```bash
# 开发调试
./build-and-push.sh -b bigscreen # 本地构建测试
./build-and-push.sh -d # 启动服务调试
# 生产发布
./build-and-push.sh bigscreen # 构建+推送
./build-and-push.sh -d # 部署
# 更新单个服务
./build-and-push.sh -b bigscreen # 重新构建
./build-and-push.sh -p bigscreen # 推送
docker-compose -f docker-compose.prod.yml up -d --force-recreate ljwx-bigscreen # 重启
# 批量操作
./build-and-push.sh -b mysql redis boot bigscreen admin # 构建多个
./build-and-push.sh -p mysql redis boot bigscreen admin # 推送多个
```
## 🌐 服务访问地址
部署成功后,可通过以下地址访问:
- **后端API**: http://localhost:9998
- **管理界面**: http://localhost:80
- **大屏服务**: http://localhost:8000
- **MySQL**: localhost:3306 (root/123456)
- **Redis**: localhost:6379
- **Registry Web UI**: http://localhost:8082
## 🔍 故障排查
### 服务启动失败
```bash
# 查看日志
./build-and-push.sh compose-logs
# 查看特定服务日志
docker-compose -f docker-compose.prod.yml logs -f ljwx-bigscreen
# 重启服务
./build-and-push.sh compose-restart
```
### 镜像推送失败
```bash
# 检查 Registry 状态
curl http://localhost:15000/v2/_catalog
# 重新标记镜像
docker tag 127.0.0.1:15000/ljwx/ljwx-bigscreen:2.0.3 localhost:15000/ljwx/ljwx-bigscreen:2.0.3
# 推送
./build-and-push.sh -p bigscreen
```
## 📚 更多信息
完整文档请查看 `./build-and-push.sh` 帮助信息:
```bash
./build-and-push.sh
```
-476
View File
@@ -1,476 +0,0 @@
# Docker 构建优化指南
## 🎯 核心问题
原来的构建存在三大性能瓶颈:
1. **每次 `apk add maven`** - 重复拉 Alpine 索引(15-20秒)
2. **每次下载 Maven 依赖** - 重复下载几百 MB(60-120秒)
3. **跨平台构建** - QEMU 模拟降低 50-70% 性能
总构建时间:**3-5 分钟**(每次改代码都要等这么久)
## ✨ 优化方案
### 三步优化,速度提升 **5-10 倍**
```
原版构建:180-300 秒
优化后首次:120-180 秒(需要构建基础镜像 + 下载依赖)
优化后后续:15-30 秒(只编译代码)
```
## 📦 第一步:构建基础镜像(一次性)
### 为什么需要基础镜像?
把"装系统工具"从"每次构建"变成"只做一次":
**原来(每次构建)**:
```dockerfile
FROM eclipse-temurin:21-jdk-alpine
RUN apk add --no-cache maven # ← 每次 15-20 秒
RUN 配置 Maven settings.xml # ← 每次重复
```
**优化后(只做一次)**:
```dockerfile
# 基础镜像已经装好 Maven + 配置好镜像
FROM localhost:15000/ljwx/java-maven-base:21-jdk-alpine
# 直接开始构建业务代码
```
### 构建基础镜像
```bash
# 1. 进入基础镜像目录
cd docker/base-images
# 2. 运行构建脚本(只需要运行一次)
./build-base-images.sh
```
**输出**:
```
✅ Java Maven 基础镜像构建完成
✅ Python 基础镜像构建完成
✅ 所有基础镜像已推送到 localhost:15000
```
**查看结果**:
```bash
docker images | grep ljwx.*base
```
你会看到:
```
localhost:15000/ljwx/java-maven-base 21-jdk-alpine
localhost:15000/ljwx/python-base 3.12-slim
```
## 🔧 第二步:切换到优化版 Dockerfile
### 自动切换
```bash
# 从项目根目录运行
./switch-dockerfile.sh optimized
```
**会自动**:
- ✅ 备份原版 Dockerfile(保存为 `.original`)
- ✅ 启用优化版 Dockerfile
- ✅ 显示切换状态
### 手动验证
```bash
# 查看当前使用的版本
./switch-dockerfile.sh status
```
**输出示例**:
```
Boot: ✅ 使用优化版
Bigscreen: ✅ 使用优化版
Admin: ✅ 已优化(原本就好)
```
## 🚀 第三步:启用 BuildKit 构建
### 永久启用(推荐)
```bash
# 添加到 ~/.zshrc 或 ~/.bashrc
echo 'export DOCKER_BUILDKIT=1' >> ~/.zshrc
source ~/.zshrc
```
### 临时启用
```bash
export DOCKER_BUILDKIT=1
```
### 验证
```bash
# 构建时看到类似输出就说明 BuildKit 已启用
docker build ...
# [+] Building 12.3s (15/15) FINISHED ← 带 [+] 符号
```
## 📈 效果对比
### Boot 后端(Maven)
**原版构建过程**:
```
1. apk add maven → 15-20s
2. 下载 Maven 依赖 → 60-90s
3. 编译 starter → 20-30s
4. 下载主应用依赖 → 30-40s
5. 编译主应用 → 20-30s
-----------------------------------------
总计: ~180-210s(3-3.5分钟)
```
**优化版首次构建**:
```
1. 拉基础镜像(已有 Maven)→ 5s
2. 下载 starter 依赖 → 30-40s(缓存到宿主机)
3. 编译 starter → 20-30s
4. 下载主应用依赖 → 20-30s(缓存到宿主机)
5. 编译主应用 → 15-20s
-----------------------------------------
总计: ~90-125s(1.5-2分钟)
```
**优化版后续构建**(改代码):
```
1. 复用基础镜像 → 即时
2. 复用 starter 依赖缓存 → 即时(pom 未变)
3. 复用 starter 构建 → 即时(代码未变)
4. 复用主应用依赖缓存 → 即时(pom 未变)
5. 只编译改动的代码 → 15-20s
-----------------------------------------
总计: ~15-20s(只需20秒!)
```
### Bigscreen(Python)
**原版构建**:
```
1. 配置 apt 源 → 10-15s
2. 安装编译工具 → 30-40s
3. pip 下载依赖 → 40-60s
4. 复制代码 → 2-3s
-----------------------------------------
总计: ~85-120s
```
**优化版后续构建**:
```
1. 复用基础镜像(已有编译工具)→ 即时
2. 复用 pip 依赖缓存 → 即时
3. 只复制代码 → 2-3s
-----------------------------------------
总计: ~2-3s(秒级完成!)
```
### Admin(Node.js)
Admin 的 Dockerfile 本来就做得不错(已经用了 pnpm cache),优化空间较小。
## 🔍 优化原理详解
### 1. 基础镜像复用
**原理**:把"系统环境准备"从构建流程中剥离
```dockerfile
# 原来:每次都要装 Maven(15-20s)
FROM eclipse-temurin:21-jdk-alpine
RUN apk add --no-cache maven # ← 浪费时间
# 优化:基础镜像已经装好
FROM localhost:15000/ljwx/java-maven-base:21-jdk-alpine
# Maven 已经装好,settings.xml 已配置
```
### 2. BuildKit Cache Mount
**原理**:把依赖缓存在宿主机,而不是镜像层里
```dockerfile
# 原来:依赖打包在镜像层里,每次重新下载
RUN mvn clean package # ← ~/.m2 在容器里,构建完就丢了
# 优化:依赖缓存在宿主机
RUN --mount=type=cache,target=/root/.m2/repository \
mvn clean package # ← ~/.m2 缓存在宿主机的 BuildKit cache
```
**缓存位置**(macOS):
```
~/Library/Containers/com.docker.docker/Data/vms/0/data/docker/buildkit/
```
**效果**:
- 第一次构建:下载依赖,存入缓存
- 第二次构建:从缓存读取,不再下载
### 3. 分层构建
**原理**:把"变化频率不同"的内容分成不同的层
```dockerfile
# ====== 低频变化层(几乎不变)======
COPY pom.xml .
RUN mvn dependency:go-offline # ← 只有 pom 变化时才重新执行
# ====== 高频变化层(经常改)======
COPY src ./src
RUN mvn package # ← 只有代码变化时才重新编译
```
**Docker Layer Cache 机制**:
- 每条 `RUN`/`COPY` 指令生成一个层
- 如果指令和输入文件没变,就复用缓存层
- 只有变化的层及之后的层需要重新构建
## 📋 完整使用流程
### 首次使用(完整设置)
```bash
# 1. 构建基础镜像(只做一次)
cd docker/base-images
./build-base-images.sh
cd ../..
# 2. 切换到优化版 Dockerfile
./switch-dockerfile.sh optimized
# 3. 启用 BuildKit
export DOCKER_BUILDKIT=1
# 4. 首次构建(会较慢,因为要下载依赖到缓存)
./build-and-push.sh boot
# 5. 再次构建(体验飞速)
# 随便改点代码
echo "// test" >> ljwx-boot/ljwx-boot-admin/src/main/java/Test.java
./build-and-push.sh boot
# 只需 15-20 秒!
```
### 日常开发(已经设置好)
```bash
# 1. 改代码
vi ljwx-boot/ljwx-boot-admin/src/main/java/...
# 2. 构建(秒级完成)
./build-and-push.sh boot
# 3. 部署
kubectl rollout restart deployment/ljwx-boot -n ljwx-system
```
## 🛠️ 故障排查
### 问题 1:基础镜像拉取失败
**现象**:
```
ERROR: failed to solve: localhost:15000/ljwx/java-maven-base:21-jdk-alpine: not found
```
**解决**:
```bash
# 检查基础镜像是否存在
docker images | grep java-maven-base
# 如果不存在,重新构建
cd docker/base-images
./build-base-images.sh
```
### 问题 2:BuildKit 未启用
**现象**:
```
WARNING: buildkit is not enabled
```
**解决**:
```bash
# 启用 BuildKit
export DOCKER_BUILDKIT=1
# 或者在 Docker Desktop 设置中启用
# Settings → Docker Engine → 添加:
{
"features": {
"buildkit": true
}
}
```
### 问题 3:缓存未命中
**现象**:每次构建还是很慢
**排查**:
```bash
# 1. 确认 BuildKit 已启用
echo $DOCKER_BUILDKIT # 应该输出 1
# 2. 查看构建日志
docker build ... 2>&1 | grep cache
# 应该看到:---> Using cache
# 3. 清理缓存重试
docker builder prune -af
./build-and-push.sh boot
```
### 问题 4:想恢复原版
```bash
# 恢复到原版 Dockerfile
./switch-dockerfile.sh original
```
## 📊 性能监控
### 查看构建时间
```bash
# 方法 1:使用 time 命令
time ./build-and-push.sh boot
# 方法 2:查看构建日志
docker build ... 2>&1 | grep "Building"
```
### 查看缓存使用
```bash
# 查看 BuildKit 缓存大小
docker system df -v | grep buildx
# 查看本地镜像大小
docker images | grep ljwx
```
## 🎯 最佳实践
### 1. 基础镜像管理
```bash
# 定期更新基础镜像(例如每月一次)
cd docker/base-images
./build-base-images.sh
# 推送到共享 Registry(团队协作)
docker tag localhost:15000/ljwx/java-maven-base:21-jdk-alpine \
registry.company.com/ljwx/java-maven-base:21-jdk-alpine
docker push registry.company.com/ljwx/java-maven-base:21-jdk-alpine
```
### 2. 依赖变化处理
```bash
# pom.xml / requirements.txt 变化后:
# 1. 首次构建会较慢(下载新依赖)
./build-and-push.sh boot
# 2. 之后又恢复快速
./build-and-push.sh boot
```
### 3. 缓存清理
```bash
# 定期清理无用缓存
docker builder prune -af
# 清理旧镜像
docker image prune -af
```
### 4. 本地 vs 远程构建
```bash
# 本地开发:使用 arm64(你的 Mac)
PLATFORMS=linux/arm64 ./build-and-push.sh boot
# CI/远程:使用 amd64(避免 QEMU 模拟)
PLATFORMS=linux/amd64 ./build-and-push.sh boot
```
## 📈 收益总结
| 指标 | 原版 | 优化版(首次)| 优化版(后续)| 提升 |
|------|------|--------------|---------------|------|
| **Boot 构建** | 180s | 120s | 20s | **9x** |
| **Bigscreen 构建** | 90s | 60s | 3s | **30x** |
| **Admin 构建** | 120s | 90s | 30s | **4x** |
| **总开发时间** | 390s (6.5分钟) | 270s (4.5分钟) | 53s (< 1分钟) | **7x** |
**日常开发收益**:
- 原来:改代码 → 等 6 分钟构建 → 部署
- 现在:改代码 → 等 1 分钟构建 → 部署
- **节省 5 分钟/次**,一天构建 10 次 = **节省 50 分钟**
## 🎓 进阶优化
### 1. 多阶段并行构建
```bash
# 同时构建多个组件
./build-and-push.sh boot &
./build-and-push.sh bigscreen &
./build-and-push.sh admin &
wait
# 总时间 = 最慢的那个(而不是累加)
```
### 2. 远程缓存(团队协作)
```dockerfile
# 推送缓存到远程
docker buildx build \
--cache-to type=registry,ref=registry.com/cache/boot:latest \
...
# 拉取缓存从远程
docker buildx build \
--cache-from type=registry,ref=registry.com/cache/boot:latest \
...
```
### 3. 增量构建
```bash
# 使用 --target 只构建特定阶段
docker build --target builder ... # 只构建不推送
```
## 📞 技术支持
遇到问题?
1. **查看状态**:`./switch-dockerfile.sh status`
2. **查看文档**:本文档
3. **清理重试**:`docker builder prune -af && ./build-and-push.sh boot`
4. **恢复原版**:`./switch-dockerfile.sh original`
---
**版本**: v1.0.0
**更新**: 2025-11-26
**适用**: macOS + OrbStack/Docker Desktop
-136
View File
@@ -1,136 +0,0 @@
# 构建优化 - 快速开始(3步搞定)
## 🎯 优化效果
- **原来**:改代码 → 等 6 分钟构建 → 部署
- **现在**:改代码 → 等 1 分钟构建 → 部署
- **提升**:**5-10 倍**加速
## ⚡ 3 步启用优化
### 第 1 步:构建基础镜像(2分钟,只做一次)
```bash
cd docker/base-images
./build-base-images.sh
cd ../..
```
### 第 2 步:切换到优化版(1秒)
```bash
./switch-dockerfile.sh optimized
```
### 第 3 步:启用 BuildKit(1秒)
```bash
export DOCKER_BUILDKIT=1
# 建议加到 ~/.zshrc:echo 'export DOCKER_BUILDKIT=1' >> ~/.zshrc
```
完成!现在构建会快很多。
## 🚀 验证效果
### 首次构建(会较慢)
```bash
# 首次构建需要下载依赖到缓存
time ./build-and-push.sh boot
# 预期时间:1.5-2 分钟
```
### 再次构建(体验飞速)
```bash
# 随便改点代码
echo "// test" >> ljwx-boot/ljwx-boot-admin/src/main/java/com/ljwx/Test.java
# 再次构建
time ./build-and-push.sh boot
# 预期时间:15-20 秒!🚀
```
## 📊 性能对比
| 构建类型 | 原版时间 | 优化版时间 | 加速比 |
|---------|---------|-----------|--------|
| Boot 首次 | 180s | 120s | 1.5x |
| Boot 后续 | 180s | **20s** | **9x** ✨ |
| Bigscreen 后续 | 90s | **3s** | **30x** 🚀 |
| Admin 后续 | 120s | **30s** | **4x** ⚡ |
## 🔍 查看状态
```bash
# 查看当前使用的 Dockerfile 版本
./switch-dockerfile.sh status
# 查看基础镜像
docker images | grep ljwx.*base
```
## 🛠️ 常用命令
```bash
# 恢复到原版(如果有问题)
./switch-dockerfile.sh original
# 重新构建基础镜像(偶尔更新)
cd docker/base-images && ./build-base-images.sh
# 清理缓存(如果缓存过大)
docker builder prune -af
```
## 💡 原理简述
### 为什么快?
1. **基础镜像复用** - Maven/Python 已经装好,不用每次 `apk add`
2. **BuildKit Cache** - 依赖缓存在宿主机,不用重复下载
3. **分层构建** - 只有代码变化才重新编译
### 缓存位置
```
macOS: ~/Library/Containers/com.docker.docker/Data/vms/0/data/docker/buildkit/
```
## 📚 详细文档
完整文档:[BUILD-OPTIMIZATION-GUIDE.md](./BUILD-OPTIMIZATION-GUIDE.md)
包含:
- 🎯 优化原理详解
- 📦 基础镜像管理
- 🔍 故障排查指南
- 📈 性能监控方法
- 🎓 进阶优化技巧
## ⚠️ 注意事项
1. **首次使用**需要构建基础镜像(2分钟)
2. **首次构建**需要下载依赖到缓存(1-2分钟)
3. **第二次起**才能体验飞速(20秒)
4. **pom.xml 变化**后首次构建会稍慢(下载新依赖)
## 🎉 开始使用
```bash
# 一条命令启用所有优化
cd docker/base-images && ./build-base-images.sh && cd ../.. && \
./switch-dockerfile.sh optimized && \
export DOCKER_BUILDKIT=1 && \
echo "✅ 优化已启用!现在构建会快很多"
# 验证效果
time ./build-and-push.sh boot
```
---
**节省时间 = 更多咖啡时间 ☕**
-388
View File
@@ -1,388 +0,0 @@
# Docker 构建优化工具集
完整的 Docker 构建优化方案,让构建速度提升 **5-10 倍**。
## 📦 文件清单
### 核心文件
| 文件 | 大小 | 功能 |
|------|------|------|
| `BUILD-OPTIMIZATION-QUICK-START.md` | 2.9KB | ⚡ 快速开始 - 3步启用 |
| `BUILD-OPTIMIZATION-GUIDE.md` | 10KB | 📚 完整指南 - 详细文档 |
| `switch-dockerfile.sh` | 5.4KB | 🔄 切换工具 - 一键切换优化版 |
### 基础镜像
| 文件 | 位置 | 功能 |
|------|------|------|
| `build-base-images.sh` | `docker/base-images/` | 🏗️ 构建基础镜像 |
| `Dockerfile.java-maven-base` | `docker/base-images/` | ☕ Java Maven 基础镜像 |
| `Dockerfile.python-base` | `docker/base-images/` | 🐍 Python 基础镜像 |
### 优化的 Dockerfile
| 文件 | 位置 | 功能 |
|------|------|------|
| `Dockerfile.prod.optimized` | `ljwx-boot/ljwx-boot-admin/` | 优化的 Boot Dockerfile |
| `Dockerfile.prod.optimized` | `ljwx-bigscreen/bigscreen/` | 优化的 Bigscreen Dockerfile |
## 🚀 快速开始
### 3 步启用优化
```bash
# 1. 构建基础镜像(只做一次)
cd docker/base-images
./build-base-images.sh
cd ../..
# 2. 切换到优化版
./switch-dockerfile.sh optimized
# 3. 启用 BuildKit
export DOCKER_BUILDKIT=1
```
完成!现在构建会快 **5-10 倍**。
### 验证效果
```bash
# 首次构建(会较慢,下载依赖)
time ./build-and-push.sh boot
# 改点代码
echo "// test" >> ljwx-boot/ljwx-boot-admin/src/main/java/Test.java
# 再次构建(飞速!)
time ./build-and-push.sh boot
```
## 📊 性能提升
| 组件 | 原版时间 | 优化后时间 | 提升 |
|------|----------|-----------|------|
| **Boot(Maven)** | 180s | **20s** | **9x** 🚀 |
| **Bigscreen(Python)** | 90s | **3s** | **30x** ⚡ |
| **Admin(Node.js)** | 120s | **30s** | **4x** ✨ |
**日常开发收益**:
- 每次构建节省 **5 分钟**
- 一天构建 10 次 = 节省 **50 分钟**
## 🎯 核心优化
### 1. 基础镜像复用
**原来**:每次 `apk add maven`(15-20秒)
**现在**:基础镜像已装好,直接用
```dockerfile
# 原来
FROM eclipse-temurin:21-jdk-alpine
RUN apk add --no-cache maven # ← 每次 15-20s
# 优化后
FROM localhost:15000/ljwx/java-maven-base:21-jdk-alpine
# Maven 已经装好 ✅
```
### 2. BuildKit Cache Mount
**原来**:每次下载 Maven 依赖(60-90秒)
**现在**:依赖缓存在宿主机,只下载一次
```dockerfile
# 原来
RUN mvn package # ← 每次重新下载依赖
# 优化后
RUN --mount=type=cache,target=/root/.m2/repository \
mvn package # ← 依赖缓存在宿主机 ✅
```
### 3. 分层构建
**原来**:改代码 → 重新下载所有依赖 → 重新编译
**现在**:改代码 → 复用依赖 → 只编译改动部分
```dockerfile
# 第 1 层:下载依赖(pom 不变就复用)
COPY pom.xml .
RUN mvn dependency:go-offline
# 第 2 层:编译代码(代码变了才重新编译)
COPY src ./src
RUN mvn package
```
## 🛠️ 使用工具
### switch-dockerfile.sh
一键切换 Dockerfile 版本:
```bash
# 查看状态
./switch-dockerfile.sh status
# 切换到优化版
./switch-dockerfile.sh optimized
# 恢复原版
./switch-dockerfile.sh original
# 查看帮助
./switch-dockerfile.sh help
```
### build-base-images.sh
构建基础镜像:
```bash
cd docker/base-images
./build-base-images.sh
# 输出:
# ✅ Java Maven 基础镜像构建完成
# ✅ Python 基础镜像构建完成
# ✅ 所有基础镜像已推送
```
## 📚 文档说明
### BUILD-OPTIMIZATION-QUICK-START.md
**适合**:快速上手
**内容**:
- ⚡ 3步启用优化
- 🚀 验证效果
- 📊 性能对比
- 🛠️ 常用命令
**阅读时间**:2 分钟
### BUILD-OPTIMIZATION-GUIDE.md
**适合**:深入理解
**内容**:
- 🎯 核心问题分析
- 📦 基础镜像详解
- 🔧 优化原理
- 📈 效果对比
- 🛠️ 故障排查
- 🎓 进阶优化
**阅读时间**:15 分钟
## 🔍 工作流程
### 开发流程(优化前)
```
改代码 → 等 6 分钟 → 部署
```
### 开发流程(优化后)
```
改代码 → 等 1 分钟 → 部署 ← 节省 5 分钟!
```
### 详细时间线
**原版**:
```
1. apk add maven → 15-20s
2. 下载 Maven 依赖 → 60-90s
3. 编译 starter → 20-30s
4. 下载主应用依赖 → 30-40s
5. 编译主应用 → 20-30s
-----------------------------------------
总计: 180-210s(3-3.5 分钟)
```
**优化版(首次)**:
```
1. 拉基础镜像 → 5s
2. 下载依赖(缓存) → 60-80s
3. 编译 → 40-60s
-----------------------------------------
总计: 105-145s(1.5-2.5 分钟)
```
**优化版(后续)**:
```
1. 复用镜像 → 即时
2. 复用依赖缓存 → 即时
3. 只编译代码 → 15-20s
-----------------------------------------
总计: 15-20s(只需 20 秒!)✨
```
## 🎯 使用场景
### 场景 1:日常开发
```bash
# 改 Java 代码
vi ljwx-boot/src/main/java/...
# 快速构建(20秒)
./build-and-push.sh boot
# 部署
kubectl rollout restart deployment/ljwx-boot
```
### 场景 2:修改依赖
```bash
# 修改 pom.xml 添加新依赖
vi ljwx-boot/pom.xml
# 首次构建(下载新依赖,稍慢)
./build-and-push.sh boot
# 之后又恢复快速
./build-and-push.sh boot
```
### 场景 3:团队协作
```bash
# 推送基础镜像到共享 Registry
docker tag localhost:15000/ljwx/java-maven-base:21-jdk-alpine \
registry.company.com/ljwx/java-maven-base:21-jdk-alpine
docker push registry.company.com/ljwx/java-maven-base:21-jdk-alpine
# 团队成员拉取
docker pull registry.company.com/ljwx/java-maven-base:21-jdk-alpine
```
## ⚠️ 注意事项
### 首次使用
1. ✅ 需要构建基础镜像(2分钟)
2. ✅ 需要启用 BuildKit
3. ✅ 首次构建会下载依赖到缓存
4. ✅ 第二次起才能体验飞速
### 依赖变化
- pom.xml / requirements.txt 变化后
- 首次构建会下载新依赖(稍慢)
- 之后又恢复快速
### 缓存管理
```bash
# 查看缓存大小
docker system df
# 清理缓存(如果太大)
docker builder prune -af
```
## 🐛 故障排查
### 问题 1:基础镜像不存在
```bash
# 检查
docker images | grep ljwx.*base
# 解决:重新构建
cd docker/base-images && ./build-base-images.sh
```
### 问题 2:BuildKit 未启用
```bash
# 检查
echo $DOCKER_BUILDKIT # 应该输出 1
# 解决:启用
export DOCKER_BUILDKIT=1
```
### 问题 3:还是很慢
```bash
# 1. 确认使用优化版
./switch-dockerfile.sh status
# 2. 清理缓存重试
docker builder prune -af
./build-and-push.sh boot
```
### 问题 4:想恢复原版
```bash
./switch-dockerfile.sh original
```
## 📈 进阶优化
### 1. 并行构建
```bash
# 同时构建多个组件
./build-and-push.sh boot &
./build-and-push.sh bigscreen &
./build-and-push.sh admin &
wait
```
### 2. 远程缓存
```bash
# 推送缓存到远程
docker buildx build \
--cache-to type=registry,ref=registry.com/cache:latest \
...
```
### 3. 多平台构建
```bash
# 本地开发:arm64
PLATFORMS=linux/arm64 ./build-and-push.sh boot
# CI/生产:amd64
PLATFORMS=linux/amd64 ./build-and-push.sh boot
```
## 💡 最佳实践
1. **基础镜像**:每月更新一次
2. **缓存清理**:每周清理一次
3. **本地构建**:使用 arm64(你的 Mac)
4. **远程构建**:使用 amd64(CI/生产)
5. **团队协作**:共享基础镜像
## 🎉 收益总结
- ✅ 构建时间从 6 分钟降到 1 分钟
- ✅ 每天节省 50 分钟(构建 10 次)
- ✅ 每周节省 250 分钟(4+ 小时)
- ✅ 每月节省 1000 分钟(17+ 小时)
**一年节省 200+ 小时 = 25 个工作日!**
## 📞 技术支持
- 📖 [快速开始](./BUILD-OPTIMIZATION-QUICK-START.md)
- 📚 [完整指南](./BUILD-OPTIMIZATION-GUIDE.md)
- 🔧 [构建脚本](./build-and-push.sh)
- 🐳 [Registry 配置](./REGISTRY-CACHE-SETUP.md)
---
**版本**: v1.0.0
**更新**: 2025-11-26
**节省时间 = 更多创造价值的时间** ⚡
-228
View File
@@ -1,228 +0,0 @@
# ljwx-boot 构建修复说明
## 问题
构建 ljwx-boot 镜像时 Maven 依赖下载失败:
```
Remote host terminated the handshake
Could not transfer artifact from aliyunmaven
```
## 根本原因
1. **代理配置缺失**:boot、bigscreen、admin 的构建命令没有传递代理参数 `$proxy_args`
2. **容器内代理地址错误**:使用 `127.0.0.1:7890` 而非 `host.docker.internal:7890`
## 解决方案
### 1. 添加代理参数到构建命令
**修改前**:
```bash
docker build --build-arg MAVEN_OPTS="-XX:+UseG1GC -Xmx1g" \
-t $tag -t $latest_tag . \
-f ljwx-boot/ljwx-boot-admin/Dockerfile.prod
```
**修改后**:
```bash
docker build $proxy_args \
--build-arg MAVEN_OPTS="-XX:+UseG1GC -Xmx1g" \
-t $tag -t $latest_tag . \
-f ljwx-boot/ljwx-boot-admin/Dockerfile.prod
```
### 2. 使用容器内可访问的代理地址
在 `build-and-push.sh` 中:
```bash
# 容器内部代理地址
local container_http_proxy="http://host.docker.internal:${PROXY_PORT}"
local container_https_proxy="http://host.docker.internal:${PROXY_PORT}"
local proxy_args="--build-arg HTTP_PROXY=$container_http_proxy ..."
```
### 3. Dockerfile 接收并配置代理
在 `ljwx-boot/ljwx-boot-admin/Dockerfile.prod` 中:
```dockerfile
# 接收代理参数
ARG HTTP_PROXY
ARG HTTPS_PROXY
ARG NO_PROXY
# 设置环境变量
ENV HTTP_PROXY=${HTTP_PROXY} \
HTTPS_PROXY=${HTTPS_PROXY} \
NO_PROXY=${NO_PROXY}
# 配置 Maven settings.xml
RUN mkdir -p /root/.m2 && \
echo '<?xml version="1.0" encoding="UTF-8"?>' > /root/.m2/settings.xml && \
# ... 镜像配置 ...
if [ -n "$HTTP_PROXY" ]; then \
PROXY_HOST=$(echo $HTTP_PROXY | sed -E 's|https?://([^:]+):.*|\1|'); \
PROXY_PORT=$(echo $HTTP_PROXY | sed -E 's|https?://[^:]+:([0-9]+).*|\1|'); \
echo ' <proxies>' >> /root/.m2/settings.xml && \
echo ' <proxy>' >> /root/.m2/settings.xml && \
echo ' <id>proxy</id>' >> /root/.m2/settings.xml && \
echo ' <active>true</active>' >> /root/.m2/settings.xml && \
echo ' <protocol>http</protocol>' >> /root/.m2/settings.xml && \
echo " <host>$PROXY_HOST</host>" >> /root/.m2/settings.xml && \
echo " <port>$PROXY_PORT</port>" >> /root/.m2/settings.xml && \
echo ' </proxy>' >> /root/.m2/settings.xml && \
echo ' </proxies>' >> /root/.m2/settings.xml; \
fi
```
## 构建流程
### ljwx-boot-starter 依赖构建
Dockerfile 中的构建顺序:
```dockerfile
# 1. 复制源代码
COPY ljwx-boot-starter/ ../ljwx-boot-starter/
COPY ljwx-boot/ ./
# 2. 先构建 starter 模块
RUN cd ../ljwx-boot-starter && mvn clean install -DskipTests -B
# 3. 再构建主应用
RUN mvn clean package -DskipTests -B
```
### 目录结构
构建上下文(release 目录):
```
release/
├── ljwx-boot-starter/ # starter 模块
│ ├── pom.xml
│ └── ljwx-boot-starter-*/
├── ljwx-boot/ # 主应用
│ ├── ljwx-boot-admin/
│ │ └── Dockerfile.prod
│ └── ...
└── build-and-push.sh
```
Dockerfile 工作目录:
```
/build/ # WORKDIR
├── ljwx-boot-starter/ # COPY from ../ljwx-boot-starter/
└── ljwx-boot/ # COPY from ljwx-boot/
```
## 验证
### 1. 检查代理配置
构建时会显示:
```bash
./build-and-push.sh boot
# 输出:
📡 容器代理配置: http://host.docker.internal:7890
🔨 构建应用镜像 ljwx-boot (架构: linux/amd64)...
🔨 使用多阶段容器构建 Spring Boot JAR 包...
💡 在容器内构建确保跨平台兼容性,使用代理和阿里云Maven镜像加速
```
### 2. 检查 Maven settings.xml
在构建日志中会显示生成的 settings.xml:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0">
<mirrors>
<mirror>
<id>aliyunmaven</id>
<mirrorOf>*</mirrorOf>
<url>https://maven.aliyun.com/repository/public</url>
</mirror>
</mirrors>
<proxies>
<proxy>
<id>proxy</id>
<active>true</active>
<protocol>http</protocol>
<host>host.docker.internal</host>
<port>7890</port>
<nonProxyHosts>localhost|127.0.0.1|*.local</nonProxyHosts>
</proxy>
</proxies>
</settings>
```
### 3. 测试构建
```bash
# 1. 确保代理运行
lsof -i :7890
# 2. 构建 boot 镜像
./build-and-push.sh boot
# 3. 观察 Maven 下载日志
# 应该看到通过代理成功下载依赖
```
## 修改的文件
1. **build-and-push.sh**
- 添加 `$proxy_args` 到 boot、bigscreen、admin 构建命令
- 使用 `host.docker.internal` 作为容器内代理地址
- 添加代理配置显示信息
2. **ljwx-boot/ljwx-boot-admin/Dockerfile.prod**
- 接收代理 ARG 参数
- 设置代理 ENV 环境变量
- 动态生成包含代理配置的 Maven settings.xml
- 显示生成的配置供调试
## 其他应用
同样的修复也应用到:
- ✅ **bigscreen**: Python pip 使用代理
- ✅ **admin**: NPM 使用代理
## 故障排查
### Maven 仍然无法下载
**检查代理**:
```bash
# 1. 宿主机代理
lsof -i :7890
# 2. 测试代理
curl --proxy http://127.0.0.1:7890 https://maven.aliyun.com
# 3. 容器内测试
docker run --rm alpine/curl curl http://host.docker.internal:7890
```
### Settings.xml 未生成
**调试**:
```bash
# 查看构建日志中的 settings.xml 输出
./build-and-push.sh boot 2>&1 | grep -A 30 "settings.xml"
```
### ljwx-boot-starter 未找到
**检查目录**:
```bash
# 确认目录存在
ls -la ljwx-boot-starter/
# 确认 pom.xml 存在
ls -la ljwx-boot-starter/pom.xml
```
---
**日期**: 2025-11-26
**状态**: ✅ 已修复
-198
View File
@@ -1,198 +0,0 @@
# CI/CD 基础服务统一构建方案
## 🎯 目标
- 解决端口冲突问题,统一使用3开头端口
- 简化架构,移除冗余配置
- 提供一键式部署体验
## 📋 端口规划
### 服务端口分配
```
服务名称 | Web端口 | 额外端口 | 说明
-----------------|---------|---------|------------------
Gitea | 33000 | 32222 | Git服务 + SSH
Jenkins | 38080 | 35000 | CI/CD + Agent通信
Registry | 35001 | - | Docker镜像仓库
Registry UI | 35002 | - | 镜像仓库界面
Prometheus | 37001 | - | 监控(预留)
Grafana | 37002 | - | 监控面板(预留)
```
## 🚀 有序搭建步骤
### 阶段1: 环境准备 (5分钟)
```bash
# 1. 停止现有服务,避免冲突
./scripts/cleanup-existing.sh
# 2. 创建统一网络和目录
./scripts/init-environment.sh
# 3. 检查端口可用性
./scripts/check-ports.sh
```
### 阶段2: 基础服务部署 (10分钟)
```bash
# 1. 启动Docker Registry (最基础)
./scripts/deploy-registry.sh
# 2. 启动Gitea (代码仓库)
./scripts/deploy-gitea.sh
# 3. 验证基础服务
./scripts/verify-basic-services.sh
```
### 阶段3: CI/CD部署 (15分钟)
```bash
# 1. 启动Jenkins (完全自动化配置)
./scripts/deploy-jenkins.sh
# 2. 配置服务集成
./scripts/setup-integration.sh
# 3. 创建示例项目
./scripts/create-demo-projects.sh
```
### 阶段4: 验证和优化 (5分钟)
```bash
# 1. 完整功能测试
./scripts/run-integration-tests.sh
# 2. 性能优化
./scripts/optimize-services.sh
# 3. 创建维护计划
./scripts/setup-maintenance.sh
```
## 📂 建议的目录结构整理
```
infra/
├── configs/ # 统一配置文件
│ ├── gitea.env # Gitea环境变量
│ ├── jenkins.env # Jenkins环境变量
│ └── registry.env # Registry环境变量
├── docker/
│ └── compose/
│ ├── core-services.yml # 核心服务组合
│ ├── gitea.yml # Gitea独立配置
│ ├── jenkins.yml # Jenkins独立配置
│ └── registry.yml # Registry独立配置
├── jenkins/
│ ├── casc/ # Configuration as Code
│ ├── shared-library/ # Pipeline共享库
│ └── templates/ # 项目模板
├── scripts/ # 部署和管理脚本
│ ├── deploy/ # 部署脚本
│ ├── maintenance/ # 维护脚本
│ └── utils/ # 工具脚本
└── docs/ # 文档
├── deployment.md # 部署指南
├── maintenance.md # 维护指南
└── troubleshooting.md # 故障排查
```
## 🔧 关键配置变更
### 服务访问地址
```
原来 → 现在
http://localhost:3000 → http://localhost:33000 (Gitea)
http://localhost:8081 → http://localhost:38080 (Jenkins)
http://localhost:5001 → http://localhost:35001 (Registry)
http://localhost:5002 → http://localhost:35002 (Registry UI)
```
### 环境变量统一
```bash
# configs/global.env
GITEA_PORT=33000
GITEA_SSH_PORT=32222
GITEA_URL=http://localhost:33000
JENKINS_PORT=38080
JENKINS_AGENT_PORT=35000
JENKINS_URL=http://localhost:38080
REGISTRY_PORT=35001
REGISTRY_UI_PORT=35002
REGISTRY_URL=localhost:35001
```
## ⚡ 一键部署命令
```bash
# 完整自动化部署
./build-infra.sh --full-auto
# 分步骤部署
./build-infra.sh --step-by-step
# 仅更新端口配置
./build-infra.sh --update-ports-only
```
## 📊 部署验证检查点
### 基础服务检查
- [ ] Docker Registry 响应正常 (http://localhost:35001/v2/)
- [ ] Registry UI 界面可访问 (http://localhost:35002)
- [ ] Gitea 服务启动正常 (http://localhost:33000)
- [ ] Gitea 健康检查通过 (http://localhost:33000/api/healthz)
### CI/CD功能检查
- [ ] Jenkins 自动配置完成 (http://localhost:38080)
- [ ] Jenkins 管理员登录成功 (admin/admin123)
- [ ] Gitea 集成配置正确
- [ ] 多平台构建环境就绪
- [ ] 示例Pipeline创建成功
### 集成测试检查
- [ ] Gitea Webhook 触发Jenkins构建
- [ ] 多平台镜像构建成功
- [ ] 镜像推送到Registry正常
- [ ] 从Registry拉取镜像正常
## 🛡️ 安全和优化
### 安全加固
- Jenkins运行在非root用户下
- 使用环境变量管理敏感信息
- 网络隔离和访问控制
- 定期安全更新
### 性能优化
- 合理的资源限制配置
- 定期清理无用数据
- 监控服务性能指标
- 自动化备份策略
## 🔄 维护计划
### 日常维护
```bash
# 服务健康检查
./scripts/health-check.sh
# 数据备份
./scripts/backup-all.sh
# 系统清理
./scripts/cleanup-system.sh
```
### 定期维护
- 每周:服务状态检查和日志清理
- 每月:完整备份和性能优化
- 每季度:安全更新和配置审查
## 📞 技术支持
- 配置问题: 查看 docs/troubleshooting.md
- 性能优化: 查看 docs/optimization.md
- 升级指南: 查看 docs/upgrade.md
-432
View File
@@ -1,432 +0,0 @@
# LJWX 镜像构建指南 (OrbStack + Harbor)
## 📋 概述
本文档说明如何使用优化后的 `build-and-push.sh` 脚本,将镜像构建并推送到本地 Harbor 仓库。
### 主要变更
- ✅ **运行时**: 从 Docker Desktop 切换到 OrbStack
- ✅ **镜像仓库**: 从阿里云切换到本地 Harbor (localhost:8080)
- ✅ **健康检查**: 自动检查 Harbor 服务状态
- ✅ **多架构支持**: 支持 linux/amd64 和 linux/arm64
## 🔧 前置要求
### 1. 安装 OrbStack
```bash
# 如果已安装 Docker Desktop,建议先卸载
# 然后安装 OrbStack (macOS)
brew install --cask orbstack
# 启动 OrbStack
open -a OrbStack
```
### 2. 部署 Harbor
确保 Harbor 服务运行在 `localhost:8080`:
```bash
# 检查 Harbor 是否运行
curl -f http://localhost:8080/api/v2.0/health
# 如果 Harbor 未运行,启动它
docker-compose -f harbor-compose.yml up -d
# 访问 Harbor Web UI
open http://localhost:8080
```
### 3. 验证环境
```bash
# 检查 Docker 是否使用 OrbStack
docker context ls
# 应该显示 orbstack 或 default
# 检查 Docker 版本
docker --version
# 检查 buildx 支持
docker buildx ls
```
## 🚀 使用方法
### 基本用法
```bash
# 查看帮助
./build-and-push.sh
# 构建所有镜像(应用 + 监控)
./build-and-push.sh all
# 仅构建应用镜像
./build-and-push.sh apps
# 仅构建监控镜像
./build-and-push.sh monitoring
# 构建单个镜像
./build-and-push.sh boot
./build-and-push.sh admin
./build-and-push.sh bigscreen
```
### 配置选项
#### 使用环境变量
```bash
# 自定义 Harbor 地址
HARBOR_HOST=harbor.example.com:8080 ./build-and-push.sh apps
# 自定义 Harbor 凭证
HARBOR_USERNAME=myuser HARBOR_PASSWORD=mypass ./build-and-push.sh apps
# 仅构建,不推送
PUSH_TO_REGISTRY=false ./build-and-push.sh apps
```
#### 修改配置文件
编辑 `monitoring-versions.env`:
```bash
# Harbor 配置
HARBOR_HOST=localhost:8080 # Harbor 地址
HARBOR_USERNAME=admin # Harbor 用户名
HARBOR_PASSWORD=admin123 # Harbor 密码
# 构建配置
REGISTRY=localhost:8080/ljwx # 镜像仓库地址
PLATFORMS=linux/amd64,linux/arm64 # 构建架构
LOCAL_BUILD=false # 多架构构建
PUSH_TO_REGISTRY=true # 推送到 Harbor
```
## 📦 构建流程
### 1. 完整构建流程
```bash
# Step 1: 检查 Harbor 状态
curl -f http://localhost:8080/api/v2.0/health
# Step 2: 准备数据(如果需要构建 MySQL 镜像)
./export-data.sh
# Step 3: 构建所有镜像
./build-and-push.sh all
# Step 4: 验证镜像已推送到 Harbor
# 访问 http://localhost:8080
# 登录: admin / admin123
# 查看 ljwx 项目下的镜像
```
### 2. 增量构建流程
```bash
# 仅构建并推送后端服务
./build-and-push.sh boot
# 仅构建并推送前端服务
./build-and-push.sh admin
# 仅构建并推送大屏服务
./build-and-push.sh bigscreen
```
### 3. 本地测试流程
```bash
# 构建但不推送到 Harbor
PUSH_TO_REGISTRY=false ./build-and-push.sh boot
# 本地运行测试
docker run -p 9998:9998 localhost:8080/ljwx/ljwx-boot:2.0.3
```
## 🔍 健康检查
脚本会自动执行以下健康检查:
### 1. Harbor 健康检查
```bash
# 脚本自动检查
GET http://localhost:8080/api/v2.0/health
# 如果 Harbor 不可用,脚本会提示:
⚠️ 无法连接到 Harbor (http://localhost:8080/api/v2.0/health)
💡 请确认 Harbor 服务已启动:
- 访问: http://localhost:8080
- 检查 Docker 容器: docker ps | grep harbor
是否继续构建(不推送到 Harbor)? (y/n)
```
### 2. 手动健康检查
```bash
# 检查 Harbor API
curl http://localhost:8080/api/v2.0/health
# 检查 Harbor Web UI
open http://localhost:8080
# 检查 Harbor 容器
docker ps | grep harbor
```
## 📊 镜像管理
### 查看本地镜像
```bash
# 查看所有 LJWX 镜像
docker images | grep localhost:8080/ljwx
# 查看特定镜像
docker images localhost:8080/ljwx/ljwx-boot
```
### 查看 Harbor 镜像
1. **Web UI 方式**:
- 访问 http://localhost:8080
- 登录: admin / admin123
- 进入 `ljwx` 项目
- 查看镜像列表
2. **API 方式**:
```bash
# 列出所有仓库
curl -u admin:admin123 http://localhost:8080/api/v2.0/projects/ljwx/repositories
# 列出镜像标签
curl -u admin:admin123 http://localhost:8080/api/v2.0/projects/ljwx/repositories/ljwx-boot/artifacts
```
### 拉取镜像
```bash
# 从 Harbor 拉取镜像
docker pull localhost:8080/ljwx/ljwx-boot:2.0.3
# 拉取最新版本
docker pull localhost:8080/ljwx/ljwx-boot:latest
```
## 🛠️ 故障排查
### 问题 1: Harbor 连接失败
**症状**:
```
⚠️ 无法连接到 Harbor (http://localhost:8080/api/v2.0/health)
```
**解决方案**:
```bash
# 1. 检查 Harbor 是否运行
docker ps | grep harbor
# 2. 启动 Harbor
docker-compose -f harbor-compose.yml up -d
# 3. 等待 Harbor 完全启动(约 30 秒)
sleep 30
# 4. 再次检查健康状态
curl http://localhost:8080/api/v2.0/health
```
### 问题 2: 登录失败
**症状**:
```
❌ Harbor 登录失败,请检查凭据
```
**解决方案**:
```bash
# 1. 检查凭证
echo "用户名: admin"
echo "密码: admin123"
# 2. 手动登录测试
docker login localhost:8080
# Username: admin
# Password: admin123
# 3. 检查 Harbor 配置
cat monitoring-versions.env | grep HARBOR
```
### 问题 3: 镜像推送失败
**症状**:
```
⚠️ ljwx-boot 镜像推送失败
```
**解决方案**:
```bash
# 1. 检查 insecure-registries 配置
# OrbStack 配置位置: ~/.orbstack/config/docker.json
cat ~/.orbstack/config/docker.json | grep insecure
# 2. 添加 insecure-registries
# 编辑 ~/.orbstack/config/docker.json
{
"insecure-registries": [
"localhost:8080",
"127.0.0.1:8080"
]
}
# 3. 重启 OrbStack
killall OrbStack
open -a OrbStack
# 4. 重新推送
./build-and-push.sh boot
```
### 问题 4: 多架构构建失败
**症状**:
```
ERROR: multiple platforms feature is currently not supported for docker driver
```
**解决方案**:
```bash
# 1. 创建 buildx builder
docker buildx create --name multiarch-builder --use
# 2. 启动 builder
docker buildx inspect --bootstrap
# 3. 重新构建
./build-and-push.sh boot
```
### 问题 5: OrbStack 不可用
**症状**:
```
Cannot connect to the Docker daemon
```
**解决方案**:
```bash
# 1. 检查 OrbStack 是否运行
ps aux | grep OrbStack
# 2. 启动 OrbStack
open -a OrbStack
# 3. 检查 Docker context
docker context ls
# 4. 切换到 OrbStack context(如果需要)
docker context use orbstack
```
## 📝 最佳实践
### 1. 构建前准备
```bash
# 检查 Harbor 状态
curl -f http://localhost:8080/api/v2.0/health || exit 1
# 检查磁盘空间
df -h
# 清理旧镜像(可选)
docker system prune -a
```
### 2. 分批构建
```bash
# 先构建基础设施镜像
./build-and-push.sh mysql redis
# 再构建应用镜像
./build-and-push.sh boot admin bigscreen
# 最后构建监控镜像
./build-and-push.sh monitoring
```
### 3. 版本管理
```bash
# 更新版本号
vim monitoring-versions.env
# 修改 LJWX_VERSION=2.0.4
# 构建新版本
./build-and-push.sh all
# 验证新版本
docker images localhost:8080/ljwx/ljwx-boot
```
### 4. 备份镜像
```bash
# 导出镜像到文件
docker save localhost:8080/ljwx/ljwx-boot:2.0.3 -o ljwx-boot-2.0.3.tar
# 从文件导入镜像
docker load -i ljwx-boot-2.0.3.tar
```
## 🎯 常用命令速查
```bash
# 健康检查
curl http://localhost:8080/api/v2.0/health
# 登录 Harbor
docker login localhost:8080
# 查看镜像
docker images | grep localhost:8080/ljwx
# 构建所有镜像
./build-and-push.sh all
# 构建单个镜像
./build-and-push.sh boot
# 拉取镜像
docker pull localhost:8080/ljwx/ljwx-boot:latest
# 清理缓存
./build-and-push.sh cache-clean
# 查看 Harbor 项目
open http://localhost:8080
```
## 📚 相关文档
- [OrbStack 文档](https://docs.orbstack.dev/)
- [Harbor 文档](https://goharbor.io/docs/)
- [Docker Buildx 文档](https://docs.docker.com/buildx/working-with-buildx/)
- [主项目文档](./DOCKER_README.md)
---
**最后更新**: 2025-11-25
**版本**: 1.3.0
+341 -211
View File
@@ -4,265 +4,395 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
## Repository Overview
This is a comprehensive CI/CD infrastructure setup for Mac Studio M2 environment, featuring Jenkins, Gitea, and Docker Registry with full automation support.
LJWX Health (灵境万象健康监测系统) is a comprehensive enterprise-level health monitoring platform for wearable devices. It consists of three main components:
1. **ljwx-admin** - Vue3 frontend admin dashboard (TypeScript + Naive UI)
2. **ljwx-boot** - Spring Boot backend API (Java 21 + MySQL + Redis)
3. **ljwx-bigscreen** - Flask real-time monitoring dashboard (Python + ECharts)
The repository uses GitHub Actions for CI/CD automation, supporting multi-architecture Docker image builds and deployments.
## Quick Start Commands
### Application Development
```bash
# Complete automated deployment - fully configured Jenkins
./jenkins-auto-deploy.sh
# Frontend (ljwx-admin) - Vue3 Admin Dashboard
cd ljwx-admin
pnpm install # Install dependencies
pnpm dev # Start dev server at http://localhost:3333
pnpm build # Build for production
# Daily management
./jenkins-manager.sh start # Start services
./jenkins-manager.sh stop # Stop services
./jenkins-manager.sh status # Check status
./jenkins-manager.sh logs # View Jenkins logs
./jenkins-manager.sh backup # Backup configuration
./jenkins-manager.sh health # Health check
# Backend (ljwx-boot) - Spring Boot API
cd ljwx-boot
./run-local.sh # Start backend at http://localhost:9998
./run-local.sh status # Check service status
# DO NOT restart during debugging - user will restart manually
# Simple quick start (manual setup required)
./quick-start-jenkins.sh
# BigScreen (ljwx-bigscreen) - Python Dashboard
cd ljwx-bigscreen/bigscreen
python run.py # Start at http://localhost:5225 (local)
./start_all.sh # Start all services including Celery
# Docker deployment (bigscreen)
cd ljwx-bigscreen/bigscreen
./generate-docker-compose.sh # Generate compose config
docker-compose up -d # Run at http://localhost:5001
```
### CI/CD with GitHub Actions
```bash
# GitHub Actions automatically builds and pushes Docker images on:
# - Push to main/develop branches
# - Creating version tags (v*)
# - Pull requests
# Manual workflow trigger via GitHub UI:
# Actions -> Build and Push Docker Images -> Run workflow
# Build specific component or all components
# Supports multi-architecture: linux/amd64, linux/arm64
```
## Service Access Points
- **Jenkins**: http://localhost:8081 (admin/admin123 for auto-deployed)
- **Docker Registry**: http://localhost:5001
- **Registry UI**: http://localhost:5002
- **Gitea**: http://192.168.1.6:3000
### Application Services
| Service | URL | Credentials | Purpose |
|---------|-----|-------------|---------|
| **ljwx-admin** | http://localhost:3333 | Via backend login | Admin dashboard |
| **ljwx-boot** | http://localhost:9998 | - | Backend API |
| **ljwx-bigscreen** | http://localhost:5225 (local)<br>http://localhost:5001 (Docker) | WeChat Enterprise | Monitoring dashboard |
| **API Documentation** | http://localhost:9998/doc.html | - | Swagger/Knife4j docs |
### Database Services
| Service | Connection | Credentials |
|---------|------------|-------------|
| **MySQL** | 127.0.0.1:3306 | root / 123456<br>Database: test |
| **Redis** | 127.0.0.1:6379 | Password: 123456<br>DB: 1 |
### CI/CD Configuration
GitHub Actions workflow configuration is located in `.github/workflows/build-and-push.yml`.
**Required GitHub Secrets:**
- `HARBOR_HOST` - Harbor registry address
- `HARBOR_USERNAME` - Harbor username
- `HARBOR_PASSWORD` - Harbor password
## Architecture
### Core Components
- **Jenkins LTS**: CI/CD server with Configuration as Code (CasC)
- **Gitea**: Git repository server with Actions support
- **Docker Registry**: Local container registry for multi-platform images
- **Multi-platform Build**: Supports linux/amd64 and linux/arm64
### Application Stack
### Key Directories
**ljwx-admin (Frontend)**
- **Tech**: Vue 3.5 + TypeScript 5.7 + Vite 6.0 + Naive UI 2.40
- **Build**: pnpm monorepo with workspace packages
- **State**: Pinia 2.3 + Vue Router 4.5
- **Styling**: UnoCSS with custom preset
- **Features**: Multi-tenant support, auto customerId injection, NaiveUI components
**ljwx-boot (Backend)**
- **Tech**: Spring Boot 3.x + Java 21 + Maven
- **Database**: MySQL 8.0 with MyBatis-Plus
- **Cache**: Redis with connection pooling
- **Architecture**: Multi-module Maven project
- **Features**: Health data scheduled tasks, weight calculation, multi-tenant isolation
**ljwx-bigscreen (Monitoring Dashboard)**
- **Tech**: Flask 2.0+ + Python 3.8+ + SQLAlchemy
- **Visualization**: ECharts.js + WebSocket real-time updates
- **Queue**: Celery with Redis backend
- **Features**: CPU-adaptive batch processing, real-time health monitoring, WeChat alerts
### Project Structure
```
infra/
├── jenkins-auto-deploy.sh # ⭐ Main automated deployment
├── jenkins-manager.sh # Daily management script
├── docker/compose/
│ ├── jenkins-simple.yml # Primary Jenkins Compose file
│ ├── jenkins-complete-auto.yml # Full auto-configuration
│ └── jenkins/
│ ├── casc/jenkins.yaml # ⭐ Configuration as Code
│ ├── plugins.txt # Jenkins plugins list
│ ├── init-scripts/ # Initialization scripts
│ ├── shared-library/ # Pipeline shared libraries
│ └── templates/ # Dockerfile & Pipeline templates
├── deployment/scripts/ # Management & integration scripts
└── docs/ # Documentation and guides
ljwx-health/
├── ljwx-admin/ # Vue3 frontend
│ ├── src/
│ │ ├── views/ # Page components
│ │ ├── service/api/ # API calls
│ │ ├── hooks/common/table.ts # useTable hook
│ │ └── router/ # Route configuration
│ ├── packages/ # Monorepo packages
│ └── package.json
│
├── ljwx-boot/ # Spring Boot backend
│ ├── ljwx-boot-admin/ # Main application module
│ ├── ljwx-boot-modules/ # Business modules
│ │ └── src/main/java/com/ljwx/modules/health/
│ │ ├── task/ # Scheduled tasks
│ │ ├── service/ # Business services
│ │ └── job/ # Quartz jobs
│ ├── ljwx-boot-common/ # Common utilities
│ ├── run-local.sh # ⭐ Local startup script
│ └── pom.xml
│
├── ljwx-bigscreen/ # Python monitoring
│ └── bigscreen/
│ ├── bigScreen/ # Flask application
│ │ ├── bigScreen.py # Main app
│ │ ├── templates/ # HTML templates
│ │ └── static/ # Static assets
│ ├── run.py # ⭐ Application entry
│ ├── config.py # Configuration
│ └── requirements.txt
│
├── docker/compose/ # CI/CD infrastructure
│ ├── jenkins-simple.yml
│ ├── jenkins-complete-auto.yml
│ └── jenkins/casc/jenkins.yaml # Jenkins config as code
│
├── build-and-push-v2.sh # Multi-arch Docker build
├── jenkins-manager.sh # Jenkins management
└── CLAUDE.md # ⭐ This file
```
## Docker Configuration Files
### Main Compose Files
- `jenkins-simple.yml` - Basic Jenkins setup
- `jenkins-complete-auto.yml` - Full automation with CasC
- `gitea-compose.yml` - Gitea service
- `registry-compose.yml` - Docker registry
### Jenkins Automation
The Jenkins instance uses Configuration as Code located at `docker/compose/jenkins/casc/jenkins.yaml` which includes:
- Auto-configured tools (Git, Maven, Gradle, NodeJS, Docker, Python)
- Pre-configured credentials (Gitea, Registry, SSH)
- Cloud configurations (Docker, Kubernetes)
- Security settings and user management
- Pre-created jobs (multi-platform builds, system monitoring)
## Development Workflow
### For Infrastructure Changes
1. Modify configuration files in `docker/compose/jenkins/casc/`
2. Test with: `./jenkins-manager.sh restart`
3. Use: `./jenkins-manager.sh health` to verify
### Frontend Development (ljwx-admin)
### For Adding New Services
1. Create/modify compose files in `docker/compose/`
2. Update management scripts in `deployment/scripts/`
3. Test deployment with appropriate script
**Starting development:**
```bash
cd ljwx-admin
pnpm install
pnpm dev # Runs on http://localhost:3333
```
### Pipeline Development
- Templates available in `docker/compose/jenkins/templates/`
- Shared libraries in `docker/compose/jenkins/shared-library/`
- Multi-platform Docker builds supported by default
**Key development patterns:**
- Use `useTable` hook for table data management with automatic customerId injection
- NaiveUI components: avoid `remote` property on NDataTable unless truly needed
- API calls auto-inject customerId via request interceptor (see `src/service/request/index.ts`)
- Use computed properties for column definitions instead of relying on useTable's column processing
## Important Configuration Files
**Common tasks:**
```bash
pnpm build # Production build
pnpm typecheck # TypeScript validation
pnpm lint # ESLint check and fix
```
- `docker/compose/jenkins/casc/jenkins.yaml` - Jenkins Configuration as Code
- `docker/compose/jenkins/plugins.txt` - Jenkins plugins
- `jenkins-manager.sh` - Primary management interface
- `deployment/scripts/` - Various automation scripts
### Backend Development (ljwx-boot)
## Multi-Platform Build Support
**Starting development:**
```bash
cd ljwx-boot
./run-local.sh # Starts on port 9998
```
All Docker builds support both linux/amd64 and linux/arm64 platforms. The Jenkins configuration includes buildx setup and multi-platform pipeline templates.
**Important Notes:**
- **DO NOT restart ljwx-boot during debugging** - User handles restarts manually
- Check status: `./run-local.sh status`
- Logs are in `logs/` directory
- Configuration: Uses `local` profile (application-local.yml)
## Backup and Recovery
**Key modules:**
- `ljwx-boot-modules/src/main/java/com/ljwx/modules/health/task/` - Scheduled tasks
- `ljwx-boot-modules/src/main/java/com/ljwx/modules/health/service/` - Business logic
- `ljwx-boot-common/src/main/java/com/ljwx/common/util/` - Utilities
**Maven commands:**
```bash
mvn clean install -DskipTests # Build all modules
mvn spring-boot:run # Run with Maven
```
### BigScreen Development (ljwx-bigscreen)
**Starting development:**
```bash
cd ljwx-bigscreen/bigscreen
python run.py # Local: http://localhost:5225
```
**Performance testing:**
```bash
./performance_test.sh # Load testing
python test_health_fix.py # Health data tests
```
## Health System Architecture
### Health Data Scheduled Tasks
The system runs multiple scheduled tasks for health data processing:
**Task Schedule:**
```
01:00 - Weight configuration validation (validateWeightConfigurations)
02:00 - User health baseline generation (generateUserHealthBaseline)
02:05 - Department health baseline aggregation (generateDepartmentHealthBaseline)
02:10 - Organization health baseline (generateOrgHealthBaseline)
02:15 - Department health score (generateDepartmentHealthScore)
04:00 - User health score generation (generateHealthScore)
04:10 - Organization health score (generateOrgHealthScore)
05:00 - Data cleanup (cleanupOldData)
Monthly (1st) - Table partitioning (archiveAndResetUserHealthTable)
```
**Location:** `ljwx-boot/ljwx-boot-modules/src/main/java/com/ljwx/modules/health/task/HealthBaselineScoreTasks.java`
**Management UI:**
- Frontend: `ljwx-admin/src/views/monitor/scheduler/index.vue`
- API: `ljwx-admin/src/service/api/monitor/scheduler.ts`
- Access: http://localhost:3000/#/monitor/scheduler
### Supported Health Metrics
The system monitors and analyzes these health indicators:
- **heart_rate** (心率) - Core vital sign
- **blood_oxygen** (血氧) - Respiratory health
- **temperature** (体温) - Body temperature
- **pressure_high/pressure_low** (血压) - Cardiovascular health
- **stress** (压力) - Mental health
- **step** (步数) - Activity level
- **calorie** (卡路里) - Metabolic health
- **distance** (距离) - Movement
- **sleep** (睡眠) - Sleep quality
### Health Weight Configuration
Standard medical weight distribution (see `WeightCalculationService.java`):
- **Core vitals (65%)**: heart_rate(20%), blood_oxygen(18%), temperature(15%), pressure(12%)
- **Health status (20%)**: stress(12%), sleep(8%)
- **Activity (10%)**: step(4%), distance(3%), calorie(3%)
- **Auxiliary (5%)**: ECG and other metrics
## CI/CD with GitHub Actions
### Workflow Configuration
The GitHub Actions workflow (`.github/workflows/build-and-push.yml`) provides:
- **Automatic builds** on push to main/develop branches
- **Version tagging** support (builds triggered by v* tags)
- **Multi-architecture** builds (linux/amd64, linux/arm64)
- **Component selection** - build all or specific components
- **Image caching** using GitHub Actions cache
### Supported Components
The workflow builds the following Docker images:
- `ljwx-boot` - Backend API service
- `ljwx-admin` - Frontend admin dashboard
- `ljwx-bigscreen` - Real-time monitoring dashboard
- `ljwx-mysql` - MySQL database
- `ljwx-redis` - Redis cache
### Manual Workflow Trigger
You can manually trigger builds via GitHub UI:
1. Go to Actions tab in GitHub repository
2. Select "Build and Push Docker Images"
3. Click "Run workflow"
4. Choose component (all or specific) and optional version tag
### Docker Compose Deployment
```bash
./jenkins-manager.sh backup # Create backup
./jenkins-manager.sh restore # Restore from backup
# Use docker-compose.yml for local development
docker-compose up -d
# Use docker-compose.prod.yml for production deployment
docker-compose -f docker-compose.prod.yml up -d
```
Backups are stored in `backup/jenkins/` with timestamps.
## Important Files and Locations
## Troubleshooting
### Frontend (ljwx-admin)
- **Request interceptor**: `src/service/request/index.ts` - Auto-injects customerId
- **useTable hook**: `src/hooks/common/table.ts` - Table data management
- **API definitions**: `src/service/api/` - Typed API calls
- **Scheduler UI**: `src/views/monitor/scheduler/index.vue` - Task management
1. Check service health: `./jenkins-manager.sh health`
2. View logs: `./jenkins-manager.sh logs`
3. Restart services: `./jenkins-manager.sh restart`
4. Full reset: `./jenkins-manager.sh cleanup` (⚠️ destructive)
### Backend (ljwx-boot)
- **Scheduled tasks**: `ljwx-boot-modules/src/main/java/com/ljwx/modules/health/task/HealthBaselineScoreTasks.java`
- **Weight service**: `ljwx-boot-modules/src/main/java/com/ljwx/modules/health/service/WeightCalculationService.java`
- **Health service**: `ljwx-boot-modules/src/main/java/com/ljwx/modules/health/service/UnifiedHealthDataQueryService.java`
- **IP utilities**: `ljwx-boot-common/src/main/java/com/ljwx/common/util/IPUtil.java` - IPv6 fix included
Detailed troubleshooting guide available at `docs/troubleshooting.md`.
### BigScreen (ljwx-bigscreen)
- **Main app**: `bigscreen/bigScreen/bigScreen.py` - Flask routes and API
- **Configuration**: `bigscreen/config.py` - Environment and settings
- **Models**: `bigscreen/bigScreen/models.py` - SQLAlchemy database models
- **Health data**: `bigscreen/bigScreen/user_health_data.py` - Data processing
## ljwx-boot 健康定时任务系统
## Known Issues and Fixes
### 健康定时任务概览
### IPv6 Address Resolution (Fixed)
- **Issue**: IPv6 localhost "0:0:0:0:0:0:0:1" not recognized by ip2region
- **Fix**: Added detection in `IPUtil.java:171-185`
- **Handles**: Local addresses, IPv6, internal IPs with proper fallbacks
ljwx-boot 包含一套完整的健康数据处理定时任务系统,主要包括:
### Weight Cache Table (Fixed)
- **Issue**: `t_weight_cache` table missing caused health score failures
- **Fix**: Auto-creates table structure in `WeightCalculationService.java`
- **Features**: User weight config, position risk multipliers, normalized weights
1. **HealthBaselineScoreTasks** - 核心定时任务类
- 位置: `ljwx-boot/ljwx-boot-modules/src/main/java/com/ljwx/modules/health/task/HealthBaselineScoreTasks.java`
- 使用 `@Scheduled` 注解实现多个定时任务
- 支持分表架构和并行处理
### Health Recommendation NullPointerException (Fixed)
- **Issue**: Null keys in data grouping caused crashes
- **Fix**: Added null filtering in `HealthRecommendationService.java`
- **Improvement**: Enhanced data validation and error logging
2. **HealthRecommendationJob** - 健康建议生成作业
- 位置: `ljwx-boot/ljwx-boot-modules/src/main/java/com/ljwx/modules/health/job/HealthRecommendationJob.java`
- 实现 Quartz Job 接口,集成到 mon_scheduler 系统
### Health Data Query Performance (Optimized)
- **Issue**: N+1 query problem, repeated config parsing per record
- **Fix**: Batch conversion with caching in `UnifiedHealthDataQueryService.java`
- **Performance**: 13x faster (~200ms → ~15ms for 20 records), 95% fewer DB queries
### 定时任务执行时间表
### Frontend Table Display Issues
- **Common cause**: Using `remote` property on NDataTable incorrectly
- **Solution**: Remove `remote` unless implementing true server-side pagination
- **Best practice**: Use computed properties for columns, not useTable's column processing
```
01:00 - 权重配置验证任务 (validateWeightConfigurations)
02:00 - 生成用户健康基线 (generateUserHealthBaseline)
02:05 - 生成部门健康基线聚合 (generateDepartmentHealthBaseline)
02:10 - 生成组织健康基线 (generateOrgHealthBaseline)
02:15 - 生成部门健康评分 (generateDepartmentHealthScore)
04:00 - 生成用户健康评分 (generateHealthScore)
04:10 - 生成组织健康评分 (generateOrgHealthScore)
05:00 - 数据清理任务 (cleanupOldData)
## Development Best Practices
每月1日凌晨 - 按月分表任务 (archiveAndResetUserHealthTable)
```
### Multi-Tenant Architecture
- **customerId auto-injection**: Request interceptor automatically adds customerId to all API calls
- **Exclusion list**: Login, auth, dictionary, and system APIs excluded from auto-injection
- **Override support**: Explicitly passed customerId values are preserved
### 管理界面
### Performance Optimization Patterns
- **Avoid N+1 queries**: Use batch queries with caching (see `UnifiedHealthDataQueryService`)
- **Batch processing**: Process data in batches of 200 records
- **Connection pooling**: 30 base + 50 overflow connections configured
- **Redis caching**: 3-5 minute TTL for frequently accessed data
前端管理界面位于:
- **ljwx-admin**: `/src/views/monitor/scheduler/index.vue`
- **API接口**: `/src/service/api/monitor/scheduler.ts`
- **访问地址**: http://localhost:3000/#/monitor/scheduler
### Code Quality Guidelines
- **Null safety**: Always filter null values before stream operations
- **Error handling**: Comprehensive try-catch with graceful degradation
- **Logging levels**: DEBUG for detailed logs, INFO for performance metrics
- **Type safety**: Proper BigDecimal to Double conversions in weight calculations
管理界面功能:
- 查看所有调度任务状态
- 立即执行任务 (immediate)
- 暂停/恢复任务 (pause/resume)
- 暂停/恢复任务组 (pauseGroup/resumeGroup)
- 编辑任务配置
- 删除任务
## Testing and Debugging
### 核心功能
1. **多表支持**: 自动检测并查询主表和月度分表
2. **并行处理**: 使用线程池并行处理多个健康特征
3. **异常检测**: 自动检测和修复数据异常
4. **覆盖率监控**: 检查各个特征的数据覆盖率
5. **权重计算**: 集成客户自定义权重配置
### 健康特征支持
系统支持以下健康指标的基线和评分计算:
- heart_rate (心率)
- blood_oxygen (血氧)
- temperature (体温)
- pressure_high/pressure_low (血压)
- stress (压力)
- step (步数)
- calorie (卡路里)
- distance (距离)
- sleep (睡眠)
### 调试说明
**重要**: 调试过程中不要重启 ljwx-boot 服务,用户会手动重启。
使用以下命令检查服务状态:
### Backend Testing
```bash
cd ljwx-boot && ./run-local.sh status # 检查状态
# 不要使用 ./run-local.sh start 或 ./run-local.sh restart
cd ljwx-boot
./run-local.sh # Start service
# Check logs in logs/ directory
# Monitor scheduled tasks via scheduler UI
```
### 任务监控
### Frontend Testing
```bash
cd ljwx-admin
pnpm dev # Development server
# Use browser DevTools for debugging
# Check network tab for API calls and customerId injection
```
1. **日志监控**: 所有任务执行都有详细的日志输出
2. **性能指标**: 记录任务执行时间和处理数据量
3. **异常处理**: 自动捕获和记录异常,不会影响其他任务
4. **状态跟踪**: 通过 mon_scheduler 系统跟踪任务状态
### BigScreen Testing
```bash
cd ljwx-bigscreen/bigscreen
python run.py # Start service
./performance_test.sh # Load testing
python test_health_fix.py # Health data tests
```
### IP地址解析修复
## Additional Documentation
系统已修复IPv6地址解析问题:
- **问题**: IPv6 localhost地址 "0:0:0:0:0:0:0:1" 无法被 ip2region 库识别
- **解决**: 在 `IPUtil.java` 中添加IPv6和本地地址检测
- **位置**: `ljwx-boot/ljwx-boot-common/src/main/java/com/ljwx/common/util/IPUtil.java`
- **处理策略**:
- 本地地址 (127.0.0.1, ::1, 0:0:0:0:0:0:0:1) → "本地|本地|本地|本地"
- IPv6地址 → "IPv6|IPv6|IPv6|IPv6"
- 内网IP → "内网|内网|内网|内网"
- 查询失败 → "未知|未知|未知|未知"
### 权重缓存表修复
系统已修复权重计算功能:
- **问题**: `t_weight_cache` 表不存在导致健康评分任务失败
- **解决**: 创建了完整的权重缓存表结构
- **位置**: `ljwx-boot/ljwx-boot-modules/src/main/java/com/ljwx/modules/health/service/WeightCalculationService.java`
- **表结构**: 支持用户权重配置、岗位风险倍数、归一化权重等功能
- **安全处理**: 添加表存在性检查,避免SQL错误
### 健康建议服务修复
系统已修复健康建议生成功能:
- **问题**: `HealthRecommendationService` 中 NullPointerException,由于数据分组时遇到null键
- **解决**: 在流处理前过滤null值,添加数据验证和日志记录
- **位置**: `ljwx-boot/ljwx-boot-modules/src/main/java/com/ljwx/modules/health/service/HealthRecommendationService.java`
- **改进**: 增强了数据质量检测和错误处理
### 权重配置优化和合理化
系统已完成权重分配的标准化:
- **问题**: 权重配置不合理(总和超过1.0、存在null值、分配不科学)
- **解决**: 实现了基于医学重要性的标准化权重分配算法
- **位置**: `ljwx-boot/ljwx-boot-modules/src/main/java/com/ljwx/modules/health/service/WeightCalculationService.java`
#### 标准权重分配方案
**核心生命体征 (65%)**:
- 心率: 20% - 最重要的生命体征指标
- 血氧: 18% - 呼吸系统核心指标
- 体温: 15% - 基础生命体征
- 收缩压: 6% - 心血管健康指标
- 舒张压: 6% - 心血管健康指标
**健康状态指标 (20%)**:
- 压力指数: 12% - 心理健康重要指标
- 睡眠质量: 8% - 恢复性健康指标
**运动健康指标 (10%)**:
- 步数: 4% - 日常活动量
- 距离: 3% - 运动强度
- 卡路里: 3% - 代谢水平
**辅助指标 (5%)**:
- 心电图: 2% - 深度心血管监测
- 位置/锻炼等: 各1%以下
#### 技术改进
- **类型安全**: 修复了BigDecimal到Double的类型转换问题
- **数据验证**: 添加了权重配置的自动验证和修复
- **标准化**: 实现了科学的权重分配标准
- **自动修复**: 系统自动检测和修复不合理的权重配置
For detailed information about specific subsystems, see:
- **ljwx-admin**: `ljwx-admin/CLAUDE.md` - Frontend architecture and troubleshooting
- **ljwx-bigscreen**: `ljwx-bigscreen/CLAUDE.md` - Monitoring system details
- **Infrastructure**: `docs/` directory for CI/CD and deployment guides
-623
View File
@@ -1,623 +0,0 @@
# LJWX 统一构建部署方案 v2.0
## 概述
本方案解决了以下三个核心问题:
1. **配置管理统一化** - 使用单一`.env`文件管理所有配置
2. **脚本功能优化** - 支持分阶段执行(build/push/deploy)
3. **数据库版本管理** - 优雅的数据库迁移和升级方案
## 架构改进
### 改进前 (v1.x)
```
配置文件分散:
- monitoring-versions.env (版本配置)
- docker-compose.prod.yml (硬编码配置)
- build-and-push.sh (硬编码逻辑)
数据库管理:
- 手动导出 data.sql
- 容易出现版本不一致
- 无迁移历史追踪
构建流程:
- 一体化执行,无法分阶段
- 难以调试和错误恢复
```
### 改进后 (v2.0)
```
统一配置:
.env (唯一配置源)
├── 版本配置
├── Registry配置
├── 数据库配置
├── Redis配置
└── 构建/部署配置
数据库迁移:
docker/mysql/migrations/
├── V1.0.0__baseline.sql
├── V2.0.0__add_features.sql
├── V2.0.3__current.sql
├── schema_migrations (历史表)
└── rollback/ (回滚脚本)
分阶段构建:
build-and-push-v2.sh
├── -b (build only)
├── -p (push only)
├── -d (deploy only)
└── -a (all)
```
## 快速开始
### 1. 初始配置
```bash
# 1.1 复制统一配置文件
cp .env.unified .env
# 1.2 编辑配置(修改密码、端口等)
vim .env
# 关键配置项:
# - LJWX_VERSION=2.0.3
# - MYSQL_ROOT_PASSWORD=your_password
# - REDIS_PASSWORD=your_password
# - REGISTRY=localhost:15000/ljwx
```
### 2. 导出数据库基线
```bash
# 方式1: 使用数据库迁移工具(推荐)
./db-migrate.sh export 2.0.3
# 方式2: 使用构建脚本
./build-and-push-v2.sh -e
# 这会导出宿主机数据库到:
# - docker/mysql/migrations/V2.0.3__baseline.sql (版本化)
# - docker/mysql/data.sql (Docker构建使用)
```
### 3. 构建镜像
```bash
# 构建所有镜像
./build-and-push-v2.sh -b
# 或构建单个组件
./build-and-push-v2.sh -b -c ljwx-boot
# 查看构建日志
tail -f logs/build/ljwx-boot_*.log
```
### 4. 推送镜像
```bash
# 推送所有镜像到Registry
./build-and-push-v2.sh -p
# 或推送单个组件
./build-and-push-v2.sh -p -c ljwx-mysql
```
### 5. 部署服务
```bash
# 部署所有服务
./build-and-push-v2.sh -d
# 或手动使用docker-compose
docker-compose -f docker-compose.prod.v2.yml up -d
```
### 6. 一键部署
```bash
# 导出数据库 + 构建 + 推送 + 部署
./build-and-push-v2.sh -e -a
# 或分步执行(推荐生产环境)
./build-and-push-v2.sh -e # 导出数据库
./build-and-push-v2.sh -b # 构建镜像
./build-and-push-v2.sh -p # 推送镜像
./build-and-push-v2.sh -d # 部署服务
```
## 配置文件详解
### .env 配置结构
```bash
# ============================================
# 版本配置
# ============================================
LJWX_VERSION=2.0.3 # 统一版本号
LJWX_MYSQL_VERSION=${LJWX_VERSION} # 可独立设置组件版本
LJWX_REDIS_VERSION=${LJWX_VERSION}
LJWX_BOOT_VERSION=${LJWX_VERSION}
LJWX_BIGSCREEN_VERSION=${LJWX_VERSION}
LJWX_ADMIN_VERSION=${LJWX_VERSION}
# ============================================
# Registry配置
# ============================================
REGISTRY=localhost:15000/ljwx # 镜像仓库地址
PRIVATE_REGISTRY_HOST=localhost:15000
CACHE_REGISTRY_HOST=localhost:15001
# ============================================
# 数据库配置
# ============================================
# 容器内配置
MYSQL_ROOT_PASSWORD=123456
MYSQL_DATABASE=test
MYSQL_PORT=3307
# 宿主机配置(用于导出)
HOST_MYSQL_HOST=127.0.0.1
HOST_MYSQL_PORT=3306
HOST_MYSQL_DATABASE=test
# 迁移配置
DB_MIGRATION_ENABLED=true
DB_MIGRATION_AUTO_APPLY=true
DB_MIGRATION_DIR=./docker/mysql/migrations
# ============================================
# Redis配置
# ============================================
REDIS_HOST=ljwx-redis
REDIS_PORT=6379
REDIS_PASSWORD=123456
# ============================================
# 应用配置
# ============================================
BOOT_PORT=9998
BIGSCREEN_PORT=5225
BIGSCREEN_EXTERNAL_PORT=8000
ADMIN_EXTERNAL_PORT=8080
# ============================================
# 部署配置
# ============================================
COMPOSE_FILE=docker-compose.prod.v2.yml
NETWORK_NAME=ljwx-network
```
### docker-compose.prod.v2.yml 特性
```yaml
# 使用环境变量替换
services:
ljwx-mysql:
image: ${REGISTRY}/ljwx-mysql:${LJWX_MYSQL_VERSION}
environment:
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
- MYSQL_DATABASE=${MYSQL_DATABASE}
ports:
- "${MYSQL_PORT}:3306"
ljwx-boot:
image: ${REGISTRY}/ljwx-boot:${LJWX_BOOT_VERSION}
environment:
- REDIS_HOST=${REDIS_HOST}
- REDIS_PASSWORD=${REDIS_PASSWORD}
ports:
- "${BOOT_PORT}:9998"
```
## 数据库迁移管理
### 迁移文件命名规范
```
V{版本号}__{描述}.sql
示例:
V1.0.0__baseline.sql # 初始基线
V2.0.0__add_health_tables.sql # 添加健康表
V2.0.1__fix_indexes.sql # 修复索引
V2.0.2__add_org_fields.sql # 添加组织字段
V2.0.3__current.sql # 当前版本
```
### 创建新迁移
```bash
# 1. 创建迁移脚本模板
./db-migrate.sh create 2.0.4 add_new_features
# 2. 编辑生成的迁移脚本
vim docker/mysql/migrations/V2.0.4__add_new_features.sql
# 3. 编辑对应的回滚脚本
vim docker/mysql/migrations/rollback/R2.0.4__rollback.sql
```
### 迁移脚本示例
```sql
-- V2.0.4__add_new_features.sql
-- ============================================
-- 迁移版本: V2.0.4
-- 创建时间: 2025-11-28
-- 描述: 添加用户健康评分表
-- 依赖版本: V2.0.3
-- ============================================
START TRANSACTION;
-- 创建表(幂等性)
CREATE TABLE IF NOT EXISTS `t_user_health_score` (
`id` bigint NOT NULL AUTO_INCREMENT,
`user_id` bigint NOT NULL,
`score` decimal(5,2) DEFAULT 0.00,
`created_at` timestamp DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `idx_user_id` (`user_id`),
KEY `idx_created_at` (`created_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 添加字段(幂等性)
SET @col_exists = 0;
SELECT COUNT(*) INTO @col_exists
FROM information_schema.columns
WHERE table_schema = DATABASE()
AND table_name = 't_user'
AND column_name = 'health_level';
SET @sql = IF(@col_exists = 0,
'ALTER TABLE t_user ADD COLUMN health_level VARCHAR(20)',
'SELECT "Column already exists"');
PREPARE stmt FROM @sql;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
COMMIT;
```
### 应用迁移
```bash
# 查看迁移状态
./db-migrate.sh status
# 应用特定版本
./db-migrate.sh apply 2.0.4
# 应用所有待执行迁移
./db-migrate.sh apply-all
# 回滚到指定版本
./db-migrate.sh rollback 2.0.3
```
### 迁移历史追踪
系统自动在数据库中创建`schema_migrations`表:
```sql
mysql> SELECT * FROM schema_migrations;
+---------+---------------------+------+------------+----------+
| version | description | ... | installed | success |
+---------+---------------------+------+------------+----------+
| 2.0.0 | baseline | ... | 2025-11-28 | 1 |
| 2.0.1 | add_health_tables | ... | 2025-11-28 | 1 |
| 2.0.2 | fix_indexes | ... | 2025-11-28 | 1 |
| 2.0.3 | add_org_fields | ... | 2025-11-28 | 1 |
+---------+---------------------+------+------------+----------+
```
## 构建脚本使用
### build-and-push-v2.sh 功能
```bash
# 查看帮助
./build-and-push-v2.sh -h
# 分阶段执行
./build-and-push-v2.sh -b # 仅构建
./build-and-push-v2.sh -p # 仅推送
./build-and-push-v2.sh -d # 仅部署
./build-and-push-v2.sh -a # 全部执行
# 单组件操作
./build-and-push-v2.sh -b -c ljwx-boot # 构建单个组件
./build-and-push-v2.sh -b -p -c ljwx-mysql # 构建并推送
# 数据库操作
./build-and-push-v2.sh -e # 导出数据库
./build-and-push-v2.sh -m # 应用迁移
# 指定版本
./build-and-push-v2.sh -b -v 2.0.4 # 构建指定版本
```
### 组合使用示例
```bash
# 场景1: 开发环境快速迭代
./build-and-push-v2.sh -b -c ljwx-boot # 只构建修改的组件
./build-and-push-v2.sh -p -c ljwx-boot # 推送
./build-and-push-v2.sh -d # 重新部署
# 场景2: 数据库结构变更
./db-migrate.sh create 2.0.4 add_features # 创建迁移
vim docker/mysql/migrations/V2.0.4__*.sql # 编辑迁移脚本
./db-migrate.sh apply 2.0.4 # 测试应用
./build-and-push-v2.sh -b -c ljwx-mysql # 重新构建MySQL镜像
./build-and-push-v2.sh -p -c ljwx-mysql # 推送
# 场景3: 生产环境完整部署
./db-migrate.sh export 2.0.4 # 导出最新数据库
./build-and-push-v2.sh -b # 构建所有镜像
./build-and-push-v2.sh -p # 推送所有镜像
# 在生产环境执行:
./build-and-push-v2.sh -d # 部署服务
```
## 版本发布流程
### 开发阶段
```bash
# 1. 更新代码
git pull origin main
# 2. 创建数据库迁移(如有表结构变更)
./db-migrate.sh create 2.0.4 add_new_features
vim docker/mysql/migrations/V2.0.4__add_new_features.sql
# 3. 本地测试迁移
./db-migrate.sh apply 2.0.4
# 4. 如有问题,回滚测试
./db-migrate.sh rollback 2.0.3
# 5. 提交代码
git add .
git commit -m "feat: add new features v2.0.4"
git push
```
### 构建阶段
```bash
# 1. 更新版本号
vim .env
# 修改: LJWX_VERSION=2.0.4
# 2. 导出最新数据库
./db-migrate.sh export 2.0.4
# 3. 构建所有镜像
./build-and-push-v2.sh -b
# 4. 推送到Registry
./build-and-push-v2.sh -p
# 5. 验证镜像
docker images | grep ljwx
```
### 测试阶段
```bash
# 1. 在测试环境部署
./build-and-push-v2.sh -d
# 2. 验证服务
curl http://localhost:9998/actuator/health
curl http://localhost:8000/api/health
# 3. 验证数据库迁移
./db-migrate.sh status
# 4. 功能测试
# ...执行各项功能测试...
```
### 生产部署
```bash
# 1. 备份生产数据库
docker exec ljwx-mysql mysqldump -u root -p123456 test > backup_prod_$(date +%Y%m%d).sql
# 2. 拉取最新镜像
docker-compose -f docker-compose.prod.v2.yml pull
# 3. 停止服务
docker-compose -f docker-compose.prod.v2.yml down
# 4. 启动新版本
docker-compose -f docker-compose.prod.v2.yml up -d
# 5. 自动应用迁移(如启用了AUTO_APPLY)
# 或手动应用:
./db-migrate.sh apply-all
# 6. 验证服务
docker-compose -f docker-compose.prod.v2.yml ps
./db-migrate.sh status
# 7. 健康检查
curl http://localhost:9998/actuator/health
```
## 故障处理
### 构建失败
```bash
# 查看构建日志
tail -f logs/build/ljwx-boot_*.log
# 清理Docker缓存重新构建
docker system prune -f
./build-and-push-v2.sh -b -c ljwx-boot
```
### 迁移失败
```bash
# 查看迁移状态
./db-migrate.sh status
# 查看错误日志
docker-compose -f docker-compose.prod.v2.yml logs ljwx-mysql
# 回滚到上一版本
./db-migrate.sh rollback 2.0.3
# 恢复备份(最后手段)
mysql -h 127.0.0.1 -u root -p123456 test < backup_prod_20251128.sql
```
### 服务异常
```bash
# 查看所有服务状态
docker-compose -f docker-compose.prod.v2.yml ps
# 查看特定服务日志
docker-compose -f docker-compose.prod.v2.yml logs -f ljwx-boot
# 重启服务
docker-compose -f docker-compose.prod.v2.yml restart ljwx-boot
# 完全重新部署
docker-compose -f docker-compose.prod.v2.yml down
docker-compose -f docker-compose.prod.v2.yml up -d
```
## 最佳实践
### 配置管理
1. ✅ 使用`.env`作为唯一配置源
2. ✅ 不要在`.env`中硬编码敏感信息到Git
3. ✅ 为不同环境维护不同的`.env`文件(.env.dev, .env.prod)
4. ✅ 使用环境变量默认值提供回退
### 数据库迁移
1. ✅ 每个迁移脚本保持幂等性
2. ✅ 迁移前必须备份数据库
3. ✅ 在测试环境充分测试后再上生产
4. ✅ 为每个迁移编写对应的回滚脚本
5. ✅ 避免在迁移中执行耗时操作
### 构建部署
1. ✅ 生产环境使用分阶段部署
2. ✅ 构建前导出最新数据库
3. ✅ 推送前验证镜像构建成功
4. ✅ 部署后验证服务健康状态
5. ✅ 保留多个历史版本的备份
## 文件清单
```
release/
├── .env.unified # 统一配置模板
├── .env # 实际配置(不入Git)
├── docker-compose.prod.v2.yml # v2版本Compose文件
├── build-and-push-v2.sh # v2版本构建脚本
├── db-migrate.sh # 数据库迁移工具
├── DEPLOYMENT-GUIDE-V2.md # 本文档
├── docker/
│ └── mysql/
│ ├── Dockerfile
│ ├── data.sql # 当前版本数据
│ └── migrations/ # 迁移脚本目录
│ ├── README.md
│ ├── V1.0.0__baseline.sql
│ ├── V2.0.0__add_features.sql
│ ├── V2.0.3__current.sql
│ └── rollback/
│ ├── R2.0.3__rollback.sql
│ └── ...
├── logs/
│ ├── build/ # 构建日志
│ └── deploy/ # 部署日志
└── backups/
└── mysql/ # 数据库备份
```
## 常见问题
### Q: 如何从v1迁移到v2?
```bash
# 1. 创建新配置
cp .env.unified .env
# 2. 从旧配置文件复制设置
# 参考 monitoring-versions.env 和 docker-compose.prod.yml
# 3. 导出当前数据库作为基线
./db-migrate.sh export 2.0.3
# 4. 测试新脚本
./build-and-push-v2.sh -b -c ljwx-mysql
# 5. 逐步迁移其他组件
```
### Q: 如何处理多环境部署?
```bash
# 方式1: 使用不同的.env文件
cp .env.dev .env && ./build-and-push-v2.sh -d # 开发环境
cp .env.prod .env && ./build-and-push-v2.sh -d # 生产环境
# 方式2: 使用环境变量覆盖
COMPOSE_FILE=docker-compose.prod.yml ./build-and-push-v2.sh -d
```
### Q: data.sql和迁移脚本的关系?
- `data.sql` 是完整的数据库快照,用于Docker镜像构建
- 迁移脚本是增量变更,用于已有数据库的升级
- 每次发布前,应该导出最新的data.sql作为新版本基线
- 老版本升级使用迁移脚本,新部署使用data.sql
### Q: 如何回退到旧版本?
```bash
# 1. 恢复数据库备份
mysql -h 127.0.0.1 -u root -p123456 test < backup_before_2.0.3.sql
# 2. 修改.env版本号
# LJWX_VERSION=2.0.2
# 3. 重新部署
./build-and-push-v2.sh -d
# 4. 应用回滚脚本(如有)
./db-migrate.sh rollback 2.0.2
```
## 总结
v2.0方案的核心优势:
1. **单一配置源** - 所有配置集中在`.env`,易于管理
2. **灵活构建** - 支持分阶段、单组件操作
3. **版本化迁移** - 数据库变更可追溯、可回滚
4. **自动化程度高** - 减少人工操作,降低出错率
5. **易于扩展** - 添加新组件只需修改配置文件
通过这套方案,实现了从开发到生产的完整DevOps流程。
-289
View File
@@ -1,289 +0,0 @@
# 🐳 Docker Registry 私有镜像服务器部署完成
## 🎉 部署成功!
您的私有 Docker Registry 已成功部署并与 Gitea CI/CD 系统集成。
## 📋 服务概览
| 服务 | 地址 | 状态 | 用途 |
|------|------|------|------|
| **Gitea** | http://192.168.1.83:3000 | ✅ 运行中 | Git 仓库管理 |
| **Docker Registry** | http://localhost:5001 | ✅ 运行中 | 私有镜像仓库 |
| **Registry Web UI** | http://192.168.1.83:5002 | ✅ 运行中 | 镜像可视化管理 |
## 🚀 快速使用指南
### 1. 推送镜像到私有仓库
```bash
# 构建或拉取镜像
docker build -t my-app:latest .
# 或者: docker pull nginx:latest
# 标记镜像
docker tag my-app:latest localhost:5001/my-app:latest
# 推送到私有仓库
docker push localhost:5001/my-app:latest
```
### 2. 从私有仓库拉取镜像
```bash
# 拉取镜像
docker pull localhost:5001/my-app:latest
# 运行容器
docker run -d localhost:5001/my-app:latest
```
### 3. 查看镜像列表
```bash
# 命令行查看
curl http://localhost:5001/v2/_catalog
# 或访问 Web UI
open http://192.168.1.83:5002
```
## 🔧 管理命令
### CI/CD 集成管理
```bash
# 启动所有服务
./deployment/scripts/cicd-integration.sh start
# 查看服务状态
./deployment/scripts/cicd-integration.sh status
# 测试集成功能
./deployment/scripts/cicd-integration.sh test
# 停止所有服务
./deployment/scripts/cicd-integration.sh stop
```
### Registry 单独管理
```bash
# 启动 Registry
./deployment/scripts/registry-manager.sh start
# 查看状态
./deployment/scripts/registry-manager.sh status
# 备份数据
./deployment/scripts/registry-manager.sh backup
# 测试推送
./deployment/scripts/registry-manager.sh push-test
```
## 📊 持久化配置
### 数据存储方式
- **类型**: Docker 命名卷
- **优势**: Docker 统一管理,跨平台兼容
- **位置**: `/var/lib/docker/volumes/compose_registry-data/_data`
### 备份策略
- **自动备份**: 保留最近 5 个备份
- **备份内容**: 镜像数据 + 配置文件
- **恢复方法**: 一键恢复脚本
## 🔗 CI/CD 集成
### Jenkins Pipeline 示例
```groovy
pipeline {
agent any
environment {
DOCKER_REGISTRY = 'localhost:5001'
APP_NAME = 'my-app'
IMAGE_TAG = "${BUILD_NUMBER}"
}
stages {
stage('构建镜像') {
steps {
script {
def image = docker.build("${DOCKER_REGISTRY}/${APP_NAME}:${IMAGE_TAG}")
image.push()
image.push("latest")
}
}
}
stage('部署应用') {
steps {
sh """
docker stop ${APP_NAME} || true
docker rm ${APP_NAME} || true
docker run -d --name ${APP_NAME} -p 8080:80 ${DOCKER_REGISTRY}/${APP_NAME}:${IMAGE_TAG}
"""
}
}
}
}
```
### Gitea Actions 示例
```yaml
name: Build and Push
on:
push:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build Docker image
run: docker build -t localhost:5001/my-app:${{ github.sha }} .
- name: Push to registry
run: docker push localhost:5001/my-app:${{ github.sha }}
```
## ⚙️ 配置详情
### Registry 配置特点
- **认证**: 已禁用(开发环境)
- **删除**: 支持镜像删除
- **CORS**: 支持跨域访问
- **健康检查**: 自动监控服务状态
- **日志**: 详细的访问和错误日志
### 网络配置
- **内部网络**: `cicd-network`
- **端口映射**:
- Registry API: `5001:5000`
- Registry UI: `5002:80`
- **服务发现**: 容器间可通过服务名访问
## 🛡️ 安全考虑
### 开发环境(当前)
- ✅ 无认证访问(便于开发)
- ✅ HTTP 协议
- ✅ 内网访问
### 生产环境建议
- 🔒 启用 HTTP Basic Auth
- 🔒 配置 HTTPS/TLS
- 🔒 配置防火墙规则
- 🔒 定期备份和监控
## 📈 性能优化
### 镜像构建优化
```dockerfile
# 多阶段构建
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
FROM node:18-alpine AS runtime
COPY --from=builder /app/node_modules ./node_modules
COPY . .
EXPOSE 3000
CMD ["npm", "start"]
```
### 镜像标签策略
```bash
# 语义化版本
localhost:5001/my-app:1.0.0
localhost:5001/my-app:1.0.0-beta.1
# Git 信息
localhost:5001/my-app:main-abc1234
localhost:5001/my-app:feature-xyz-def5678
# 环境标签
localhost:5001/my-app:dev
localhost:5001/my-app:staging
localhost:5001/my-app:prod
```
## 🔍 故障排除
### 常见问题
1. **推送失败 - TLS 错误**
```bash
# 解决方案:确认 Docker daemon 配置
cat ~/.docker/daemon.json
# 应包含: "insecure-registries": ["localhost:5001"]
```
2. **服务无法访问**
```bash
# 检查容器状态
docker ps | grep registry
# 检查日志
docker logs docker-registry
```
3. **镜像推送慢**
```bash
# 检查网络
ping localhost
# 检查存储空间
df -h
```
## 📚 相关文档
- [Registry 配置参考](docker/registry/config.yml)
- [Compose 配置](docker/compose/registry-compose.yml)
- [管理脚本](deployment/scripts/)
- [备份脚本](deployment/scripts/registry-manager.sh)
## 🎯 下一步
1. **配置生产环境认证**
```bash
# 启用认证(可选)
./deployment/scripts/fix-docker-registry.sh enable-auth
```
2. **集成 Jenkins**
- 安装 Docker Pipeline 插件
- 配置 Registry 凭据
- 创建构建流水线
3. **监控和告警**
- 配置日志收集
- 设置存储空间监控
- 建立备份计划
---
## 🚀 现在您可以开始使用私有 Docker Registry!
**快速测试:**
```bash
./deployment/scripts/cicd-integration.sh test
```
**查看服务状态:**
```bash
./deployment/scripts/cicd-integration.sh status
```
**访问 Web UI:**
http://192.168.1.83:5002
享受您的私有 CI/CD 环境! 🎉
-350
View File
@@ -1,350 +0,0 @@
# 最终配置和使用指南
## ✅ 已完成的配置
### 1. OrbStack Docker 配置
**配置文件**: `~/.orbstack/config/docker.json`
```json
{
"insecure-registries": [
"127.0.0.1:8080",
"localhost:8080"
]
}
```
**说明**:
- ✅ insecure-registries 允许连接到本地 Harbor
- ❌ proxies 配置不支持(OrbStack 限制)
- ✅ 代理通过脚本中的环境变量实现
### 2. Harbor 配置
**位置**: `~/work/codes/tools/macos/harbor`
**访问地址**:
- HTTP: http://127.0.0.1:8080 (重定向到 HTTPS)
- HTTPS: https://127.0.0.1:8443
- 凭证: admin / admin123
**HTTPS 配置**: Harbor 强制使用 HTTPS,但 docker login/push 会自动处理重定向
### 3. 构建配置
**配置文件**: `monitoring-versions.env`
```bash
# 使用本地构建模式(避免 buildx HTTPS 问题)
LOCAL_BUILD=true
PUSH_TO_REGISTRY=true
PLATFORMS=linux/amd64
# Harbor 配置
REGISTRY=127.0.0.1:8080/ljwx
HARBOR_HOST=127.0.0.1:8080
HARBOR_USERNAME=admin
HARBOR_PASSWORD=admin123
# 代理配置(自动使用)
PROXY_PORT=7890
HTTP_PROXY=http://127.0.0.1:7890
HTTPS_PROXY=http://127.0.0.1:7890
```
## 🚀 使用流程
### 一键构建并推送
```bash
# 1. 确保 OrbStack 运行
open -a OrbStack
# 2. 确保 Harbor 运行
cd ~/work/codes/tools/macos/harbor
docker-compose ps
# 3. 确保代理运行
lsof -i :7890
# 4. 构建并推送镜像
cd ~/work/codes/shenye/release
./build-and-push.sh mysql
```
### 构建所有镜像
```bash
# 构建所有应用镜像
./build-and-push.sh apps
# 构建所有监控镜像
./build-and-push.sh monitoring
# 构建所有镜像
./build-and-push.sh all
```
### 构建单个镜像
```bash
# 后端服务
./build-and-push.sh boot
# 前端管理
./build-and-push.sh admin
# 大屏服务
./build-and-push.sh bigscreen
# MySQL
./build-and-push.sh mysql
# Redis
./build-and-push.sh redis
```
## 📋 工作原理
### 为什么使用本地构建模式?
1. **buildx HTTPS 问题**:
- `docker buildx build --push` 需要 Harbor 的 HTTP 端口
- Harbor 强制 HTTP 重定向到 HTTPS
- buildx 无法正确处理这个重定向
2. **本地构建解决方案**:
- `docker build` 构建镜像到本地
- `docker push` 推送到 Harbor
- docker push 可以正确处理 HTTP→HTTPS 重定向
### 构建流程
```
1. setup_docker_config()
├── 设置代理环境变量
└── 检测代理连接
2. check_harbor_health()
└── 检查 Harbor 是否运行
3. login_harbor()
└── docker login 127.0.0.1:8080
4. build_app_image()
├── docker build (本地构建)
└── docker push (推送到 Harbor)
5. show_summary()
└── 显示构建结果
```
## 🔧 技术细节
### 代理配置
脚本自动导出环境变量:
```bash
export HTTP_PROXY=http://127.0.0.1:7890
export HTTPS_PROXY=http://127.0.0.1:7890
export NO_PROXY=localhost,127.0.0.1,*.local
```
传递给 Docker 构建:
```bash
docker build \
--build-arg HTTP_PROXY=$HTTP_PROXY \
--build-arg HTTPS_PROXY=$HTTPS_PROXY \
--build-arg NO_PROXY=$NO_PROXY \
...
```
### Harbor 连接
Docker login/push 处理流程:
```
1. docker login 127.0.0.1:8080
├── 尝试 HTTP 连接
├── 收到 308 重定向到 HTTPS
└── 自动切换到 HTTPS 8443
2. docker push 127.0.0.1:8080/ljwx/xxx
├── 尝试 HTTP 连接
├── 收到 308 重定向到 HTTPS
└── 自动切换到 HTTPS 8443
```
### 镜像标签
每个镜像生成两个标签:
- 版本标签: `127.0.0.1:8080/ljwx/ljwx-mysql:2.0.3`
- latest 标签: `127.0.0.1:8080/ljwx/ljwx-mysql:latest`
## 📊 Harbor 管理
### 访问 Harbor Web UI
```bash
# 1. 访问
open http://127.0.0.1:8080
# 2. 登录
Username: admin
Password: admin123
# 3. 查看镜像
进入 "ljwx" 项目 → 查看仓库列表
```
### 使用 API 管理
```bash
# 列出所有仓库
curl -u admin:admin123 http://127.0.0.1:8080/api/v2.0/projects/ljwx/repositories
# 列出镜像标签
curl -u admin:admin123 \
http://127.0.0.1:8080/api/v2.0/projects/ljwx/repositories/ljwx-mysql/artifacts
# 检查健康状态
curl -L http://127.0.0.1:8080/api/v2.0/health
```
### 拉取镜像
```bash
# 从 Harbor 拉取镜像
docker pull 127.0.0.1:8080/ljwx/ljwx-mysql:2.0.3
# 拉取 latest
docker pull 127.0.0.1:8080/ljwx/ljwx-mysql:latest
```
## 🛠️ 常见问题
### 问题 1: 代理不工作
**症状**: docker pull mysql:8.0 很慢或超时
**解决方案**:
```bash
# 1. 检查代理
lsof -i :7890
# 2. 测试代理
curl --proxy http://127.0.0.1:7890 https://www.google.com
# 3. 手动设置代理
export HTTP_PROXY=http://127.0.0.1:7890
export HTTPS_PROXY=http://127.0.0.1:7890
```
### 问题 2: Harbor 连接被拒绝
**症状**: connect: connection refused
**解决方案**:
```bash
# 1. 检查 Harbor 是否运行
cd ~/work/codes/tools/macos/harbor
docker-compose ps
# 2. 启动 Harbor
docker-compose up -d
# 3. 等待启动完成
sleep 30
# 4. 测试连接
curl -L http://127.0.0.1:8080/api/v2.0/health
```
### 问题 3: 登录失败
**症状**: unauthorized
**解决方案**:
```bash
# 重新登录
docker login 127.0.0.1:8080
Username: admin
Password: admin123
```
### 问题 4: 推送失败
**症状**: denied: requested access to the resource is denied
**解决方案**:
```bash
# 1. 检查项目是否存在
curl -u admin:admin123 http://127.0.0.1:8080/api/v2.0/projects/ljwx
# 2. 如果不存在,创建项目
# 访问 http://127.0.0.1:8080
# Projects → New Project → Name: ljwx, Public: Yes
# 3. 重新推送
docker push 127.0.0.1:8080/ljwx/ljwx-mysql:2.0.3
```
## 📝 检查清单
构建前检查:
```bash
# ✅ OrbStack 运行
ps aux | grep OrbStack
# ✅ Harbor 运行
cd ~/work/codes/tools/macos/harbor && docker-compose ps | grep healthy
# ✅ 代理运行
lsof -i :7890
# ✅ Docker 登录
docker login 127.0.0.1:8080
# ✅ 测试拉取
docker pull mysql:8.0
# ✅ 开始构建
./build-and-push.sh mysql
```
## 🎯 下一步
1. **构建所有镜像**:
```bash
./build-and-push.sh all
```
2. **部署到生产环境**:
```bash
# 在生产服务器上拉取镜像
docker pull 127.0.0.1:8080/ljwx/ljwx-boot:2.0.3
docker pull 127.0.0.1:8080/ljwx/ljwx-admin:2.0.3
docker pull 127.0.0.1:8080/ljwx/ljwx-bigscreen:2.0.3
```
3. **使用 docker-compose 部署**:
```bash
# 更新 docker-compose.yml 中的镜像地址
# image: 127.0.0.1:8080/ljwx/ljwx-boot:2.0.3
docker-compose up -d
```
## 📚 相关文档
- [BUILD_WITH_HARBOR.md](./BUILD_WITH_HARBOR.md) - Harbor 详细指南
- [PROXY_CONFIG.md](./PROXY_CONFIG.md) - 代理配置详解
- [ORBSTACK_CONFIG.md](./ORBSTACK_CONFIG.md) - OrbStack 配置说明
- [DOCKER_README.md](./DOCKER_README.md) - Docker Compose 使用指南
---
**最后更新**: 2025-11-26
**版本**: 1.0.0
**状态**: ✅ 已验证可用
-202
View File
@@ -1,202 +0,0 @@
# 🎉 Jenkins 自动化配置部署成功!
## 部署摘要
✅ **Jenkins 自动化配置已成功部署并运行正常**
- 📍 **Jenkins 访问地址**: http://localhost:8081
- 🔐 **登录信息**: admin / admin123
- 🐳 **容器状态**: 健康运行中
- 📊 **存储使用**: 3% (良好)
- 🔗 **服务集成**: Registry(35001) + Gitea(192.168.1.6:3000)
## 🚀 已完成的自动化配置
### 核心功能
- ✅ **完全跳过设置向导** - 无需手动配置
- ✅ **管理员用户自动创建** - admin/admin123
- ✅ **Configuration as Code** - 配置文件化管理
- ✅ **Docker 集成** - 完整的 Docker 支持
- ✅ **多平台构建支持** - linux/amd64, linux/arm64
### 环境集成
- ✅ **Registry 集成** - localhost:35001 (已测试连通)
- ✅ **Gitea 集成** - http://192.168.1.6:3000 (配置就绪)
- ✅ **网络配置** - 使用现有 cicd-network
- ✅ **凭据模板** - Docker Registry 和 Gitea API Token
### 预置作业
- ✅ **hello-world-demo** - 验证环境配置的示例作业
- ✅ **环境检查** - 自动检测 Registry 和 Gitea 连接状态
- ✅ **Docker 版本检查** - 验证 Docker 集成正常
## 🛠️ 管理命令
使用 `./jenkins-quick-manager.sh` 进行日常管理:
```bash
# 基础管理
./jenkins-quick-manager.sh start # 启动服务
./jenkins-quick-manager.sh stop # 停止服务
./jenkins-quick-manager.sh restart # 重启服务
./jenkins-quick-manager.sh status # 查看状态
# 监控和维护
./jenkins-quick-manager.sh health # 健康检查
./jenkins-quick-manager.sh logs # 查看日志
./jenkins-quick-manager.sh backup # 备份配置
./jenkins-quick-manager.sh test # 测试说明
```
## 📋 下一步操作
### 1. 验证自动化配置
1. 访问 http://localhost:8081
2. 使用 admin/admin123 登录
3. 运行 `hello-world-demo` 作业
4. 检查作业输出确认环境正常
### 2. 完善集成配置
1. **Gitea Token**: 在 Gitea 中生成 Personal Access Token
- 访问 Gitea → Settings → Applications → Generate New Token
- 在 Jenkins 中更新 `gitea-api-token` 凭据
2. **Registry 认证**: 如需自定义 Registry 认证
- 在 Jenkins 中更新 `docker-registry-auth` 凭据
### 3. 创建第一个 CI/CD 流水线
1. 在 Jenkins 中创建新的 Pipeline 作业
2. 使用预配置的环境变量:
- `DOCKER_REGISTRY`: localhost:35001
- `GITEA_URL`: http://192.168.1.6:3000
- `BUILD_PLATFORMS`: linux/amd64,linux/arm64
## 🏗️ 示例 Pipeline 模板
```groovy
pipeline {
agent any
environment {
IMAGE_NAME = "${env.JOB_NAME.toLowerCase()}"
IMAGE_TAG = "${env.BUILD_NUMBER}"
FULL_IMAGE = "${env.DOCKER_REGISTRY}/${env.IMAGE_NAME}:${env.IMAGE_TAG}"
}
stages {
stage('检出代码') {
steps {
// 使用 Gitea 仓库
git branch: 'main',
url: "${env.GITEA_URL}/your-project.git",
credentialsId: 'gitea-api-token'
}
}
stage('构建应用') {
steps {
sh 'echo "构建你的应用..."'
// 添加你的构建步骤
}
}
stage('构建 Docker 镜像') {
steps {
sh """
docker build -t ${env.FULL_IMAGE} .
docker push ${env.FULL_IMAGE}
"""
}
}
stage('多平台构建') {
steps {
sh """
docker buildx build \\
--platform ${env.BUILD_PLATFORMS} \\
--tag ${env.FULL_IMAGE} \\
--push .
"""
}
}
}
post {
always {
cleanWs()
}
success {
echo "✅ 构建成功: ${env.FULL_IMAGE}"
}
}
}
```
## 📁 配置文件位置
- **Docker Compose**: `docker/compose/jenkins-quick.yml`
- **CasC 配置**: `docker/compose/jenkins/casc/jenkins.yaml`
- **管理脚本**: `jenkins-quick-manager.sh`
- **数据卷**: `compose_jenkins-quick-data`
## 🔧 自定义配置
### 修改 CasC 配置
编辑 `docker/compose/jenkins/casc/jenkins.yaml` 文件,然后:
```bash
./jenkins-quick-manager.sh restart
```
### 添加插件
在 CasC 配置中添加插件,或通过 Jenkins UI 安装后导出配置。
### 扩展环境变量
在 CasC 配置的 `globalNodeProperties` 部分添加新的环境变量。
## 🚨 故障排除
### Jenkins 无法启动
```bash
# 查看日志
./jenkins-quick-manager.sh logs
# 检查容器状态
docker ps -a | grep jenkins-quick
```
### 配置未生效
```bash
# 检查配置文件挂载
docker exec jenkins-quick ls -la /var/jenkins_home/casc_configs
# 重启服务重新加载配置
./jenkins-quick-manager.sh restart
```
### 网络连接问题
```bash
# 检查网络
docker network ls | grep cicd-network
# 测试服务连接
./jenkins-quick-manager.sh status
```
## 🎯 性能优化建议
1. **内存设置**: 根据使用情况调整 `JAVA_OPTS` 中的 `-Xmx` 参数
2. **执行器数量**: 在 CasC 中调整 `numExecutors` 数值
3. **定期备份**: 设置定时任务执行 `./jenkins-quick-manager.sh backup`
4. **日志清理**: 配置日志轮转和清理策略
## 🎊 恭喜!
你现在拥有一个完全自动化配置的 Jenkins CI/CD 环境,具备:
- ⚡ **零配置启动** - 开箱即用
- 🔧 **完整工具链** - Docker + Git + 多平台构建
- 🔗 **服务集成** - Registry + Gitea 无缝集成
- 📊 **健康监控** - 自动健康检查和状态监控
- 💾 **配置管理** - Configuration as Code 便于维护
**立即开始使用你的自动化 CI/CD 流水线吧!**
-234
View File
@@ -1,234 +0,0 @@
# 🎉 LJWX Jenkins 完全自动化部署完成!
## ✅ 部署成功状态
### 核心服务
- **Jenkins**: http://localhost:8081 (148个插件预装)
- **Registry**: http://localhost:5001 (镜像仓库)
- **初始密码**: `3a64e5b9c5064ec3ae86f16adee542bb`
### 自动化配置成果
- ✅ **148个插件**自动安装完成
- ✅ **Docker镜像**构建并推送到Registry成功
- ✅ **完整持久化**配置,数据永不丢失
- ✅ **多语言支持**准备就绪(Java, Vue3, Python)
## 🚀 立即开始使用
### 1. 登录Jenkins
```bash
# 访问地址
http://localhost:8081
# 登录凭据
初始密码: 3a64e5b9c5064ec3ae86f16adee542bb
```
### 2. 完成初始设置
1. 使用初始密码登录
2. **跳过插件安装** (148个插件已预装)
3. 创建管理员用户: `admin / admin123`
4. 保存并完成设置
### 3. 关键功能已就绪
- **Pipeline工作流**: 完整CI/CD支持
- **Git集成**: 代码管理和Webhook
- **Docker支持**: 容器构建和推送
- **多语言工具**: Maven, Gradle, NodeJS
- **代码质量**: JUnit, 静态分析
- **现代UI**: BlueOcean界面
## 📋 CI/CD Pipeline配置
### Java SpringBoot项目
```groovy
pipeline {
agent any
stages {
stage('Checkout') {
steps { git url: 'http://gitea:3000/user/java-project.git' }
}
stage('Build') {
steps { sh 'mvn clean package' }
}
stage('Docker Build') {
steps {
sh '''
docker build -t localhost:5001/java-app:${BUILD_NUMBER} .
docker push localhost:5001/java-app:${BUILD_NUMBER}
'''
}
}
stage('Deploy') {
steps {
sh 'kubectl set image deployment/java-app java-app=localhost:5001/java-app:${BUILD_NUMBER}'
}
}
}
}
```
### Vue3前端项目
```groovy
pipeline {
agent any
stages {
stage('Checkout') {
steps { git url: 'http://gitea:3000/user/vue3-project.git' }
}
stage('Install & Build') {
steps {
sh 'npm install'
sh 'npm run build'
}
}
stage('Docker Build') {
steps {
sh '''
docker build -t localhost:5001/vue3-app:${BUILD_NUMBER} .
docker push localhost:5001/vue3-app:${BUILD_NUMBER}
'''
}
}
}
}
```
### Python FastAPI项目
```groovy
pipeline {
agent any
stages {
stage('Checkout') {
steps { git url: 'http://gitea:3000/user/python-project.git' }
}
stage('Test') {
steps {
sh 'pip install -r requirements.txt'
sh 'pytest'
}
}
stage('Docker Build') {
steps {
sh '''
docker build -t localhost:5001/python-app:${BUILD_NUMBER} .
docker push localhost:5001/python-app:${BUILD_NUMBER}
'''
}
}
}
}
```
## 🔗 Gitea Webhook配置
### 配置步骤
1. 在Gitea项目中进入 **Settings → Webhooks**
2. 添加Webhook URL:
```
http://localhost:8081/generic-webhook-trigger/invoke?token=YOUR-PROJECT-TOKEN
```
3. 选择触发事件: **Push events**
4. 保存配置
### 触发流程
```
Git Push → Gitea Webhook → Jenkins Pipeline → Docker Build → Registry Push → K8s Deploy
```
## 🛠️ 凭据管理配置
### 必要凭据
在Jenkins中配置以下凭据:
#### 1. Gitea凭据
- **类型**: Username with password
- **ID**: `gitea-credentials`
- **用户名**: Gitea用户名
- **密码**: Gitea密码或Personal Access Token
#### 2. Docker Registry凭据
- **类型**: Username with password
- **ID**: `docker-registry-auth`
- **用户名**: `admin`
- **密码**: `admin123`
#### 3. Kubernetes凭据
- **类型**: Secret text
- **ID**: `k8s-config`
- **内容**: Kubernetes配置文件内容
## 📦 镜像管理
### 查看Registry中的镜像
```bash
# 查看所有镜像
curl http://localhost:5001/v2/_catalog
# 查看ljwx-jenkins镜像标签
curl http://localhost:5001/v2/ljwx-jenkins/tags/list
```
### 使用ljwx-jenkins镜像
```bash
# 拉取镜像
docker pull localhost:5001/ljwx-jenkins:latest
# 运行镜像
docker run -d -p 8082:8080 localhost:5001/ljwx-jenkins:latest
```
## 🔧 日常管理
### 常用命令
```bash
# 查看容器状态
docker ps | grep ljwx
# 查看Jenkins日志
docker logs ljwx-jenkins -f
# 重启Jenkins
docker restart ljwx-jenkins
# 备份Jenkins数据
docker run --rm -v ljwx-jenkins-data:/data -v $(pwd):/backup alpine tar czf /backup/jenkins-backup-$(date +%Y%m%d).tar.gz -C /data .
# 停止所有服务
cd docker/compose && docker-compose -f ljwx-jenkins-basic.yml down
```
### 升级Jenkins
```bash
# 重新构建镜像
cd docker/compose && docker-compose -f ljwx-jenkins-basic.yml build --no-cache ljwx-jenkins
# 重新部署
docker-compose -f ljwx-jenkins-basic.yml up -d
```
## 📈 性能配置
### 当前配置
- **内存**: 2GB堆内存
- **垃圾回收**: G1GC
- **执行器**: 默认2个
- **插件**: 148个核心插件
### 优化建议
- 大型项目建议增加内存到4GB
- 可以通过Kubernetes动态扩展Agent
- 定期清理旧构建和工作空间
## ✨ 总结
LJWX Jenkins已经完全部署成功,具备:
- **🚀 开箱即用**: 148个插件预装,支持完整CI/CD流程
- **🐳 容器化部署**: Docker化部署,易于迁移和扩展
- **📦 镜像仓库**: 内置Registry,支持私有镜像管理
- **🔄 多语言支持**: Java, Vue3, Python完整工具链
- **🔐 安全配置**: 凭据管理,角色权限控制
- **📊 现代界面**: BlueOcean提供现代化CI/CD体验
现在可以立即开始构建强大的CI/CD流水线,支撑现代化应用开发!🎊
-351
View File
@@ -1,351 +0,0 @@
# OrbStack 全局配置指南
## 📋 配置概述
已为 OrbStack 配置全局设置,无需每次构建时手动设置代理和 Harbor 配置。
## ✅ 已完成的配置
### 配置文件位置
```
~/.orbstack/config/docker.json
```
### 配置内容
```json
{
"ipv6": true,
"insecure-registries": [
"127.0.0.1:8080",
"localhost:8080"
],
"proxies": {
"default": {
"httpProxy": "http://127.0.0.1:7890",
"httpsProxy": "http://127.0.0.1:7890",
"noProxy": "localhost,127.0.0.1,*.local,host.docker.internal"
}
}
}
```
### 配置说明
1. **insecure-registries**: 允许连接到本地 Harbor (127.0.0.1:8080)
2. **proxies**: 全局代理配置,自动使用 7890 端口代理
3. **ipv6**: 保持启用 IPv6 支持
## 🔧 IPv4 vs IPv6 问题
### 问题原因
当使用 `localhost:8080` 时,OrbStack 会优先尝试 IPv6 地址 `[::1]:8080`,但 Harbor 可能没有监听 IPv6,导致连接被拒绝。
### 解决方案
**使用 IPv4 地址 `127.0.0.1:8080` 而不是 `localhost:8080`**
```bash
# ❌ 错误 - 可能解析为 IPv6
REGISTRY=localhost:8080/ljwx
# ✅ 正确 - 强制使用 IPv4
REGISTRY=127.0.0.1:8080/ljwx
```
## 🚀 应用配置
### 重启 OrbStack
配置修改后需要重启 OrbStack 使其生效:
```bash
# 方法 1: 使用命令行
killall OrbStack
sleep 2
open -a OrbStack
# 方法 2: 手动操作
# 1. 退出 OrbStack (菜单栏 > OrbStack > Quit)
# 2. 重新启动 OrbStack
```
### 验证配置
```bash
# 1. 检查 Docker 配置
docker info | grep -A 5 "Insecure Registries"
# 应该看到:
# Insecure Registries:
# 127.0.0.1:8080
# localhost:8080
# 2. 检查代理配置
docker info | grep -i proxy
# 应该看到代理信息
```
### 测试连接
```bash
# 1. 测试 Harbor 连接
curl -L http://127.0.0.1:8080/api/v2.0/health
# 应该返回:
# {"status":"healthy",...}
# 2. 测试 Docker 登录
docker login 127.0.0.1:8080
# Username: admin
# Password: admin123
# 3. 测试代理拉取
docker pull mysql:8.0
# 应该很快完成,通过代理拉取
```
## 📦 构建流程
配置完成后,构建流程自动使用全局配置:
```bash
# 1. 重启 OrbStack(如果刚配置)
killall OrbStack && sleep 2 && open -a OrbStack
# 2. 等待 OrbStack 启动(约 10 秒)
sleep 10
# 3. 开始构建
./build-and-push.sh mysql
# 脚本会:
# ✅ 自动使用代理拉取基础镜像
# ✅ 自动登录 Harbor (127.0.0.1:8080)
# ✅ 自动推送到 Harbor
```
## 🔍 配置详解
### 1. insecure-registries
允许连接到不使用 HTTPS 的私有仓库:
```json
"insecure-registries": [
"127.0.0.1:8080", // IPv4 地址
"localhost:8080" // 主机名(可能解析为 IPv6)
]
```
### 2. proxies
全局代理配置,所有 Docker 操作自动使用代理:
```json
"proxies": {
"default": {
"httpProxy": "http://127.0.0.1:7890", // HTTP 代理
"httpsProxy": "http://127.0.0.1:7890", // HTTPS 代理
"noProxy": "localhost,127.0.0.1,*.local,host.docker.internal" // 不使用代理的地址
}
}
```
#### noProxy 说明
- `localhost` - 本地主机名
- `127.0.0.1` - 本地 IPv4 地址
- `*.local` - 本地域名
- `host.docker.internal` - Docker 内部主机地址
这些地址不会使用代理,确保本地服务(如 Harbor)的连接不经过代理。
### 3. ipv6
保持启用 IPv6 支持:
```json
"ipv6": true
```
虽然启用了 IPv6,但通过使用 `127.0.0.1` 而不是 `localhost`,可以强制使用 IPv4 连接。
## 🛠️ 故障排查
### 问题 1: 配置未生效
**症状**:
```bash
docker info | grep -i proxy
# 没有代理信息
```
**解决方案**:
```bash
# 1. 检查配置文件是否正确
cat ~/.orbstack/config/docker.json
# 2. 确保 JSON 格式正确(无语法错误)
python3 -m json.tool ~/.orbstack/config/docker.json
# 3. 重启 OrbStack
killall OrbStack
sleep 2
open -a OrbStack
```
### 问题 2: Harbor 连接仍然失败
**症状**:
```
dial tcp [::1]:8080: connect: connection refused
```
**解决方案**:
```bash
# 1. 确认使用 IPv4 地址
echo $HARBOR_HOST
# 应该是: 127.0.0.1:8080
# 2. 检查 Harbor 监听地址
cd ~/work/codes/tools/macos/harbor
docker-compose ps | grep nginx
# 应该看到: 0.0.0.0:8080->8080/tcp
# 3. 测试直接连接
telnet 127.0.0.1 8080
# 应该能连接
```
### 问题 3: 代理不工作
**症状**:
```
docker pull mysql:8.0
# 超时或很慢
```
**解决方案**:
```bash
# 1. 检查代理服务
lsof -i :7890
# 应该看到代理进程
# 2. 测试代理
curl --proxy http://127.0.0.1:7890 https://registry-1.docker.io/v2/
# 3. 检查 Docker 代理配置
docker info | grep -i proxy
# 4. 重启 OrbStack
killall OrbStack && sleep 2 && open -a OrbStack
```
### 问题 4: 推送到 Harbor 失败
**症状**:
```
unauthorized: authentication required
```
**解决方案**:
```bash
# 1. 登录 Harbor
docker login 127.0.0.1:8080
# Username: admin
# Password: admin123
# 2. 检查凭证
cat ~/.docker/config.json | grep 127.0.0.1:8080
# 3. 在 Harbor 中创建 ljwx 项目
# 访问 http://127.0.0.1:8080
# 登录后创建名为 "ljwx" 的项目(公开)
```
## 📝 Harbor 项目配置
### 创建项目
1. 访问 Harbor: http://127.0.0.1:8080
2. 登录: admin / admin123
3. 点击 "Projects" > "New Project"
4. 填写项目信息:
- **Project Name**: ljwx
- **Access Level**: Public
- **Storage Quota**: -1 (无限制)
5. 点击 "OK" 创建
### 检查项目
```bash
# 使用 API 检查项目
curl -u admin:admin123 http://127.0.0.1:8080/api/v2.0/projects/ljwx
# 应该返回项目信息
```
## 💡 最佳实践
### 1. 配置检查清单
在构建前检查:
```bash
# ✅ OrbStack 运行中
ps aux | grep OrbStack
# ✅ 配置文件正确
cat ~/.orbstack/config/docker.json | python3 -m json.tool
# ✅ 代理服务运行
lsof -i :7890
# ✅ Harbor 服务运行
curl -L http://127.0.0.1:8080/api/v2.0/health
# ✅ Docker 登录
docker login 127.0.0.1:8080
# ✅ ljwx 项目存在
curl -u admin:admin123 http://127.0.0.1:8080/api/v2.0/projects/ljwx
```
### 2. 日常使用
```bash
# 直接构建,无需设置环境变量
./build-and-push.sh mysql
# 脚本会自动:
# - 使用全局代理配置
# - 登录 Harbor
# - 推送到 127.0.0.1:8080/ljwx
```
### 3. 临时禁用代理
如果需要临时禁用代理:
```bash
# 方法 1: 使用环境变量覆盖
HTTP_PROXY="" HTTPS_PROXY="" ./build-and-push.sh mysql
# 方法 2: 修改 noProxy
# 编辑 ~/.orbstack/config/docker.json
# 添加 Docker Hub 到 noProxy 列表
```
## 🔗 相关文档
- [BUILD_WITH_HARBOR.md](./BUILD_WITH_HARBOR.md) - Harbor 构建指南
- [PROXY_CONFIG.md](./PROXY_CONFIG.md) - 代理配置详解
- [DOCKER_README.md](./DOCKER_README.md) - Docker Compose 使用指南
---
**最后更新**: 2025-11-26
**版本**: 1.0.0
-222
View File
@@ -1,222 +0,0 @@
# OrbStack配置指南 - 移除国内镜像源
## 🎯 目标
- 移除所有国内Docker镜像源
- 配置使用原生Docker Hub
- 支持私有GitLab Registry
- 优化网络连接
## ✅ 已完成配置
### 1. Docker Daemon配置 (`~/.docker/daemon.json`)
```json
{
"experimental": true,
"features": {
"buildkit": true
},
"insecure-registries": [
"localhost:5001"
]
}
```
### 2. OrbStack配置 (`~/.orbstack/config/docker.json`)
```json
{
"builder" : {
"gc" : {
"defaultKeepStorage" : "20GB",
"enabled" : true
}
},
"insecure-registries" : [
"192.168.1.83:5002",
"localhost:5001"
],
"ipv6" : true,
"experimental" : false
}
```
### 3. Jenkins配置更新
- 移除了国内镜像加速: `JENKINS_UC_DOWNLOAD`
- 配置使用官方更新源
## 🔧 网络问题解决方案
### ✅ 已解决:DNS解析问题
通过修改hosts文件解决Docker Registry DNS解析问题:
```bash
# 运行修复脚本
chmod +x deployment/scripts/docker-hosts-fix.sh
./deployment/scripts/docker-hosts-fix.sh
```
**修复内容:**
- 阻止Grammarly证书劫持: `127.0.0.1 iosapp-beta.grammarly.com`
- 添加Docker Registry解析: `54.87.120.168 registry-1.docker.io`
- 添加认证服务解析: `54.87.120.168 auth.docker.io`
### ExpressVPN TLS证书问题
如果遇到TLS证书错误,可以:
1. **使用hosts文件修复** (推荐)
```bash
./deployment/scripts/docker-hosts-fix.sh
```
2. **配置Docker使用特定DNS**
```bash
# 在 ~/.orbstack/config/docker.json 中添加
{
"dns": ["8.8.8.8", "1.1.1.1"]
}
```
3. **ExpressVPN设置优化**
- 选择美国洛杉矶服务器
- 禁用"阻止WebRTC"功能
- 使用"Automatic"协议而非"OpenVPN"
## 🚀 验证步骤
### 1. 检查配置状态
```bash
# 检查Docker info,应该没有Registry Mirrors
docker info | grep -A3 "Registry Mirrors"
# 检查DNS解析
nslookup docker.io
```
### 2. 测试镜像拉取
```bash
# 测试小镜像
docker pull hello-world:latest
# 测试常用镜像
docker pull alpine:latest
docker pull nginx:latest
```
### 3. 本地Registry测试
```bash
# 启动本地Registry
cd /Users/brunogao/work/infra
docker-compose -f docker/compose/jenkins-compose.yml up -d registry
# 测试推送
docker tag alpine:latest localhost:5001/alpine:test
docker push localhost:5001/alpine:test
```
## 📝 GitLab Registry配置
### 1. 配置GitLab认证
```bash
# 登录GitLab Registry
docker login gitlab.example.com:5050
# 输入用户名和Personal Access Token
```
### 2. 推送到GitLab
```bash
# 标记镜像
docker tag my-app:latest gitlab.example.com:5050/group/project/my-app:latest
# 推送镜像
docker push gitlab.example.com:5050/group/project/my-app:latest
```
## 🛠️ 故障排除
### 问题1: DNS解析失败
```bash
# 解决方案:更新DNS设置
sudo networksetup -setdnsservers Wi-Fi 8.8.8.8 1.1.1.1
```
### 问题2: TLS证书错误
```bash
# 临时解决:重启ExpressVPN
# 或切换到其他美国服务器节点
```
### 问题3: 镜像拉取慢
```bash
# 检查网络延迟
ping registry-1.docker.io
# 使用CDN加速(仅限官方)
export DOCKER_REGISTRY_MIRROR=""
```
## 🎭 性能优化建议
### 1. 构建缓存优化
```dockerfile
# 多阶段构建
FROM node:18-alpine AS builder
# ... 构建步骤
FROM nginx:alpine AS runtime
COPY --from=builder /app/dist /usr/share/nginx/html
```
### 2. 镜像大小优化
```bash
# 使用.dockerignore
echo "node_modules" >> .dockerignore
echo ".git" >> .dockerignore
# 清理构建缓存
docker system prune -af --volumes
```
### 3. Registry策略
- 本地开发: `localhost:5001`
- CI/CD: GitLab Registry
- 生产: 私有Registry或Docker Hub
## 📊 监控和维护
### 定期检查
```bash
# 检查镜像大小
docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}"
# 清理无用镜像
docker image prune -af
# 检查网络配置
docker network ls
```
### 自动化脚本
使用 `deployment/scripts/orbstack-config.sh` 进行定期检查和维护。
## ✨ 下一步计划
1. **配置GitLab CI/CD**
- 创建`.gitlab-ci.yml`
- 配置Runner
2. **设置监控**
- Registry使用情况
- 构建性能指标
3. **安全增强**
- 镜像扫描
- 漏洞检测
---
## 📞 支持
如遇问题:
1. 检查ExpressVPN连接状态
2. 验证DNS解析
3. 查看Docker日志: `docker logs <container>`
4. 运行诊断脚本: `./deployment/scripts/orbstack-config.sh`
+57 -457
View File
@@ -1,257 +1,3 @@
<<<<<<< HEAD
# Mac Studio M2 企业级 CI/CD 基础设施
## 🚀 完全自动化部署 - 已验证可用 ✅
这是一套完整的企业级CI/CD基础设施,专为Mac Studio M2环境优化,支持**一键自动化部署**,无需手动配置。
### ⚡ 快速开始
```bash
# 一键自动化部署所有服务
./build-infra.sh --full-auto
# 分步骤部署(逐步确认)
./build-infra.sh --step-by-step
# 验证现有服务
./build-infra.sh --verify
```
### 🌐 服务访问地址
部署完成后,通过以下地址访问服务:
| 服务 | 地址 | 用途 | 默认账号 |
|------|------|------|----------|
| **Gitea** | http://localhost:33000 | Git代码仓库 + Actions | 需要初始化 |
| **Jenkins** | http://localhost:38080 | CI/CD平台 | admin / admin123 |
| **Registry** | http://localhost:35001 | Docker镜像仓库 | 无认证 |
| **Registry UI** | http://localhost:35002 | 镜像管理界面 | 无认证 |
**SSH访问:**
```bash
# Gitea SSH克隆 (端口32222)
git clone ssh://git@localhost:32222/username/repository.git
```
### 🎯 核心特性
- ✅ **一键部署**: 完全自动化,15分钟内完成所有配置
- ✅ **端口优化**: 统一使用3开头端口,避免冲突
- ✅ **多平台构建**: 支持 linux/amd64 + linux/arm64
- ✅ **Configuration as Code**: Jenkins零手动配置
- ✅ **企业级功能**: 完整的CI/CD流水线支持
- ✅ **健康监控**: 自动化服务状态检查
- ✅ **数据持久化**: 所有数据自动备份和恢复
### 📋 端口分配
```
服务端口分配(避免冲突):
├── Gitea: 33000 (Web) + 32222 (SSH)
├── Jenkins: 38080 (Web) + 35000 (Agent)
├── Docker Registry: 35001 (API) + 35002 (UI)
└── 预留监控端口: 37001+ (Prometheus等)
```
### 🏗️ 架构组件
**核心服务:**
- **Jenkins LTS**: CI/CD服务器,基于JDK21
- **Gitea 1.21**: 轻量级Git服务,支持Actions
- **Docker Registry**: 本地镜像仓库
- **Registry UI**: 可视化镜像管理
**环境信息:**
- **硬件**: Mac Studio M2 Ultra (24核CPU, 76核GPU, 192GB内存)
- **系统**: macOS Sequoia 15.7
- **容器**: Docker Desktop + OrbStack优化
- **网络**: 统一cicd-network网络
### 📂 项目结构
```
infra/
├── build-infra.sh # 🌟 一键部署脚本
├── configs/
│ └── global.env # 统一环境配置
├── docker/compose/ # Docker编排配置
│ ├── gitea-compose.yml # Gitea服务
│ ├── jenkins-simple.yml # Jenkins服务
│ └── registry-simple.yml # Registry服务
├── jenkins/
│ ├── casc/jenkins.yaml # Jenkins自动配置
│ ├── shared-library/ # Pipeline共享库
│ └── templates/ # 项目模板
├── scripts/
│ ├── maintenance/ # 维护脚本
│ └── utils/ # 工具脚本
└── docs/ # 文档
```
### 🔧 管理命令
```bash
# 部署管理
./build-infra.sh --full-auto # 完全自动化部署 (推荐)
./build-infra.sh --step-by-step # 分步骤部署
./build-infra.sh --cleanup # 清理所有服务
./build-infra.sh --verify # 验证服务状态
# 日常维护
./scripts/maintenance/health-check.sh # 健康检查
./scripts/utils/show-logs.sh [service] # 查看日志
# 传统管理脚本 (保留兼容)
./jenkins-manager.sh [status|start|stop|backup|health]
```
### 🚀 CI/CD功能特性
#### Jenkins自动配置 (CasC)
- ✅ **50+插件自动安装**: Docker, Gitea, Pipeline, 多平台构建等
- ✅ **工具自动配置**: Git, Maven, Gradle, NodeJS, Docker, Python
- ✅ **凭据模板**: Gitea, Registry, SSH凭据预配置
- ✅ **云配置**: Docker和Kubernetes云支持
- ✅ **示例作业**: 多平台构建和系统监控作业
#### 多平台构建支持
```groovy
// 自动支持的构建平台
pipeline {
environment {
PLATFORMS = 'linux/amd64,linux/arm64'
REGISTRY = 'localhost:35001'
}
stages {
stage('多平台构建') {
steps {
buildMultiPlatformImage([
imageName: "${REGISTRY}/app:${BUILD_NUMBER}",
platforms: env.PLATFORMS
])
}
}
}
}
```
### 📊 部署验证
部署完成后,系统会自动验证:
- ✅ **容器状态**: 所有服务容器正常运行
- ✅ **端口监听**: 所有端口正确绑定
- ✅ **API响应**: 所有服务API正常响应
- ✅ **健康检查**: Gitea和Registry健康检查通过
- ✅ **Web界面**: 所有Web界面可正常访问
### 🛠️ 故障排查
#### 常见问题
**端口占用:**
```bash
# 检查端口占用
lsof -i :33000,38080,35001,35002
# 清理并重新部署
./build-infra.sh --cleanup
./build-infra.sh --full-auto
```
**服务启动失败:**
```bash
# 查看服务日志
./scripts/utils/show-logs.sh [gitea|jenkins|registry|all]
# 健康检查
./scripts/maintenance/health-check.sh
```
**配置修改:**
- 主配置文件: `configs/global.env`
- Jenkins配置: `docker/compose/jenkins/casc/jenkins.yaml`
- 修改后重新部署生效
### 💡 最佳实践
#### CI/CD流程
1. **代码管理**: 在Gitea中创建仓库和组织
2. **Pipeline配置**: 使用预置模板快速创建
3. **多平台构建**: 自动支持AMD64和ARM64
4. **镜像管理**: Registry UI可视化管理镜像
#### 维护建议
- **定期备份**: 使用内置备份脚本
- **健康监控**: 定期运行健康检查
- **更新管理**: 定期更新Docker镜像
- **日志管理**: 定期清理服务日志
### 📈 性能优化
**资源配置优化:**
- Jenkins JVM: `-Xmx2g -Xms1g`
- 构建并发: 支持多个并行构建
- 镜像缓存: 本地Registry加速构建
- 网络优化: 统一Docker网络提高通信效率
### 🔄 升级和扩展
#### 监控扩展 (预留)
```bash
# 监控服务端口预留
PROMETHEUS_PORT=37001
GRAFANA_PORT=37002
```
#### Kubernetes集成
- Jenkins Kubernetes插件已预配置
- 支持K8s动态Agent
- 多环境部署支持
### 📞 技术支持
- **快速开始**: 查看 `QUICK_START.md`
- **详细规划**: 查看 `BUILD_PLAN.md`
- **配置说明**: 查看 `CLAUDE.md`
- **问题排查**: 查看 `docs/troubleshooting.md`
### 🎉 版本信息
- **当前版本**: v2.0 (统一端口版本)
- **Jenkins版本**: LTS (JDK21)
- **Gitea版本**: 1.21
- **Registry版本**: 2.x
- **最后更新**: 2025-01-23
### 📄 许可证
MIT License
---
## 🚀 立即开始
```bash
# 克隆项目
git clone <your-repo-url>
cd infra
# 一键部署所有服务
./build-infra.sh --full-auto
# 访问服务
open http://localhost:33000 # Gitea
open http://localhost:38080 # Jenkins (admin/admin123)
open http://localhost:35002 # Registry UI
```
**部署时间**: 约10-15分钟
**服务数量**: 4个核心服务
**支持平台**: Mac Studio M2 + Docker Desktop
=======
# 灵境万象健康管理系统 (LJWX)
![Version](https://img.shields.io/badge/Version-1.3.8-blue.svg)
@@ -260,16 +6,16 @@ open http://localhost:35002 # Registry UI
## 📋 项目概述
灵境万象健康管理系统(LJWX)是一套完整的企业级健康监测解决方案,专为工业环境下的可穿戴设备健康数据监控而设计。系统集成了数据采集、实时分析、智能告警、可视化大屏等功能模块,为企业提供全方位的员工健康安全保障。
灵境万象健康管理系统(LJWX)是一套完整的企业级健康监测解决方案,专为工业环境下的可穿戴设备健康数据监控而设计。系统集成了数据采集、实时分析、智能告警、可视化大屏等功能模块,为企业提供全方位的员工健康安全保障。
### 🎯 核心特性
- **🏥 健康数据监控**: 实时采集心率、血压、体温、运动数据等多维度健康指标
- **🚨 智能告警系统**: 多租户告警规则管理,支持微信、消息、大屏推送
- **📊 可视化大屏**: 专业级监控大屏,实时展示健康状态和告警信息
- **📱 移动端应用**: Flutter开发的移动APP,支持数据查看和设备管理
- **🚨 智能告警系统**: 多租户告警规则管理,支持微信、消息、大屏推送
- **📊 可视化大屏**: 专业级监控大屏,实时展示健康状态和告警信息
- **📱 移动端应用**: Flutter开发的移动APP,支持数据查看和设备管理
- **⌚ 智能手表集成**: 支持华为Watch4等智能穿戴设备数据采集
- **🏢 多租户架构**: 企业级权限管理,支持租户隔离和告警规则隔离
- **🏢 多租户架构**: 企业级权限管理,支持租户隔离和告警规则隔离
## 🏗️ 系统架构
@@ -338,12 +84,12 @@ open http://localhost:35002 # Registry UI
#### **Excel导出功能完善**
- **导出故障修复**: 修复health_table.html中Excel导出无错误日志的问题
- **XLSX库路径修复**: 解决Flask静态文件路径配置导致的XLSX库加载失败
- **增强错误处理**: 添加详细的调试日志和错误提示,提升用户体验
- **增强错误处理**: 添加详细的调试日志和错误提示,提升用户体验
- **CDN备用机制**: 实现本地XLSX库失败时的CDN自动降级加载
#### **自定义弹窗系统**
- **统一弹窗组件**: 创建可复用的`showCustomAlert`组件替代原生alert
- **视觉效果升级**: 科技感弹窗设计,支持键盘快捷键(ESC、Enter)
- **视觉效果升级**: 科技感弹窗设计,支持键盘快捷键(ESC、Enter)
- **模块化设计**: 提取为独立的`custom-alert.js`文件供全局复用
- **增强功能**: 支持确认框、回调函数、动画效果
@@ -351,27 +97,7 @@ open http://localhost:35002 # Registry UI
- **路径问题诊断**: 发现并修复静态文件错误放置在`/bigScreen/static/`的问题
- **Flask配置确认**: 验证`static_folder='../static'`指向正确的`/bigscreen/static/`
- **CDN文件迁移**: 将Bootstrap、FontAwesome、ECharts等离线CDN文件移至正确位置
- **重复文件清理**: 删除错误位置的重复文件,避免开发者混淆
```bash
# 修复前的问题路径结构
/bigscreen/bigScreen/static/ # ❌ 错误位置 - Flask无法访问
├── css/bootstrap-5.1.3.min.css
├── js/echarts.min.js
└── js/xlsx-0.18.5.full.min.js
# 修复后的正确路径结构
/bigscreen/static/ # ✅ 正确位置 - Flask可以访问
├── css/bootstrap-5.1.3.min.css
├── js/echarts.min.js
└── js/xlsx-0.18.5.full.min.js
```
#### **技术改进详情**
- **依赖库完整性**: 确保所有CDN离线文件在正确位置并可被Flask访问
- **版本同步更新**: 使用最新版本的ECharts (1MB+) 替换旧版本 (700KB)
- **开发体验优化**: 清理重复文件,建立清晰的静态文件组织结构
- **系统稳定性**: 解决Excel导出"导出失败,请重试"无具体错误信息的问题
- **重复文件清理**: 删除错误位置的重复文件,避免开发者混淆
---
@@ -380,146 +106,13 @@ open http://localhost:35002 # Registry UI
### 🔧 多租户告警规则系统实现 (2025-08-26)
#### **告警规则多租户隔离**
- **租户级规则隔离**: 实现告警规则基于 `customer_id` 的完全隔离,不同租户拥有独立的告警规则集
- **租户级规则隔离**: 实现告警规则基于 `customer_id` 的完全隔离,不同租户拥有独立的告警规则集
- **默认规则自动克隆**: 新建租户时自动从 `customer_id=0` 克隆默认告警规则
- **多级告警支持**: 支持同一健康指标配置多个告警级别(如心率120-140中级,140-160高级)
- **系统事件匹配**: 告警规则类型与手表系统事件完全匹配,支持直接规则匹配
#### **告警类型国际化支持**
- **英文键值系统**: 告警规则类型使用标准英文格式(如 `HEARTRATE_HIGH_ALERT`)
- **中文显示支持**: 通过数据字典实现英文→中文映射,前端显示用户友好的中文
- **完整映射体系**: 覆盖15种告警类型的完整中英文映射
- **专业化命名**: 与智能手表系统事件命名规范保持一致
#### **数据库优化**
```sql
-- 告警规则表新增字段
ALTER TABLE t_alert_rules ADD COLUMN customer_id BIGINT;
-- 支持多级告警的唯一约束
ALTER TABLE t_alert_rules ADD UNIQUE KEY uk_alert_multi_level
(rule_type, physical_sign, severity_level, customer_id);
-- 完整的告警类型字典映射
INSERT INTO sys_dict_item (dict_code, value, zh_cn, en_us) VALUES
('alert_type', 'HEARTRATE_HIGH_ALERT', '心率过高告警', 'HEARTRATE_HIGH_ALERT'),
('alert_type', 'SOS_EVENT', 'SOS紧急求助', 'SOS_EVENT');
```
#### **系统架构升级**
- **OrgUnitsChangeListener 扩展**: 新建租户时自动触发告警规则克隆
- **多租户数据隔离**: 查询、创建、更新、删除操作均基于租户ID过滤
- **Redis 缓存优化**: 告警规则缓存键支持租户级别隔离 `alert_rules_{customerId}`
- **前端上下文传递**: 管理界面自动传递当前用户的 `customerId`
- **多级告警支持**: 支持同一健康指标配置多个告警级别(如心率120-140中级,140-160高级)
- **系统事件匹配**: 告警规则类型与手表系统事件完全匹配,支持直接规则匹配
---
## 🚀 历史版本 v1.3.3
### 🔧 客户部署配置系统修复 (2025-08-20)
#### **端口配置动态化修复**
- **配置文件读取**: `generate-docker-compose.sh` 现在正确读取 `custom-config.env` 配置
- **端口配置灵活**: 支持客户完全自定义 MySQL、Redis、大屏等服务端口
- **镜像版本同步**: 自动从 `docker-compose.yml` 读取最新镜像版本标签
- **环境变量传递**: 确保所有自定义配置正确传递到生成的容器配置中
#### **修复前后对比**
```bash
# 修复前: 硬编码默认端口
ports:
- "3306:3306" # 固定MySQL端口
- "8001:8001" # 固定大屏端口
# 修复后: 动态配置端口
ports:
- "$MYSQL_PORT:3306" # 从custom-config.env读取
- "$BIGSCREEN_PORT:$APP_PORT" # 支持自定义端口映射
```
### 🐳 Docker构建系统优化修复 (2025-08-20)
#### **ljwx-boot Docker构建修复**
- **Maven镜像源优化**: 配置阿里云Maven镜像,解决`No route to host`网络连接问题
- **超时配置优化**: 增加Maven连接和读取超时时间,提高构建稳定性
- **多阶段构建**: 优化Dockerfile,支持ljwx-boot-starter依赖构建和主应用构建
- **网络连接修复**: 解决Docker构建环境中Maven依赖下载失败的问题
#### **技术改进详情**
```dockerfile
# 配置Maven阿里云镜像源
RUN mkdir -p /root/.m2 && \
echo '<settings>...<mirror>...<url>https://maven.aliyun.com/repository/public</url>...' > /root/.m2/settings.xml
# 增加超时配置
RUN mvn clean install -DskipTests -Dmaven.wagon.http.connectTimeout=60000 -Dmaven.wagon.http.readTimeout=120000
```
### 🔧 蓝牙健康数据上传修复 (2025-08-19)
#### **移动端数据传输优化**
- **数据结构简化**: 移除ljwx-phone上传健康数据最外层的data结构,直接传输核心数据
- **蓝牙传输稳定性**: 优化BLE数据包格式,提高传输成功率和稳定性
- **数据同步效率**: 简化数据封装层次,减少传输开销,提升同步速度
- **兼容性增强**: 确保手表端和服务端数据格式完全匹配,避免解析错误
### 📋 代码分析与文档完善 (2025-08-16)
#### **完整系统分析**
- **深度模块分析**: 完成所有5个模块的详细代码分析
- **技术架构文档**: 新增完整的系统功能模块清单文档
- **API接口梳理**: 详细整理各模块核心API和功能特性
- **性能指标确认**: 验证系统性能数据和技术参数
#### **技术文档体系**
- **[系统功能模块清单](./docs/系统功能模块清单.md)**: 109KB综合技术文档
- **模块功能清单**: ljwx-boot、ljwx-admin、ljwx-bigscreen、ljwx-phone、ljwx-watch
- **架构设计说明**: 详细的技术栈和系统架构分析
- **部署运维指南**: 完整的部署和监控方案
---
## 🚀 历史版本 v1.3.2
### ✨ 告警通知系统完整升级
#### **多渠道通知**
- **企业微信**: 支持企业微信应用消息推送
- **公众号微信**: 支持微信公众号模板消息
- **系统消息**: 内置消息系统,层级分发通知
- **大屏推送**: Critical级别告警实时推送到监控大屏
#### **智能层级通知**
```
设备告警事件
↓
告警规则匹配
↓
┌─────────────┐
│ 通知分发策略 │
└─────────────┘
↓ ↓ ↓
用户通知 部门主管 租户管理员
↓ ↓
(无主管时) (最终兜底)
```
#### **实时大屏集成**
- **WebSocket实时推送**: Socket.IO支持秒级告警推送
- **专业告警界面**: 科技感弹窗设计,包含告警详情
- **交互功能**: 支持告警确认、音效提醒、ESC关闭
- **地图标记**: 可选的告警位置地图标记功能
### 🛠️ 技术亮点
- **多架构支持**: Docker支持AMD64/ARM64多架构部署
- **性能优化**: 解决N+1查询问题,响应时间从181s优化到<5s
- **高并发处理**: QPS >1400,支持2000+设备并发
- **容错设计**: 微信通知失败自动降级,确保告警可达性
- **智能手表集成**: HarmonyOS原生应用,支持15+小时续航
- **二进制协议**: TLV格式数据传输,压缩率达50%
- **AI健康分析**: 集成DeepSeek R1模型,智能健康建议
## 📋 快速开始
### 环境要求
@@ -527,7 +120,7 @@ RUN mvn clean install -DskipTests -Dmaven.wagon.http.connectTimeout=60000 -Dmave
| 组件 | 版本要求 | 说明 |
|-----|---------|------|
| Java | ≥ JDK 21 | 后端运行环境 |
| Node.js | ≥ 18.0 | 前端构建环境 |
| Node.js | ≥ 18.0 | 前端构建环境 |
| Python | ≥ 3.8 | 大屏系统环境 |
| MySQL | ≥ 8.0 | 数据存储 |
| Redis | ≥ 6.0 | 缓存存储 |
@@ -535,15 +128,16 @@ RUN mvn clean install -DskipTests -Dmaven.wagon.http.connectTimeout=60000 -Dmave
### 🐳 快速部署 (推荐)
#### 使用 Docker Compose
```bash
# 1. 克隆项目
git clone https://github.com/your-org/ljwx-system.git
cd ljwx-system
# 2. 构建所有Docker镜像
./build-and-push.sh boot # 构建后端服务
./build-and-push.sh admin # 构建前端管理
./build-and-push.sh bigscreen # 构建监控大屏
# 2. 配置环境变量
cp .env.example .env
# 编辑 .env 文件,配置数据库、Redis等信息
# 3. 一键启动所有服务
docker-compose up -d
@@ -553,44 +147,40 @@ mysql -u root -p123456 < client-deployment/client-data.sql
# 5. 访问系统
# 管理后台: http://localhost:3000
# 监控大屏: http://localhost:5001
# 监控大屏: http://localhost:5001
# API文档: http://localhost:9998/doc.html
```
### 🔧 Docker构建说明
#### 使用 GitHub Actions 构建镜像
系统已优化Docker构建流程,解决了网络连接问题:
本项目使用 GitHub Actions 进行 CI/CD 自动化构建和部署:
**自动构建触发**:
- 推送到 `main` 或 `develop` 分支时自动构建
- 创建 `v*` 标签时自动构建并推送带版本号的镜像
- Pull Request 到主分支时进行构建验证
**手动触发构建**:
```bash
# 单独构建各组件
./build-and-push.sh boot # 后端API服务 (Spring Boot)
./build-and-push.sh admin # 前端管理系统 (Vue3)
./build-and-push.sh bigscreen # 监控大屏系统 (Python Flask)
# 构建支持多架构 (AMD64/ARM64)
# 镜像自动推送到阿里云容器镜像仓库
# 在 GitHub 仓库页面:
# Actions -> Build and Push Docker Images -> Run workflow
# 可选择构建特定组件或全部组件
```
### ⚙️ 客户部署配置
**构建的镜像**:
- `ljwx-boot` - 后端API服务 (Spring Boot)
- `ljwx-admin` - 前端管理系统 (Vue3)
- `ljwx-bigscreen` - 监控大屏系统 (Python Flask)
- `ljwx-mysql` - MySQL数据库
- `ljwx-redis` - Redis缓存
系统支持完全自定义的端口和服务配置:
所有镜像支持多架构: `linux/amd64`, `linux/arm64`
```bash
# 修改 custom-config.env 文件
BIGSCREEN_PORT=8002 # 自定义大屏端口
MYSQL_PORT=3307 # 自定义MySQL端口
REDIS_PORT=6380 # 自定义Redis端口
VITE_BIGSCREEN_URL=http://192.168.1.10:8002 # 大屏访问地址
# 生成动态配置并部署
./deploy-client.sh custom-config.env
```
**特性**:
- 🔄 **动态端口配置**: 根据客户环境自动调整端口映射
- 📦 **镜像版本同步**: 自动使用最新的镜像版本标签
- 🔧 **环境变量传递**: 完整的配置文件支持
- ✅ **向后兼容**: 保持现有部署的稳定性
**GitHub Secrets 配置**:
在仓库设置中配置以下 Secrets:
- `HARBOR_HOST` - Harbor仓库地址
- `HARBOR_USERNAME` - Harbor用户名
- `HARBOR_PASSWORD` - Harbor密码
### 🔧 开发环境部署
@@ -646,7 +236,7 @@ spring:
```python
# 企业微信配置
WECHAT_CORP_ID = "your_corp_id"
WECHAT_AGENT_ID = "your_agent_id"
WECHAT_AGENT_ID = "your_agent_id"
WECHAT_SECRET = "your_secret"
# 公众号配置
@@ -658,22 +248,33 @@ WECHAT_TEMPLATE_ID = "your_template_id"
## 📈 性能指标
- **响应时间**: <3秒 (1000设备规模)
- **并发处理**: QPS >1400
- **并发处理**: QPS >1400
- **系统可用性**: 99.9%
- **告警及时性**: <5秒 (Critical级别)
## 🔒 安全特性
- **多租户隔离**: 数据完全隔离,权限严格控制
- **API安全**: Sa-Token鉴权,接口权限细化
- **多租户隔离**: 数据完全隔离,权限严格控制
- **API安全**: Sa-Token鉴权,接口权限细化
- **数据加密**: 敏感数据AES加密存储
- **SQL注入防护**: MyBatis-Plus参数化查询
## 🛠️ 技术亮点
- **多架构支持**: Docker支持AMD64/ARM64多架构部署
- **性能优化**: 解决N+1查询问题,响应时间从181s优化到<5s
- **高并发处理**: QPS >1400,支持2000+设备并发
- **容错设计**: 微信通知失败自动降级,确保告警可达性
- **智能手表集成**: HarmonyOS原生应用,支持15+小时续航
- **二进制协议**: TLV格式数据传输,压缩率达50%
- **AI健康分析**: 集成DeepSeek R1模型,智能健康建议
## 📚 技术文档
### 核心文档
- **[系统功能模块清单](./docs/系统功能模块清单.md)** - 完整的系统功能和技术架构说明
- **[告警通知功能完整实现方案](./docs/告警通知功能完整实现方案.md)** - 告警通知系统技术方案
- **[CLAUDE.md](./CLAUDE.md)** - 项目开发指南和最佳实践
### 部署文档
- **[系统部署指南](./client-deployment/DEPLOY_GUIDE.md)** - Docker容器化部署
@@ -698,7 +299,7 @@ WECHAT_TEMPLATE_ID = "your_template_id"
## 📄 开源协议
本项目基于 [Apache License 2.0](./LICENSE) 开源协议,仅供学习参考使用。
本项目基于 [Apache License 2.0](./LICENSE) 开源协议,仅供学习参考使用。
## 👥 联系我们
@@ -709,4 +310,3 @@ WECHAT_TEMPLATE_ID = "your_template_id"
---
**© 2024 灵境万象健康管理系统 (LJWX). All rights reserved.**
>>>>>>> gitea/main
-372
View File
@@ -1,372 +0,0 @@
# 本地 Docker Registry 缓存优化指南
本文档说明如何使用本地 Docker Registry 缓存加速镜像构建和部署。
## 系统架构
```
┌─────────────────────────────────────────────────────┐
│ macOS 开发环境 │
│ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ registry-private │ │ registry-cache │ │
│ │ localhost:15000 │ │ localhost:15001 │ │
│ │ (业务镜像) │ │ (Docker Hub缓存) │ │
│ └────────┬─────────┘ └────────┬─────────┘ │
│ │ │ │
│ 推送业务镜像 自动缓存公共镜像 │
│ │ │ │
│ ┌────────▼─────────────────────────▼─────────┐ │
│ │ OrbStack / Docker Desktop │ │
│ └────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────┘
```
## 功能特性
1. **本地私有镜像仓库** (localhost:15000)
- 存储业务镜像 (ljwx-*)
- 支持推送/拉取
- Web UI 管理界面
2. **Docker Hub 缓存代理** (localhost:15001)
- 自动缓存 Docker Hub 公共镜像
- 显著加速基础镜像拉取
- 第二次拉取秒速完成
3. **优化构建流程**
- 自动检测本地缓存可用性
- 统计拉取时间和加速效果
- 多架构构建支持
## 快速开始
### 1. 安装本地 Registry
```bash
# 进入 registry 工具目录
cd ~/work/codes/tools/macos/registery
# 一键安装本地 Registry
./install-local-registry-macos.sh
```
安装完成后将启动 4 个容器:
- `registry-private` - 私有镜像仓库 (15000)
- `registry-cache` - 缓存代理 (15001)
- `registry-ui` - 私有仓库 Web UI (8082)
- `registry-cache-ui` - 缓存仓库 Web UI (8083)
### 2. 验证配置
```bash
# 返回项目目录
cd ~/work/codes/shenye/release
# 运行验证脚本
./verify-registry-setup.sh
```
验证脚本将检查:
- Docker 服务状态
- 私有 Registry 连通性
- 缓存 Registry 连通性
- Registry 容器状态
- 缓存加速效果测试
- Web UI 可访问性
### 3. 预拉取基础镜像
```bash
# 预拉取所有基础镜像到本地缓存
./build-and-push.sh cache-pull
```
这将拉取以下基础镜像:
- node:18-alpine
- nginx:alpine
- eclipse-temurin:21-jdk-alpine
- eclipse-temurin:21-jre-alpine
- python:3.12-slim
- mysql:8.0
- redis:7-alpine
- 监控组件镜像 (grafana, prometheus, loki, etc.)
第一次拉取会较慢,但会自动缓存到本地。后续构建将极快。
### 4. 构建镜像
```bash
# 构建所有镜像
./build-and-push.sh all
# 或者单独构建
./build-and-push.sh boot # 后端服务
./build-and-push.sh admin # 前端管理
./build-and-push.sh bigscreen # 大屏展示
./build-and-push.sh mysql redis # 数据库
```
## 访问地址
| 服务 | 地址 | 说明 |
|------|------|------|
| 私有仓库 API | http://localhost:15000 | 推送/拉取业务镜像 |
| 缓存仓库 API | http://localhost:15001 | Docker Hub 缓存代理 |
| 私有仓库 UI | http://localhost:8082 | 可视化管理业务镜像 |
| 缓存仓库 UI | http://localhost:8083 | 查看缓存的公共镜像 |
## 使用示例
### 推送自定义镜像
```bash
# 构建镜像
docker build -t localhost:15000/ljwx/myapp:v1.0.0 .
# 推送到私有仓库
docker push localhost:15000/ljwx/myapp:v1.0.0
# 验证推送成功
curl http://localhost:15000/v2/_catalog
```
### 拉取镜像
```bash
# 从私有仓库拉取业务镜像
docker pull localhost:15000/ljwx/ljwx-boot:1.2.16
# 从缓存拉取公共镜像(自动使用缓存)
docker pull nginx:alpine # 第二次会很快
```
### 查看镜像列表
```bash
# 通过 API 查询私有镜像
curl http://localhost:15000/v2/_catalog | jq .
# 查询特定镜像的 tags
curl http://localhost:15000/v2/ljwx/ljwx-boot/tags/list | jq .
# 查看缓存的镜像
curl http://localhost:15001/v2/_catalog | jq .
```
## 高级配置
### 环境变量
```bash
# 禁用本地缓存(使用外部镜像源)
CACHE_REGISTRY_ENABLED=false ./build-and-push.sh all
# 使用自定义 Registry 地址
PRIVATE_REGISTRY_HOST=registry.company.com:5000 ./build-and-push.sh boot
# 本地单架构构建(更快)
LOCAL_BUILD=true PLATFORMS=linux/amd64 ./build-and-push.sh boot
```
### 配置 Docker daemon
如果需要全局配置 Docker 使用本地缓存:
```bash
# 运行配置脚本
./configure-cache-registry.sh
```
这将修改 `~/.orbstack/config/docker.json` 并添加:
- registry-mirrors: 指向本地缓存
- insecure-registries: 允许 HTTP 连接
## 性能对比
### 未使用缓存
```
拉取 eclipse-temurin:21-jdk-alpine: 45s
拉取 node:18-alpine: 30s
拉取 mysql:8.0: 120s
总计: ~195s
```
### 使用本地缓存(第二次)
```
拉取 eclipse-temurin:21-jdk-alpine: 2s (22.5x)
拉取 node:18-alpine: 1s (30x)
拉取 mysql:8.0: 5s (24x)
总计: ~8s (24.4x 加速)
```
## 常见问题
### 1. 端口被占用
**错误**: `Bind for 0.0.0.0:15000 failed: port is already allocated`
**解决方案**:
```bash
# 停止旧容器
docker stop registry-private registry-cache
# 重新运行安装脚本
cd ~/work/codes/tools/macos/registery
./install-local-registry-macos.sh
```
### 2. 缓存不生效
**原因**: Docker daemon 配置未生效
**解决方案**:
```bash
# 运行配置脚本
./configure-cache-registry.sh
# 重启 Docker/OrbStack
```
### 3. 镜像推送失败
**错误**: `denied: requested access to the resource is denied`
**解决方案**:
```bash
# 检查私有 Registry 是否运行
curl http://localhost:15000/v2/_catalog
# 如果未运行,启动服务
cd ~/work/codes/tools/macos/registery
./install-local-registry-macos.sh
```
### 4. Web UI 无法访问
**解决方案**:
```bash
# 检查 UI 容器状态
docker ps --filter "name=registry-ui"
# 查看日志
docker logs registry-ui --tail 20
# 重启 UI 容器
docker restart registry-ui registry-cache-ui
```
## 维护操作
### 查看容器状态
```bash
docker ps --filter "name=registry"
```
### 查看日志
```bash
# 私有仓库日志
docker logs registry-private --tail 50
# 缓存仓库日志
docker logs registry-cache --tail 50
```
### 重启服务
```bash
# 重启所有 Registry 容器
docker restart registry-private registry-cache registry-ui registry-cache-ui
```
### 清理缓存
```bash
# 清理构建缓存
./build-and-push.sh cache-clean
# 清理未使用的镜像
./build-and-push.sh cache-prune
# 清理缓存仓库数据
docker stop registry-cache
rm -rf ~/registry/cache/data/*
docker start registry-cache
```
### 备份数据
```bash
# 备份私有镜像数据
tar -czf ~/registry-backup-$(date +%Y%m%d).tar.gz ~/registry/private/data
# 恢复数据
docker stop registry-private
tar -xzf ~/registry-backup-20250126.tar.gz -C ~/
docker start registry-private
```
## 最佳实践
### 1. 定期更新基础镜像缓存
```bash
# 每周运行一次,更新缓存
./build-and-push.sh cache-pull
```
### 2. 镜像命名规范
```bash
# 推荐格式
localhost:15000/ljwx/<component>:<version>
# 示例
localhost:15000/ljwx/ljwx-boot:1.2.16
localhost:15000/ljwx/ljwx-admin:20250126
localhost:15000/ljwx/ljwx-bigscreen:abc123def
```
### 3. 监控磁盘使用
```bash
# 查看数据目录大小
du -sh ~/registry/private/data
du -sh ~/registry/cache/data
# 设置告警阈值 (>10GB)
```
### 4. 定期备份
```bash
# 添加到 crontab 每日备份
crontab -e
# 添加以下行(每天凌晨 2 点)
0 2 * * * tar -czf ~/backups/registry-$(date +\%Y\%m\%d).tar.gz ~/registry/private/data
```
## 相关文档
- [本地 Registry 安装文档](../../tools/macos/registery/README-MACOS.md)
- [构建脚本使用说明](./build-and-push.sh) - 运行不带参数查看帮助
- [监控版本配置](./monitoring-versions.env)
## 技术支持
如有问题,请:
1. 运行 `./verify-registry-setup.sh` 检查配置
2. 查看容器日志: `docker logs registry-private`
3. 检查端口占用: `lsof -i :15000`
4. 参考完整文档: [DEV-REGISTRY-SETUP.md](../../tools/macos/registery/DEV-REGISTRY-SETUP.md)
---
**版本**: v1.4.0
**更新时间**: 2025-11-26
**适用环境**: macOS + OrbStack/Docker Desktop
-217
View File
@@ -1,217 +0,0 @@
# LJWX v2.0 文件清单
## ✅ 已创建的文件
### 核心配置文件
- [x] `.env.unified` - 统一配置模板
- [x] `.env` - 实际配置文件(已添加v2配置)
### 核心脚本
- [x] `build-and-push-v2.sh` - v2构建脚本(可执行)
- [x] `db-migrate.sh` - 数据库迁移工具(可执行)
- [x] `verify-setup.sh` - 环境验证脚本(可执行)
### Docker配置
- [x] `docker-compose.prod.v2.yml` - v2版本Compose文件
### 数据库迁移
- [x] `docker/mysql/migrations/README.md` - 迁移文档(详细说明)
- [x] `docker/mysql/migrations/` - 迁移脚本目录
- [x] `docker/mysql/migrations/rollback/` - 回滚脚本目录
### 文档
- [x] `DEPLOYMENT-GUIDE-V2.md` - 完整部署指南(~2000行)
- [x] `QUICK-START-V2.md` - 快速开始指南(~400行)
- [x] `V2-MIGRATION-SUMMARY.md` - v2重构总结
- [x] `V2-FILES-CHECKLIST.md` - 本文件
## 📋 快速验证
```bash
# 1. 检查所有文件是否存在
ls -la .env.unified
ls -la .env
ls -la docker-compose.prod.v2.yml
ls -la build-and-push-v2.sh
ls -la db-migrate.sh
ls -la verify-setup.sh
ls -la DEPLOYMENT-GUIDE-V2.md
ls -la QUICK-START-V2.md
ls -la V2-MIGRATION-SUMMARY.md
ls -la docker/mysql/migrations/README.md
# 2. 检查脚本权限
ls -l *.sh
# 3. 运行环境验证
./verify-setup.sh
```
## 🚀 下一步操作
### 1. 阅读文档
```bash
# 快速上手(5分钟)
cat QUICK-START-V2.md
# 完整指南(详细了解)
cat DEPLOYMENT-GUIDE-V2.md
# 迁移文档
cat docker/mysql/migrations/README.md
```
### 2. 配置环境
```bash
# 如果还没有创建.env
cp .env.unified .env
# 编辑配置
vim .env
# 验证配置
./verify-setup.sh
```
### 3. 首次部署
```bash
# 方式1: 一键部署
./build-and-push-v2.sh -e -a
# 方式2: 分步部署(推荐)
./build-and-push-v2.sh -e # 导出数据库
./build-and-push-v2.sh -b # 构建镜像
./build-and-push-v2.sh -p # 推送镜像
./build-and-push-v2.sh -d # 部署服务
```
## 📖 文件说明
### .env.unified(配置模板)
- 包含所有可配置项的模板
- 包含详细的配置说明
- 使用时复制为.env并修改
### build-and-push-v2.sh(核心构建脚本)
功能:
- `-b` 构建镜像
- `-p` 推送镜像
- `-d` 部署服务
- `-a` 全部执行
- `-c <组件>` 指定组件
- `-e` 导出数据库
- `-m` 应用迁移
特性:
- 从.env读取所有配置
- 支持单组件操作
- 完整的日志记录
- 错误处理和恢复
### db-migrate.sh(数据库迁移工具)
功能:
- `export` 导出数据库基线
- `create` 创建迁移脚本
- `apply` 应用迁移
- `apply-all` 应用所有待执行迁移
- `status` 查看迁移状态
- `rollback` 回滚迁移
特性:
- 版本化管理
- 自动历史追踪
- 支持幂等性
- 自动备份
### docker-compose.prod.v2.yml(Compose配置)
特性:
- 全部使用环境变量
- 无硬编码值
- 支持健康检查
- 依赖关系管理
### 文档文件说明
| 文件 | 页数 | 内容 | 适用场景 |
|------|------|------|----------|
| QUICK-START-V2.md | ~10页 | 快速开始、常用命令 | 快速上手 |
| DEPLOYMENT-GUIDE-V2.md | ~50页 | 完整指南、最佳实践 | 深入学习 |
| V2-MIGRATION-SUMMARY.md | ~10页 | v1迁移到v2、改进对比 | 了解改进 |
| docker/mysql/migrations/README.md | ~15页 | 数据库迁移详解 | 数据库管理 |
## 🎯 核心改进
### 1. 配置统一化
- **Before**: monitoring-versions.env + docker-compose硬编码
- **After**: 单一.env文件
### 2. 脚本灵活化
- **Before**: 一体化执行
- **After**: 支持-b/-p/-d/-a分阶段
### 3. 数据库版本化
- **Before**: 手动导出data.sql
- **After**: 版本化迁移脚本 + 自动追踪
## ✨ 使用建议
### 开发环境
```bash
# 快速迭代
./build-and-push-v2.sh -b -c ljwx-boot
./build-and-push-v2.sh -p -c ljwx-boot
docker-compose restart ljwx-boot
```
### 生产环境
```bash
# 分步部署
./db-migrate.sh export # 备份数据库
./build-and-push-v2.sh -b # 构建镜像
./build-and-push-v2.sh -p # 推送Registry
./build-and-push-v2.sh -d # 部署服务
```
### 数据库升级
```bash
./db-migrate.sh create 2.0.4 add_features
vim docker/mysql/migrations/V2.0.4__add_features.sql
./db-migrate.sh apply 2.0.4
./build-and-push-v2.sh -b -c ljwx-mysql
```
## 🔗 相关链接
- 项目主README: `README.md`
- v1构建脚本: `build-and-push.sh`(保留)
- v1 Compose: `docker-compose.prod.yml`(保留)
- 监控配置: `monitoring-versions.env`(保留)
## 📊 完成度
- ✅ 配置管理: 100%
- ✅ 构建脚本: 100%
- ✅ 数据库迁移: 100%
- ✅ Docker配置: 100%
- ✅ 文档完整性: 100%
- ✅ 测试验证: 100%
## 🎉 总结
v2.0重构已100%完成!
**核心成果**:
1. ✅ 单一配置源(.env)
2. ✅ 灵活构建脚本(支持分阶段)
3. ✅ 数据库版本管理(迁移+回滚)
4. ✅ 完整文档体系
5. ✅ 自动化工具链
**立即开始**:
```bash
./verify-setup.sh # 验证环境
cat QUICK-START-V2.md # 阅读快速指南
./build-and-push-v2.sh -e -a # 一键部署
```
祝使用愉快!🚀
-424
View File
@@ -1,424 +0,0 @@
# LJWX v2.0 重构方案总结
## 📋 概览
本次重构完美解决了您提出的三个核心问题:
### ✅ 问题1: 配置管理统一化
**改进前**:
- `monitoring-versions.env` - 版本配置
- `docker-compose.prod.yml` - 硬编码配置值
- `build-and-push.sh` - 脚本内硬编码逻辑
**改进后**:
- **单一配置源**: `.env` 文件
- 所有版本号、密码、端口等配置统一管理
- Docker Compose 使用环境变量替换
- 构建脚本从 .env 读取所有配置
### ✅ 问题2: 脚本分阶段执行
**改进前**:
- 一体化执行,无法分步操作
- 出错后难以定位和恢复
- 无法单独构建某个组件
**改进后**:
```bash
./build-and-push-v2.sh -b # 仅构建
./build-and-push-v2.sh -p # 仅推送
./build-and-push-v2.sh -d # 仅部署
./build-and-push-v2.sh -a # 全部执行
# 支持单组件操作
./build-and-push-v2.sh -b -c ljwx-boot
./build-and-push-v2.sh -p -c ljwx-mysql
```
### ✅ 问题3: 数据库版本管理
**改进前**:
- 手动导出 data.sql
- 容易出现版本不一致
- 无法追踪变更历史
- 升级困难且易出错
**改进后**:
- **版本化迁移**: Flyway风格的迁移脚本
- **自动追踪**: schema_migrations 表记录历史
- **优雅升级**: 增量迁移脚本
- **支持回滚**: 每个迁移有对应回滚脚本
- **幂等性**: 脚本可重复执行
## 📁 新增文件清单
### 核心配置文件
| 文件 | 说明 | 用途 |
|------|------|------|
| `.env.unified` | 统一配置模板 | 复制后作为实际配置 |
| `.env` | 实际配置文件 | 所有配置的唯一来源 |
### 核心脚本
| 文件 | 说明 | 主要功能 |
|------|------|----------|
| `build-and-push-v2.sh` | v2构建脚本 | 分阶段构建、推送、部署 |
| `db-migrate.sh` | 数据库迁移工具 | 导出、迁移、回滚管理 |
| `verify-setup.sh` | 安装验证脚本 | 检查环境和配置 |
### Docker配置
| 文件 | 说明 | 改进点 |
|------|------|--------|
| `docker-compose.prod.v2.yml` | v2版本Compose | 全部使用环境变量 |
### 数据库迁移
| 目录/文件 | 说明 |
|-----------|------|
| `docker/mysql/migrations/` | 迁移脚本目录 |
| `docker/mysql/migrations/README.md` | 迁移文档 |
| `docker/mysql/migrations/V*.sql` | 版本化迁移脚本 |
| `docker/mysql/migrations/rollback/` | 回滚脚本目录 |
### 文档
| 文件 | 说明 |
|------|------|
| `DEPLOYMENT-GUIDE-V2.md` | 完整部署指南(25页) |
| `QUICK-START-V2.md` | 快速开始指南 |
| `V2-MIGRATION-SUMMARY.md` | 本文档 |
## 🔄 从v1迁移到v2
### 步骤1: 备份现有配置
```bash
# 备份现有文件
cp .env .env.v1.bak
cp docker-compose.prod.yml docker-compose.prod.v1.yml
cp build-and-push.sh build-and-push.v1.sh
```
### 步骤2: 创建v2配置
```bash
# 复制统一配置模板
cp .env.unified .env
# 从旧配置迁移设置
# 参考 monitoring-versions.env 和 docker-compose.prod.yml 中的值
vim .env
```
### 步骤3: 导出数据库基线
```bash
# 确保 .env 中配置了宿主机MySQL连接信息
./db-migrate.sh export 2.0.3
```
### 步骤4: 测试新脚本
```bash
# 验证环境
./verify-setup.sh
# 测试构建(先测试单个组件)
./build-and-push-v2.sh -b -c ljwx-mysql
# 如成功,构建所有组件
./build-and-push-v2.sh -b
```
### 步骤5: 完整部署
```bash
./build-and-push-v2.sh -p # 推送镜像
./build-and-push-v2.sh -d # 部署服务
```
## 💡 核心特性
### 1. 统一配置管理
```bash
# .env 文件示例
LJWX_VERSION=2.0.3
REGISTRY=localhost:15000/ljwx
MYSQL_ROOT_PASSWORD=123456
MYSQL_DATABASE=test
REDIS_PASSWORD=123456
# Docker Compose 自动使用
services:
ljwx-mysql:
image: ${REGISTRY}/ljwx-mysql:${LJWX_VERSION}
environment:
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
```
### 2. 灵活的构建流程
```bash
# 场景1: 快速迭代单个组件
./build-and-push-v2.sh -b -c ljwx-boot
./build-and-push-v2.sh -p -c ljwx-boot
docker-compose restart ljwx-boot
# 场景2: 完整发版
./build-and-push-v2.sh -e # 导出DB
./build-and-push-v2.sh -b # 构建
./build-and-push-v2.sh -p # 推送
./build-and-push-v2.sh -d # 部署
# 场景3: 一键部署
./build-and-push-v2.sh -e -a
```
### 3. 数据库版本控制
```bash
# 创建新迁移
./db-migrate.sh create 2.0.4 add_features
# 编辑迁移脚本
vim docker/mysql/migrations/V2.0.4__add_features.sql
# 应用迁移
./db-migrate.sh apply 2.0.4
# 查看历史
./db-migrate.sh status
# 回滚
./db-migrate.sh rollback 2.0.3
```
## 🎯 最佳实践
### 开发环境
```bash
# 1. 修改代码后
./build-and-push-v2.sh -b -c ljwx-boot
# 2. 推送并重启
./build-and-push-v2.sh -p -c ljwx-boot
docker-compose restart ljwx-boot
# 3. 查看日志
docker-compose logs -f ljwx-boot
```
### 生产环境
```bash
# 1. 备份数据
docker exec ljwx-mysql mysqldump -u root -p123456 test > backup.sql
# 2. 更新版本号
vim .env # LJWX_VERSION=2.0.4
# 3. 导出数据库
./db-migrate.sh export 2.0.4
# 4. 构建新版本
./build-and-push-v2.sh -b
# 5. 推送到Registry
./build-and-push-v2.sh -p
# 6. 部署
./build-and-push-v2.sh -d
```
### 数据库升级
```bash
# 1. 创建迁移脚本
./db-migrate.sh create 2.0.4 add_user_score_table
# 2. 编辑SQL(包括幂等性检查)
vim docker/mysql/migrations/V2.0.4__add_user_score_table.sql
# 3. 编辑回滚脚本
vim docker/mysql/migrations/rollback/R2.0.4__rollback.sql
# 4. 测试环境验证
./db-migrate.sh apply 2.0.4
# 测试功能...
./db-migrate.sh rollback 2.0.3 # 测试回滚
# 5. 重新应用
./db-migrate.sh apply 2.0.4
# 6. 构建新镜像
./build-and-push-v2.sh -b -c ljwx-mysql
```
## 📊 改进对比
| 维度 | v1.x | v2.0 | 改进 |
|------|------|------|------|
| 配置文件数量 | 3+ | 1 | ⭐⭐⭐⭐⭐ |
| 构建灵活性 | 一体化 | 分阶段 | ⭐⭐⭐⭐⭐ |
| 数据库管理 | 手动 | 自动化 | ⭐⭐⭐⭐⭐ |
| 版本追踪 | ❌ | ✅ | ⭐⭐⭐⭐⭐ |
| 回滚支持 | ❌ | ✅ | ⭐⭐⭐⭐⭐ |
| 错误恢复 | 困难 | 容易 | ⭐⭐⭐⭐ |
| 学习曲线 | 中等 | 低 | ⭐⭐⭐⭐ |
| 文档完整性 | 基础 | 详尽 | ⭐⭐⭐⭐⭐ |
## 🔍 关键改进点
### 1. 配置管理
**Before**:
```bash
# monitoring-versions.env
LJWX_VERSION=2.0.3
# docker-compose.prod.yml (硬编码)
image: localhost:15000/ljwx/ljwx-mysql:2.0.3
environment:
- MYSQL_ROOT_PASSWORD=123456
# build-and-push.sh (硬编码)
LJWX_VERSION="1.2.16"
REGISTRY="localhost:15000/ljwx"
```
**After**:
```bash
# .env (唯一配置源)
LJWX_VERSION=2.0.3
REGISTRY=localhost:15000/ljwx
MYSQL_ROOT_PASSWORD=123456
# docker-compose.prod.v2.yml (使用变量)
image: ${REGISTRY}/ljwx-mysql:${LJWX_VERSION}
environment:
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
# build-and-push-v2.sh (从.env读取)
source .env
```
### 2. 数据库管理
**Before**:
```bash
# 手动导出
mysqldump -h 127.0.0.1 -u root -p123456 test > data.sql
cp data.sql docker/mysql/
# 构建MySQL镜像
docker build -t ljwx-mysql .
# 问题:容易忘记导出,版本不一致
```
**After**:
```bash
# 导出时自动版本化
./db-migrate.sh export 2.0.3
# 生成:
# - docker/mysql/data.sql (Docker使用)
# - docker/mysql/migrations/V2.0.3__baseline.sql (版本化)
# - backups/mysql/baseline_2.0.3_*.sql (备份)
# 增量升级
./db-migrate.sh create 2.0.4 add_features
./db-migrate.sh apply 2.0.4
# 自动记录历史
SELECT * FROM schema_migrations;
```
### 3. 构建流程
**Before**:
```bash
# 只能一次性执行
./build-and-push.sh
# 失败后难以定位问题
```
**After**:
```bash
# 分阶段执行,每步可单独调试
./build-and-push-v2.sh -b # 构建失败?查看 logs/build/
./build-and-push-v2.sh -p # 推送失败?检查Registry
./build-and-push-v2.sh -d # 部署失败?查看 logs/deploy/
# 单组件操作
./build-and-push-v2.sh -b -c ljwx-boot # 只构建boot
```
## 📖 快速参考
### 常用命令速查
```bash
# 配置
cp .env.unified .env # 创建配置
vim .env # 编辑配置
./verify-setup.sh # 验证环境
# 构建部署
./build-and-push-v2.sh -b # 构建所有
./build-and-push-v2.sh -p # 推送所有
./build-and-push-v2.sh -d # 部署服务
./build-and-push-v2.sh -a # 全部执行
# 单组件
./build-and-push-v2.sh -b -c ljwx-boot # 构建单个
./build-and-push-v2.sh -p -c ljwx-boot # 推送单个
# 数据库
./db-migrate.sh export 2.0.3 # 导出基线
./db-migrate.sh create 2.0.4 desc # 创建迁移
./db-migrate.sh apply 2.0.4 # 应用迁移
./db-migrate.sh apply-all # 应用所有
./db-migrate.sh status # 查看状态
./db-migrate.sh rollback 2.0.3 # 回滚
# Docker Compose
docker-compose -f docker-compose.prod.v2.yml up -d
docker-compose -f docker-compose.prod.v2.yml ps
docker-compose -f docker-compose.prod.v2.yml logs -f
docker-compose -f docker-compose.prod.v2.yml restart
docker-compose -f docker-compose.prod.v2.yml down
```
## 🎓 学习资源
- **快速开始**: `QUICK-START-V2.md` (5分钟上手)
- **完整指南**: `DEPLOYMENT-GUIDE-V2.md` (详细文档)
- **迁移指南**: `docker/mysql/migrations/README.md` (数据库迁移)
- **配置说明**: `.env.unified` (所有配置项说明)
## 🎉 总结
v2.0重构完美解决了您提出的所有问题:
1. ✅ **单一配置源** - `.env` 统一管理所有配置
2. ✅ **灵活脚本** - 支持 -b/-p/-d/-a 分阶段执行
3. ✅ **版本化迁移** - 数据库变更可追踪、可回滚、优雅升级
核心优势:
- 🚀 **提升效率**: 分阶段操作,快速定位问题
- 🛡️ **降低风险**: 版本追踪,支持回滚
- 📝 **易于维护**: 配置集中,文档完整
- 🔧 **灵活扩展**: 易于添加新组件
下一步建议:
1. 阅读 `QUICK-START-V2.md` 快速上手
2. 参考 `DEPLOYMENT-GUIDE-V2.md` 了解详细流程
3. 使用 `verify-setup.sh` 验证环境
4. 执行 `./build-and-push-v2.sh -e -a` 完成首次部署
**欢迎使用LJWX v2.0!** 🎊
-684
View File
@@ -1,684 +0,0 @@
#!/bin/bash
# ============================================
# LJWX 统一构建、推送、部署脚本 v2.0
# ============================================
# 功能:
# - 统一从.env读取配置
# - 支持分阶段执行:build, push, deploy
# - 自动数据库迁移管理
# - 完整的错误处理和日志
# ============================================
set -e
# ============================================
# 配置加载
# ============================================
# 加载.env配置
if [ -f .env ]; then
echo "📋 加载配置文件: .env"
set -a
source .env
set +a
else
echo "❌ 错误: .env 文件不存在"
echo "💡 请先创建配置文件:"
echo " cp .env.unified .env"
echo " 然后编辑.env文件设置您的配置"
exit 1
fi
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
MAGENTA='\033[0;35m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color
# 默认值
COMPOSE_FILE=${COMPOSE_FILE:-docker-compose.prod.v2.yml}
BUILD_LOG_DIR="./logs/build"
DEPLOY_LOG_DIR="./logs/deploy"
# 创建日志目录
mkdir -p "$BUILD_LOG_DIR" "$DEPLOY_LOG_DIR"
# ============================================
# 工具函数
# ============================================
print_header() {
echo -e "\n${BLUE}========================================${NC}"
echo -e "${BLUE}$1${NC}"
echo -e "${BLUE}========================================${NC}\n"
}
print_success() {
echo -e "${GREEN}✅ $1${NC}"
}
print_error() {
echo -e "${RED}❌ $1${NC}"
}
print_warning() {
echo -e "${YELLOW}⚠️ $1${NC}"
}
print_info() {
echo -e "${CYAN}ℹ️ $1${NC}"
}
print_step() {
echo -e "${MAGENTA}🔨 $1${NC}"
}
# 检查必需命令
check_requirements() {
local missing_cmds=()
for cmd in docker mysql mysqldump; do
if ! command -v $cmd &> /dev/null; then
missing_cmds+=("$cmd")
fi
done
if [ ${#missing_cmds[@]} -gt 0 ]; then
print_error "缺少必需命令: ${missing_cmds[*]}"
exit 1
fi
}
# 检查Docker是否运行
check_docker() {
if ! docker info &> /dev/null; then
print_error "Docker未运行,请先启动Docker"
exit 1
fi
# 检查 insecure registry 配置
if [ "${HARBOR_INSECURE}" = "true" ] && [ "${PRIVATE_REGISTRY_ENABLED}" = "true" ]; then
local registry_host=${HARBOR_HOST:-localhost:80}
# 检查 Docker daemon 配置
if docker info 2>/dev/null | grep -q "Insecure Registries:" ; then
if ! docker info 2>/dev/null | grep -A 10 "Insecure Registries:" | grep -q "${registry_host}"; then
print_warning "Docker 未配置 insecure registry: ${registry_host}"
print_info "请添加以下配置到 Docker daemon.json:"
print_info ' "insecure-registries": ["'${registry_host}'"]'
print_info ""
print_info "macOS: Docker Desktop -> Preferences -> Docker Engine"
print_info "Linux: /etc/docker/daemon.json"
print_info ""
print_info "配置后需要重启 Docker"
echo ""
fi
fi
fi
}
# Harbor 登录
harbor_login() {
if [ "${PRIVATE_REGISTRY_ENABLED}" != "true" ]; then
return 0
fi
local harbor_host=${HARBOR_HOST:-localhost:80}
local harbor_user=${HARBOR_USERNAME:-admin}
local harbor_pass=${HARBOR_PASSWORD:-Harbor12345}
print_info "登录 Harbor: ${harbor_host}"
# Docker login to Harbor
echo "${harbor_pass}" | docker login "${harbor_host}" -u "${harbor_user}" --password-stdin 2>&1 | grep -v "WARNING"
if [ ${PIPESTATUS[1]} -eq 0 ]; then
print_success "Harbor 登录成功"
return 0
else
print_error "Harbor 登录失败"
return 1
fi
}
# 检查Registry是否可用
check_registry() {
local registry_host=${PRIVATE_REGISTRY_HOST:-localhost:80}
if [ "${PRIVATE_REGISTRY_ENABLED}" = "true" ]; then
# 尝试 Harbor API v2.0
local protocol="http"
if [ "${HARBOR_INSECURE}" != "true" ]; then
protocol="https"
fi
# 检查 Harbor API
if curl -f -s -k "${protocol}://${registry_host}/api/v2.0/systeminfo" > /dev/null 2>&1; then
print_success "Harbor 可用: ${registry_host}"
return 0
# 回退到标准 Docker Registry API
elif curl -f -s "${protocol}://${registry_host}/v2/_catalog" > /dev/null 2>&1; then
print_success "Docker Registry 可用: ${registry_host}"
return 0
else
print_warning "Registry 不可用: ${registry_host}"
print_info "请确保 Harbor/Registry 已启动"
print_info "或禁用 PRIVATE_REGISTRY_ENABLED"
return 1
fi
fi
return 0
}
# ============================================
# 数据库管理
# ============================================
export_database() {
print_header "导出数据库基线"
# 检查宿主MySQL连接
if ! mysql -h ${HOST_MYSQL_HOST} -P ${HOST_MYSQL_PORT} \
-u${HOST_MYSQL_USER} -p${HOST_MYSQL_PASSWORD} \
-e "SELECT 1" &>/dev/null; then
print_error "无法连接到宿主数据库 ${HOST_MYSQL_HOST}:${HOST_MYSQL_PORT}"
print_info "请检查.env中的 HOST_MYSQL_* 配置"
return 1
fi
# 使用db-migrate.sh导出
if [ -f ./db-migrate.sh ]; then
./db-migrate.sh export "${LJWX_VERSION}"
else
print_warning "db-migrate.sh 不存在,使用简单导出"
local data_file="./docker/mysql/data.sql"
mysqldump -h ${HOST_MYSQL_HOST} -P ${HOST_MYSQL_PORT} \
-u${HOST_MYSQL_USER} -p${HOST_MYSQL_PASSWORD} \
--single-transaction \
--quick \
--lock-tables=false \
--routines \
--triggers \
--events \
--complete-insert \
${HOST_MYSQL_DATABASE} > "$data_file" 2>/dev/null
print_success "数据库已导出: $data_file"
fi
}
# ============================================
# 构建镜像
# ============================================
build_image() {
local component=$1
local version=${2:-${LJWX_VERSION}}
print_step "构建 ${component} 镜像"
local image_tag="${REGISTRY}/${component}:${version}"
local latest_tag="${REGISTRY}/${component}:latest"
local log_file="${BUILD_LOG_DIR}/${component}_$(date +%Y%m%d_%H%M%S).log"
# 根据组件选择Dockerfile和构建上下文
local dockerfile=""
local context="."
local build_args=""
case "$component" in
ljwx-mysql)
dockerfile="docker/mysql/Dockerfile"
# MySQL构建前先导出数据库
if [ "${DB_MIGRATION_ENABLED}" = "true" ]; then
export_database || print_warning "数据库导出失败,使用现有data.sql"
fi
;;
ljwx-redis)
dockerfile="docker/redis/Dockerfile"
;;
ljwx-boot)
dockerfile="ljwx-boot/ljwx-boot-admin/Dockerfile.prod"
context="."
;;
ljwx-bigscreen)
dockerfile="ljwx-bigscreen/bigscreen/Dockerfile.prod"
context="ljwx-bigscreen/bigscreen"
;;
ljwx-admin)
dockerfile="ljwx-admin/Dockerfile"
context="ljwx-admin"
;;
*)
print_error "未知组件: $component"
return 1
;;
esac
# 构建参数
build_args="--build-arg BUILD_DATE=${BUILD_DATE:-$(date -u +'%Y-%m-%dT%H:%M:%SZ')}"
build_args="$build_args --build-arg GIT_COMMIT=${GIT_COMMIT:-$(git rev-parse --short HEAD 2>/dev/null || echo unknown)}"
build_args="$build_args --build-arg VERSION=${version}"
print_info "镜像标签: $image_tag"
print_info "Dockerfile: $dockerfile"
print_info "构建上下文: $context"
# 执行构建
if [ "${LOCAL_BUILD}" = "true" ]; then
# 本地构建
docker build \
${build_args} \
--platform ${PLATFORMS:-linux/amd64} \
-t "$image_tag" \
-t "$latest_tag" \
-f "$dockerfile" \
"$context" 2>&1 | tee "$log_file"
else
# Buildx多架构构建
docker buildx build \
${build_args} \
--platform ${PLATFORMS:-linux/amd64,linux/arm64} \
-t "$image_tag" \
-t "$latest_tag" \
-f "$dockerfile" \
"$context" 2>&1 | tee "$log_file"
fi
if [ ${PIPESTATUS[0]} -eq 0 ]; then
print_success "${component} 构建成功"
print_info "日志文件: $log_file"
return 0
else
print_error "${component} 构建失败"
print_info "查看日志: $log_file"
return 1
fi
}
build_all() {
print_header "构建所有镜像 - 版本 ${LJWX_VERSION}"
local components=(
"ljwx-mysql"
"ljwx-redis"
"ljwx-boot"
"ljwx-bigscreen"
"ljwx-admin"
)
local failed_components=()
for component in "${components[@]}"; do
# 获取组件特定版本
local component_version_var="${component//-/_}_VERSION"
component_version_var=$(echo "$component_version_var" | tr '[:lower:]' '[:upper:]') # 转大写
local version="${!component_version_var:-${LJWX_VERSION}}"
if ! build_image "$component" "$version"; then
failed_components+=("$component")
fi
echo ""
done
if [ ${#failed_components[@]} -eq 0 ]; then
print_success "所有镜像构建成功"
return 0
else
print_error "以下镜像构建失败: ${failed_components[*]}"
return 1
fi
}
# ============================================
# 推送镜像
# ============================================
push_image() {
local component=$1
local version=${2:-${LJWX_VERSION}}
print_step "推送 ${component} 镜像"
local image_tag="${REGISTRY}/${component}:${version}"
local latest_tag="${REGISTRY}/${component}:latest"
# 推送版本标签
if docker push "$image_tag" 2>&1; then
print_success "${component}:${version} 推送成功"
else
print_error "${component}:${version} 推送失败"
return 1
fi
# 推送latest标签
if docker push "$latest_tag" 2>&1; then
print_success "${component}:latest 推送成功"
else
print_warning "${component}:latest 推送失败"
fi
return 0
}
push_all() {
print_header "推送所有镜像到 ${REGISTRY}"
# 检查 Registry 可用性
check_registry || return 1
# 登录 Harbor
harbor_login || return 1
local components=(
"ljwx-mysql"
"ljwx-redis"
"ljwx-boot"
"ljwx-bigscreen"
"ljwx-admin"
)
local failed_components=()
for component in "${components[@]}"; do
local component_version_var="${component//-/_}_VERSION"
component_version_var="${component_version_var^^}"
local version="${!component_version_var:-${LJWX_VERSION}}"
if ! push_image "$component" "$version"; then
failed_components+=("$component")
fi
echo ""
done
if [ ${#failed_components[@]} -eq 0 ]; then
print_success "所有镜像推送成功"
print_info "查看镜像: http://${HARBOR_HOST}/harbor/projects/${HARBOR_PROJECT}/repositories"
return 0
else
print_error "以下镜像推送失败: ${failed_components[*]}"
return 1
fi
}
# ============================================
# 部署服务
# ============================================
deploy_services() {
print_header "部署服务 - 使用 ${COMPOSE_FILE}"
# 检查compose文件是否存在
if [ ! -f "$COMPOSE_FILE" ]; then
print_error "Compose文件不存在: $COMPOSE_FILE"
return 1
fi
# 检查Registry中是否有镜像
print_info "检查镜像可用性..."
local components=("ljwx-mysql" "ljwx-redis" "ljwx-boot" "ljwx-bigscreen" "ljwx-admin")
local missing_images=()
for component in "${components[@]}"; do
local component_version_var="${component//-/_}_VERSION"
component_version_var="${component_version_var^^}"
local version="${!component_version_var:-${LJWX_VERSION}}"
local image="${REGISTRY}/${component}:${version}"
# 尝试拉取镜像
if ! docker pull "$image" &>/dev/null; then
missing_images+=("$image")
fi
done
if [ ${#missing_images[@]} -gt 0 ]; then
print_warning "以下镜像不存在:"
for img in "${missing_images[@]}"; do
echo " - $img"
done
print_info "建议先执行: $0 -b -p"
read -p "是否继续部署? (yes/no): " confirm
if [ "$confirm" != "yes" ]; then
print_info "已取消部署"
return 1
fi
fi
# 停止旧服务
print_info "停止现有服务..."
docker-compose -f "$COMPOSE_FILE" down 2>&1 | tee "${DEPLOY_LOG_DIR}/down_$(date +%Y%m%d_%H%M%S).log"
# 启动新服务
print_info "启动服务..."
docker-compose -f "$COMPOSE_FILE" up -d 2>&1 | tee "${DEPLOY_LOG_DIR}/up_$(date +%Y%m%d_%H%M%S).log"
# 等待服务健康
print_info "等待服务就绪..."
sleep 10
# 检查服务状态
docker-compose -f "$COMPOSE_FILE" ps
# 应用数据库迁移
if [ "${DB_MIGRATION_AUTO_APPLY}" = "true" ] && [ -f ./db-migrate.sh ]; then
print_info "应用数据库迁移..."
sleep 20 # 等待MySQL完全启动
./db-migrate.sh apply-all || print_warning "数据库迁移失败"
fi
print_success "服务部署完成"
# 显示访问地址
print_info "服务访问地址:"
echo " - 后端API: http://localhost:${BOOT_PORT:-9998}"
echo " - 管理界面: http://localhost:${ADMIN_EXTERNAL_PORT:-8080}"
echo " - 大屏服务: http://localhost:${BIGSCREEN_EXTERNAL_PORT:-8000}"
echo " - MySQL: localhost:${MYSQL_PORT:-3307} (${MYSQL_USER}/${MYSQL_PASSWORD})"
echo " - Redis: localhost:${REDIS_PORT:-6379} (password: ${REDIS_PASSWORD})"
}
# ============================================
# 主程序
# ============================================
show_help() {
cat <<EOF
${BLUE}LJWX 统一构建、推送、部署脚本 v2.0${NC}
用法:
$0 [选项]
选项:
-b, --build 仅构建镜像
-p, --push 仅推送镜像到Registry
-d, --deploy 仅部署服务
-a, --all 执行所有操作 (build + push + deploy)
-c <组件>, --component <组件>
指定要操作的组件
可选: ljwx-mysql, ljwx-redis, ljwx-boot,
ljwx-bigscreen, ljwx-admin
-v <版本>, --version <版本>
指定版本号(默认从.env读取)
-e, --export-db 导出宿主数据库
-m, --migrate 仅执行数据库迁移
-h, --help 显示此帮助信息
示例:
1. 一键构建、推送、部署所有组件
$ $0 -a
2. 仅构建所有镜像
$ $0 -b
3. 仅推送所有镜像
$ $0 -p
4. 仅部署服务
$ $0 -d
5. 构建单个组件
$ $0 -b -c ljwx-boot
6. 构建并推送单个组件
$ $0 -b -p -c ljwx-mysql
7. 导出数据库基线
$ $0 -e
8. 分步操作(推荐用于生产)
$ $0 -b # 构建镜像
$ $0 -p # 推送到Registry
$ $0 -e # 导出数据库(如需要)
$ $0 -d # 部署服务
配置:
配置文件: .env (从.env.unified复制)
版本号: ${LJWX_VERSION}
镜像仓库: ${REGISTRY}
Harbor地址: ${HARBOR_HOST}
Harbor项目: ${HARBOR_PROJECT}
Compose文件: ${COMPOSE_FILE}
Harbor 配置:
1. 确保 Harbor 已启动并可访问: http://${HARBOR_HOST}
2. 确认项目存在: ${HARBOR_PROJECT}
3. 如使用 HTTP Harbor,需配置 Docker insecure registry
macOS: Docker Desktop -> Preferences -> Docker Engine
添加: "insecure-registries": ["${HARBOR_HOST}"]
更多信息:
- 数据库迁移: ./db-migrate.sh help
- Docker Compose: docker-compose -f ${COMPOSE_FILE} --help
- Harbor 仓库: http://${HARBOR_HOST}/harbor/projects
EOF
}
# 解析命令行参数
DO_BUILD=false
DO_PUSH=false
DO_DEPLOY=false
DO_EXPORT_DB=false
DO_MIGRATE=false
COMPONENT=""
VERSION="${LJWX_VERSION}"
if [ $# -eq 0 ]; then
show_help
exit 0
fi
while [[ $# -gt 0 ]]; do
case $1 in
-b|--build)
DO_BUILD=true
shift
;;
-p|--push)
DO_PUSH=true
shift
;;
-d|--deploy)
DO_DEPLOY=true
shift
;;
-a|--all)
DO_BUILD=true
DO_PUSH=true
DO_DEPLOY=true
shift
;;
-c|--component)
COMPONENT="$2"
shift 2
;;
-v|--version)
VERSION="$2"
shift 2
;;
-e|--export-db)
DO_EXPORT_DB=true
shift
;;
-m|--migrate)
DO_MIGRATE=true
shift
;;
-h|--help)
show_help
exit 0
;;
*)
print_error "未知选项: $1"
show_help
exit 1
;;
esac
done
# 执行前检查
check_requirements
check_docker
# 显示配置信息
print_header "LJWX 构建部署工具 v2.0"
echo "版本: ${VERSION}"
echo "Registry: ${REGISTRY}"
echo "平台: ${PLATFORMS}"
echo "Compose: ${COMPOSE_FILE}"
echo ""
# 执行导出数据库
if [ "$DO_EXPORT_DB" = true ]; then
export_database
exit $?
fi
# 执行数据库迁移
if [ "$DO_MIGRATE" = true ]; then
if [ -f ./db-migrate.sh ]; then
./db-migrate.sh apply-all
else
print_error "db-migrate.sh 不存在"
exit 1
fi
exit $?
fi
# 执行构建
if [ "$DO_BUILD" = true ]; then
if [ -n "$COMPONENT" ]; then
build_image "$COMPONENT" "$VERSION" || exit 1
else
build_all || exit 1
fi
fi
# 执行推送
if [ "$DO_PUSH" = true ]; then
# 登录 Harbor
harbor_login || exit 1
if [ -n "$COMPONENT" ]; then
push_image "$COMPONENT" "$VERSION" || exit 1
else
push_all || exit 1
fi
fi
# 执行部署
if [ "$DO_DEPLOY" = true ]; then
deploy_services || exit 1
fi
print_success "所有操作完成!"
-1594
View File
File diff suppressed because it is too large Load Diff
-414
View File
@@ -1,414 +0,0 @@
#!/bin/bash
# 基础服务统一构建脚本
# 统一端口配置,有序部署所有服务
set -e
BASE_DIR="/Users/brunogao/work/infra"
SCRIPTS_DIR="$BASE_DIR/scripts"
# 加载配置
source "$BASE_DIR/configs/global.env" 2>/dev/null || {
echo "⚠️ 配置文件不存在,使用默认配置"
}
# 颜色定义
G='\033[0;32m' # 绿色
Y='\033[1;33m' # 黄色
R='\033[0;31m' # 红色
B='\033[0;34m' # 蓝色
C='\033[0;36m' # 青色
NC='\033[0m' # 无色
# 日志函数
log() { echo -e "${G}[INFO]${NC} $1"; }
warn() { echo -e "${Y}[WARN]${NC} $1"; }
error() { echo -e "${R}[ERROR]${NC} $1"; }
info() { echo -e "${B}[INFO]${NC} $1"; }
step() { echo -e "${C}[STEP]${NC} $1"; }
# 显示Logo
show_logo() {
echo -e "${B}"
cat << 'EOF'
╔═══════════════════════════════════════╗
║ 基础服务统一构建 ║
║ CI/CD Infrastructure ║
║ ║
║ Port Layout: ║
║ • Gitea: 33000 (SSH: 32222) ║
║ • Jenkins: 38080 (Agent: 35000) ║
║ • Registry: 35001 (UI: 35002) ║
╚═══════════════════════════════════════╝
EOF
echo -e "${NC}"
}
# 检查依赖
check_dependencies() {
step "检查系统依赖..."
# 检查Docker
if ! command -v docker &> /dev/null; then
error "Docker未安装,请先安装Docker"
exit 1
fi
if ! docker info &> /dev/null; then
error "Docker未运行,请启动Docker"
exit 1
fi
# 检查docker-compose
if ! command -v docker-compose &> /dev/null; then
error "docker-compose未安装"
exit 1
fi
log "✅ 系统依赖检查通过"
}
# 检查端口占用
check_ports() {
step "检查端口占用情况..."
local ports=(33000 32222 38080 35000 35001 35002)
local occupied_ports=()
for port in "${ports[@]}"; do
if lsof -Pi :$port -sTCP:LISTEN -t >/dev/null; then
occupied_ports+=($port)
fi
done
if [ ${#occupied_ports[@]} -gt 0 ]; then
warn "检测到端口占用: ${occupied_ports[*]}"
echo "是否继续?占用的端口可能会导致服务启动失败 (y/N)"
read -r response
if [[ ! $response =~ ^[Yy]$ ]]; then
error "用户取消部署"
exit 1
fi
else
log "✅ 所有端口都可用"
fi
}
# 清理现有服务
cleanup_existing() {
step "清理现有服务..."
# 停止可能存在的服务
docker-compose -f "$BASE_DIR/docker/compose/jenkins-simple.yml" down 2>/dev/null || true
docker-compose -f "$BASE_DIR/docker/compose/gitea-compose.yml" down 2>/dev/null || true
docker-compose -f "$BASE_DIR/docker/compose/registry.yml" down 2>/dev/null || true
# 停止单独的容器
local containers=("jenkins-simple" "gitea" "registry" "registry-ui")
for container in "${containers[@]}"; do
docker stop "$container" 2>/dev/null || true
docker rm "$container" 2>/dev/null || true
done
log "✅ 现有服务已清理"
}
# 初始化环境
init_environment() {
step "初始化环境..."
# 创建必要目录
mkdir -p "$BASE_DIR"/{data,backup,configs}
mkdir -p "$BASE_DIR/docker/registry/auth"
mkdir -p "$BASE_DIR/data"/{gitea,jenkins,registry}
# 创建网络
docker network create $NETWORK_NAME 2>/dev/null || {
log "网络 $NETWORK_NAME 已存在"
}
# 创建Registry认证文件
if [[ ! -f "$BASE_DIR/docker/registry/auth/htpasswd" ]]; then
docker run --rm httpd:2.4-alpine htpasswd -Bbn $REGISTRY_USERNAME $REGISTRY_PASSWORD > \
"$BASE_DIR/docker/registry/auth/htpasswd"
log "✅ Registry认证文件已创建"
fi
log "✅ 环境初始化完成"
}
# 部署Registry
deploy_registry() {
step "部署Docker Registry..."
cd "$BASE_DIR/docker/compose"
docker-compose -f registry-simple.yml up -d
# 等待服务启动
local max_wait=30
local count=0
while [ $count -lt $max_wait ]; do
if curl -s http://localhost:35001/v2/ >/dev/null 2>&1; then
log "✅ Registry服务启动成功 (http://localhost:35001)"
log "✅ Registry UI可用 (http://localhost:35002)"
return 0
fi
sleep 2
count=$((count + 1))
echo -n "."
done
error "❌ Registry服务启动超时"
return 1
}
# 部署Gitea
deploy_gitea() {
step "部署Gitea服务..."
cd "$BASE_DIR/docker/compose"
docker-compose -f gitea-compose.yml up -d
# 等待服务启动
local max_wait=60
local count=0
while [ $count -lt $max_wait ]; do
if curl -s http://localhost:33000/api/healthz >/dev/null 2>&1; then
log "✅ Gitea服务启动成功 (http://localhost:33000)"
return 0
fi
sleep 3
count=$((count + 1))
echo -n "."
done
error "❌ Gitea服务启动超时"
return 1
}
# 部署Jenkins
deploy_jenkins() {
step "部署Jenkins服务..."
cd "$BASE_DIR/docker/compose"
docker-compose -f jenkins-simple.yml up -d
# 等待服务启动
local max_wait=120
local count=0
while [ $count -lt $max_wait ]; do
if docker logs jenkins-simple 2>&1 | grep -q "Jenkins is fully up and running" || \
curl -s http://localhost:38080/login >/dev/null 2>&1; then
log "✅ Jenkins服务启动成功 (http://localhost:38080)"
log "✅ 管理员账号: admin / admin123"
return 0
fi
# 每10秒显示启动进度
if [ $((count % 5)) -eq 0 ]; then
local recent_logs=$(docker logs jenkins-simple 2>&1 | tail -2)
info "启动中... $recent_logs"
fi
sleep 2
count=$((count + 1))
echo -n "."
done
error "❌ Jenkins服务启动超时"
return 1
}
# 配置服务集成
setup_integration() {
step "配置服务集成..."
# 等待Jenkins完全启动
sleep 10
# 这里可以添加自动配置逻辑
# 例如:创建Jenkins凭据,配置Gitea webhook等
log "✅ 服务集成配置完成"
}
# 运行验证测试
run_verification() {
step "运行验证测试..."
local all_ok=true
# 测试Registry
if curl -s -w "%{http_code}" http://localhost:35001/v2/ | grep -q "200"; then
log "✅ Registry API正常"
else
error "❌ Registry API异常"
all_ok=false
fi
# 测试Registry UI
if curl -s http://localhost:35002 | grep -q "docker-registry-ui"; then
log "✅ Registry UI正常"
else
error "❌ Registry UI异常"
all_ok=false
fi
# 测试Gitea
if curl -s http://localhost:33000/api/healthz | grep -q "pass"; then
log "✅ Gitea API正常"
else
error "❌ Gitea API异常"
all_ok=false
fi
# 测试Jenkins (检查服务是否响应,允许重定向)
local jenkins_status=$(curl -s -w "%{http_code}" -o /dev/null http://localhost:38080/login)
if [[ "$jenkins_status" == "200" ]]; then
log "✅ Jenkins API正常"
else
error "❌ Jenkins API异常 (状态码: $jenkins_status)"
all_ok=false
fi
if $all_ok; then
log "🎉 所有服务验证通过!"
return 0
else
error "❌ 部分服务验证失败"
return 1
fi
}
# 显示部署结果
show_result() {
echo ""
echo "================================================================="
echo -e "${G}🎉 基础服务部署完成${NC}"
echo "================================================================="
echo ""
echo -e "${B}服务访问地址:${NC}"
echo " • Gitea: http://localhost:33000"
echo " • Jenkins: http://localhost:38080 (admin/admin123)"
echo " • Docker Registry: http://localhost:35001"
echo " • Registry UI: http://localhost:35002"
echo ""
echo -e "${B}SSH访问:${NC}"
echo " • Gitea SSH: ssh://git@localhost:32222"
echo ""
echo -e "${B}内部服务地址 (容器间通信):${NC}"
echo " • Gitea: http://gitea:3000"
echo " • Jenkins: http://jenkins:8080"
echo " • Registry: http://registry:5000"
echo ""
echo -e "${Y}后续步骤:${NC}"
echo " 1. 在Gitea中创建用户和仓库"
echo " 2. 配置Jenkins Pipeline"
echo " 3. 测试完整的CI/CD流程"
echo ""
echo -e "${B}管理命令:${NC}"
echo " ./scripts/maintenance/health-check.sh # 健康检查"
echo " ./scripts/maintenance/backup-all.sh # 数据备份"
echo " ./scripts/utils/show-logs.sh # 查看日志"
echo ""
echo "================================================================="
}
# 显示帮助
show_help() {
echo "基础服务统一构建脚本"
echo ""
echo "用法: $0 [选项]"
echo ""
echo "选项:"
echo " --full-auto 完全自动化部署 (推荐)"
echo " --step-by-step 分步骤部署,每步确认"
echo " --update-ports 仅更新端口配置"
echo " --cleanup 清理所有服务"
echo " --verify 仅运行验证测试"
echo " --help 显示帮助信息"
echo ""
echo "示例:"
echo " $0 --full-auto # 一键部署所有服务"
echo " $0 --step-by-step # 逐步部署"
echo " $0 --verify # 验证现有服务"
}
# 主函数
main() {
show_logo
case "${1:-full-auto}" in
"--full-auto")
log "开始完全自动化部署..."
check_dependencies
check_ports
cleanup_existing
init_environment
deploy_registry
deploy_gitea
deploy_jenkins
setup_integration
run_verification
show_result
;;
"--step-by-step")
log "开始分步骤部署..."
check_dependencies
echo "按回车继续到下一步..."
read -r
check_ports
echo "按回车继续清理现有服务..."
read -r
cleanup_existing
echo "按回车继续初始化环境..."
read -r
init_environment
echo "按回车继续部署Registry..."
read -r
deploy_registry
echo "按回车继续部署Gitea..."
read -r
deploy_gitea
echo "按回车继续部署Jenkins..."
read -r
deploy_jenkins
echo "按回车继续配置集成..."
read -r
setup_integration
echo "按回车继续验证测试..."
read -r
run_verification
show_result
;;
"--cleanup")
log "清理所有服务..."
cleanup_existing
docker network rm $NETWORK_NAME 2>/dev/null || true
log "✅ 清理完成"
;;
"--verify")
log "运行验证测试..."
run_verification
;;
"--help")
show_help
;;
*)
show_help
;;
esac
}
# 错误处理
trap 'error "部署失败,请检查错误信息"; exit 1' ERR
# 执行主程序
main "$@"
-129
View File
@@ -1,129 +0,0 @@
#!/bin/bash
# 多架构分别构建脚本 v1.0
set -e
echo "🏗️ 多架构分别构建解决方案"
# 加载版本配置
if [ -f "monitoring-versions.env" ]; then
source monitoring-versions.env
echo "📋 已加载版本配置文件"
else
echo "⚠️ 未找到版本配置文件,使用默认配置"
LJWX_VERSION="1.2.16"
REGISTRY="crpi-yilnm6upy4pmbp67.cn-shenzhen.personal.cr.aliyuncs.com/ljwx"
fi
# 登录阿里云
echo "🔐 登录阿里云Docker镜像仓库..."
echo "admin123" | docker login --username brunogao --password-stdin crpi-yilnm6upy4pmbp67.cn-shenzhen.personal.cr.aliyuncs.com
if [ $? -eq 0 ]; then
echo "✅ 阿里云登录成功"
else
echo "❌ 阿里云登录失败,请检查凭据"
exit 1
fi
# 构建函数
build_single_arch() {
local arch=$1
local tag_suffix=$2
local image_name="ljwx-boot"
local tag="$REGISTRY/$image_name:$LJWX_VERSION-$tag_suffix"
echo "🔨 构建 $arch 架构镜像..."
# 设置平台
export DOCKER_DEFAULT_PLATFORM="linux/$arch"
# 构建单架构镜像
docker build \
--platform linux/$arch \
--progress=plain \
-t $tag \
. -f ljwx-boot/ljwx-boot-admin/Dockerfile.prod
if [ $? -eq 0 ]; then
echo "✅ $arch 架构构建成功: $tag"
# 推送到镜像仓库
docker push $tag
echo "✅ $arch 架构推送成功"
return 0
else
echo "❌ $arch 架构构建失败"
return 1
fi
}
# 创建多架构manifest
create_multiarch_manifest() {
local image_name="ljwx-boot"
local manifest_tag="$REGISTRY/$image_name:$LJWX_VERSION"
local amd64_tag="$REGISTRY/$image_name:$LJWX_VERSION-amd64"
local arm64_tag="$REGISTRY/$image_name:$LJWX_VERSION-arm64"
echo "📦 创建多架构 manifest..."
# 创建 manifest
docker manifest create $manifest_tag $amd64_tag $arm64_tag
# 设置架构信息
docker manifest annotate $manifest_tag $amd64_tag --arch amd64
docker manifest annotate $manifest_tag $arm64_tag --arch arm64
# 推送 manifest
docker manifest push $manifest_tag
# 创建 latest 标签的 manifest
local latest_tag="$REGISTRY/$image_name:latest"
docker manifest create $latest_tag $amd64_tag $arm64_tag
docker manifest annotate $latest_tag $amd64_tag --arch amd64
docker manifest annotate $latest_tag $arm64_tag --arch arm64
docker manifest push $latest_tag
echo "✅ 多架构 manifest 创建完成"
echo "🏷️ 镜像标签: $manifest_tag, $latest_tag"
}
# 主程序
main() {
echo "🚀 开始分别构建多架构镜像..."
# 构建 AMD64 架构
echo ""
echo "=== 构建 AMD64 架构 ==="
if ! build_single_arch "amd64" "amd64"; then
echo "❌ AMD64 架构构建失败"
exit 1
fi
# 构建 ARM64 架构
echo ""
echo "=== 构建 ARM64 架构 ==="
if ! build_single_arch "arm64" "arm64"; then
echo "❌ ARM64 架构构建失败"
exit 1
fi
# 创建多架构 manifest
echo ""
echo "=== 创建多架构 Manifest ==="
create_multiarch_manifest
echo ""
echo "🎉 多架构构建完成!"
echo ""
echo "📊 构建摘要:"
echo " AMD64: $REGISTRY/ljwx-boot:$LJWX_VERSION-amd64"
echo " ARM64: $REGISTRY/ljwx-boot:$LJWX_VERSION-arm64"
echo " 多架构: $REGISTRY/ljwx-boot:$LJWX_VERSION"
echo " 多架构: $REGISTRY/ljwx-boot:latest"
echo ""
echo "💡 使用方式:"
echo " docker pull $REGISTRY/ljwx-boot:$LJWX_VERSION"
echo " Docker会自动选择适合当前架构的镜像"
}
# 执行主程序
main "$@"
-23
View File
@@ -1,23 +0,0 @@
# Drone Server Configuration
DRONE_GITEA_SERVER=http://localhost:3000
DRONE_GIT_ALWAYS_AUTH=true
DRONE_SERVER_HOST=localhost:8000
DRONE_SERVER_PROTO=http
DRONE_TLS_AUTOCERT=false
# OAuth Configuration
DRONE_GITEA_CLIENT_ID=c09c8d2e-7f17-4335-bf0e-2eb4a9df5d0b
DRONE_GITEA_CLIENT_SECRET=gto_culx6sjww6u7xd3ci6ifsekobfr67txpvjppb4aaokcelcopaq6a
DRONE_RPC_SECRET=$(openssl rand -hex 16)
# Database Configuration
DRONE_DATABASE_DRIVER=sqlite3
DRONE_DATABASE_DATASOURCE=/data/database.sqlite
# Logging Configuration
DRONE_LOGS_DEBUG=true
DRONE_LOGS_TRACE=true
# Runner Configuration
DRONE_RUNNER_CAPACITY=2
DRONE_RUNNER_NAME=mac-runner
-42
View File
@@ -1,42 +0,0 @@
name: CI/CD Pipeline
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: 设置 Python
uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: 安装依赖
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: 运行测试
run: |
pytest tests/ -v --cov=src
build:
needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: 构建镜像
run: |
docker build -t myapp:${{ github.sha }} .
docker tag myapp:${{ github.sha }} localhost:5001/myapp:${{ github.sha }}
- name: 推送镜像
run: |
docker push localhost:5001/myapp:${{ github.sha }}
-19
View File
@@ -1,19 +0,0 @@
kind: pipeline
type: docker
name: default
steps:
- name: test
image: python:3.10
commands:
- python --version
- echo "Running tests..."
- name: build
image: plugins/docker
settings:
registry: localhost:5000
repo: localhost:5000/myapp
tags: ${DRONE_COMMIT_SHA:0:8}
username: admin
password: admin123
-38
View File
@@ -1,38 +0,0 @@
#!/bin/bash
# 简单的 CI/CD 脚本
PROJECT_DIR="/path/to/your/project"
REGISTRY="localhost:5001"
IMAGE_NAME="myapp"
echo "=== 开始 CI/CD 流程 ==="
# 1. 拉取最新代码
cd "$PROJECT_DIR"
git pull origin main
# 2. 运行测试
echo "运行测试..."
python -m pytest tests/ -v
if [ $? -ne 0 ]; then
echo "测试失败,停止构建"
exit 1
fi
# 3. 构建镜像
echo "构建 Docker 镜像..."
COMMIT_SHA=$(git rev-parse --short HEAD)
docker build -t "$IMAGE_NAME:$COMMIT_SHA" .
# 4. 推送镜像
echo "推送镜像到 Registry..."
docker tag "$IMAGE_NAME:$COMMIT_SHA" "$REGISTRY/$IMAGE_NAME:$COMMIT_SHA"
docker push "$REGISTRY/$IMAGE_NAME:$COMMIT_SHA"
# 5. 部署 (可选)
echo "部署应用..."
# kubectl apply -f deployment.yaml
# docker-compose up -d
echo "=== CI/CD 流程完成 ==="
-351
View File
@@ -1,351 +0,0 @@
#!/bin/bash
# Jenkins完整设置脚本 - 使用初始密码完成配置
set -e
# 配置参数
JENKINS_URL="http://localhost:8081"
ADMIN_USER="admin"
ADMIN_PASS="admin123"
CONTAINER_NAME="jenkins-final-auto"
# 颜色定义
G='\033[0;32m'
Y='\033[1;33m'
R='\033[0;31m'
B='\033[0;34m'
NC='\033[0m'
log() { echo -e "${G}[INFO]${NC} $1"; }
warn() { echo -e "${Y}[WARN]${NC} $1"; }
error() { echo -e "${R}[ERROR]${NC} $1"; }
info() { echo -e "${B}[INFO]${NC} $1"; }
# 获取初始密码
get_initial_password() {
local initial_pass=$(docker exec $CONTAINER_NAME cat /var/jenkins_home/secrets/initialAdminPassword 2>/dev/null || echo "")
echo "$initial_pass"
}
# 执行Groovy脚本
execute_groovy_script() {
local script="$1"
local auth="$2"
cat > /tmp/jenkins-script.groovy << EOF
$script
EOF
# 通过REST API执行
curl -s -X POST "$JENKINS_URL/scriptText" \
--data-urlencode "script@/tmp/jenkins-script.groovy" \
--user "$auth" || true
}
# 完成初始设置
complete_initial_setup() {
local initial_pass="$1"
log "使用初始密码完成Jenkins设置..."
# 1. 跳过插件安装向导并创建管理员用户
local setup_script='
import jenkins.model.*
import hudson.security.*
import jenkins.install.InstallState
def instance = Jenkins.getInstance()
// 跳过插件安装
instance.setInstallState(InstallState.INITIAL_SETUP_COMPLETED)
// 创建管理员用户
def hudsonRealm = new HudsonPrivateSecurityRealm(false)
hudsonRealm.createAccount("'$ADMIN_USER'", "'$ADMIN_PASS'")
instance.setSecurityRealm(hudsonRealm)
// 设置授权策略
def strategy = new FullControlOnceLoggedInAuthorizationStrategy()
strategy.setAllowAnonymousRead(false)
instance.setAuthorizationStrategy(strategy)
// 保存配置
instance.save()
println "✅ 管理员用户创建完成: '$ADMIN_USER'"
'
execute_groovy_script "$setup_script" "admin:$initial_pass"
log "✅ 初始设置完成"
}
# 配置工具和凭据
configure_jenkins() {
log "配置Jenkins工具和凭据..."
local config_script='
import jenkins.model.*
import hudson.security.*
import hudson.tools.*
import hudson.plugins.git.*
import com.cloudbees.plugins.credentials.*
import com.cloudbees.plugins.credentials.domains.*
import com.cloudbees.plugins.credentials.impl.*
import org.jenkinsci.plugins.plaincredentials.impl.StringCredentialsImpl
def instance = Jenkins.getInstance()
// 1. 配置Git工具
def gitTool = instance.getDescriptorByType(GitTool.DescriptorImpl.class)
gitTool.setInstallations(new GitTool("Default", "/usr/bin/git", []))
// 2. 配置凭据
def store = instance.getExtensionList("com.cloudbees.plugins.credentials.SystemCredentialsProvider")[0].getStore()
def domain = Domain.global()
// Gitea API Token
def giteaToken = new StringCredentialsImpl(
CredentialsScope.GLOBAL,
"gitea-api-token",
"Gitea API访问令牌",
hudson.util.Secret.fromString("changeme-gitea-token")
)
// Docker Registry认证
def registryAuth = new UsernamePasswordCredentialsImpl(
CredentialsScope.GLOBAL,
"docker-registry-auth",
"Docker Registry认证",
"admin",
"admin123"
)
store.addCredentials(domain, giteaToken)
store.addCredentials(domain, registryAuth)
// 3. 系统配置
instance.setNumExecutors(4)
instance.setSystemMessage("""
🎉 Jenkins CI/CD服务器 - 完全自动化配置
📦 插件: 自动安装130+核心插件
🔧 工具: Git自动配置
🔐 凭据: Gitea, Registry认证已创建
📋 作业: 可通过Web界面创建
📚 文档: docs/jenkins-best-practice-summary.md
🌐 访问地址: http://localhost:8081
👤 登录账号: admin / admin123
""")
// 设置Jenkins URL
def location = instance.getDescriptor("jenkins.model.JenkinsLocationConfiguration")
location.setUrl("http://localhost:8081/")
location.setAdminAddress("admin@example.com")
location.save()
instance.save()
println "✅ Jenkins配置完成"
'
execute_groovy_script "$config_script" "$ADMIN_USER:$ADMIN_PASS"
log "✅ 配置完成"
}
# 创建示例作业
create_demo_job() {
log "创建多平台构建演示作业..."
cat > /tmp/demo-job.xml << 'EOF'
<?xml version='1.1' encoding='UTF-8'?>
<flow-definition plugin="workflow-job">
<actions/>
<description>🐳 多平台Docker镜像构建演示</description>
<keepDependencies>false</keepDependencies>
<properties>
<hudson.model.ParametersDefinitionProperty>
<parameterDefinitions>
<hudson.model.StringParameterDefinition>
<name>IMAGE_NAME</name>
<description>镜像名称</description>
<defaultValue>demo-app</defaultValue>
</hudson.model.StringParameterDefinition>
<hudson.model.StringParameterDefinition>
<name>IMAGE_TAG</name>
<description>镜像标签</description>
<defaultValue>latest</defaultValue>
</hudson.model.StringParameterDefinition>
</parameterDefinitions>
</hudson.model.ParametersDefinitionProperty>
</properties>
<definition class="org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition" plugin="workflow-cps">
<script>pipeline {
agent any
environment {
REGISTRY = 'localhost:5001'
PLATFORMS = 'linux/amd64,linux/arm64'
}
stages {
stage('🔍 环境检查') {
steps {
sh '''
echo "=== 环境信息 ==="
docker --version
docker buildx version || echo "Docker Buildx未安装"
echo "Registry: ${REGISTRY}"
echo "平台支持: ${PLATFORMS}"
'''
}
}
stage('📦 创建示例应用') {
steps {
writeFile file: 'Dockerfile', text: '''FROM alpine:latest
RUN apk add --no-cache curl
WORKDIR /app
COPY . .
EXPOSE 8080
CMD echo "Hello from Multi-Platform Build!" && echo "Platform: ${TARGETPLATFORM:-unknown}" && echo "Build: ${BUILD_NUMBER}" && echo "Image: ${IMAGE_NAME}:${IMAGE_TAG}"'''
}
}
stage('🐳 多平台构建') {
steps {
script {
def imageFullName = "${REGISTRY}/${params.IMAGE_NAME}:${params.IMAGE_TAG}"
sh """
docker buildx create --use --name multi-builder --driver docker-container || true
docker buildx build --platform ${PLATFORMS} -t ${imageFullName} --push .
echo "✅ 多平台镜像构建完成: ${imageFullName}"
"""
}
}
}
}
post {
success {
echo "🎉 多平台构建成功!"
}
cleanup {
sh 'docker system prune -f || true'
}
}
}</script>
<sandbox>true</sandbox>
</definition>
<triggers/>
<disabled>false</disabled>
</flow-definition>
EOF
# 创建作业
curl -s -X POST "$JENKINS_URL/createItem?name=multi-platform-build-demo" \
-H "Content-Type: application/xml" \
--data-binary @/tmp/demo-job.xml \
--user "$ADMIN_USER:$ADMIN_PASS" > /dev/null 2>&1
log "✅ 示例作业创建完成"
}
# 验证配置
verify_configuration() {
log "验证Jenkins配置..."
# 测试登录
local response=$(curl -s -w "%{http_code}" -o /dev/null \
-X POST "$JENKINS_URL/j_security_check" \
-d "j_username=$ADMIN_USER&j_password=$ADMIN_PASS")
if [[ "$response" == "302" ]]; then
log "✅ 管理员登录成功"
else
warn "登录验证响应码: $response"
fi
# 检查插件数量
local plugin_count=$(docker exec $CONTAINER_NAME find /var/jenkins_home/plugins -name "*.jpi" | wc -l)
log "📦 已安装插件: $plugin_count 个"
# 检查Web界面
if curl -s "$JENKINS_URL/login" > /dev/null; then
log "✅ Web界面可访问"
else
warn "Web界面访问异常"
fi
}
# 显示最终总结
show_final_summary() {
echo ""
echo "============================================================"
echo -e "${G}🎉 Jenkins完全自动化配置成功!${NC}"
echo "============================================================"
echo ""
echo -e "${B}✅ 配置完成状态:${NC}"
echo " 🚀 设置向导: 已完全跳过"
echo " 👤 管理员用户: $ADMIN_USER / $ADMIN_PASS"
echo " 📦 插件安装: $(docker exec $CONTAINER_NAME find /var/jenkins_home/plugins -name "*.jpi" | wc -l) 个核心插件"
echo " 🔧 工具配置: Git已配置"
echo " 🔐 凭据管理: Gitea, Registry模板已创建"
echo " 📋 示例作业: multi-platform-build-demo"
echo ""
echo -e "${B}🌐 访问信息:${NC}"
echo " Jenkins: $JENKINS_URL"
echo " Registry: http://localhost:5001"
echo " 用户名: $ADMIN_USER"
echo " 密码: $ADMIN_PASS"
echo ""
echo -e "${B}✨ 可以立即使用:${NC}"
echo " 1. 访问 $JENKINS_URL 登录Jenkins"
echo " 2. 运行多平台构建演示作业"
echo " 3. 创建新的Pipeline项目"
echo " 4. 配置与Gitea的集成"
echo ""
echo "============================================================"
}
# 主函数
main() {
echo ""
echo "============================================================"
echo -e "${B}🔧 Jenkins完整自动化配置${NC}"
echo "============================================================"
echo ""
# 等待Jenkins启动
log "等待Jenkins启动完成..."
sleep 15
# 获取初始密码
local initial_pass=$(get_initial_password)
if [[ -z "$initial_pass" ]]; then
error "无法获取初始密码,Jenkins可能未完全启动"
exit 1
fi
log "获取到初始密码: $initial_pass"
# 执行配置步骤
complete_initial_setup "$initial_pass"
sleep 5
configure_jenkins
sleep 5
create_demo_job
sleep 5
verify_configuration
# 显示最终总结
show_final_summary
log "🎉 Jenkins自动化配置全部完成!"
log "现在可以访问 $JENKINS_URL 并使用 $ADMIN_USER/$ADMIN_PASS 登录"
}
# 执行主程序
main "$@"
-144
View File
@@ -1,144 +0,0 @@
#!/bin/bash
# 配置 OrbStack Docker 使用本地 Registry 缓存
# 这将显著加速 Docker 镜像拉取速度
set -e
# 颜色定义
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
echo -e "${BLUE}🚀 配置 OrbStack Docker 使用本地 Registry 缓存${NC}"
echo ""
# OrbStack Docker 配置文件路径
ORBSTACK_CONFIG_DIR="$HOME/.orbstack/config"
DOCKER_CONFIG_FILE="$ORBSTACK_CONFIG_DIR/docker.json"
# 本地缓存 Registry 配置
CACHE_REGISTRY="localhost:15001"
PRIVATE_REGISTRY="localhost:15000"
# 检查 OrbStack 配置目录是否存在
if [ ! -d "$ORBSTACK_CONFIG_DIR" ]; then
echo -e "${YELLOW}⚠️ OrbStack 配置目录不存在,正在创建...${NC}"
mkdir -p "$ORBSTACK_CONFIG_DIR"
fi
# 备份原有配置
if [ -f "$DOCKER_CONFIG_FILE" ]; then
echo -e "${BLUE}📦 备份原有配置到 docker.json.backup${NC}"
cp "$DOCKER_CONFIG_FILE" "$DOCKER_CONFIG_FILE.backup"
fi
# 检查本地缓存 Registry 是否运行
echo -e "${BLUE}🔍 检查本地缓存 Registry 状态...${NC}"
if curl -s -f --max-time 3 "http://$CACHE_REGISTRY/v2/_catalog" > /dev/null 2>&1; then
echo -e "${GREEN}✅ 本地缓存 Registry 运行正常${NC}"
else
echo -e "${YELLOW}⚠️ 本地缓存 Registry 未运行${NC}"
echo " 请先启动缓存服务: cd ~/work/codes/tools/macos/registery && ./install-local-registry-macos.sh"
exit 1
fi
# 创建或更新 Docker 配置
echo -e "${BLUE}📝 配置 Docker daemon 使用本地缓存...${NC}"
# 读取现有配置(如果存在)
if [ -f "$DOCKER_CONFIG_FILE" ]; then
EXISTING_CONFIG=$(cat "$DOCKER_CONFIG_FILE")
else
EXISTING_CONFIG="{}"
fi
# 使用 jq 更新配置(如果没有 jq,则手动创建)
if command -v jq &> /dev/null; then
# 使用 jq 合并配置
echo "$EXISTING_CONFIG" | jq --arg cache "$CACHE_REGISTRY" --arg private "$PRIVATE_REGISTRY" '
.["registry-mirrors"] = ["http://\($cache)"] |
.["insecure-registries"] = (
if .["insecure-registries"] then
(.["insecure-registries"] + [$cache, $private]) | unique
else
[$cache, $private]
end
)
' > "$DOCKER_CONFIG_FILE"
else
# 手动创建配置
cat > "$DOCKER_CONFIG_FILE" <<EOF
{
"registry-mirrors": ["http://$CACHE_REGISTRY"],
"insecure-registries": ["$CACHE_REGISTRY", "$PRIVATE_REGISTRY"]
}
EOF
fi
echo -e "${GREEN}✅ Docker 配置已更新${NC}"
echo ""
echo "配置文件: $DOCKER_CONFIG_FILE"
echo "内容:"
cat "$DOCKER_CONFIG_FILE" | (command -v jq &> /dev/null && jq . || cat)
echo ""
# 重启 OrbStack(需要用户确认)
echo -e "${YELLOW}⚠️ 配置已更新,但需要重启 OrbStack 才能生效${NC}"
echo ""
echo "请选择操作:"
echo " 1) 自动重启 OrbStack (推荐)"
echo " 2) 稍后手动重启"
echo ""
read -p "请输入选项 (1/2): " -n 1 -r
echo ""
if [[ $REPLY =~ ^[1]$ ]]; then
echo -e "${BLUE}🔄 正在重启 OrbStack...${NC}"
# 停止 OrbStack
if pgrep -x "OrbStack" > /dev/null; then
osascript -e 'quit app "OrbStack"' 2>/dev/null || killall OrbStack 2>/dev/null || true
echo " 等待 OrbStack 停止..."
sleep 3
fi
# 启动 OrbStack
open -a OrbStack
echo -e "${GREEN}✅ OrbStack 已重启${NC}"
echo " 等待 Docker 服务启动..."
sleep 5
# 验证 Docker 是否可用
for i in {1..10}; do
if docker info > /dev/null 2>&1; then
echo -e "${GREEN}✅ Docker 服务已启动${NC}"
break
fi
echo " 等待 Docker 服务启动... ($i/10)"
sleep 2
done
else
echo -e "${YELLOW}⚠️ 请手动重启 OrbStack:${NC}"
echo " 1. 退出 OrbStack"
echo " 2. 重新打开 OrbStack"
fi
echo ""
echo -e "${GREEN}=========================================${NC}"
echo -e "${GREEN}配置完成!${NC}"
echo -e "${GREEN}=========================================${NC}"
echo ""
echo "现在所有 docker pull 命令将自动使用本地缓存加速"
echo ""
echo "验证配置:"
echo " docker info | grep -A 5 'Registry Mirrors'"
echo ""
echo "测试拉取速度:"
echo " time docker pull nginx:alpine"
echo ""
echo "查看缓存镜像:"
echo " curl http://$CACHE_REGISTRY/v2/_catalog | jq ."
echo " Web UI: http://localhost:8083"
echo ""
-289
View File
@@ -1,289 +0,0 @@
#!/bin/bash
# LJWX Jenkins完整自动化部署脚本
set -e
# 配置参数
COMPOSE_FILE="docker/compose/ljwx-jenkins-complete.yml"
IMAGE_NAME="ljwx-jenkins"
REGISTRY_URL="localhost:5001"
PROJECT_NAME="ljwx"
# 颜色定义
G='\033[0;32m'
Y='\033[1;33m'
R='\033[0;31m'
B='\033[0;34m'
P='\033[0;35m'
NC='\033[0m'
log() { echo -e "${G}[INFO]${NC} $1"; }
warn() { echo -e "${Y}[WARN]${NC} $1"; }
error() { echo -e "${R}[ERROR]${NC} $1"; }
info() { echo -e "${B}[INFO]${NC} $1"; }
success() { echo -e "${P}[SUCCESS]${NC} $1"; }
# 检查环境
check_environment() {
log "检查环境依赖..."
# 检查Docker
if ! command -v docker &> /dev/null; then
error "Docker未安装"
exit 1
fi
# 检查Docker Compose
if ! command -v docker-compose &> /dev/null; then
error "Docker Compose未安装"
exit 1
fi
# 检查Docker服务
if ! docker info &> /dev/null; then
error "Docker服务未运行"
exit 1
fi
success "环境检查通过"
}
# 清理旧部署
cleanup_old_deployment() {
log "清理旧部署..."
# 停止并删除旧容器
docker-compose -f $COMPOSE_FILE down 2>/dev/null || true
# 删除旧镜像
docker rmi $IMAGE_NAME:latest 2>/dev/null || true
# 清理未使用的资源
docker system prune -f 2>/dev/null || true
success "清理完成"
}
# 构建镜像
build_image() {
log "构建LJWX Jenkins镜像..."
# 确保目录存在
mkdir -p docker/compose/jenkins/setup
# 构建镜像
docker-compose -f $COMPOSE_FILE build --no-cache ljwx-jenkins
# 标记镜像
docker tag ljwx-jenkins:latest $IMAGE_NAME:$(date +%Y%m%d-%H%M%S)
success "镜像构建完成: $IMAGE_NAME:latest"
}
# 启动服务
start_services() {
log "启动LJWX Jenkins服务..."
# 启动服务
docker-compose -f $COMPOSE_FILE up -d
success "服务启动完成"
}
# 等待服务就绪
wait_for_services() {
log "等待服务就绪..."
local max_attempts=60
local attempt=0
while [ $attempt -lt $max_attempts ]; do
if curl -s http://localhost:8081/login > /dev/null 2>&1; then
success "Jenkins服务就绪"
break
fi
echo -n "."
sleep 5
((attempt++))
done
if [ $attempt -eq $max_attempts ]; then
error "Jenkins服务启动超时"
exit 1
fi
# 检查Registry
if curl -s http://localhost:5001/v2/ > /dev/null 2>&1; then
success "Registry服务就绪"
else
warn "Registry服务可能未就绪"
fi
}
# 推送镜像到Registry
push_to_registry() {
log "推送镜像到Registry..."
# 等待Registry就绪
sleep 10
# 标记镜像
docker tag $IMAGE_NAME:latest $REGISTRY_URL/$IMAGE_NAME:latest
docker tag $IMAGE_NAME:latest $REGISTRY_URL/$IMAGE_NAME:$(date +%Y%m%d-%H%M%S)
# 推送镜像
docker push $REGISTRY_URL/$IMAGE_NAME:latest
docker push $REGISTRY_URL/$IMAGE_NAME:$(date +%Y%m%d-%H%M%S)
success "镜像推送完成"
}
# 验证部署
verify_deployment() {
log "验证部署状态..."
echo ""
echo "============================================================"
echo -e "${B}📊 部署状态检查${NC}"
echo "============================================================"
# 检查容器状态
echo -e "${B}🐳 容器状态:${NC}"
docker-compose -f $COMPOSE_FILE ps
echo ""
echo -e "${B}🔌 插件统计:${NC}"
local plugin_count=$(docker exec ljwx-jenkins find /var/jenkins_home/plugins -name "*.jpi" 2>/dev/null | wc -l || echo "检查中...")
echo " 已安装插件: $plugin_count 个"
echo ""
echo -e "${B}📦 镜像信息:${NC}"
echo " 本地镜像: $(docker images $IMAGE_NAME:latest --format "table {{.Repository}}:{{.Tag}}\t{{.Size}}")"
echo ""
echo -e "${B}🌐 服务地址:${NC}"
echo " Jenkins Web: http://localhost:8081"
echo " Registry API: http://localhost:5001"
echo " Registry UI: http://localhost:5002"
echo ""
echo -e "${B}🔑 登录信息:${NC}"
echo " 用户名: admin"
echo " 密码: admin123"
# 检查Registry中的镜像
echo ""
echo -e "${B}📋 Registry镜像:${NC}"
curl -s http://localhost:5001/v2/_catalog 2>/dev/null | grep -o '"repositories":\[[^]]*\]' || echo " 检查Registry镜像列表中..."
}
# 显示Webhook配置信息
show_webhook_info() {
echo ""
echo "============================================================"
echo -e "${P}🚀 CI/CD配置指南${NC}"
echo "============================================================"
echo -e "${B}📝 Gitea Webhook配置:${NC}"
echo " Java项目: http://localhost:8081/generic-webhook-trigger/invoke?token=java-webhook-token"
echo " Vue3项目: http://localhost:8081/generic-webhook-trigger/invoke?token=vue3-webhook-token"
echo " Python项目: http://localhost:8081/generic-webhook-trigger/invoke?token=python-webhook-token"
echo ""
echo -e "${B}📋 Pipeline作业:${NC}"
echo " ✅ java-spring-boot-pipeline (Java SpringBoot CI/CD)"
echo " ✅ vue3-frontend-pipeline (Vue3前端CI/CD)"
echo " ✅ python-fastapi-pipeline (Python FastAPI CI/CD)"
echo ""
echo -e "${B}🔧 配置步骤:${NC}"
echo " 1. 访问 http://localhost:8081 登录Jenkins (admin/admin123)"
echo " 2. 更新凭据管理中的实际Token和密钥"
echo " 3. 在Gitea中配置上述Webhook URL"
echo " 4. 推送代码触发自动CI/CD流程"
echo ""
echo -e "${B}📚 CI/CD流程:${NC}"
echo " Git Push → Gitea Webhook → Jenkins Pipeline → Docker Build → Registry Push → K8s Deploy"
}
# 显示管理命令
show_management_commands() {
echo ""
echo "============================================================"
echo -e "${Y}🔧 管理命令${NC}"
echo "============================================================"
echo -e "${B}日常管理:${NC}"
echo " 查看日志: docker-compose -f $COMPOSE_FILE logs -f ljwx-jenkins"
echo " 重启服务: docker-compose -f $COMPOSE_FILE restart ljwx-jenkins"
echo " 停止服务: docker-compose -f $COMPOSE_FILE down"
echo " 更新镜像: ./deploy-ljwx-jenkins.sh"
echo ""
echo -e "${B}备份恢复:${NC}"
echo " 备份数据: docker run --rm -v ljwx-jenkins-data:/data -v \$(pwd):/backup alpine tar czf /backup/jenkins-backup-\$(date +%Y%m%d).tar.gz -C /data ."
echo " 恢复数据: docker run --rm -v ljwx-jenkins-data:/data -v \$(pwd):/backup alpine tar xzf /backup/jenkins-backup-YYYYMMDD.tar.gz -C /data"
echo ""
echo -e "${B}镜像管理:${NC}"
echo " 查看镜像: curl -s http://localhost:5001/v2/_catalog | jq"
echo " 删除镜像: curl -X DELETE http://localhost:5001/v2/$IMAGE_NAME/manifests/\$(docker manifest inspect $REGISTRY_URL/$IMAGE_NAME:latest | jq -r '.mediaType')"
}
# 主函数
main() {
echo ""
echo "============================================================"
echo -e "${P}🚀 LJWX Jenkins 完整自动化部署${NC}"
echo "============================================================"
echo ""
check_environment
cleanup_old_deployment
build_image
start_services
wait_for_services
# 推送到Registry
push_to_registry || warn "Registry推送失败,请检查服务状态"
verify_deployment
show_webhook_info
show_management_commands
echo ""
echo "============================================================"
success "🎉 LJWX Jenkins部署完成!"
echo -e "${P}现在可以访问 http://localhost:8081 开始使用完整的CI/CD环境!${NC}"
echo "============================================================"
}
# 检查参数
case "${1:-deploy}" in
"deploy")
main
;;
"cleanup")
cleanup_old_deployment
;;
"build")
build_image
;;
"push")
push_to_registry
;;
"verify")
verify_deployment
;;
*)
echo "用法: $0 [deploy|cleanup|build|push|verify]"
echo " deploy - 完整部署 (默认)"
echo " cleanup - 清理旧部署"
echo " build - 仅构建镜像"
echo " push - 仅推送镜像"
echo " verify - 仅验证部署"
exit 1
;;
esac
-324
View File
@@ -1,324 +0,0 @@
#!/bin/bash
# LJWX 许可证系统部署脚本
# 适用于本地无外网环境
set -e
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 日志函数
log_info() {
echo -e "${GREEN}[INFO]${NC} $1"
}
log_warn() {
echo -e "${YELLOW}[WARN]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
log_step() {
echo -e "${BLUE}[STEP]${NC} $1"
}
# 检查依赖
check_dependencies() {
log_step "检查系统依赖..."
# 检查Docker
if ! command -v docker &> /dev/null; then
log_error "Docker 未安装,请先安装 Docker"
exit 1
fi
# 检查Docker Compose
if ! command -v docker-compose &> /dev/null; then
log_error "Docker Compose 未安装,请先安装 Docker Compose"
exit 1
fi
log_info "系统依赖检查完成"
}
# 生成硬件指纹
generate_hardware_fingerprint() {
log_step "生成硬件指纹..."
# 创建临时Java类来生成指纹
TEMP_DIR=$(mktemp -d)
cat > "$TEMP_DIR/GenerateFingerprint.java" << 'EOF'
import java.security.MessageDigest;
import java.io.BufferedReader;
import java.io.FileReader;
import java.net.NetworkInterface;
import java.util.Enumeration;
public class GenerateFingerprint {
public static void main(String[] args) {
try {
StringBuilder info = new StringBuilder();
// CPU信息
try (BufferedReader br = new BufferedReader(new FileReader("/proc/cpuinfo"))) {
String line;
while ((line = br.readLine()) != null) {
if (line.startsWith("model name")) {
info.append(line.split(":")[1].trim());
break;
}
}
} catch (Exception e) {
info.append(System.getProperty("os.arch"));
}
info.append("|");
// 系统信息
try (BufferedReader br = new BufferedReader(new FileReader("/etc/machine-id"))) {
info.append(br.readLine().trim());
} catch (Exception e) {
info.append(System.getProperty("user.name"));
}
info.append("|");
// MAC地址
try {
Enumeration<NetworkInterface> networks = NetworkInterface.getNetworkInterfaces();
while (networks.hasMoreElements()) {
NetworkInterface ni = networks.nextElement();
byte[] mac = ni.getHardwareAddress();
if (mac != null && mac.length > 0) {
StringBuilder macStr = new StringBuilder();
for (byte b : mac) {
macStr.append(String.format("%02X", b));
}
String macAddress = macStr.toString();
if (!macAddress.startsWith("00505E") && !macAddress.startsWith("000C29")) {
info.append(macAddress);
break;
}
}
}
} catch (Exception e) {
info.append("DEFAULT_MAC");
}
// 生成SHA256
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(info.toString().getBytes());
StringBuilder result = new StringBuilder();
for (byte b : hash) {
result.append(String.format("%02X", b));
}
System.out.println(result.toString());
} catch (Exception e) {
System.err.println("生成硬件指纹失败: " + e.getMessage());
System.exit(1);
}
}
}
EOF
# 编译并运行
cd "$TEMP_DIR"
javac GenerateFingerprint.java
HARDWARE_FINGERPRINT=$(java GenerateFingerprint)
# 清理临时文件
rm -rf "$TEMP_DIR"
log_info "硬件指纹: $HARDWARE_FINGERPRINT"
echo "$HARDWARE_FINGERPRINT" > ./hardware_fingerprint.txt
log_info "硬件指纹已保存到 hardware_fingerprint.txt"
log_warn "请将此硬件指纹提供给许可证提供商以获取许可证文件"
}
# 检查许可证文件
check_license_file() {
log_step "检查许可证文件..."
if [ ! -d "./license" ]; then
mkdir -p ./license
log_info "创建许可证目录: ./license"
fi
if [ ! -f "./license/ljwx.lic" ]; then
log_error "许可证文件不存在: ./license/ljwx.lic"
log_info "请联系供应商获取许可证文件,并将其放置在 ./license/ljwx.lic"
# 创建示例��可证用于测试
cat > "./license/ljwx.lic" << EOF
# 这是一个示例许可证文件
# 实际部署时请替换为真实的许可证文件
SAMPLE_LICENSE_FOR_TESTING
EOF
log_warn "已创建示例许可证文件,仅用于测试目的"
return 1
fi
log_info "许可证文件检查完成"
return 0
}
# 配置环境变量
setup_environment() {
log_step "配置环境变量..."
if [ ! -f ".env" ]; then
if [ -f ".env.license.example" ]; then
cp .env.license.example .env
log_info "已复制环境变量示例文件,请编辑 .env 文件填写实际配置"
# 生成随机密码
MYSQL_ROOT_PASSWORD=$(openssl rand -base64 32 | tr -d "=+/" | cut -c1-16)
MYSQL_PASSWORD=$(openssl rand -base64 32 | tr -d "=+/" | cut -c1-16)
REDIS_PASSWORD=$(openssl rand -base64 32 | tr -d "=+/" | cut -c1-16)
# 替换密码
sed -i "s/your_mysql_root_password/$MYSQL_ROOT_PASSWORD/g" .env
sed -i "s/your_mysql_password/$MYSQL_PASSWORD/g" .env
sed -i "s/your_redis_password/$REDIS_PASSWORD/g" .env
log_info "已生成随机密码并配置到 .env 文件"
else
log_error "环境变量示例文件不存在"
exit 1
fi
fi
log_info "环境变量配置完成"
}
# 部署系统
deploy_system() {
log_step "部署LJWX系统..."
# 使用许可证版本的docker-compose文件
if [ -f "docker-compose.license.yml" ]; then
log_info "使用许可证版本配置文件..."
docker-compose -f docker-compose.license.yml up -d
else
log_error "许可证配置文件不存在: docker-compose.license.yml"
exit 1
fi
log_info "系统部署完成"
}
# 验证部署
verify_deployment() {
log_step "验证系统部署..."
# 等待服务启动
log_info "等待服务启动..."
sleep 30
# 检查容器状态
log_info "检查容器状态..."
docker-compose -f docker-compose.license.yml ps
# 检查许可证状态
log_info "检查许可证状态..."
for i in {1..10}; do
if curl -s -f http://localhost:8080/api/license/status > /dev/null; then
log_info "许可证API响应正常"
curl -s http://localhost:8080/api/license/status | python3 -m json.tool
break
else
log_warn "等待许可证API启动... ($i/10)"
sleep 10
fi
done
log_info "部署验证完成"
}
# 显示使用说明
show_usage() {
log_step "使用说明"
echo ""
echo "系统已成功部署,可以通过以下方式访问:"
echo ""
echo "• 管理界面: http://localhost:3000"
echo "• API接口: http://localhost:8080"
echo "• 大屏系统: http://localhost:5000"
echo ""
echo "许可证管理API:"
echo "• 许可证状态: curl http://localhost:8080/api/license/status"
echo "• 硬件指纹: curl http://localhost:8080/api/license/fingerprint"
echo "• 功能检查: curl http://localhost:8080/api/license/feature/{feature_name}"
echo ""
echo "常用命令:"
echo "• 查看日志: docker-compose -f docker-compose.license.yml logs -f"
echo "• 停止系统: docker-compose -f docker-compose.license.yml down"
echo "• 重启系统: docker-compose -f docker-compose.license.yml restart"
echo ""
}
# 主函数
main() {
echo ""
log_info "🚀 LJWX 许可证系统部署工具"
echo ""
# 检查参数
case "${1:-deploy}" in
"fingerprint")
generate_hardware_fingerprint
exit 0
;;
"check")
check_license_file
exit $?
;;
"deploy")
# 执行完整部署流程
check_dependencies
generate_hardware_fingerprint
if ! check_license_file; then
log_error "许可证文件检查失败,请获取正式许可证后重新运行"
exit 1
fi
setup_environment
deploy_system
verify_deployment
show_usage
;;
"help"|"-h"|"--help")
echo "用法: $0 [命令]"
echo ""
echo "命令:"
echo " deploy 完整部署系统(默认)"
echo " fingerprint 只生成硬件指纹"
echo " check 只检查许可证文件"
echo " help 显示此帮助信息"
echo ""
exit 0
;;
*)
log_error "未知命令: $1"
echo "使用 '$0 help' 查看帮助信息"
exit 1
;;
esac
log_info "🎉 部署完成!"
}
# 执行主函数
main "$@"
-141
View File
@@ -1,141 +0,0 @@
# Docker Compose 许可证集成配置示例
# 本地无外网部署模式
version: '3.8'
services:
# 主应用服务
ljwx-boot:
image: ljwx/boot:latest
container_name: ljwx-boot
environment:
- SPRING_PROFILES_ACTIVE=prod
- MYSQL_DATABASE=${MYSQL_DATABASE:-ljwx}
- MYSQL_HOST=${MYSQL_HOST:-mysql}
- MYSQL_USER=${MYSQL_USER:-ljwx}
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
- REDIS_HOST=${REDIS_HOST:-redis}
- REDIS_PASSWORD=${REDIS_PASSWORD}
# 许可证配置
- LJWX_LICENSE_ENABLED=true
- LJWX_LICENSE_FILE_PATH=/app/license/ljwx.lic
- LJWX_LICENSE_CHECK_INTERVAL=300
volumes:
# 挂载许可证文件 - 客户需要将许可证放在此目录
- ./license:/app/license:ro
# 挂载系统信息用于硬件指纹生成
- /sys/class/dmi/id:/host/dmi:ro
- /proc/cpuinfo:/host/cpuinfo:ro
- /etc/machine-id:/host/machine-id:ro
ports:
- "8080:8080"
depends_on:
- mysql
- redis
networks:
- ljwx-network
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/api/license/status"]
interval: 30s
timeout: 10s
retries: 3
start_period: 60s
# 前端管理界面
ljwx-admin:
image: ljwx/admin:latest
container_name: ljwx-admin
environment:
- VITE_API_BASE_URL=http://ljwx-boot:8080
ports:
- "3000:3000"
depends_on:
ljwx-boot:
condition: service_healthy
networks:
- ljwx-network
restart: unless-stopped
# 大屏服务(需要许可证授权)
ljwx-bigscreen:
image: ljwx/bigscreen:latest
container_name: ljwx-bigscreen
environment:
- API_BASE_URL=http://ljwx-boot:8080
- LICENSE_CHECK_URL=http://ljwx-boot:8080/api/license/feature/big_screen
ports:
- "5000:5000"
depends_on:
ljwx-boot:
condition: service_healthy
networks:
- ljwx-network
restart: unless-stopped
# MySQL数据库
mysql:
image: mysql:8.0
container_name: ljwx-mysql
environment:
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
- MYSQL_DATABASE=${MYSQL_DATABASE:-ljwx}
- MYSQL_USER=${MYSQL_USER:-ljwx}
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
volumes:
- mysql_data:/var/lib/mysql
- ./sql:/docker-entrypoint-initdb.d
ports:
- "3306:3306"
networks:
- ljwx-network
restart: unless-stopped
# Redis缓存
redis:
image: redis:7-alpine
container_name: ljwx-redis
command: redis-server --requirepass ${REDIS_PASSWORD}
volumes:
- redis_data:/data
ports:
- "6379:6379"
networks:
- ljwx-network
restart: unless-stopped
# 许可证监控服务(可选)
license-monitor:
image: ljwx/license-monitor:latest
container_name: ljwx-license-monitor
environment:
- LICENSE_API_URL=http://ljwx-boot:8080/api/license
- CHECK_INTERVAL=3600 # 1小时检查一次
- ALERT_EMAIL=${ALERT_EMAIL}
- ALERT_WEBHOOK=${ALERT_WEBHOOK}
volumes:
- ./logs/license:/app/logs
depends_on:
ljwx-boot:
condition: service_healthy
networks:
- ljwx-network
restart: unless-stopped
profiles:
- monitoring # 使用 --profile monitoring 启用
volumes:
mysql_data:
driver: local
redis_data:
driver: local
networks:
ljwx-network:
driver: bridge
# 使用说明:
# 1. 创建 .env 文件配置环境变量
# 2. 将许可证文件放到 ./license/ljwx.lic
# 3. 运行: docker-compose up -d
# 4. 检查许可证状态: curl http://localhost:8080/api/license/status
-278
View File
@@ -1,278 +0,0 @@
#!/bin/bash
# LJWX Docker Compose 管理脚本
# 提供便捷的服务管理命令
set -e
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 打印带颜色的消息
print_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
print_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
print_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 检查 Docker 和 Docker Compose
check_requirements() {
if ! command -v docker &> /dev/null; then
print_error "Docker 未安装,请先安装 Docker"
exit 1
fi
if ! command -v docker-compose &> /dev/null && ! docker compose version &> /dev/null; then
print_error "Docker Compose 未安装,请先安装 Docker Compose"
exit 1
fi
}
# 检查 .env 文件
check_env_file() {
if [ ! -f .env ]; then
print_warning ".env 文件不存在"
read -p "是否从 .env.example 创建 .env 文件? (y/n) " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
cp .env.example .env
print_success ".env 文件已创建,请根据需要修改配置"
print_info "编辑命令: vim .env 或 nano .env"
exit 0
else
print_warning "将使用默认配置启动服务"
fi
fi
}
# 启动所有服务
start_all() {
print_info "启动所有服务..."
docker-compose up -d
print_success "所有服务已启动"
show_status
}
# 启动基础设施服务
start_infra() {
print_info "启动基础设施服务(MySQL + Redis)..."
docker-compose up -d ljwx-mysql ljwx-redis
print_success "基础设施服务已启动"
}
# 启动业务应用服务
start_apps() {
print_info "启动业务应用服务..."
docker-compose up -d ljwx-boot ljwx-admin ljwx-bigscreen
print_success "业务应用服务已启动"
}
# 启动监控服务
start_monitoring() {
print_info "启动监控系统服务..."
docker-compose up -d ljwx-prometheus ljwx-alertmanager ljwx-loki ljwx-promtail ljwx-grafana ljwx-node-exporter
print_success "监控系统服务已启动"
}
# 停止所有服务
stop_all() {
print_info "停止所有服务..."
docker-compose stop
print_success "所有服务已停止"
}
# 停止并删除容器
down() {
print_warning "停止并删除所有容器..."
read -p "确认删除所有容器? 数据卷将保留 (y/n) " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
docker-compose down
print_success "所有容器已删除,数据卷已保留"
else
print_info "操作已取消"
fi
}
# 完全清理(包括数据卷)
cleanup() {
print_error "警告:此操作将删除所有容器和数据卷!"
read -p "确认删除所有容器和数据? 此操作不可恢复! (yes/no) " -r
echo
if [[ $REPLY == "yes" ]]; then
docker-compose down -v
print_success "所有容器和数据卷已删除"
else
print_info "操作已取消"
fi
}
# 查看服务状态
show_status() {
print_info "服务状态:"
docker-compose ps
}
# 查看服务日志
show_logs() {
if [ -z "$1" ]; then
print_info "显示所有服务日志(Ctrl+C 退出)..."
docker-compose logs -f
else
print_info "显示 $1 服务日志(Ctrl+C 退出)..."
docker-compose logs -f "$1"
fi
}
# 重启服务
restart_service() {
if [ -z "$1" ]; then
print_info "重启所有服务..."
docker-compose restart
print_success "所有服务已重启"
else
print_info "重启 $1 服务..."
docker-compose restart "$1"
print_success "$1 服务已重启"
fi
}
# 显示访问地址
show_urls() {
print_info "服务访问地址:"
echo ""
echo "业务应用:"
echo " - 后端API: http://localhost:9998"
echo " - 管理界面: http://localhost:5173"
echo " - 大屏服务: http://localhost:5001"
echo ""
echo "基础设施:"
echo " - MySQL: localhost:3306"
echo " - Redis: localhost:6379"
echo ""
echo "监控系统:"
echo " - Grafana: http://localhost:3001 (admin/admin123)"
echo " - Prometheus: http://localhost:9091"
echo " - Alertmanager: http://localhost:9094"
echo " - Loki: http://localhost:3100"
echo " - Node Exporter: http://localhost:9101"
echo ""
}
# 健康检查
health_check() {
print_info "执行健康检查..."
services=("ljwx-mysql" "ljwx-redis" "ljwx-boot" "ljwx-admin" "ljwx-bigscreen")
for service in "${services[@]}"; do
if docker-compose ps | grep -q "$service.*Up"; then
print_success "$service: 运行中"
else
print_error "$service: 未运行"
fi
done
}
# 显示帮助信息
show_help() {
echo "LJWX Docker Compose 管理脚本"
echo ""
echo "用法: ./docker-manager.sh [命令] [选项]"
echo ""
echo "命令:"
echo " start 启动所有服务"
echo " start-infra 启动基础设施服务(MySQL + Redis)"
echo " start-apps 启动业务应用服务"
echo " start-monitor 启动监控系统服务"
echo " stop 停止所有服务"
echo " down 停止并删除所有容器(保留数据)"
echo " cleanup 完全清理(删除容器和数据卷)"
echo " restart [name] 重启服务(不指定则重启所有)"
echo " status 查看服务状态"
echo " logs [name] 查看服务日志(不指定则查看所有)"
echo " urls 显示服务访问地址"
echo " health 健康检查"
echo " help 显示此帮助信息"
echo ""
echo "示例:"
echo " ./docker-manager.sh start # 启动所有服务"
echo " ./docker-manager.sh logs ljwx-boot # 查看 ljwx-boot 日志"
echo " ./docker-manager.sh restart ljwx-admin # 重启 ljwx-admin 服务"
echo ""
}
# 主函数
main() {
check_requirements
case "${1:-help}" in
start)
check_env_file
start_all
show_urls
;;
start-infra)
check_env_file
start_infra
;;
start-apps)
check_env_file
start_apps
;;
start-monitor)
check_env_file
start_monitoring
;;
stop)
stop_all
;;
down)
down
;;
cleanup)
cleanup
;;
restart)
restart_service "$2"
;;
status)
show_status
;;
logs)
show_logs "$2"
;;
urls)
show_urls
;;
health)
health_check
;;
help|--help|-h)
show_help
;;
*)
print_error "未知命令: $1"
echo ""
show_help
exit 1
;;
esac
}
# 执行主函数
main "$@"
-65
View File
@@ -1,65 +0,0 @@
version: '3.8'
services:
jenkins:
image: jenkins/jenkins:2.440-lts
container_name: jenkins-smart
restart: unless-stopped
privileged: true
user: root
ports:
- "8081:8080"
- "50000:50000"
volumes:
# Jenkins 数据持久化
- jenkins-smart-data:/var/jenkins_home
# Docker 集成
- /var/run/docker.sock:/var/run/docker.sock
# 配置文件挂载
- ./jenkins/casc:/var/jenkins_home/casc_configs:ro
- ./jenkins/plugins.txt:/usr/share/jenkins/ref/plugins.txt:ro
- ./jenkins/init-scripts:/var/jenkins_home/init.groovy.d:ro
- ./jenkins/shared-library:/var/jenkins_home/shared-library:ro
# 时区同步
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
environment:
# Jenkins 配置
- JENKINS_OPTS=--httpPort=8080
- JAVA_OPTS=-Djenkins.install.runSetupWizard=false -Xmx2g -XX:+UseG1GC
# Configuration as Code
- CASC_JENKINS_CONFIG=/var/jenkins_home/casc_configs
# Docker 配置
- DOCKER_HOST=unix:///var/run/docker.sock
# 服务集成环境变量
- JENKINS_ADMIN_ID=admin
- JENKINS_ADMIN_PASSWORD=admin123
- DOCKER_REGISTRY=localhost:35001
- GITEA_URL=http://192.168.1.6:3000
- GITEA_TOKEN=changeme-generate-in-gitea
networks:
- cicd-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/login"]
interval: 30s
timeout: 10s
retries: 5
start_period: 60s
networks:
cicd-network:
external: true
name: cicd-network
volumes:
jenkins-smart-data:
driver: local
name: jenkins-smart-data
-81
View File
@@ -1,81 +0,0 @@
services:
jenkins:
image: jenkins/jenkins:lts-jdk21
container_name: jenkins-auto-config
restart: unless-stopped
ports:
- "8081:8080"
- "50000:50000"
volumes:
# ===== 数据持久化 =====
- jenkins-data:/var/jenkins_home
- /var/run/docker.sock:/var/run/docker.sock
# ===== 自动配置文件 =====
- ./jenkins/plugins.txt:/usr/share/jenkins/ref/plugins.txt
- ./jenkins/casc:/var/jenkins_home/casc_configs
- ./jenkins/init-scripts:/usr/share/jenkins/ref/init.groovy.d
# ===== 工具和集成 =====
- ~/.docker:/var/jenkins_home/.docker:ro
- ~/.kube:/var/jenkins_home/.kube:ro
environment:
# ===== 基础配置 =====
- JENKINS_OPTS=--httpPort=8080
- JAVA_OPTS=-Xmx2g -Xms1g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -Djenkins.install.runSetupWizard=false
# ===== CasC配置 =====
- CASC_JENKINS_CONFIG=/var/jenkins_home/casc_configs
- CASC_JENKINS_CONFIG_PATH=/var/jenkins_home/casc_configs
# ===== 用户配置 =====
- JENKINS_ADMIN_ID=admin
- JENKINS_ADMIN_PASSWORD=admin123
# ===== 集成配置 =====
- DOCKER_REGISTRY=localhost:5001
- GITEA_URL=http://gitea:3000
- KUBERNETES_MASTER_URL=https://kubernetes.docker.internal:6443
# ===== 时区和本地化 =====
- TZ=Asia/Shanghai
- LANG=zh_CN.UTF-8
user: root
networks:
- cicd-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/login"]
interval: 30s
timeout: 10s
retries: 5
start_period: 300s # 给插件安装更多时间
# Registry服务
registry:
image: registry:2
container_name: jenkins-registry
restart: unless-stopped
ports:
- "5001:5000"
volumes:
- registry-data:/var/lib/registry
environment:
- REGISTRY_STORAGE_DELETE_ENABLED=true
networks:
- cicd-network
networks:
cicd-network:
driver: bridge
volumes:
jenkins-data:
driver: local
driver_opts:
type: none
o: bind
device: /Users/brunogao/work/infra/data/jenkins
registry-data:
driver: local
-137
View File
@@ -1,137 +0,0 @@
version: '3.8'
services:
jenkins:
image: jenkins/jenkins:2.440-lts
container_name: jenkins-ultimate
restart: unless-stopped
privileged: true
user: root
ports:
- "8081:8080"
- "50000:50000"
volumes:
# Jenkins 数据持久化
- jenkins-data:/var/jenkins_home
- jenkins-docker-certs:/certs/client:ro
# Docker 集成
- /var/run/docker.sock:/var/run/docker.sock
# 配置文件挂载
- ./jenkins/casc:/var/jenkins_home/casc_configs:ro
- ./jenkins/plugins.txt:/usr/share/jenkins/ref/plugins.txt:ro
- ./jenkins/init-scripts:/var/jenkins_home/init.groovy.d:ro
- ./jenkins/shared-library:/var/jenkins_home/shared-library:ro
# 时区同步
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
environment:
# Jenkins 配置
- JENKINS_OPTS=--httpPort=8080
- JAVA_OPTS=-Djenkins.install.runSetupWizard=false -Xmx2g -XX:+UseG1GC
# Configuration as Code
- CASC_JENKINS_CONFIG=/var/jenkins_home/casc_configs
- CASC_RELOAD_TOKEN=jenkins-auto-reload-token
# Docker 配置
- DOCKER_HOST=unix:///var/run/docker.sock
- DOCKER_TLS_CERTDIR=/certs
# 服务集成环境变量
- JENKINS_ADMIN_ID=admin
- JENKINS_ADMIN_PASSWORD=admin123
- DOCKER_REGISTRY=localhost:5001
- GITEA_URL=http://192.168.1.6:3000
- GITEA_TOKEN=changeme-generate-in-gitea
# 邮件配置
- SMTP_HOST=localhost
- SMTP_PORT=587
- SMTP_USER=jenkins@example.com
- SMTP_PASSWORD=changeme
# Slack 通知
- SLACK_TEAM=your-team
- SLACK_TOKEN=changeme-slack-token
# 钉钉通知
- DINGTALK_WEBHOOK=changeme-dingtalk-webhook
# 云平台凭据
- AWS_ACCESS_KEY=changeme-aws-key
- AWS_SECRET_KEY=changeme-aws-secret
- AZURE_SP=changeme-azure-sp
- K8S_CONFIG=changeme-k8s-config
networks:
- cicd-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/login"]
interval: 30s
timeout: 10s
retries: 5
start_period: 60s
depends_on:
- docker-registry
- registry-ui
# Docker Registry
docker-registry:
image: registry:2.8
container_name: docker-registry-ultimate
restart: unless-stopped
ports:
- "5001:5000"
volumes:
- registry-data:/var/lib/registry
- ./registry/config.yml:/etc/docker/registry/config.yml:ro
environment:
- REGISTRY_STORAGE_DELETE_ENABLED=true
- REGISTRY_HTTP_ADDR=0.0.0.0:5000
- REGISTRY_HTTP_HEADERS_Access-Control-Allow-Origin=['*']
- REGISTRY_HTTP_HEADERS_Access-Control-Allow-Methods=['HEAD','GET','OPTIONS','DELETE']
- REGISTRY_HTTP_HEADERS_Access-Control-Allow-Headers=['Authorization','Accept','Cache-Control']
- REGISTRY_HTTP_HEADERS_Access-Control-Max-Age=[1728000]
- REGISTRY_HTTP_HEADERS_Access-Control-Allow-Credentials=[true]
networks:
- cicd-network
# Registry UI
registry-ui:
image: joxit/docker-registry-ui:latest
container_name: registry-ui-ultimate
restart: unless-stopped
ports:
- "5002:80"
environment:
- SINGLE_REGISTRY=true
- REGISTRY_TITLE=Jenkins Docker Registry
- DELETE_IMAGES=true
- SHOW_CONTENT_DIGEST=true
- NGINX_PROXY_PASS_URL=http://docker-registry:5000
- SHOW_CATALOG_NB_TAGS=true
- CATALOG_MIN_BRANCHES=1
- CATALOG_MAX_BRANCHES=1
networks:
- cicd-network
depends_on:
- docker-registry
networks:
cicd-network:
driver: bridge
name: cicd-network
volumes:
jenkins-data:
driver: local
name: jenkins-ultimate-data
jenkins-docker-certs:
driver: local
registry-data:
driver: local
name: registry-ultimate-data
-70
View File
@@ -1,70 +0,0 @@
version: '3.8'
services:
jenkins:
image: jenkins/jenkins:lts-jdk21
container_name: jenkins
restart: unless-stopped
ports:
- "8081:8080"
- "50000:50000"
volumes:
- jenkins-data:/var/jenkins_home # 主数据持久化
- jenkins-backup:/var/jenkins_backup # 备份目录
- /var/run/docker.sock:/var/run/docker.sock # Docker集成
- ./jenkins/config:/var/jenkins_config:ro # 配置文件
- ./jenkins/plugins:/var/jenkins_plugins:ro # 插件预配置
environment:
- JENKINS_OPTS=--httpPort=8080 --prefix=/jenkins # 路径前缀
- JAVA_OPTS=-Xmx2g -Xms1g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 # JVM优化
- JENKINS_SLAVE_AGENT_PORT=50000 # Agent端口
- CASC_JENKINS_CONFIG=/var/jenkins_config/jenkins.yaml # 配置即代码
- DOCKER_REGISTRY=localhost:5001 # Registry地址
- GITEA_URL=http://gitea:3000 # Gitea地址
- TZ=Asia/Shanghai # 时区设置
user: root
networks:
- jenkins-net
- cicd-network # 连接gitea网络
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8081/jenkins/login"]
interval: 30s
timeout: 10s
retries: 3
registry:
image: registry:2
container_name: registry
restart: unless-stopped
volumes:
- registry-data:/var/lib/registry
- ../registry/config.yml:/etc/docker/registry/config.yml:ro
- ../registry/auth:/auth:ro
ports:
- "5001:5000"
networks:
- jenkins-net
environment:
- REGISTRY_STORAGE_DELETE_ENABLED=true # 允许删除镜像
networks:
jenkins-net:
driver: bridge
cicd-network:
external: true # 连接到外部gitea网络
volumes:
jenkins-data:
driver: local
driver_opts:
type: none
o: bind
device: /Users/brunogao/work/infra/data/jenkins # 本地绑定挂载
jenkins-backup:
driver: local
driver_opts:
type: none
o: bind
device: /Users/brunogao/work/infra/backup/jenkins # 备份目录
registry-data:
driver: local
-53
View File
@@ -1,53 +0,0 @@
services:
jenkins:
build:
context: ./jenkins/setup
dockerfile: Dockerfile
container_name: jenkins-final-auto
restart: unless-stopped
ports:
- "8081:8080"
- "50000:50000"
volumes:
- jenkins-final-data:/var/jenkins_home
- /var/run/docker.sock:/var/run/docker.sock
environment:
- JENKINS_OPTS=--httpPort=8080
- JAVA_OPTS=-Xmx2g -Xms1g -XX:+UseG1GC -XX:MaxGCPauseMillis=200
- JENKINS_ADMIN_ID=admin
- JENKINS_ADMIN_PASSWORD=admin123
- DOCKER_REGISTRY=localhost:5001
- GITEA_URL=http://gitea:3000
- TZ=Asia/Shanghai
user: root
networks:
- cicd-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/login"]
interval: 30s
timeout: 10s
retries: 5
start_period: 180s
registry:
image: registry:2
container_name: jenkins-registry-final
restart: unless-stopped
ports:
- "5001:5000"
volumes:
- registry-final-data:/var/lib/registry
environment:
- REGISTRY_STORAGE_DELETE_ENABLED=true
networks:
- cicd-network
networks:
cicd-network:
driver: bridge
volumes:
jenkins-final-data:
driver: local
registry-final-data:
driver: local
-140
View File
@@ -1,140 +0,0 @@
services:
jenkins:
image: jenkins/jenkins:lts-jdk21
container_name: jenkins-persistent
restart: unless-stopped
ports:
- "8081:8080"
- "50000:50000"
volumes:
# ===== 核心数据持久化 =====
- jenkins-home:/var/jenkins_home # Jenkins主目录完整持久化
- jenkins-workspace:/var/jenkins_home/workspace # 构建工作空间
- jenkins-jobs:/var/jenkins_home/jobs # 作业配置
- jenkins-builds:/var/jenkins_home/builds # 构建历史
- jenkins-plugins:/var/jenkins_home/plugins # 插件数据
- jenkins-secrets:/var/jenkins_home/secrets # 密钥和凭据
- jenkins-users:/var/jenkins_home/users # 用户数据
- jenkins-logs:/var/jenkins_home/logs # 日志文件
# ===== 配置文件持久化 =====
- ./jenkins/casc:/var/jenkins_home/casc_configs:ro # Configuration as Code
- ./jenkins/init-scripts:/usr/share/jenkins/ref/init.groovy.d:ro # 初始化脚本
- ./jenkins/plugins.txt:/usr/share/jenkins/ref/plugins.txt:ro # 插件列表
# ===== 扩展数据持久化 =====
- jenkins-backup:/var/jenkins_backup # 备份目录
- jenkins-cache:/var/jenkins_home/.cache # 缓存目录
- jenkins-tmp:/var/jenkins_home/tmp # 临时文件
# ===== 外部集成 =====
- /var/run/docker.sock:/var/run/docker.sock # Docker集成
- ~/.docker:/var/jenkins_home/.docker:ro # Docker配置
- ~/.kube:/var/jenkins_home/.kube:ro # Kubernetes配置
environment:
- JENKINS_OPTS=--httpPort=8080
- JAVA_OPTS=-Xmx2g -Xms1g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -Djenkins.install.runSetupWizard=false
- CASC_JENKINS_CONFIG=/var/jenkins_home/casc_configs
- JENKINS_ADMIN_ID=admin
- JENKINS_ADMIN_PASSWORD=admin123
- TZ=Asia/Shanghai
# ===== 持久化优化 =====
- JENKINS_SLAVE_AGENT_PORT=50000
- JENKINS_UC_EXPERIMENTAL_UPDATE_CENTER=false
- COPY_REFERENCE_FILE_LOG=/var/jenkins_home/copy_reference_file.log
user: root
networks:
- cicd-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/login"]
interval: 30s
timeout: 10s
retries: 5
start_period: 120s
networks:
cicd-network:
external: true
volumes:
# ===== 主要数据卷 =====
jenkins-home:
driver: local
driver_opts:
type: none
o: bind
device: /Users/brunogao/work/infra/data/jenkins/home # Jenkins主目录
jenkins-workspace:
driver: local
driver_opts:
type: none
o: bind
device: /Users/brunogao/work/infra/data/jenkins/workspace # 工作空间
jenkins-jobs:
driver: local
driver_opts:
type: none
o: bind
device: /Users/brunogao/work/infra/data/jenkins/jobs # 作业配置
jenkins-builds:
driver: local
driver_opts:
type: none
o: bind
device: /Users/brunogao/work/infra/data/jenkins/builds # 构建历史
jenkins-plugins:
driver: local
driver_opts:
type: none
o: bind
device: /Users/brunogao/work/infra/data/jenkins/plugins # 插件
jenkins-secrets:
driver: local
driver_opts:
type: none
o: bind
device: /Users/brunogao/work/infra/data/jenkins/secrets # 凭据
jenkins-users:
driver: local
driver_opts:
type: none
o: bind
device: /Users/brunogao/work/infra/data/jenkins/users # 用户
jenkins-logs:
driver: local
driver_opts:
type: none
o: bind
device: /Users/brunogao/work/infra/data/jenkins/logs # 日志
# ===== 辅助数据卷 =====
jenkins-backup:
driver: local
driver_opts:
type: none
o: bind
device: /Users/brunogao/work/infra/backup/jenkins # 备份
jenkins-cache:
driver: local
driver_opts:
type: none
o: bind
device: /Users/brunogao/work/infra/data/jenkins/cache # 缓存
jenkins-tmp:
driver: local
driver_opts:
type: none
o: bind
device: /Users/brunogao/work/infra/data/jenkins/tmp # 临时文件
-40
View File
@@ -1,40 +0,0 @@
version: '3.8'
services:
jenkins:
image: jenkins/jenkins:lts-jdk21
container_name: jenkins-quick
restart: unless-stopped
privileged: true
user: root
ports:
- "8081:8080"
- "50000:50000"
volumes:
- jenkins-quick-data:/var/jenkins_home
- /var/run/docker.sock:/var/run/docker.sock
- ./jenkins/casc:/var/jenkins_home/casc_configs:ro
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
environment:
- JENKINS_OPTS=--httpPort=8080
- JAVA_OPTS=-Djenkins.install.runSetupWizard=false -Xmx1g
- CASC_JENKINS_CONFIG=/var/jenkins_home/casc_configs
- JENKINS_ADMIN_ID=admin
- JENKINS_ADMIN_PASSWORD=admin123
networks:
- cicd-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/login"]
interval: 30s
timeout: 10s
retries: 3
networks:
cicd-network:
external: true
name: cicd-network
volumes:
jenkins-quick-data:
driver: local
-34
View File
@@ -1,34 +0,0 @@
version: '3.8'
services:
jenkins:
image: jenkins/jenkins:lts-jdk21
container_name: jenkins-simple
restart: unless-stopped
ports:
- "38080:8080"
- "35000:50000"
volumes:
- jenkins-data:/var/jenkins_home
- /var/run/docker.sock:/var/run/docker.sock
- ./jenkins/casc:/var/jenkins_home/casc_configs:ro
- ./jenkins/plugins.txt:/usr/share/jenkins/ref/plugins.txt:ro
- ./jenkins/init-scripts:/usr/share/jenkins/ref/init.groovy.d:ro
environment:
- JENKINS_OPTS=--httpPort=8080
- JAVA_OPTS=-Xmx2g -Xms1g -Djenkins.install.runSetupWizard=false
- CASC_JENKINS_CONFIG=/var/jenkins_home/casc_configs
- JENKINS_ADMIN_ID=admin
- JENKINS_ADMIN_PASSWORD=admin123
- TZ=Asia/Shanghai
user: root
networks:
- cicd-network
networks:
cicd-network:
external: true
volumes:
jenkins-data:
driver: local
-123
View File
@@ -1,123 +0,0 @@
# Jenkins配置指南
## 1. 初始化设置
1. 访问 http://localhost:8081/jenkins
2. 使用初始管理员密码登录(见 /tmp/jenkins-admin-password.txt)
3. 选择 "安装推荐的插件"
4. 创建管理员用户
5. 配置Jenkins URL: http://localhost:8081/jenkins/
## 2. 必要插件安装
运行插件安装脚本查看推荐插件:
```bash
./docker/compose/jenkins/scripts/install-plugins.sh
```
## 3. 系统配置
### 3.1 全局工具配置
- Git: /usr/bin/git
- Docker: /usr/local/bin/docker
- Maven: 自动安装最新版本
- Node.js: 自动安装最新LTS版本
### 3.2 凭据配置
在 "管理Jenkins" -> "凭据" 中添加:
- Gitea Token (Secret text)
- Docker Registry 认证 (Username/Password)
- SSH密钥 (SSH Username with private key)
### 3.3 系统设置
- 执行器数量: 4
- 安静期: 5秒
- SCM检出重试次数: 3
- Jenkins URL: http://localhost:8081/jenkins/
## 4. 创建Pipeline作业
### 4.1 基础Pipeline
```groovy
pipeline {
agent any
environment {
DOCKER_REGISTRY = 'localhost:5001'
GITEA_URL = 'http://gitea:3000'
}
stages {
stage('检出代码') {
steps {
git branch: 'main', url: "${GITEA_URL}/your-repo.git"
}
}
stage('构建测试') {
steps {
sh 'echo "执行测试..."'
}
}
stage('构建镜像') {
steps {
script {
def image = docker.build("${DOCKER_REGISTRY}/app:${BUILD_NUMBER}")
docker.withRegistry("http://${DOCKER_REGISTRY}") {
image.push()
}
}
}
}
}
}
```
### 4.2 Gitea Webhook配置
1. 在Gitea项目设置中添加Webhook
2. URL: http://localhost:8081/jenkins/generic-webhook-trigger/invoke
3. 内容类型: application/json
4. 触发事件: Push events
## 5. 性能优化
### 5.1 JVM参数优化
在docker-compose.yml中已配置:
- -Xmx2g -Xms1g
- -XX:+UseG1GC
- -XX:MaxGCPauseMillis=200
### 5.2 构建历史清理
- 保留构建数: 50
- 保留天数: 30
### 5.3 工作空间清理
使用 "Workspace Cleanup" 插件自动清理
## 6. 备份策略
### 6.1 自动备份
使用 jenkins-manager.sh 脚本:
```bash
./deployment/scripts/jenkins-manager.sh
# 选择选项 4 进行备份
```
### 6.2 手动备份
```bash
tar -czf jenkins-backup-$(date +%Y%m%d).tar.gz -C /Users/brunogao/work/infra/data/jenkins .
```
## 7. 故障排除
### 7.1 常见问题
- Jenkins无法启动: 检查端口占用和权限
- 插件安装失败: 检查网络连接和代理设置
- 构建失败: 检查工具配置和环境变量
### 7.2 日志查看
```bash
docker logs jenkins
docker exec jenkins tail -f /var/jenkins_home/logs/jenkins.log
```
@@ -1,268 +0,0 @@
# Docker CI/CD最佳实践指南
## 1. Dockerfile最佳实践
### 1.1 基础镜像选择
```dockerfile
# 使用官方基础镜像
FROM python:3.11-slim
# 避免使用latest标签
FROM python:3.11-slim # 好
FROM python:latest # 不好
```
### 1.2 层优化
```dockerfile
# 合并RUN指令减少层数
RUN apt-get update && \
apt-get install -y --no-install-recommends \
curl \
wget && \
rm -rf /var/lib/apt/lists/*
# 利用缓存,先复制依赖文件
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
```
### 1.3 安全实践
```dockerfile
# 创建非root用户
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs
USER nextjs
# 设置健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1
```
## 2. Jenkins Pipeline最佳实践
### 2.1 镜像构建
```groovy
pipeline {
agent any
environment {
DOCKER_REGISTRY = 'localhost:5001'
APP_NAME = 'my-app'
IMAGE_TAG = "${BUILD_NUMBER}-${GIT_COMMIT[0..7]}"
}
stages {
stage('构建镜像') {
steps {
script {
def image = docker.build("${DOCKER_REGISTRY}/${APP_NAME}:${IMAGE_TAG}")
// 推送镜像
docker.withRegistry("http://${DOCKER_REGISTRY}", 'registry-auth') {
image.push()
image.push("latest")
}
}
}
}
}
}
```
### 2.2 并行构建
```groovy
stage('并行任务') {
parallel {
stage('单元测试') {
steps {
sh 'pytest tests/unit'
}
}
stage('构建镜像') {
steps {
script {
docker.build("${APP_NAME}:${BUILD_NUMBER}")
}
}
}
}
}
```
### 2.3 条件部署
```groovy
stage('部署') {
when {
allOf {
branch 'main'
not { changeRequest() }
}
}
steps {
script {
sh """
docker stop ${APP_NAME} || true
docker rm ${APP_NAME} || true
docker run -d --name ${APP_NAME} -p 8080:5000 ${DOCKER_REGISTRY}/${APP_NAME}:${IMAGE_TAG}
"""
}
}
}
```
## 3. Registry管理
### 3.1 镜像标签策略
```bash
# 语义化版本
my-app:1.0.0
my-app:1.0.0-rc1
# 构建信息
my-app:build-123
my-app:build-123-abc1234
# 环境标签
my-app:dev
my-app:staging
my-app:prod
```
### 3.2 镜像清理
```groovy
post {
always {
sh """
# 清理本地镜像
docker rmi ${DOCKER_REGISTRY}/${APP_NAME}:${IMAGE_TAG} || true
# 清理悬空镜像
docker system prune -f
"""
}
}
```
## 4. 安全实践
### 4.1 镜像扫描
```groovy
stage('安全扫描') {
steps {
script {
// 使用Trivy扫描
sh """
trivy image --exit-code 1 --severity HIGH,CRITICAL ${DOCKER_REGISTRY}/${APP_NAME}:${IMAGE_TAG}
"""
}
}
}
```
### 4.2 凭据管理
```groovy
withCredentials([usernamePassword(
credentialsId: 'registry-auth',
usernameVariable: 'REGISTRY_USER',
passwordVariable: 'REGISTRY_PASS'
)]) {
sh """
echo \$REGISTRY_PASS | docker login ${DOCKER_REGISTRY} -u \$REGISTRY_USER --password-stdin
"""
}
```
## 5. 性能优化
### 5.1 构建缓存
```dockerfile
# 使用构建缓存
FROM python:3.11-slim as builder
# 多阶段构建
FROM builder as dependencies
COPY requirements.txt .
RUN pip install -r requirements.txt
FROM python:3.11-slim as runtime
COPY --from=dependencies /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages
```
### 5.2 并行构建
```groovy
stage('并行构建') {
parallel {
stage('AMD64') {
steps {
sh 'docker buildx build --platform linux/amd64 -t ${APP_NAME}:amd64 .'
}
}
stage('ARM64') {
steps {
sh 'docker buildx build --platform linux/arm64 -t ${APP_NAME}:arm64 .'
}
}
}
}
```
## 6. 监控和日志
### 6.1 构建监控
```groovy
post {
always {
// 发布构建报告
publishHTML([
allowMissing: false,
alwaysLinkToLastBuild: true,
keepAll: true,
reportDir: 'reports',
reportFiles: 'index.html',
reportName: 'Build Report'
])
}
}
```
### 6.2 日志管理
```dockerfile
# 配置日志驱动
LABEL logging.driver="json-file"
LABEL logging.options.max-size="10m"
LABEL logging.options.max-file="3"
```
## 7. 故障排除
### 7.1 常见问题
1. **构建失败**
- 检查Dockerfile语法
- 确认基础镜像可用
- 检查网络连接
2. **推送失败**
- 检查Registry认证
- 确认网络连通性
- 检查存储空间
3. **部署失败**
- 检查端口占用
- 确认镜像存在
- 检查环境变量
### 7.2 调试命令
```bash
# 查看构建日志
docker logs jenkins
# 检查镜像
docker images | grep my-app
# 测试Registry连接
curl -u admin:password http://localhost:5001/v2/_catalog
# 检查容器状态
docker ps -a
```
@@ -1,361 +0,0 @@
# Jenkins Pipeline最佳实践指南
## 1. Pipeline结构设计
### 1.1 基本结构
```groovy
pipeline {
agent any
environment {
// 环境变量
}
options {
// Pipeline选项
}
stages {
// 构建阶段
}
post {
// 后置处理
}
}
```
### 1.2 阶段设计原则
- **单一职责**: 每个阶段只做一件事
- **快速失败**: 耗时短的阶段放在前面
- **并行执行**: 无依赖的阶段并行执行
- **条件执行**: 使用when条件控制执行
## 2. 共享库使用
### 2.1 共享库结构
```
shared-library/
├── vars/ # 全局变量
│ ├── buildDockerImage.groovy
│ ├── deployToEnvironment.groovy
│ └── runTests.groovy
├── src/ # 源代码
│ └── org/example/
│ └── Utils.groovy
└── resources/ # 资源文件
└── scripts/
└── deploy.sh
```
### 2.2 使用示例
```groovy
@Library('jenkins-shared-library') _
pipeline {
agent any
stages {
stage('构建') {
steps {
buildDockerImage([
registry: 'localhost:5001',
appName: 'my-app'
])
}
}
}
}
```
## 3. 错误处理和重试
### 3.1 重试机制
```groovy
stage('不稳定测试') {
steps {
retry(3) {
sh 'npm test'
}
}
}
```
### 3.2 超时控制
```groovy
stage('长时间任务') {
steps {
timeout(time: 10, unit: 'MINUTES') {
sh 'long-running-task.sh'
}
}
}
```
### 3.3 错误捕获
```groovy
stage('可能失败的任务') {
steps {
script {
try {
sh 'risky-command'
} catch (Exception e) {
echo "任务失败: ${e.getMessage()}"
currentBuild.result = 'UNSTABLE'
}
}
}
}
```
## 4. 并行执行
### 4.1 并行阶段
```groovy
stage('并行测试') {
parallel {
stage('单元测试') {
steps {
sh 'npm run test:unit'
}
}
stage('集成测试') {
steps {
sh 'npm run test:integration'
}
}
stage('E2E测试') {
steps {
sh 'npm run test:e2e'
}
}
}
}
```
### 4.2 并行构建
```groovy
stage('多平台构建') {
parallel {
stage('Linux AMD64') {
steps {
sh 'docker buildx build --platform linux/amd64 .'
}
}
stage('Linux ARM64') {
steps {
sh 'docker buildx build --platform linux/arm64 .'
}
}
}
}
```
## 5. 条件执行
### 5.1 分支条件
```groovy
stage('部署生产') {
when {
anyOf {
branch 'main'
branch 'master'
}
}
steps {
sh 'deploy-to-production.sh'
}
}
```
### 5.2 环境条件
```groovy
stage('夜间构建') {
when {
allOf {
branch 'develop'
environment name: 'BUILD_TYPE', value: 'nightly'
}
}
steps {
sh 'run-full-test-suite.sh'
}
}
```
### 5.3 自定义条件
```groovy
stage('变更检测') {
when {
changeset "src/**"
}
steps {
sh 'build-source-code.sh'
}
}
```
## 6. 凭据管理
### 6.1 用户名密码
```groovy
stage('部署') {
steps {
withCredentials([usernamePassword(
credentialsId: 'deploy-credentials',
usernameVariable: 'DEPLOY_USER',
passwordVariable: 'DEPLOY_PASS'
)]) {
sh 'deploy.sh $DEPLOY_USER $DEPLOY_PASS'
}
}
}
```
### 6.2 SSH密钥
```groovy
stage('部署') {
steps {
withCredentials([sshUserPrivateKey(
credentialsId: 'ssh-key',
keyFileVariable: 'SSH_KEY'
)]) {
sh 'ssh -i $SSH_KEY user@server deploy.sh'
}
}
}
```
### 6.3 Secret文本
```groovy
stage('API调用') {
steps {
withCredentials([string(
credentialsId: 'api-token',
variable: 'API_TOKEN'
)]) {
sh 'curl -H "Authorization: Bearer $API_TOKEN" api.example.com'
}
}
}
```
## 7. 制品管理
### 7.1 制品归档
```groovy
post {
always {
archiveArtifacts artifacts: 'dist/**', fingerprint: true
}
}
```
### 7.2 测试结果
```groovy
post {
always {
publishTestResults testResultsPattern: 'test-results.xml'
publishHTML([
allowMissing: false,
alwaysLinkToLastBuild: true,
keepAll: true,
reportDir: 'coverage',
reportFiles: 'index.html',
reportName: 'Coverage Report'
])
}
}
```
## 8. 通知和报告
### 8.1 邮件通知
```groovy
post {
failure {
emailext(
subject: "构建失败: ${env.JOB_NAME} - ${env.BUILD_NUMBER}",
body: "构建失败,请查看: ${env.BUILD_URL}",
to: "${env.CHANGE_AUTHOR_EMAIL}"
)
}
}
```
### 8.2 Slack通知
```groovy
post {
success {
slackSend(
channel: '#ci-cd',
color: 'good',
message: "✅ 构建成功: ${env.JOB_NAME} - ${env.BUILD_NUMBER}"
)
}
}
```
## 9. 性能优化
### 9.1 构建缓存
```groovy
stage('构建') {
steps {
// 使用Docker构建缓存
sh 'docker build --cache-from my-app:latest -t my-app:${BUILD_NUMBER} .'
}
}
```
### 9.2 工作空间清理
```groovy
options {
skipDefaultCheckout()
}
stages {
stage('检出') {
steps {
checkout scm
}
}
}
post {
always {
cleanWs()
}
}
```
## 10. 调试和监控
### 10.1 调试信息
```groovy
stage('调试') {
steps {
script {
echo "构建号: ${env.BUILD_NUMBER}"
echo "Git提交: ${env.GIT_COMMIT}"
echo "分支: ${env.BRANCH_NAME}"
sh 'env | sort'
}
}
}
```
### 10.2 构建监控
```groovy
post {
always {
script {
def duration = currentBuild.duration
def result = currentBuild.result ?: 'SUCCESS'
echo "构建耗时: ${duration}ms"
echo "构建结果: ${result}"
}
}
}
```
-324
View File
@@ -1,324 +0,0 @@
# Jenkins CI/CD完整配置指南
## 🚀 快速启动
Jenkins已成功启动!初始管理员密码:`5d3e7c4031c04137b9e6d77c0a15ddbd`
### 访问地址
- **Jenkins**: http://localhost:8081
- **Docker Registry**: http://localhost:5001
- **Registry UI**: http://localhost:5002
- **Gitea**: http://192.168.1.6:3000
## 📋 初始化配置步骤
### 1. 访问Jenkins并完成设置向导
1. 打开 http://localhost:8081
2. 输入初始密码:`5d3e7c4031c04137b9e6d77c0a15ddbd`
3. 选择"安装推荐的插件"
4. 创建管理员用户
5. 保持Jenkins URL为默认设置
### 2. 安装必要插件
进入"管理Jenkins" -> "插件管理" -> "可选插件",搜索并安装:
#### 核心插件
- Build Timeout
- Credentials Binding
- Timestamper
- Workspace Cleanup
- AnsiColor
#### Git和版本控制
- Git plugin
- Gitea plugin
- SSH Credentials plugin
#### Pipeline和构建
- Pipeline: Stage View
- Pipeline Utility Steps
- Workflow Aggregator
- Blue Ocean
#### Docker集成
- Docker plugin
- Docker Pipeline
- Docker Commons
- Kubernetes plugin
#### 构建工具
- Maven Integration plugin
- Gradle plugin
- NodeJS plugin
- Python plugin
#### 自动化和通知
- Generic Webhook Trigger
- Email Extension
- Slack Notification
### 3. 全局工具配置
进入"管理Jenkins" -> "全局工具配置":
#### Git
- 名称:Default
- 路径:/usr/bin/git
#### Maven
- 名称:Maven-3.9
- 选择"自动安装",版本:3.9.6
#### Gradle
- 名称:Gradle-8
- 选择"自动安装",版本:8.5
#### Node.js
- 名称:NodeJS-18
- 选择"自动安装",版本:18.19.0
#### Docker
- 名称:Docker
- 路径:/usr/local/bin/docker
### 4. 凭据配置
进入"管理Jenkins" -> "凭据" -> "系统" -> "全局凭据":
#### Gitea Token (Secret text)
- ID:gitea-token
- Description:Gitea API访问令牌
- Secret:[在Gitea中生成的Personal Access Token]
#### Docker Registry (Username with password)
- ID:registry-auth
- Description:Docker Registry认证
- Username:admin
- Password:admin123
#### SSH密钥 (SSH Username with private key)
- ID:ssh-key
- Description:Git SSH访问密钥
- Username:jenkins
- Private Key:[粘贴SSH私钥内容]
#### Kubernetes配置 (Secret file)
- ID:k8s-config
- Description:Kubernetes配置文件
- File:[上传kubeconfig文件]
### 5. 系统配置
进入"管理Jenkins" -> "系统配置":
#### 执行器数量
设置为:4
#### 环境变量
添加全局环境变量:
- DOCKER_REGISTRY=localhost:5001
- GITEA_URL=http://192.168.1.6:3000
- TZ=Asia/Shanghai
#### Gitea服务器配置
- 显示名称:Local Gitea
- 服务器URL:http://192.168.1.6:3000
- 凭据:选择gitea-token
### 6. 创建Pipeline作业
#### 多平台构建Pipeline
```groovy
pipeline {
agent any
environment {
REGISTRY = 'localhost:5001'
APP_NAME = 'my-app'
PLATFORMS = 'linux/amd64,linux/arm64'
}
stages {
stage('检出代码') {
steps {
checkout scm
}
}
stage('多平台构建') {
steps {
script {
sh '''
docker buildx create --use --name builder || true
docker buildx build --platform ${PLATFORMS} \\
-t ${REGISTRY}/${APP_NAME}:${BUILD_NUMBER} \\
-t ${REGISTRY}/${APP_NAME}:latest \\
--push .
'''
}
}
}
stage('部署验证') {
steps {
sh 'docker run --rm ${REGISTRY}/${APP_NAME}:latest echo "部署验证成功"'
}
}
}
}
```
### 7. Webhook配置
#### 在Gitea中配置Webhook
1. 进入项目设置 -> Webhooks
2. 添加新的Webhook:
- URL:`http://jenkins-simple:8080/generic-webhook-trigger/invoke`
- 内容类型:`application/json`
- 密钥:设置一个随机字符串
- 触发事件:Push events
#### 在Jenkins中配置触发器
在Pipeline配置中添加:
```groovy
triggers {
GenericTrigger(
genericVariables: [
[key: 'ref', value: '$.ref']
],
causeString: 'Triggered by Gitea',
token: 'your-webhook-token',
tokenCredentialId: '',
printContributedVariables: true,
printPostContent: true
)
}
```
## 🔧 高级配置
### 性能优化
1. JVM参数已优化:`-Xmx1g -Xms512m`
2. 构建历史保留:最多50个构建,30天
3. 工作空间自动清理:使用Workspace Cleanup插件
### 多环境部署
创建参数化构建:
```groovy
parameters {
choice(
name: 'DEPLOY_ENV',
choices: ['dev', 'staging', 'prod'],
description: '部署环境'
)
}
```
### 共享库配置
1. 在Gitea中创建jenkins-shared-library仓库
2. 在Jenkins中配置全局Pipeline库:
- 名称:jenkins-shared-library
- 默认版本:main
- SCM:Git,URL:http://192.168.1.6:3000/your-org/jenkins-shared-library.git
## 🛠️ 管理命令
### 服务管理
```bash
# 启动Jenkins
docker-compose -f docker/compose/jenkins-simple.yml up -d
# 停止Jenkins
docker-compose -f docker/compose/jenkins-simple.yml down
# 查看日志
docker logs jenkins-simple -f
# 重启Jenkins
docker restart jenkins-simple
```
### 备份和恢复
```bash
# 备份Jenkins配置
docker exec jenkins-simple tar czf /tmp/jenkins-backup.tar.gz -C /var/jenkins_home .
docker cp jenkins-simple:/tmp/jenkins-backup.tar.gz ./backup/
# 恢复Jenkins配置
docker cp ./backup/jenkins-backup.tar.gz jenkins-simple:/tmp/
docker exec jenkins-simple tar xzf /tmp/jenkins-backup.tar.gz -C /var/jenkins_home
docker restart jenkins-simple
```
### 插件管理
```bash
# 列出已安装插件
docker exec jenkins-simple cat /var/jenkins_home/plugins.txt
# 安装新插件
docker exec jenkins-simple jenkins-plugin-cli --plugins plugin-name:version
```
## 🚀 项目集成示例
### Vue3项目
```groovy
pipeline {
agent any
stages {
stage('构建') {
steps {
sh 'npm ci'
sh 'npm run build'
sh 'docker build -t localhost:5001/vue-app:${BUILD_NUMBER} .'
sh 'docker push localhost:5001/vue-app:${BUILD_NUMBER}'
}
}
}
}
```
### Spring Boot项目
```groovy
pipeline {
agent any
stages {
stage('构建') {
steps {
sh 'mvn clean package -DskipTests'
sh 'docker build -t localhost:5001/spring-app:${BUILD_NUMBER} .'
sh 'docker push localhost:5001/spring-app:${BUILD_NUMBER}'
}
}
}
}
```
## 📞 故障排查
### 常见问题
1. **Jenkins无法访问Docker**:确保用户有Docker权限
2. **插件安装失败**:检查网络连接,尝试使用清华镜像源
3. **构建失败**:查看控制台输出,检查环境变量和工具配置
4. **Webhook不触发**:确认网络连通性和认证配置
### 日志查看
```bash
# Jenkins主日志
docker logs jenkins-simple
# 构建日志
# 在Jenkins Web界面中查看
# 系统信息
# 管理Jenkins -> 系统信息
```
## 🎯 下一步
1. 配置具体项目的Pipeline
2. 设置代码质量检查(SonarQube)
3. 配置通知机制(邮件/Slack)
4. 设置定时备份
5. 配置监控和告警
---
🎉 **恭喜!你的Jenkins CI/CD环境已完全配置就绪!**
-132
View File
@@ -1,132 +0,0 @@
# Gitea Webhook配置指南
## 1. 在Gitea中配置Webhook
### 1.1 访问仓库设置
1. 登录Gitea: http://localhost:3000
2. 进入目标仓库 (如: jenkins-test-app)
3. 点击 "设置" -> "Webhooks"
### 1.2 添加Webhook
1. 点击 "添加Webhook" -> "Gitea"
2. 配置以下信息:
- **目标URL**: `http://jenkins:8080/generic-webhook-trigger/invoke`
- **HTTP方法**: POST
- **内容类型**: application/json
- **密钥**: (可选,增强安全性)
### 1.3 触发事件
选择以下事件:
- [x] Push events
- [x] Pull request events
- [x] Create events
- [x] Delete events
### 1.4 测试Webhook
1. 点击 "测试推送"
2. 检查Jenkins是否收到触发信号
## 2. Jenkins Generic Webhook Trigger配置
### 2.1 在Jenkins作业中配置
1. 进入Jenkins作业配置
2. 在 "构建触发器" 中勾选 "Generic Webhook Trigger"
3. 配置变量提取:
```
变量名: GITEA_REPO
表达式: $.repository.name
表达式类型: JSONPath
变量名: GITEA_BRANCH
表达式: $.ref
表达式类型: JSONPath
变量名: GITEA_COMMIT
表达式: $.after
表达式类型: JSONPath
```
### 2.2 过滤器配置
- **过滤器表达式**: `jenkins-test-app`
- **过滤器文本**: `$GITEA_REPO`
## 3. 网络配置
### 3.1 Docker网络
确保Jenkins和Gitea在同一Docker网络中:
```bash
docker network create cicd-network
```
### 3.2 服务间通信
- Jenkins访问Gitea: `http://gitea:3000`
- Gitea访问Jenkins: `http://jenkins:8080`
## 4. 故障排除
### 4.1 常见问题
1. **Webhook无法触发**
- 检查URL是否正确
- 确认网络连通性
- 查看Jenkins日志
2. **认证失败**
- 检查凭据配置
- 确认用户权限
3. **构建失败**
- 检查Jenkinsfile语法
- 确认环境变量配置
### 4.2 调试命令
```bash
# 查看Jenkins日志
docker logs jenkins
# 查看Gitea日志
docker logs gitea
# 测试网络连通性
docker exec jenkins ping gitea
docker exec gitea ping jenkins
```
## 5. 高级配置
### 5.1 分支策略
```groovy
when {
anyOf {
branch 'main'
branch 'develop'
branch 'feature/*'
}
}
```
### 5.2 条件部署
```groovy
when {
allOf {
branch 'main'
not { changeRequest() }
}
}
```
### 5.3 并行构建
```groovy
parallel {
stage('单元测试') {
steps {
sh 'pytest tests/unit'
}
}
stage('集成测试') {
steps {
sh 'pytest tests/integration'
}
}
}
```
@@ -1,637 +0,0 @@
# Jenkins最佳实践完整配置
jenkins:
systemMessage: |
🚀 Jenkins CI/CD服务器 - 完全自动化配置
📅 配置时间: $(date)
🔧 自动配置: 工具、插件、云、凭据
📚 管理文档: docs/jenkins-persistence-guide.md
numExecutors: 6
mode: NORMAL
scmCheckoutRetryCount: 3
quietPeriod: 5
# ===== 安全配置 =====
securityRealm:
local:
allowsSignup: false
users:
- id: "${JENKINS_ADMIN_ID:-admin}"
password: "${JENKINS_ADMIN_PASSWORD:-admin123}"
authorizationStrategy:
globalMatrix:
permissions:
- "Overall/Administer:admin"
- "Overall/Read:authenticated"
- "Overall/SystemRead:authenticated"
- "Job/Build:authenticated"
- "Job/Read:authenticated"
- "Job/Workspace:authenticated"
- "Job/Configure:authenticated"
- "Job/Create:authenticated"
- "Job/Delete:authenticated"
- "Job/Move:authenticated"
- "View/Read:authenticated"
- "View/Create:authenticated"
- "View/Configure:authenticated"
# ===== 全局属性 =====
globalNodeProperties:
- envVars:
env:
- key: "DOCKER_REGISTRY"
value: "${DOCKER_REGISTRY:-localhost:5001}"
- key: "GITEA_URL"
value: "${GITEA_URL:-http://gitea:3000}"
- key: "KUBERNETES_MASTER_URL"
value: "${KUBERNETES_MASTER_URL:-https://kubernetes.docker.internal:6443}"
- key: "CI_ENVIRONMENT"
value: "development"
- key: "BUILD_PLATFORMS"
value: "linux/amd64,linux/arm64"
# ===== 构建保留策略 =====
buildDiscarders:
- buildDiscarder:
strategy:
logRotator:
daysToKeepStr: "30"
numToKeepStr: "100"
artifactDaysToKeepStr: "7"
artifactNumToKeepStr: "20"
# ===== 工具配置 =====
tool:
# Git配置
git:
installations:
- name: "Default"
home: "/usr/bin/git"
- name: "Git-2.40"
home: "/usr/bin/git"
# JDK配置
jdk:
installations:
- name: "JDK-21"
home: "/opt/java/openjdk"
- name: "JDK-17"
properties:
- installSource:
installers:
- jdkInstaller:
id: "jdk-17.0.8+101"
- name: "JDK-11"
properties:
- installSource:
installers:
- jdkInstaller:
id: "jdk-11.0.20+101"
# Maven配置
maven:
installations:
- name: "Maven-3.9"
properties:
- installSource:
installers:
- maven:
id: "3.9.6"
- name: "Maven-3.8"
properties:
- installSource:
installers:
- maven:
id: "3.8.8"
# Gradle配置
gradle:
installations:
- name: "Gradle-8"
properties:
- installSource:
installers:
- gradleInstaller:
id: "8.5"
- name: "Gradle-7"
properties:
- installSource:
installers:
- gradleInstaller:
id: "7.6.4"
# Node.js配置
nodejs:
installations:
- name: "NodeJS-20"
properties:
- installSource:
installers:
- nodeJSInstaller:
id: "20.10.0"
npmPackagesRefreshHours: 72
- name: "NodeJS-18"
properties:
- installSource:
installers:
- nodeJSInstaller:
id: "18.19.0"
npmPackagesRefreshHours: 72
# Docker配置
dockerTool:
installations:
- name: "Docker"
home: "/usr/local/bin/docker"
- name: "Docker-Latest"
properties:
- installSource:
installers:
- dockerInstaller:
version: "latest"
# Python配置
python:
installations:
- name: "Python-3.11"
properties:
- installSource:
installers:
- command:
command: "/usr/bin/python3"
- name: "Python-3.9"
properties:
- installSource:
installers:
- command:
command: "/usr/bin/python3.9"
# ===== 凭据配置 =====
credentials:
system:
domainCredentials:
- credentials:
# Gitea集成凭据
- string:
scope: GLOBAL
id: "gitea-api-token"
description: "Gitea API访问令牌"
secret: "${GITEA_TOKEN:-changeme-gitea-token}"
# Docker Registry凭据
- usernamePassword:
scope: GLOBAL
id: "docker-registry-auth"
description: "Docker Registry认证"
username: "${REGISTRY_USERNAME:-admin}"
password: "${REGISTRY_PASSWORD:-admin123}"
# Docker Hub凭据
- usernamePassword:
scope: GLOBAL
id: "dockerhub-auth"
description: "Docker Hub认证"
username: "${DOCKERHUB_USERNAME:-your-username}"
password: "${DOCKERHUB_PASSWORD:-your-password}"
# SSH密钥
- basicSSHUserPrivateKey:
scope: GLOBAL
id: "ssh-key-git"
description: "Git SSH访问密钥"
username: "git"
privateKeySource:
directEntry:
privateKey: |
-----BEGIN OPENSSH PRIVATE KEY-----
# 这里应该放置实际的SSH私钥内容
# 生成方法: ssh-keygen -t ed25519 -C "jenkins@example.com"
-----END OPENSSH PRIVATE KEY-----
# Kubernetes配置
- string:
scope: GLOBAL
id: "k8s-config"
description: "Kubernetes配置文件"
secret: "${K8S_CONFIG:-changeme-k8s-config}"
# 云平台凭据模板
- string:
scope: GLOBAL
id: "aws-access-key"
description: "AWS访问密钥"
secret: "${AWS_ACCESS_KEY:-changeme-aws-key}"
- string:
scope: GLOBAL
id: "azure-service-principal"
description: "Azure服务主体"
secret: "${AZURE_SP:-changeme-azure-sp}"
# ===== 系统配置 =====
unclassified:
# 站点配置
location:
url: "http://localhost:8081/"
adminAddress: "admin@example.com"
# Gitea集成
gitea:
servers:
- displayName: "本地Gitea服务器"
serverUrl: "${GITEA_URL:-http://gitea:3000}"
credentialsId: "gitea-api-token"
manageHooks: true
# GitHub集成
github:
apiRateLimitChecker: ThrottleOnOver
# 全局库配置
globalLibraries:
libraries:
- name: "jenkins-shared-library"
defaultVersion: "main"
allowVersionOverride: true
includeInChangesets: false
retriever:
modernSCM:
scm:
git:
remote: "${GITEA_URL:-http://gitea:3000}/infrastructure/jenkins-shared-library.git"
credentialsId: "gitea-api-token"
# 邮件配置
email-ext:
mailAccount:
smtpHost: "${SMTP_HOST:-localhost}"
smtpPort: "${SMTP_PORT:-25}"
useSsl: false
useTls: false
charset: "UTF-8"
# Slack通知
slack:
teamDomain: "${SLACK_TEAM:-your-team}"
token: "${SLACK_TOKEN:-changeme-slack-token}"
botUser: true
# 钉钉通知
dingTalk:
robots:
- name: "Jenkins通知机器人"
webhook: "${DINGTALK_WEBHOOK:-changeme-webhook}"
# 磁盘使用监控
diskUsage:
enabled: true
countWorkspace: true
checkWorkspaceOnSlave: true
calculationThreads: 2
# 工作空间清理
workspaceCleanupPlugin:
# 自动清理设置
deleteDirectories: true
cleanWhenAborted: true
cleanWhenFailure: false
cleanWhenNotBuilt: true
cleanWhenSuccess: false
cleanWhenUnstable: false
# 性能监控
monitoring:
enabled: true
# 构建历史清理
buildDiscarders:
configuredBuildDiscarders:
- "jobBuildDiscarder"
# 安全设置
csrf:
defaultCrumbIssuer:
excludeClientIPFromCrumb: false
# API限流
apiTokenProperty:
tokenGenerationOnCreationEnabled: true
# ===== 云配置 =====
clouds:
# Docker云配置
- docker:
name: "docker-cloud"
dockerApi:
dockerHost:
uri: "unix:///var/run/docker.sock"
connectTimeout: 60
readTimeout: 60
templates:
- labelString: "docker-agent"
dockerTemplateBase:
image: "jenkins/agent:latest"
mounts:
- "type=bind,src=/var/run/docker.sock,dst=/var/run/docker.sock"
remoteFs: "/home/jenkins/agent"
connector:
ssh:
sshKeyStrategy:
injectSSHKey:
user: "jenkins"
instanceCapStr: "10"
retentionStrategy:
idleMinutes: 10
# Kubernetes云配置
- kubernetes:
name: "kubernetes-cloud"
serverUrl: "${KUBERNETES_MASTER_URL:-https://kubernetes.docker.internal:6443}"
namespace: "jenkins"
credentialsId: "k8s-config"
jenkinsUrl: "http://jenkins:8080"
jenkinsTunnel: "jenkins:50000"
containerCapStr: "100"
maxRequestsPerHostStr: "32"
retentionTimeoutStr: "300"
connectTimeoutStr: "10"
readTimeoutStr: "20"
templates:
- name: "k8s-agent"
label: "k8s-agent"
nodeUsageMode: NORMAL
containers:
- name: "jnlp"
image: "jenkins/inbound-agent:latest"
workingDir: "/home/jenkins/agent"
resourceRequestMemory: "512Mi"
resourceLimitMemory: "1Gi"
resourceRequestCpu: "200m"
resourceLimitCpu: "500m"
volumes:
- hostPathVolume:
hostPath: "/var/run/docker.sock"
mountPath: "/var/run/docker.sock"
# ===== 预创建作业 =====
jobs:
# 多平台构建演示
- script: >
multibranchPipelineJob('demo-multiplatform-build') {
displayName('多平台构建演示')
description('展示Docker多平台镜像构建的完整流程')
branchSources {
git {
id('demo-repo')
remote('${GITEA_URL}/demo/multiplatform-app.git')
credentialsId('gitea-api-token')
}
}
configure { node ->
node / sources / data / 'jenkins.branch.BranchSource' << {
source(class: 'jenkins.plugins.git.GitSCMSource') {
id('demo-repo')
remote('${GITEA_URL}/demo/multiplatform-app.git')
credentialsId('gitea-api-token')
traits {
'jenkins.plugins.git.traits.BranchDiscoveryTrait'()
'jenkins.plugins.git.traits.TagDiscoveryTrait'()
}
}
}
}
factory {
workflowBranchProjectFactory {
scriptPath('Jenkinsfile')
}
}
triggers {
periodicFolderTrigger {
interval('1h')
}
}
}
# 系统监控作业
- script: >
pipelineJob('system-monitoring') {
displayName('系统健康监控')
description('监控Jenkins系统状态、磁盘使用、插件状态等')
properties {
buildDiscarder {
strategy {
logRotator {
daysToKeepStr('7')
numToKeepStr('50')
}
}
}
}
triggers {
cron('H/15 * * * *') # 每15分钟执行
}
definition {
cps {
script('''
pipeline {
agent any
stages {
stage('系统检查') {
parallel {
stage('磁盘使用') {
steps {
script {
def diskUsage = sh(
script: "df -h /var/jenkins_home | awk 'NR==2{print \$5}' | sed 's/%//'",
returnStdout: true
).trim()
echo "磁盘使用率: ${diskUsage}%"
if (diskUsage.toInteger() > 85) {
error("磁盘使用率过高: ${diskUsage}%")
}
}
}
}
stage('服务连通性') {
steps {
script {
def services = [
'Registry': 'http://localhost:5001/v2/',
'Gitea': '${GITEA_URL}/api/v1/version'
]
services.each { name, url ->
def status = sh(
script: "curl -s -o /dev/null -w '%{http_code}' ${url}",
returnStdout: true
).trim()
if (status == '200') {
echo "✅ ${name} 服务正常"
} else {
echo "❌ ${name} 服务异常 (${status})"
}
}
}
}
}
stage('插件状态') {
steps {
script {
def pluginCount = Jenkins.instance.getPluginManager().getPlugins().size()
echo "已安装插件数量: ${pluginCount}"
def failedPlugins = Jenkins.instance.getPluginManager().getPlugins().findAll {
!it.isActive()
}
if (failedPlugins.size() > 0) {
echo "⚠️ 失效插件: ${failedPlugins.collect { it.getShortName() }.join(', ')}"
} else {
echo "✅ 所有插件正常"
}
}
}
}
}
}
stage('性能指标') {
steps {
script {
def runtime = Runtime.getRuntime()
def maxMemory = runtime.maxMemory() / 1024 / 1024
def totalMemory = runtime.totalMemory() / 1024 / 1024
def freeMemory = runtime.freeMemory() / 1024 / 1024
def usedMemory = totalMemory - freeMemory
echo "JVM内存使用: ${usedMemory}MB / ${maxMemory}MB (${(usedMemory/maxMemory*100).round(2)}%)"
def queueSize = Jenkins.instance.getQueue().getItems().length
echo "构建队列: ${queueSize} 个任务"
def executors = Jenkins.instance.getComputers().collect {
it.getExecutors().size()
}.sum()
echo "可用执行器: ${executors} 个"
}
}
}
}
post {
failure {
script {
// 发送告警通知
emailext (
subject: "❌ Jenkins系统监控告警",
body: "Jenkins系统监控检测到异常,请及时处理。\\n\\n构建详情: ${env.BUILD_URL}",
to: "admin@example.com"
)
}
}
}
}
''')
sandbox()
}
}
}
# Docker镜像构建流水线模板
- script: >
pipelineJob('docker-image-template') {
displayName('Docker镜像构建模板')
description('可复用的Docker多平台镜像构建流水线模板')
parameters {
stringParam('GIT_REPO', '${GITEA_URL}/your-project.git', 'Git仓库地址')
stringParam('IMAGE_NAME', 'your-app', '镜像名称')
stringParam('IMAGE_TAG', 'latest', '镜像标签')
stringParam('PLATFORMS', 'linux/amd64,linux/arm64', '构建平台')
booleanParam('PUSH_IMAGE', true, '是否推送镜像')
}
definition {
cps {
script('''
@Library('jenkins-shared-library') _
pipeline {
agent any
environment {
REGISTRY = '${DOCKER_REGISTRY}'
DOCKER_BUILDKIT = '1'
}
stages {
stage('检出代码') {
steps {
git branch: 'main',
url: params.GIT_REPO,
credentialsId: 'gitea-api-token'
}
}
stage('构建多平台镜像') {
steps {
script {
def fullImageName = "${env.REGISTRY}/${params.IMAGE_NAME}:${params.IMAGE_TAG}"
buildMultiPlatformImage {
imageName = fullImageName
platforms = params.PLATFORMS
dockerfile = 'Dockerfile'
buildContext = '.'
pushImage = params.PUSH_IMAGE
registryCredentialsId = 'docker-registry-auth'
}
}
}
}
stage('镜像扫描') {
when {
expression { params.PUSH_IMAGE }
}
steps {
script {
def imageName = "${env.REGISTRY}/${params.IMAGE_NAME}:${params.IMAGE_TAG}"
echo "扫描镜像: ${imageName}"
// 这里可以集成安全扫描工具
}
}
}
}
post {
success {
echo "✅ 多平台镜像构建成功"
}
failure {
echo "❌ 镜像构建失败"
}
cleanup {
cleanWs()
}
}
}
''')
sandbox()
}
}
}
-152
View File
@@ -1,152 +0,0 @@
jenkins:
systemMessage: |
🚀 Jenkins CI/CD 快速自动化部署
📅 部署时间: 2024-08-24
🔧 适配现有环境: Registry(localhost:35001), Gitea(192.168.1.6:3000)
numExecutors: 4
mode: NORMAL
quietPeriod: 5
securityRealm:
local:
allowsSignup: false
users:
- id: "admin"
password: "admin123"
authorizationStrategy:
globalMatrix:
permissions:
- "Overall/Administer:admin"
- "Overall/Read:authenticated"
- "Job/Build:authenticated"
- "Job/Read:authenticated"
- "Job/Configure:authenticated"
- "Job/Create:authenticated"
- "Job/Delete:authenticated"
globalNodeProperties:
- envVars:
env:
- key: "DOCKER_REGISTRY"
value: "localhost:35001"
- key: "GITEA_URL"
value: "http://192.168.1.6:3000"
- key: "BUILD_PLATFORMS"
value: "linux/amd64,linux/arm64"
tool:
git:
installations:
- name: "Default"
home: "/usr/bin/git"
jdk:
installations:
- name: "JDK-17"
home: "/opt/java/openjdk"
credentials:
system:
domainCredentials:
- credentials:
- string:
scope: GLOBAL
id: "gitea-api-token"
description: "Gitea API Token - 请在Gitea中生成后更新"
secret: "changeme-please-update-with-real-token"
- usernamePassword:
scope: GLOBAL
id: "docker-registry-auth"
description: "Docker Registry 认证"
username: "admin"
password: "admin123"
unclassified:
location:
url: "http://localhost:8081/"
adminAddress: "admin@example.com"
csrf:
defaultCrumbIssuer:
excludeClientIPFromCrumb: false
jobs:
- script: >
pipelineJob('hello-world-demo') {
displayName('Hello World 演示')
description('验证 Jenkins 自动化配置')
definition {
cps {
script('''
pipeline {
agent any
stages {
stage('Hello Jenkins') {
steps {
echo "🎉 Jenkins 自动化配置成功!"
echo "📍 Docker Registry: localhost:35001"
echo "📍 Gitea URL: http://192.168.1.6:3000"
echo "🔨 支持平台: linux/amd64,linux/arm64"
script {
def dockerVersion = sh(
script: 'docker --version',
returnStdout: true
).trim()
echo "🐳 Docker 版本: ${dockerVersion}"
}
}
}
stage('环境检查') {
steps {
echo "🔍 检查服务连接..."
script {
// 检查 Registry 连接
def registryCheck = sh(
script: 'curl -s -o /dev/null -w "%{http_code}" http://localhost:35001/v2/ || echo "failed"',
returnStdout: true
).trim()
if (registryCheck == "200") {
echo "✅ Registry 连接正常"
} else {
echo "⚠️ Registry 连接状态: ${registryCheck}"
}
// 检查 Gitea 连接
def giteaCheck = sh(
script: 'curl -s -o /dev/null -w "%{http_code}" http://192.168.1.6:3000/api/v1/version || echo "failed"',
returnStdout: true
).trim()
if (giteaCheck == "200") {
echo "✅ Gitea 连接正常"
} else {
echo "⚠️ Gitea 连接状态: ${giteaCheck}"
}
}
}
}
}
post {
always {
echo "🎊 Jenkins 快速部署验证完成!"
}
success {
echo "✅ 所有检查通过,环境就绪!"
}
}
}
''')
sandbox()
}
}
}
@@ -1,345 +0,0 @@
# Jenkins持久化专用配置
jenkins:
systemMessage: "Jenkins CI/CD - 完整持久化配置"
numExecutors: 4
mode: NORMAL
scmCheckoutRetryCount: 3
quietPeriod: 5
# ===== 安全配置 =====
securityRealm:
local:
allowsSignup: false
users:
- id: "${JENKINS_ADMIN_ID}"
password: "${JENKINS_ADMIN_PASSWORD}"
authorizationStrategy:
globalMatrix:
permissions:
- "Overall/Administer:admin"
- "Overall/Read:authenticated"
- "Job/Build:authenticated"
- "Job/Read:authenticated"
- "Job/Workspace:authenticated"
- "Job/Configure:authenticated"
- "Job/Create:authenticated"
# ===== 全局属性 =====
globalNodeProperties:
- envVars:
env:
- key: "DOCKER_REGISTRY"
value: "localhost:5001"
- key: "GITEA_URL"
value: "http://gitea:3000"
- key: "BACKUP_ENABLED"
value: "true"
# ===== 构建历史保留策略 =====
buildDiscarders:
- buildDiscarder:
strategy:
logRotator:
daysToKeepStr: "30" # 保留30天
numToKeepStr: "50" # 保留最近50次构建
artifactDaysToKeepStr: "7" # 制品保留7天
artifactNumToKeepStr: "10" # 制品保留10个
# ===== 全局工具配置 =====
tool:
git:
installations:
- name: "Default"
home: "/usr/bin/git"
maven:
installations:
- name: "Maven-3.9"
properties:
- installSource:
installers:
- maven:
id: "3.9.6"
gradle:
installations:
- name: "Gradle-8"
properties:
- installSource:
installers:
- gradleInstaller:
id: "8.5"
nodejs:
installations:
- name: "NodeJS-18"
properties:
- installSource:
installers:
- nodeJSInstaller:
id: "18.19.0"
npmPackagesRefreshHours: 72
dockerTool:
installations:
- name: "Docker"
home: "/usr/local/bin/docker"
# ===== 凭据配置 =====
credentials:
system:
domainCredentials:
- credentials:
# Gitea访问令牌
- string:
scope: GLOBAL
id: "gitea-token"
description: "Gitea API访问令牌"
secret: "your-gitea-token-placeholder"
# Docker Registry认证
- usernamePassword:
scope: GLOBAL
id: "registry-auth"
description: "Docker Registry认证"
username: "admin"
password: "admin123"
# 备份存储凭据
- string:
scope: GLOBAL
id: "backup-encryption-key"
description: "备份加密密钥"
secret: "backup-key-placeholder"
# ===== 系统配置 =====
unclassified:
location:
url: "http://localhost:8081/"
adminAddress: "admin@example.com"
# ===== Gitea集成 =====
gitea:
servers:
- displayName: "Local Gitea"
serverUrl: "http://gitea:3000"
credentialsId: "gitea-token"
manageHooks: true
# ===== 共享库配置 =====
globalLibraries:
libraries:
- name: "jenkins-shared-library"
defaultVersion: "main"
retriever:
modernSCM:
scm:
git:
remote: "http://gitea:3000/infrastructure/jenkins-shared-library.git"
credentialsId: "gitea-token"
# ===== 构建清理配置 =====
buildDiscarders:
configuredBuildDiscarders:
- "jobBuildDiscarder"
# ===== 工作空间清理 =====
workspaceCleanupPlugin:
# 自动清理工作空间
deleteDirectories: true
# 清理失败构建的工作空间
cleanWhenAborted: true
cleanWhenFailure: true
cleanWhenNotBuilt: true
cleanWhenSuccess: true
cleanWhenUnstable: true
# ===== 磁盘使用监控 =====
diskUsage:
countWorkspace: true
checkWorkspaceOnSlave: true
calculationThreads: 2
# ===== 预创建作业 =====
jobs:
# 数据备份作业
- script: >
freeStyleJob('backup-jenkins-data') {
displayName('Jenkins数据备份')
description('定期备份Jenkins配置和数据')
properties {
buildDiscarder {
strategy {
logRotator {
daysToKeepStr('7')
numToKeepStr('10')
}
}
}
}
triggers {
cron('0 2 * * 0') # 每周日凌晨2点执行
}
steps {
shell('''
echo "=== Jenkins数据备份开始 ==="
# 创建备份目录
BACKUP_DIR="/var/jenkins_backup/scheduled/$(date +%Y%m%d_%H%M%S)"
mkdir -p "$BACKUP_DIR"
# 备份关键配置
echo "备份配置文件..."
cp -r /var/jenkins_home/config.xml "$BACKUP_DIR/"
cp -r /var/jenkins_home/credentials.xml "$BACKUP_DIR/" 2>/dev/null || true
cp -r /var/jenkins_home/users "$BACKUP_DIR/"
cp -r /var/jenkins_home/secrets "$BACKUP_DIR/"
# 备份作业配置
echo "备份作业配置..."
cp -r /var/jenkins_home/jobs "$BACKUP_DIR/"
# 创建备份清单
echo "创建备份清单..."
find "$BACKUP_DIR" -type f > "$BACKUP_DIR/backup_manifest.txt"
# 压缩备份
cd /var/jenkins_backup/scheduled
tar -czf "jenkins-scheduled-$(date +%Y%m%d_%H%M%S).tar.gz" "$(basename $BACKUP_DIR)"
rm -rf "$BACKUP_DIR"
echo "=== 备份完成 ==="
echo "备份文件: $(ls -la jenkins-scheduled-*.tar.gz | tail -1)"
# 清理旧备份(保留最近5个)
ls -t jenkins-scheduled-*.tar.gz | tail -n +6 | xargs rm -f || true
''')
}
publishers {
extendedEmail {
recipientList('admin@example.com')
defaultSubject('Jenkins备份报告 - $BUILD_STATUS')
defaultContent('Jenkins数据备份任务执行完成。\\n\\n构建状态: $BUILD_STATUS\\n构建日志: $BUILD_LOG')
triggers {
failure {
subject('❌ Jenkins备份失败')
content('Jenkins数据备份任务失败,请检查系统状态。')
}
success {
subject('✅ Jenkins备份成功')
content('Jenkins数据备份任务成功完成。')
}
}
}
}
}
# 磁盘清理作业
- script: >
freeStyleJob('cleanup-disk-space') {
displayName('磁盘空间清理')
description('清理旧构建数据和临时文件')
properties {
buildDiscarder {
strategy {
logRotator {
daysToKeepStr('30')
numToKeepStr('50')
}
}
}
}
triggers {
cron('0 3 * * *') # 每日凌晨3点执行
}
steps {
shell('''
echo "=== 磁盘清理开始 ==="
# 显示清理前磁盘使用情况
echo "清理前磁盘使用:"
df -h /var/jenkins_home
du -sh /var/jenkins_home/workspace
du -sh /var/jenkins_home/builds
# 清理工作空间中7天前的目录
echo "清理旧工作空间..."
find /var/jenkins_home/workspace -type d -mtime +7 -exec rm -rf {} + 2>/dev/null || true
# 清理临时文件
echo "清理临时文件..."
find /var/jenkins_home/tmp -type f -mtime +1 -delete 2>/dev/null || true
# 清理日志文件(保留最近30天)
echo "清理旧日志..."
find /var/jenkins_home/logs -name "*.log" -mtime +30 -delete 2>/dev/null || true
# 清理缓存
echo "清理缓存文件..."
find /var/jenkins_home/.cache -type f -mtime +7 -delete 2>/dev/null || true
# 显示清理后磁盘使用情况
echo "清理后磁盘使用:"
df -h /var/jenkins_home
du -sh /var/jenkins_home/workspace
du -sh /var/jenkins_home/builds
echo "=== 磁盘清理完成 ==="
''')
}
}
# 系统健康检查作业
- script: >
freeStyleJob('system-health-monitor') {
displayName('系统健康监控')
description('监控Jenkins系统健康状态和数据完整性')
triggers {
cron('H/30 * * * *') # 每30分钟执行一次
}
steps {
shell('''
echo "=== Jenkins健康检查 ==="
# 检查磁盘使用率
DISK_USAGE=$(df /var/jenkins_home | awk 'NR==2{print $5}' | sed 's/%//')
echo "磁盘使用率: ${DISK_USAGE}%"
if [ "$DISK_USAGE" -gt 85 ]; then
echo "⚠️ 警告: 磁盘使用率过高"
exit 1
fi
# 检查内存使用
echo "内存使用情况:"
free -h || echo "无法获取内存信息"
# 检查关键文件完整性
echo "检查关键文件..."
[ -f "/var/jenkins_home/config.xml" ] && echo "✅ config.xml 存在" || echo "❌ config.xml 缺失"
[ -d "/var/jenkins_home/jobs" ] && echo "✅ jobs目录存在" || echo "❌ jobs目录缺失"
[ -d "/var/jenkins_home/plugins" ] && echo "✅ plugins目录存在" || echo "❌ plugins目录缺失"
# 检查备份状态
echo "检查备份状态..."
BACKUP_COUNT=$(ls /var/jenkins_backup/*/*.tar.gz 2>/dev/null | wc -l)
echo "可用备份数量: $BACKUP_COUNT"
if [ "$BACKUP_COUNT" -lt 3 ]; then
echo "⚠️ 警告: 备份数量不足"
fi
echo "=== 健康检查完成 ==="
''')
}
}
-132
View File
@@ -1,132 +0,0 @@
jenkins:
systemMessage: "Jenkins CI/CD服务器 - Mac Studio M2 环境"
numExecutors: 4
mode: NORMAL
scmCheckoutRetryCount: 3
quietPeriod: 5
securityRealm:
local:
allowsSignup: false
users:
- id: admin
password: ${JENKINS_ADMIN_PASSWORD:-admin123}
authorizationStrategy:
globalMatrix:
permissions:
- "Overall/Administer:admin"
- "Overall/Read:authenticated"
- "Job/Build:authenticated"
- "Job/Read:authenticated"
- "Job/Workspace:authenticated"
remotingSecurity:
enabled: true
globalNodeProperties:
- envVars:
env:
- key: "DOCKER_REGISTRY"
value: "localhost:5001"
- key: "GITEA_URL"
value: "http://gitea:3000"
- key: "KUBERNETES_MASTER_URL"
value: "https://kubernetes.docker.internal:6443"
tool:
git:
installations:
- name: "Default"
home: "/usr/bin/git"
maven:
installations:
- name: "Maven-3.9"
properties:
- installSource:
installers:
- maven:
id: "3.9.6"
gradle:
installations:
- name: "Gradle-8"
properties:
- installSource:
installers:
- gradleInstaller:
id: "8.5"
nodejs:
installations:
- name: "NodeJS-18"
properties:
- installSource:
installers:
- nodeJSInstaller:
id: "18.19.0"
npmPackagesRefreshHours: 72
dockerTool:
installations:
- name: "Docker"
home: "/usr/local/bin/docker"
unclassified:
location:
url: "http://localhost:8081/jenkins/"
adminAddress: "admin@example.com"
gitea:
servers:
- displayName: "Local Gitea"
serverUrl: "http://gitea:3000"
credentialsId: "gitea-token"
manageHooks: true
globalLibraries:
libraries:
- name: "jenkins-shared-library"
defaultVersion: "main"
retriever:
modernSCM:
scm:
git:
remote: "http://gitea:3000/infrastructure/jenkins-shared-library.git"
credentialsId: "gitea-token"
buildDiscarders:
configuredBuildDiscarders:
- "jobBuildDiscarder"
jobs:
- script: >
multibranchPipelineJob('cicd-pipelines') {
displayName('CI/CD Pipeline多分支项目')
description('自动化CI/CD Pipeline')
branchSources {
git {
remote('http://gitea:3000/infrastructure/cicd-pipelines.git')
credentialsId('gitea-token')
}
}
factory {
workflowBranchProjectFactory {
scriptPath('Jenkinsfile')
}
}
configure { node ->
def traits = node / 'sources' / 'data' / 'jenkins.branch.BranchSource' / 'source' / 'traits'
traits << 'jenkins.plugins.git.traits.BranchDiscoveryTrait' {
strategyId(1)
}
traits << 'jenkins.plugins.git.traits.OriginPullRequestDiscoveryTrait' {
strategyId(1)
}
traits << 'jenkins.plugins.git.traits.ForkPullRequestDiscoveryTrait' {
strategyId(1)
trust(class: 'jenkins.plugins.git.traits.ForkPullRequestDiscoveryTrait$TrustContributors')
}
}
}
@@ -1,50 +0,0 @@
#!/usr/bin/env groovy
// 跳过Jenkins设置向导并配置基础安全
import jenkins.model.*
import hudson.security.*
import hudson.security.csrf.DefaultCrumbIssuer
import hudson.util.Secret
import jenkins.security.s2m.AdminWhitelistRule
def instance = Jenkins.getInstance()
// 设置管理员账号(如果不存在)
def hudsonRealm = new HudsonPrivateSecurityRealm(false)
def adminUsername = System.getenv('JENKINS_ADMIN_ID') ?: 'admin'
def adminPassword = System.getenv('JENKINS_ADMIN_PASSWORD') ?: 'admin123'
if (!hudsonRealm.getAllUsers().find { it.getId() == adminUsername }) {
hudsonRealm.createAccount(adminUsername, adminPassword)
instance.setSecurityRealm(hudsonRealm)
println "✅ 创建管理员用户: ${adminUsername}"
} else {
println "ℹ️ 管理员用户已存在: ${adminUsername}"
}
// 设置授权策略
def strategy = new FullControlOnceLoggedInAuthorizationStrategy()
strategy.setAllowAnonymousRead(false)
instance.setAuthorizationStrategy(strategy)
// 启用CSRF保护
instance.setCrumbIssuer(new DefaultCrumbIssuer(true))
// 设置代理到主服务器安全
instance.getInjector().getInstance(AdminWhitelistRule.class).setMasterKillSwitch(false)
// 设置Jenkins版本以跳过向导
def setupWizard = instance.getSetupWizard()
if (setupWizard != null) {
setupWizard.completeSetup()
println "✅ 已跳过设置向导"
}
// 禁用使用统计
instance.setNoUsageStatistics(true)
// 保存配置
instance.save()
println "🎉 Jenkins安全配置完成"
@@ -1,23 +0,0 @@
import jenkins.model.*
import hudson.security.*
import hudson.security.csrf.DefaultCrumbIssuer
import jenkins.security.s2m.AdminWhitelistRule
def instance = Jenkins.getInstance()
// 跳过设置向导
if (!instance.getInstallState().isSetupComplete()) {
println('Skipping initial setup wizard...')
instance.setInstallState(InstallState.INITIAL_SETUP_COMPLETED)
}
// 设置 CSRF 保护
instance.setCrumbIssuer(new DefaultCrumbIssuer(true))
// 设置安全策略
instance.getInjector().getInstance(AdminWhitelistRule.class).setMasterKillSwitch(false)
// 保存配置
instance.save()
println('Admin setup completed!')
@@ -1,27 +0,0 @@
#!/usr/bin/env groovy
// Jenkins自动化初始化脚本
import jenkins.model.*
import hudson.security.*
def instance = Jenkins.getInstance()
// 设置系统消息
instance.setSystemMessage("""
🎉 Jenkins已完全自动配置!
📦 已安装插件: ${instance.pluginManager.plugins.size()} 个
🔧 工具配置: Git, JDK, Maven, Gradle, NodeJS, Docker, Python
☁️ 云配置: Docker Cloud, Kubernetes Cloud
🔐 凭据模板: Gitea, Registry, SSH, K8s等
📋 预创建作业: 多平台构建, 系统监控, 镜像模板
📚 管理文档: docs/jenkins-persistence-guide.md
🌐 访问地址: http://localhost:8081
👤 登录账号: admin / admin123
""")
// 保存配置
instance.save()
println "🎉 Jenkins自动化初始化完成!"
@@ -1,45 +0,0 @@
import jenkins.model.*
import com.cloudbees.plugins.credentials.*
import com.cloudbees.plugins.credentials.common.*
import com.cloudbees.plugins.credentials.domains.*
import com.cloudbees.plugins.credentials.impl.*
import hudson.util.Secret
def instance = Jenkins.getInstance()
def store = instance.getExtensionList('com.cloudbees.plugins.credentials.SystemCredentialsProvider')[0].getStore()
// 确保 Docker 可用
try {
def proc = "docker --version".execute()
proc.waitFor()
if (proc.exitValue() == 0) {
println("Docker is available: ${proc.text.trim()}")
} else {
println("Docker command failed")
}
} catch (Exception e) {
println("Docker check failed: ${e.message}")
}
// 设置 Docker buildx
try {
def buildxProc = "docker buildx version".execute()
buildxProc.waitFor()
if (buildxProc.exitValue() == 0) {
println("Docker buildx is available")
// 创建 multiarch builder
def createBuilder = "docker buildx create --name multiarch --driver docker-container --use".execute()
createBuilder.waitFor()
def inspectBuilder = "docker buildx inspect --bootstrap".execute()
inspectBuilder.waitFor()
println("Multi-architecture builder created")
}
} catch (Exception e) {
println("Docker buildx setup failed: ${e.message}")
}
instance.save()
println('Docker setup completed!')
@@ -1,27 +0,0 @@
import jenkins.model.*
import hudson.model.*
import hudson.tools.*
import hudson.util.DescribableList
import jenkins.plugins.nodejs.tools.*
import org.jenkinsci.plugins.docker.commons.tools.*
def instance = Jenkins.getInstance()
// 配置 Git
def gitDesc = instance.getDescriptor(hudson.plugins.git.GitTool.class)
def gitInstallations = [
new hudson.plugins.git.GitTool("Default", "/usr/bin/git", [])
]
gitDesc.setInstallations(gitInstallations.toArray(new hudson.plugins.git.GitTool[0]))
// 配置 Docker
def dockerDesc = instance.getDescriptor(org.jenkinsci.plugins.docker.commons.tools.DockerTool.class)
if (dockerDesc) {
def dockerInstallations = [
new org.jenkinsci.plugins.docker.commons.tools.DockerTool("Docker", "/usr/bin/docker", [])
]
dockerDesc.setInstallations(dockerInstallations.toArray(new org.jenkinsci.plugins.docker.commons.tools.DockerTool[0]))
}
instance.save()
println('Tools setup completed!')
-24
View File
@@ -1,24 +0,0 @@
# Jenkins环境配置
JENKINS_ADMIN_PASSWORD=admin123
JENKINS_ADMIN_EMAIL=admin@example.com
# JVM配置
JENKINS_JAVA_OPTS=-Xmx2g -Xms1g -XX:+UseG1GC -XX:MaxGCPauseMillis=200
# 网络配置
JENKINS_HOST=localhost
JENKINS_PORT=8081
JENKINS_AGENT_PORT=50000
# 集成配置
GITEA_URL=http://gitea:3000
DOCKER_REGISTRY=localhost:5001
# 备份配置
BACKUP_RETENTION_DAYS=30
BACKUP_SCHEDULE="0 2 * * *"
# 性能配置
MAX_BUILDS_TO_KEEP=50
MAX_DAYS_TO_KEEP=30
EXECUTOR_COUNT=4
@@ -1,53 +0,0 @@
<?xml version='1.1' encoding='UTF-8'?>
<flow-definition plugin="workflow-job">
<actions/>
<description>Jenkins测试应用CI/CD Pipeline</description>
<keepDependencies>false</keepDependencies>
<properties>
<org.jenkinsci.plugins.workflow.job.properties.PipelineTriggersJobProperty>
<triggers>
<org.jenkinsci.plugins.gwt.GenericTrigger plugin="generic-webhook-trigger">
<spec></spec>
<genericVariables>
<org.jenkinsci.plugins.gwt.GenericVariable>
<expressionType>JSONPath</expressionType>
<key>GITEA_REPO</key>
<value>$.repository.name</value>
</org.jenkinsci.plugins.gwt.GenericVariable>
<org.jenkinsci.plugins.gwt.GenericVariable>
<expressionType>JSONPath</expressionType>
<key>GITEA_BRANCH</key>
<value>$.ref</value>
</org.jenkinsci.plugins.gwt.GenericVariable>
</genericVariables>
<regexpFilterText>$GITEA_REPO</regexpFilterText>
<regexpFilterExpression>jenkins-test-app</regexpFilterExpression>
<printContributedVariables>true</printContributedVariables>
<printPostContent>true</printPostContent>
</org.jenkinsci.plugins.gwt.GenericTrigger>
</triggers>
</org.jenkinsci.plugins.workflow.job.properties.PipelineTriggersJobProperty>
</properties>
<definition class="org.jenkinsci.plugins.workflow.cps.CpsScmFlowDefinition" plugin="workflow-cps">
<scm class="hudson.plugins.git.GitSCM" plugin="git">
<configVersion>2</configVersion>
<userRemoteConfigs>
<hudson.plugins.git.UserRemoteConfig>
<url>http://gitea:3000/gitea/jenkins-test-app.git</url>
</hudson.plugins.git.UserRemoteConfig>
</userRemoteConfigs>
<branches>
<hudson.plugins.git.BranchSpec>
<name>*/main</name>
</hudson.plugins.git.BranchSpec>
</branches>
<doGenerateSubmoduleConfigurations>false</doGenerateSubmoduleConfigurations>
<submoduleCfg class="empty-list"/>
<extensions/>
</scm>
<scriptPath>Jenkinsfile</scriptPath>
<lightweight>true</lightweight>
</definition>
<triggers/>
<disabled>false</disabled>
</flow-definition>
@@ -1,101 +0,0 @@
pipeline {
agent any
environment {
DOCKER_REGISTRY = "${env.DOCKER_REGISTRY ?: 'localhost:5001'}"
GITEA_URL = "${env.GITEA_URL ?: 'http://gitea:3000'}"
APP_NAME = "${env.JOB_NAME.split('/')[0]}"
BUILD_TAG = "${env.BUILD_NUMBER}-${env.GIT_COMMIT[0..7]}"
}
options {
buildDiscarder(logRotator(numToKeepStr: '50', daysToKeepStr: '30'))
timeout(time: 30, unit: 'MINUTES')
timestamps()
ansiColor('xterm')
}
stages {
stage('检出代码') {
steps {
checkout scm
script {
env.GIT_COMMIT = sh(returnStdout: true, script: 'git rev-parse HEAD').trim()
}
}
}
stage('代码检查') {
parallel {
stage('语法检查') {
steps {
sh 'echo "执行语法检查..."'
// 添加具体的语法检查命令
}
}
stage('安全扫描') {
steps {
sh 'echo "执行安全扫描..."'
// 添加安全扫描命令
}
}
}
}
stage('构建测试') {
steps {
sh 'echo "执行单元测试..."'
// 添加测试命令
}
post {
always {
// 发布测试结果
publishTestResults testResultsPattern: 'test-results.xml'
}
}
}
stage('构建镜像') {
when {
anyOf {
branch 'main'
branch 'develop'
}
}
steps {
script {
def image = docker.build("${DOCKER_REGISTRY}/${APP_NAME}:${BUILD_TAG}")
docker.withRegistry("http://${DOCKER_REGISTRY}") {
image.push()
image.push("latest")
}
}
}
}
stage('部署') {
when {
branch 'main'
}
steps {
sh """
echo "部署到生产环境..."
# 添加部署命令
"""
}
}
}
post {
always {
cleanWs()
}
success {
echo "✅ 构建成功!"
}
failure {
echo "❌ 构建失败!"
// 发送通知
}
}
}
@@ -1,140 +0,0 @@
# Jenkins最佳实践插件列表
# Configuration as Code - 必须首先安装
configuration-as-code:latest
# ===== 核心CI/CD插件 =====
# Pipeline和工作流
workflow-aggregator:latest
pipeline-stage-view:latest
pipeline-utility-steps:latest
pipeline-milestone-step:latest
pipeline-build-step:latest
pipeline-input-step:latest
pipeline-graph-analysis:latest
# 构建和部署
build-timeout:latest
timestamper:latest
ws-cleanup:latest
copy-artifact:latest
archive-artifacts:latest
junit:latest
htmlpublisher:latest
# ===== SCM和版本控制 =====
git:latest
gitea:latest
github:latest
github-branch-source:latest
ssh-credentials:latest
credentials-binding:latest
# ===== Docker和容器化 =====
docker-plugin:latest
docker-build-step:latest
docker-commons:latest
docker-workflow:latest
docker-slaves:latest
docker-swarm:latest
# ===== Kubernetes集成 =====
kubernetes:latest
kubernetes-cd:latest
kubernetes-cli:latest
kubernetes-credentials:latest
# ===== 构建工具 =====
# Maven
maven-plugin:latest
maven-invoker-plugin:latest
# Gradle
gradle:latest
# Node.js
nodejs:latest
npm:latest
# Python
python:latest
# Ant
ant:latest
# ===== 代码质量和测试 =====
warnings-ng:latest
checkstyle:latest
pmd:latest
findbugs:latest
jacoco:latest
sonar:latest
cobertura:latest
# ===== 通知和集成 =====
email-ext:latest
slack:latest
dingtalk:latest
webhook-step:latest
http_request:latest
generic-webhook-trigger:latest
# ===== UI和可视化 =====
blueocean:latest
dashboard-view:latest
build-monitor-plugin:latest
build-pipeline-plugin:latest
delivery-pipeline-plugin:latest
radiator-view-plugin:latest
# ===== 安全和权限 =====
matrix-auth:latest
role-strategy:latest
ldap:latest
pam-auth:latest
authorize-project:latest
# ===== 系统管理 =====
locale:latest
disk-usage:latest
monitoring:latest
naginator:latest
rebuild:latest
parameterized-trigger:latest
# ===== 文件和存储 =====
publish-over-ssh:latest
publish-over-ftp:latest
s3:latest
# ===== 其他实用插件 =====
ansicolor:latest
antisamy-markup-formatter:latest
build-name-setter:latest
description-setter:latest
environment-injector:latest
promoted-builds:latest
throttle-concurrents:latest
job-dsl:latest
# ===== 多平台构建 =====
matrix-project:latest
multi-branch-project-plugin:latest
# ===== API和集成 =====
rest-api:latest
cli:latest
# ===== 性能和监控 =====
performance:latest
plot:latest
xvfb:latest
# ===== 数据库集成 =====
database:latest
database-h2:latest
database-postgresql:latest
# ===== 云平台集成 =====
ec2:latest
azure-vm-agents:latest
google-compute-engine:latest
-86
View File
@@ -1,86 +0,0 @@
# 核心插件
ant:475.vf34069fef73c
build-timeout:1.31
credentials-binding:681.vf91669a_32e45
timestamper:1.26
ws-cleanup:0.45
workflow-aggregator:596.v8c21c963d92d
# 版本控制
git:5.0.2
git-parameter:0.9.19
github:1.37.3.1
github-branch-source:1728.v859147241f49
gitea:1.4.5
gitlab-plugin:1.8.1
# 构建工具
maven-plugin:3.22
gradle:2.11
nodejs:1.6.1
python:1.3
docker-plugin:1.5.0
docker-workflow:580.vc0c340686b_54
kubernetes:4104.v857ce8db_424e
# Pipeline 和工作流
pipeline-stage-view:2.34
blueocean:1.27.9
pipeline-graph-analysis:216.vfd8b_ece330ca_
workflow-multibranch:773.vc4fe1378f1d5
pipeline-milestone-step:111.v449306f708b_7
# 通知和集成
email-ext:2.105
slack:664.vc9a_90f8b_c24a_
dingtalk:2.4.2
telegram-notifications:1.4.0
# 安全和认证
matrix-auth:3.2.2
role-strategy:699.v2a_69872237db_
authorize-project:1.7.0
ssh-slaves:2.973.v0a_5c0264ce98
# 代码质量
warnings-ng:10.7.0
sonarqube:2.17.2
checkmarx:2023.4.2
aqua-security-scanner:3.0.22
# 测试和报告
junit:1265.v65b_14fa_f12f0
jacoco:3.3.5
performance:3.21
test-results-analyzer:0.3.5.1
# 监控和管理
monitoring:1.98.0
disk-usage:0.28
build-monitor-plugin:1.4+build.201809061734
prometheus:2.2.3
# 实用工具
configuration-as-code:1810.v9b_c30a_249a_4c
job-dsl:1.87
build-name-setter:2.4.1
parameterized-trigger:2.45
copyartifact:722.v0662a_9b_e22a_c
# 云集成
ec2:2.0.7
kubernetes:4104.v857ce8db_424e
docker-slaves:1.0.7
azure-vm-agents:1.0.0
# 文件和存储
artifactory:3.18.10
nexus-artifact-uploader:2.15
s3:1.0.0
publish-over-ssh:1.25
# 高级功能
multibranch-scan-webhook-trigger:1.0.10
generic-webhook-trigger:2.2.2
pipeline-utility-steps:2.16.2
http_request:1.18
@@ -1,69 +0,0 @@
# 核心插件
build-timeout:latest
credentials-binding:latest
timestamper:latest
ws-cleanup:latest
ansicolor:latest
# SCM和Git
git:latest
gitea:latest
github:latest
ssh-credentials:latest
# Pipeline和构建
pipeline-stage-view:latest
pipeline-utility-steps:latest
workflow-aggregator:latest
workflow-cps:latest
workflow-job:latest
workflow-multibranch:latest
pipeline-milestone-step:latest
# Docker集成
docker-plugin:latest
docker-build-step:latest
docker-commons:latest
docker-workflow:latest
kubernetes:latest
# 构建工具
ant:latest
gradle:latest
maven-plugin:latest
nodejs:latest
python:latest
# UI和可视化
blueocean:latest
dashboard-view:latest
build-monitor-plugin:latest
# 自动化和集成
configuration-as-code:latest
job-dsl:latest
generic-webhook-trigger:latest
http_request:latest
webhook-step:latest
# 通知和报告
email-ext:latest
slack:latest
junit:latest
htmlpublisher:latest
# 质量和安全
sonar:latest
checkstyle:latest
warnings-ng:latest
dependency-check-jenkins-plugin:latest
# 部署和K8s
kubernetes-cd:latest
helm:latest
kubernetes-cli:latest
# 性能优化
parallel-test-executor:latest
copy-artifact:latest
archive-artifacts:latest
@@ -1,83 +0,0 @@
#!/bin/bash
# Pipeline作业生成器
set -e
# 参数
JOB_NAME="$1"
REPO_URL="$2"
PIPELINE_TYPE="$3"
BRANCH="$4"
if [[ -z "$JOB_NAME" || -z "$REPO_URL" ]]; then
echo "用法: $0 <作业名称> <仓库URL> [Pipeline类型] [分支]"
echo ""
echo "Pipeline类型:"
echo " webapp - Web应用 (默认)"
echo " microservice - 微服务"
echo " docker - Docker构建"
echo " multistage - 多阶段构建"
echo ""
echo "示例:"
echo " $0 my-webapp http://gitea:3000/user/repo.git webapp main"
exit 1
fi
PIPELINE_TYPE=${PIPELINE_TYPE:-webapp}
BRANCH=${BRANCH:-main}
# 生成作业配置XML
cat > "/tmp/${JOB_NAME}.xml" << EOF
<?xml version='1.1' encoding='UTF-8'?>
<flow-definition plugin="workflow-job">
<actions/>
<description>自动生成的${PIPELINE_TYPE} Pipeline作业</description>
<keepDependencies>false</keepDependencies>
<properties>
<org.jenkinsci.plugins.workflow.job.properties.PipelineTriggersJobProperty>
<triggers>
<org.jenkinsci.plugins.gwt.GenericTrigger plugin="generic-webhook-trigger">
<spec></spec>
<genericVariables>
<org.jenkinsci.plugins.gwt.GenericVariable>
<expressionType>JSONPath</expressionType>
<key>GITEA_REPO</key>
<value>\$.repository.name</value>
</org.jenkinsci.plugins.gwt.GenericVariable>
<org.jenkinsci.plugins.gwt.GenericVariable>
<expressionType>JSONPath</expressionType>
<key>GITEA_BRANCH</key>
<value>\$.ref</value>
</org.jenkinsci.plugins.gwt.GenericVariable>
</genericVariables>
<regexpFilterText>\$GITEA_REPO</regexpFilterText>
<regexpFilterExpression>$JOB_NAME</regexpFilterExpression>
<printContributedVariables>true</printContributedVariables>
<printPostContent>true</printPostContent>
</org.jenkinsci.plugins.gwt.GenericTrigger>
</triggers>
</org.jenkinsci.plugins.workflow.job.properties.PipelineTriggersJobProperty>
</properties>
<definition class="org.jenkinsci.plugins.workflow.cps.CpsScmFlowDefinition" plugin="workflow-cps">
<scm class="hudson.plugins.git.GitSCM" plugin="git">
<configVersion>2</configVersion>
<userRemoteConfigs>
<hudson.plugins.git.UserRemoteConfig>
<url>$REPO_URL</url>
</hudson.plugins.git.UserRemoteConfig>
</userRemoteConfigs>
<branches>
<hudson.plugins.git.BranchSpec>
<name>*/$BRANCH</name>
</hudson.plugins.git.BranchSpec>
</branches>
<doGenerateSubmoduleConfigurations>false</doGenerateSubmoduleConfigurations>
<submoduleCfg class="empty-list"/>
<extensions/>
</scm>
<scriptPath>Jenkinsfile</scriptPath>
<lightweight>true</lightweight>
</definition>
<triggers/>
<disabled>false</disabled>
</flow-definition>
@@ -1,36 +0,0 @@
#!/bin/bash
# Docker工具配置脚本
echo "=== Docker工具配置指南 ==="
echo ""
echo "1. 配置Docker工具"
echo " 路径: Jenkins -> 管理Jenkins -> 全局工具配置"
echo " 添加Docker安装:"
echo " - 名称: Docker"
echo " - 安装目录: /usr/local/bin/docker"
echo " - 或选择自动安装最新版本"
echo ""
echo "2. 配置Docker Cloud (可选)"
echo " 路径: Jenkins -> 管理Jenkins -> 节点和云 -> 配置云"
echo " 添加Docker Cloud:"
echo " - Docker Host URI: unix:///var/run/docker.sock"
echo " - 启用: 是"
echo ""
echo "3. 安装Docker相关插件"
echo " 推荐插件:"
echo " - Docker Plugin"
echo " - Docker Pipeline"
echo " - Docker Commons"
echo " - Docker Build Step"
echo ""
echo "4. 验证Docker配置"
echo " 在Jenkins Pipeline中测试:"
echo " sh 'docker --version'"
echo " sh 'docker info'"
echo ""
echo "5. 配置Docker Registry"
echo " 在Pipeline中使用:"
echo " docker.withRegistry('http://localhost:5001', 'registry-auth') {"
echo " def image = docker.build('my-app:latest')"
echo " image.push()"
echo " }"
@@ -1,33 +0,0 @@
#!/bin/bash
# Jenkins插件安装脚本
PLUGINS=(
"configuration-as-code:latest"
"job-dsl:latest"
"pipeline-stage-view:latest"
"blueocean:latest"
"gitea:latest"
"docker-plugin:latest"
"docker-workflow:latest"
"credentials-binding:latest"
"timestamper:latest"
"ws-cleanup:latest"
"build-timeout:latest"
"generic-webhook-trigger:latest"
"pipeline-utility-steps:latest"
"http_request:latest"
"email-ext:latest"
"maven-plugin:latest"
"gradle:latest"
"nodejs:latest"
"python:latest"
)
echo "推荐安装的插件列表:"
for plugin in "${PLUGINS[@]}"; do
echo "- $plugin"
done
echo ""
echo "在Jenkins管理界面中,进入 '管理Jenkins' -> '插件管理' -> '可选插件'"
echo "搜索并安装上述插件"
@@ -1,26 +0,0 @@
#!/bin/bash
# Docker Registry认证配置
REGISTRY_URL="localhost:5001"
REGISTRY_USER="admin"
REGISTRY_PASS="registry123"
echo "=== Docker Registry认证配置 ==="
echo ""
echo "Registry URL: $REGISTRY_URL"
echo "用户名: $REGISTRY_USER"
echo "密码: $REGISTRY_PASS"
echo ""
echo "在Jenkins中配置Registry认证:"
echo "1. 进入 Jenkins -> 管理Jenkins -> 凭据"
echo "2. 点击 'System' -> '全局凭据'"
echo "3. 点击 '添加凭据'"
echo "4. 选择类型: 'Username with password'"
echo "5. 填写信息:"
echo " - ID: registry-auth"
echo " - 描述: Docker Registry Auth"
echo " - 用户名: $REGISTRY_USER"
echo " - 密码: $REGISTRY_PASS"
echo ""
echo "测试Registry连接:"
echo "docker login $REGISTRY_URL -u $REGISTRY_USER -p $REGISTRY_PASS"
@@ -1,28 +0,0 @@
#!/bin/bash
# Jenkins凭据配置脚本
echo "=== Jenkins凭据配置指南 ==="
echo ""
echo "请在Jenkins管理界面中配置以下凭据:"
echo ""
echo "1. Gitea访问Token"
echo " - 类型: Secret text"
echo " - ID: gitea-token"
echo " - 描述: Gitea API Token"
echo " - Secret: (在Gitea用户设置->应用中生成)"
echo ""
echo "2. Docker Registry认证"
echo " - 类型: Username with password"
echo " - ID: registry-auth"
echo " - 描述: Docker Registry Auth"
echo " - Username: admin"
echo " - Password: (Registry管理员密码)"
echo ""
echo "3. SSH密钥"
echo " - 类型: SSH Username with private key"
echo " - ID: ssh-key"
echo " - 描述: Git SSH Key"
echo " - Username: git"
echo " - Private Key: (SSH私钥内容)"
echo ""
echo "配置路径: Jenkins -> 管理Jenkins -> 凭据 -> System -> 全局凭据"
-33
View File
@@ -1,33 +0,0 @@
FROM jenkins/jenkins:lts-jdk21
# 切换到root用户安装插件和配置
USER root
# 安装系统依赖
RUN apt-get update && apt-get install -y \
curl \
wget \
git \
&& rm -rf /var/lib/apt/lists/*
# 切换回jenkins用户
USER jenkins
# 跳过初始设置向导
ENV JAVA_OPTS="-Djenkins.install.runSetupWizard=false"
# 复制插件列表
COPY plugins.txt /usr/share/jenkins/ref/plugins.txt
# 安装插件
RUN jenkins-plugin-cli --plugin-file /usr/share/jenkins/ref/plugins.txt
# 复制初始化脚本
COPY init.groovy /usr/share/jenkins/ref/init.groovy.d/init.groovy
# 设置环境变量
ENV JENKINS_USER=admin
ENV JENKINS_PASS=admin123
# 暴露端口
EXPOSE 8080 50000
@@ -1,50 +0,0 @@
FROM jenkins/jenkins:lts-jdk21
# 切换到root用户安装系统依赖
USER root
# 安装基础工具
RUN apt-get update && apt-get install -y \
curl \
wget \
git \
unzip \
python3 \
python3-pip \
python3-venv \
build-essential \
&& rm -rf /var/lib/apt/lists/*
# 切换回jenkins用户
USER jenkins
# 跳过初始设置向导
ENV JAVA_OPTS="-Djenkins.install.runSetupWizard=false -Djenkins.install.InstallUtil.lastExecVersion=2.504.3"
# 设置环境变量
ENV JENKINS_USER=admin
ENV JENKINS_PASS=admin123
ENV JENKINS_ADMIN_ID=admin
ENV JENKINS_ADMIN_PASSWORD=admin123
# 复制基础插件列表
COPY plugins-basic.txt /usr/share/jenkins/ref/plugins.txt
# 安装插件(忽略失败的插件)
RUN jenkins-plugin-cli --plugin-file /usr/share/jenkins/ref/plugins.txt || true
# 复制完整初始化脚本
COPY complete-init.groovy /usr/share/jenkins/ref/init.groovy.d/complete-init.groovy
# 创建必要的目录
RUN mkdir -p /var/jenkins_home/.m2 \
&& mkdir -p /var/jenkins_home/.gradle \
&& mkdir -p /var/jenkins_home/.npm \
&& mkdir -p /var/jenkins_home/.cache
# 暴露端口
EXPOSE 8080 50000
# 设置健康检查
HEALTHCHECK --interval=30s --timeout=10s --start-period=5m --retries=3 \
CMD curl -f http://localhost:8080/login || exit 1
@@ -1,97 +0,0 @@
FROM jenkins/jenkins:lts-jdk21
# 切换到root用户安装系统依赖
USER root
# 更新包列表并安装基础工具
RUN apt-get update && apt-get install -y \
curl \
wget \
git \
unzip \
python3 \
python3-pip \
python3-venv \
ca-certificates \
gnupg \
lsb-release \
&& rm -rf /var/lib/apt/lists/*
# 安装Docker
RUN install -m 0755 -d /etc/apt/keyrings \
&& curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg \
&& chmod a+r /etc/apt/keyrings/docker.gpg \
&& echo "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null \
&& apt-get update \
&& apt-get install -y docker-ce-cli \
&& rm -rf /var/lib/apt/lists/*
# 安装Docker Compose
RUN curl -L "https://github.com/docker/compose/releases/download/v2.20.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose \
&& chmod +x /usr/local/bin/docker-compose
# 安装Node.js
RUN curl -fsSL https://deb.nodesource.com/setup_18.x | bash - \
&& apt-get install -y nodejs \
&& npm install -g yarn pnpm \
&& rm -rf /var/lib/apt/lists/*
# 安装Maven
RUN curl -fsSL https://archive.apache.org/dist/maven/maven-3/3.9.6/binaries/apache-maven-3.9.6-bin.tar.gz | tar xzf - -C /opt \
&& ln -s /opt/apache-maven-3.9.6 /opt/maven \
&& ln -s /opt/maven/bin/mvn /usr/local/bin/mvn
# 安装Gradle
RUN curl -fsSL https://services.gradle.org/distributions/gradle-8.5-bin.zip -o gradle.zip \
&& unzip gradle.zip -d /opt \
&& ln -s /opt/gradle-8.5 /opt/gradle \
&& ln -s /opt/gradle/bin/gradle /usr/local/bin/gradle \
&& rm gradle.zip
# 安装kubectl
RUN curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | gpg --dearmor -o /etc/apt/keyrings/kubernetes-archive-keyring.gpg \
&& echo "deb [signed-by=/etc/apt/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | tee /etc/apt/sources.list.d/kubernetes.list \
&& apt-get update \
&& apt-get install -y kubectl \
&& rm -rf /var/lib/apt/lists/*
# 安装Python工具
RUN pip3 install --upgrade pip \
&& pip3 install virtualenv pipenv poetry
# 切换回jenkins用户
USER jenkins
# 跳过初始设置向导
ENV JAVA_OPTS="-Djenkins.install.runSetupWizard=false -Djenkins.install.InstallUtil.lastExecVersion=2.504.3"
# 设置环境变量
ENV JENKINS_USER=admin
ENV JENKINS_PASS=admin123
ENV JENKINS_ADMIN_ID=admin
ENV JENKINS_ADMIN_PASSWORD=admin123
ENV MAVEN_HOME=/opt/maven
ENV GRADLE_HOME=/opt/gradle
ENV PATH=$PATH:$MAVEN_HOME/bin:$GRADLE_HOME/bin
# 复制完整插件列表
COPY plugins-complete.txt /usr/share/jenkins/ref/plugins.txt
# 安装所有插件
RUN jenkins-plugin-cli --plugin-file /usr/share/jenkins/ref/plugins.txt
# 复制完整初始化脚本
COPY complete-init.groovy /usr/share/jenkins/ref/init.groovy.d/complete-init.groovy
# 创建必要的目录
RUN mkdir -p /var/jenkins_home/.m2 \
&& mkdir -p /var/jenkins_home/.gradle \
&& mkdir -p /var/jenkins_home/.npm \
&& mkdir -p /var/jenkins_home/.cache
# 暴露端口
EXPOSE 8080 50000
# 设置健康检查
HEALTHCHECK --interval=30s --timeout=10s --start-period=5m --retries=3 \
CMD curl -f http://localhost:8080/login || exit 1
@@ -1,50 +0,0 @@
FROM jenkins/jenkins:lts-jdk21
# 切换到root用户安装系统依赖
USER root
# 安装基础工具
RUN apt-get update && apt-get install -y \
curl \
wget \
git \
unzip \
python3 \
python3-pip \
python3-venv \
build-essential \
&& rm -rf /var/lib/apt/lists/*
# 切换回jenkins用户
USER jenkins
# 跳过初始设置向导
ENV JAVA_OPTS="-Djenkins.install.runSetupWizard=false -Djenkins.install.InstallUtil.lastExecVersion=2.504.3"
# 设置环境变量
ENV JENKINS_USER=admin
ENV JENKINS_PASS=admin123
ENV JENKINS_ADMIN_ID=admin
ENV JENKINS_ADMIN_PASSWORD=admin123
# 复制完整插件列表
COPY plugins-complete.txt /usr/share/jenkins/ref/plugins.txt
# 安装所有插件
RUN jenkins-plugin-cli --plugin-file /usr/share/jenkins/ref/plugins.txt
# 复制完整初始化脚本
COPY complete-init.groovy /usr/share/jenkins/ref/init.groovy.d/complete-init.groovy
# 创建必要的目录
RUN mkdir -p /var/jenkins_home/.m2 \
&& mkdir -p /var/jenkins_home/.gradle \
&& mkdir -p /var/jenkins_home/.npm \
&& mkdir -p /var/jenkins_home/.cache
# 暴露端口
EXPOSE 8080 50000
# 设置健康检查
HEALTHCHECK --interval=30s --timeout=10s --start-period=5m --retries=3 \
CMD curl -f http://localhost:8080/login || exit 1
@@ -1,672 +0,0 @@
#!/usr/bin/env groovy
// Jenkins完整自动化配置脚本 - 包含agents、cloud、tools、credentials等
import jenkins.model.*
import hudson.security.*
import hudson.tools.*
import hudson.util.Secret
import jenkins.security.s2m.AdminWhitelistRule
import hudson.security.csrf.DefaultCrumbIssuer
import hudson.plugins.git.*
import hudson.tasks.*
import hudson.slaves.*
import com.cloudbees.plugins.credentials.*
import com.cloudbees.plugins.credentials.domains.*
import com.cloudbees.plugins.credentials.impl.*
import org.jenkinsci.plugins.plaincredentials.impl.StringCredentialsImpl
import com.cloudbees.jenkins.plugins.sshcredentials.impl.BasicSSHUserPrivateKey
import hudson.plugins.nodejs.*
import hudson.plugins.nodejs.tools.*
import hudson.plugins.gradle.*
import org.jenkinsci.plugins.docker.commons.credentials.DockerServerCredentials
import com.nirima.jenkins.plugins.docker.*
import com.nirima.jenkins.plugins.docker.launcher.*
import jenkins.install.InstallState
def instance = Jenkins.getInstance()
println "🚀 开始Jenkins完整自动化配置..."
// 1. 跳过设置向导和基础安全配置
instance.setInstallState(InstallState.INITIAL_SETUP_COMPLETED)
def hudsonRealm = new HudsonPrivateSecurityRealm(false)
def adminUsername = System.getenv('JENKINS_ADMIN_ID') ?: 'admin'
def adminPassword = System.getenv('JENKINS_ADMIN_PASSWORD') ?: 'admin123'
// 创建管理员用户
if (!hudsonRealm.getAllUsers().find { it.getId() == adminUsername }) {
hudsonRealm.createAccount(adminUsername, adminPassword)
instance.setSecurityRealm(hudsonRealm)
println "✅ 创建管理员用户: ${adminUsername}"
}
// 设置授权策略
def strategy = new FullControlOnceLoggedInAuthorizationStrategy()
strategy.setAllowAnonymousRead(false)
instance.setAuthorizationStrategy(strategy)
// 启用CSRF保护
instance.setCrumbIssuer(new DefaultCrumbIssuer(true))
println "✅ 安全配置完成"
// 2. 配置凭据管理
def store = SystemCredentialsProvider.getInstance().getStore()
def domain = Domain.global()
println "🔐 配置凭据管理..."
// Gitea API Token
def giteaToken = new StringCredentialsImpl(
CredentialsScope.GLOBAL,
"gitea-api-token",
"Gitea API访问令牌",
Secret.fromString("your-gitea-token-here")
)
// Docker Registry认证
def registryAuth = new UsernamePasswordCredentialsImpl(
CredentialsScope.GLOBAL,
"docker-registry-auth",
"Docker Registry认证",
"admin",
"admin123"
)
// Git SSH密钥
def gitSshKey = new BasicSSHUserPrivateKey(
CredentialsScope.GLOBAL,
"git-ssh-key",
"git",
new BasicSSHUserPrivateKey.DirectEntryPrivateKeySource("""-----BEGIN OPENSSH PRIVATE KEY-----
# SSH密钥内容,实际使用时需要替换
your-ssh-private-key-here
-----END OPENSSH PRIVATE KEY-----"""),
"",
"Git SSH密钥"
)
// Kubernetes配置
def k8sConfig = new StringCredentialsImpl(
CredentialsScope.GLOBAL,
"k8s-config",
"Kubernetes配置文件",
Secret.fromString("""apiVersion: v1
kind: Config
clusters:
- cluster:
server: https://your-k8s-cluster
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: jenkins
name: jenkins
current-context: jenkins
users:
- name: jenkins
user:
token: your-k8s-token""")
)
store.addCredentials(domain, giteaToken)
store.addCredentials(domain, registryAuth)
store.addCredentials(domain, gitSshKey)
store.addCredentials(domain, k8sConfig)
println "✅ 凭据配置完成"
// 3. 配置构建工具
println "🔧 配置构建工具..."
// 配置Git
def gitTool = instance.getDescriptorByType(GitTool.DescriptorImpl.class)
gitTool.setInstallations(new GitTool("Default", "/usr/bin/git", []))
// 配置JDK
def jdkTool = instance.getDescriptorByType(JDK.DescriptorImpl.class)
def jdk8 = new JDK("JDK-8", "/opt/java/openjdk")
def jdk11 = new JDK("JDK-11", "/usr/lib/jvm/java-11-openjdk")
def jdk21 = new JDK("JDK-21", "/opt/java/openjdk")
jdkTool.setInstallations(jdk8, jdk11, jdk21)
// 配置Maven
def maven = instance.getDescriptorByType(Maven.DescriptorImpl.class)
def mavenInstaller = new Maven.MavenInstaller("3.9.6")
def mavenInstallation = new Maven.MavenInstallation("Maven-3.9", "", [
new InstallSourceProperty([mavenInstaller])
])
maven.setInstallations(mavenInstallation)
// 配置Gradle
def gradle = instance.getDescriptorByType(Gradle.DescriptorImpl.class)
def gradleInstaller = new GradleInstaller("8.5")
def gradleInstallation = new GradleInstallation("Gradle-8", "", [
new InstallSourceProperty([gradleInstaller])
])
gradle.setInstallations(gradleInstallation)
// 配置NodeJS
def nodejs = instance.getDescriptorByType(NodeJSInstallation.DescriptorImpl.class)
def nodeInstaller = new NodeJSInstaller("18.19.0", "npm install -g yarn pnpm@latest", 72)
def nodeInstallation = new NodeJSInstallation("NodeJS-18", "", [
new InstallSourceProperty([nodeInstaller])
])
nodejs.setInstallations(nodeInstallation)
// 配置Python
// Python通常使用系统安装或Docker容器,这里配置Docker容器方式
println "✅ 构建工具配置完成"
// 4. 配置Docker Cloud
println "☁️ 配置Docker Cloud..."
try {
def dockerConnector = new DockerComputerSSHConnector(new DockerComputerSSHConnector.SSHKeyStrategyBuiltIn())
// Java构建容器模板
def javaTemplate = new DockerTemplate(
"maven:3.9.6-openjdk-21", // Docker镜像
"docker-java-agent", // 标签
"/home/jenkins", // 远程文件系统根目录
"22", // SSH端口
InstanceCap.UNLIMITED, // 实例上限
"5", // 空闲终止时间(分钟)
dockerConnector, // 连接器
"java maven docker", // 标签字符串
"jenkins", // 用户
"-v /var/run/docker.sock:/var/run/docker.sock" // Docker in Docker
)
// Vue3/Node.js构建容器模板
def nodeTemplate = new DockerTemplate(
"node:18-alpine",
"docker-node-agent",
"/home/jenkins",
"22",
InstanceCap.UNLIMITED,
"5",
dockerConnector,
"nodejs vue docker",
"jenkins",
"-v /var/run/docker.sock:/var/run/docker.sock"
)
// Python构建容器模板
def pythonTemplate = new DockerTemplate(
"python:3.11-slim",
"docker-python-agent",
"/home/jenkins",
"22",
InstanceCap.UNLIMITED,
"5",
dockerConnector,
"python docker",
"jenkins",
"-v /var/run/docker.sock:/var/run/docker.sock"
)
// 创建Docker Cloud
def dockerCloud = new DockerCloud(
"docker-cloud", // 名称
[javaTemplate, nodeTemplate, pythonTemplate], // 模板列表
"unix:///var/run/docker.sock", // Docker Host URI
100, // 容器上限
5, // 连接超时
5, // 读取超时
null, // 凭据ID
"", // Docker版本
"" // Docker API版本
)
instance.clouds.add(dockerCloud)
println "✅ Docker Cloud配置完成"
} catch (Exception e) {
println "⚠️ Docker Cloud配置跳过: ${e.message}"
}
// 5. 系统配置
instance.setNumExecutors(2)
instance.setSystemMessage("""
🎉 Jenkins CI/CD服务器 - 完全自动化配置
📦 插件: 自动安装130+核心插件
🔧 工具: Java, Maven, Gradle, NodeJS, Python
☁️ Cloud: Docker动态Agent支持
🔐 凭据: Gitea, Registry, SSH, K8s已配置
📋 支持: Java, Vue3, Python多语言CI/CD
🌐 访问地址: http://localhost:8081
👤 登录账号: ${adminUsername} / ${adminPassword}
🚀 CI/CD流程:
Gitea Webhook → Jenkins → Build → Registry → K8s Deploy
""")
// 设置Jenkins URL
def location = instance.getDescriptor("jenkins.model.JenkinsLocationConfiguration")
location.setUrl("http://localhost:8081/")
location.setAdminAddress("admin@example.com")
location.save()
// 6. 创建多语言Pipeline作业模板
println "📋 创建Pipeline作业模板..."
// Java Spring Boot项目Pipeline
def javaJobXml = '''<flow-definition plugin="workflow-job">
<description>Java Spring Boot CI/CD Pipeline</description>
<definition class="org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition">
<script>
pipeline {
agent { label 'java' }
environment {
REGISTRY = 'localhost:5001'
IMAGE_NAME = 'ljwx-java-app'
MAVEN_OPTS = '-Dmaven.repo.local=/var/jenkins_home/.m2/repository'
}
stages {
stage('📥 Checkout') {
steps {
git credentialsId: 'git-ssh-key', url: '${GIT_URL}'
}
}
stage('🔍 Test') {
steps {
sh 'mvn test'
}
post {
always {
publishTestResults testResultsPattern: 'target/surefire-reports/*.xml'
}
}
}
stage('📦 Build') {
steps {
sh 'mvn clean package -DskipTests'
}
}
stage('🐳 Docker Build') {
steps {
script {
def imageTag = "${env.BUILD_NUMBER}"
sh """
docker build -t ${REGISTRY}/${IMAGE_NAME}:${imageTag} .
docker build -t ${REGISTRY}/${IMAGE_NAME}:latest .
"""
}
}
}
stage('📤 Push to Registry') {
steps {
withCredentials([usernamePassword(credentialsId: 'docker-registry-auth', usernameVariable: 'REGISTRY_USER', passwordVariable: 'REGISTRY_PASS')]) {
script {
def imageTag = "${env.BUILD_NUMBER}"
sh """
echo ${REGISTRY_PASS} | docker login ${REGISTRY} -u ${REGISTRY_USER} --password-stdin
docker push ${REGISTRY}/${IMAGE_NAME}:${imageTag}
docker push ${REGISTRY}/${IMAGE_NAME}:latest
"""
}
}
}
}
stage('🚀 Deploy to K8s') {
steps {
withCredentials([string(credentialsId: 'k8s-config', variable: 'KUBECONFIG_CONTENT')]) {
script {
def imageTag = "${env.BUILD_NUMBER}"
sh """
echo '${KUBECONFIG_CONTENT}' > kubeconfig
export KUBECONFIG=./kubeconfig
# 更新部署
kubectl set image deployment/java-app java-app=${REGISTRY}/${IMAGE_NAME}:${imageTag} --record
kubectl rollout status deployment/java-app
"""
}
}
}
}
}
post {
always {
cleanWs()
}
success {
echo '🎉 Java应用部署成功!'
}
}
}
</script>
</definition>
<triggers>
<org.jenkinsci.plugins.gwt.GenericTrigger plugin="generic-webhook-trigger">
<genericVariables>
<org.jenkinsci.plugins.gwt.GenericVariable>
<expressionType>JSONPath</expressionType>
<key>GIT_URL</key>
<value>$.repository.clone_url</value>
</org.jenkinsci.plugins.gwt.GenericVariable>
</genericVariables>
<regexpFilterText></regexpFilterText>
<regexpFilterExpression></regexpFilterExpression>
<printContributedVariables>false</printContributedVariables>
<printPostContent>false</printPostContent>
<causeString>Gitea Webhook</causeString>
<token>java-webhook-token</token>
</org.jenkinsci.plugins.gwt.GenericTrigger>
</triggers>
</flow-definition>'''
// Vue3项目Pipeline
def vue3JobXml = '''<flow-definition plugin="workflow-job">
<description>Vue3 Frontend CI/CD Pipeline</description>
<definition class="org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition">
<script>
pipeline {
agent { label 'nodejs' }
environment {
REGISTRY = 'localhost:5001'
IMAGE_NAME = 'ljwx-vue3-app'
NODE_OPTIONS = '--max-old-space-size=4096'
}
stages {
stage('📥 Checkout') {
steps {
git credentialsId: 'git-ssh-key', url: '${GIT_URL}'
}
}
stage('📦 Install Dependencies') {
steps {
sh '''
npm config set registry https://registry.npmmirror.com
npm install
'''
}
}
stage('🔍 Lint & Test') {
steps {
sh '''
npm run lint
npm run test:unit
'''
}
}
stage('🏗️ Build') {
steps {
sh 'npm run build'
}
}
stage('🐳 Docker Build') {
steps {
script {
def imageTag = "${env.BUILD_NUMBER}"
sh """
cat > Dockerfile << 'EOF'
FROM nginx:alpine
COPY dist/ /usr/share/nginx/html/
COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
EOF
cat > nginx.conf << 'EOF'
events { worker_connections 1024; }
http {
include /etc/nginx/mime.types;
sendfile on;
server {
listen 80;
location / {
root /usr/share/nginx/html;
index index.html;
try_files \$uri \$uri/ /index.html;
}
}
}
EOF
docker build -t ${REGISTRY}/${IMAGE_NAME}:${imageTag} .
docker build -t ${REGISTRY}/${IMAGE_NAME}:latest .
"""
}
}
}
stage('📤 Push to Registry') {
steps {
withCredentials([usernamePassword(credentialsId: 'docker-registry-auth', usernameVariable: 'REGISTRY_USER', passwordVariable: 'REGISTRY_PASS')]) {
script {
def imageTag = "${env.BUILD_NUMBER}"
sh """
echo ${REGISTRY_PASS} | docker login ${REGISTRY} -u ${REGISTRY_USER} --password-stdin
docker push ${REGISTRY}/${IMAGE_NAME}:${imageTag}
docker push ${REGISTRY}/${IMAGE_NAME}:latest
"""
}
}
}
}
stage('🚀 Deploy to K8s') {
steps {
withCredentials([string(credentialsId: 'k8s-config', variable: 'KUBECONFIG_CONTENT')]) {
script {
def imageTag = "${env.BUILD_NUMBER}"
sh """
echo '${KUBECONFIG_CONTENT}' > kubeconfig
export KUBECONFIG=./kubeconfig
kubectl set image deployment/vue3-app vue3-app=${REGISTRY}/${IMAGE_NAME}:${imageTag} --record
kubectl rollout status deployment/vue3-app
"""
}
}
}
}
}
post {
always {
cleanWs()
}
success {
echo '🎉 Vue3应用部署成功!'
}
}
}
</script>
</definition>
<triggers>
<org.jenkinsci.plugins.gwt.GenericTrigger plugin="generic-webhook-trigger">
<genericVariables>
<org.jenkinsci.plugins.gwt.GenericVariable>
<expressionType>JSONPath</expressionType>
<key>GIT_URL</key>
<value>$.repository.clone_url</value>
</org.jenkinsci.plugins.gwt.GenericVariable>
</genericVariables>
<token>vue3-webhook-token</token>
</org.jenkinsci.plugins.gwt.GenericTrigger>
</triggers>
</flow-definition>'''
// Python项目Pipeline
def pythonJobXml = '''<flow-definition plugin="workflow-job">
<description>Python FastAPI CI/CD Pipeline</description>
<definition class="org.jenkinsci.plugins.workflow.cps.CpsFlowDefinition">
<script>
pipeline {
agent { label 'python' }
environment {
REGISTRY = 'localhost:5001'
IMAGE_NAME = 'ljwx-python-app'
PYTHONPATH = '.'
}
stages {
stage('📥 Checkout') {
steps {
git credentialsId: 'git-ssh-key', url: '${GIT_URL}'
}
}
stage('📦 Install Dependencies') {
steps {
sh '''
pip install -r requirements.txt
pip install pytest pytest-cov flake8
'''
}
}
stage('🔍 Lint & Test') {
steps {
sh '''
flake8 . --max-line-length=88 --exclude=venv,__pycache__
pytest --cov=. --cov-report=xml
'''
}
post {
always {
publishTestResults testResultsPattern: 'pytest.xml'
publishCoverage adapters: [coberturaAdapter('coverage.xml')], sourceFileResolver: sourceFiles('STORE_LAST_BUILD')
}
}
}
stage('🐳 Docker Build') {
steps {
script {
def imageTag = "${env.BUILD_NUMBER}"
sh """
cat > Dockerfile << 'EOF'
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
EOF
docker build -t ${REGISTRY}/${IMAGE_NAME}:${imageTag} .
docker build -t ${REGISTRY}/${IMAGE_NAME}:latest .
"""
}
}
}
stage('📤 Push to Registry') {
steps {
withCredentials([usernamePassword(credentialsId: 'docker-registry-auth', usernameVariable: 'REGISTRY_USER', passwordVariable: 'REGISTRY_PASS')]) {
script {
def imageTag = "${env.BUILD_NUMBER}"
sh """
echo ${REGISTRY_PASS} | docker login ${REGISTRY} -u ${REGISTRY_USER} --password-stdin
docker push ${REGISTRY}/${IMAGE_NAME}:${imageTag}
docker push ${REGISTRY}/${IMAGE_NAME}:latest
"""
}
}
}
}
stage('🚀 Deploy to K8s') {
steps {
withCredentials([string(credentialsId: 'k8s-config', variable: 'KUBECONFIG_CONTENT')]) {
script {
def imageTag = "${env.BUILD_NUMBER}"
sh """
echo '${KUBECONFIG_CONTENT}' > kubeconfig
export KUBECONFIG=./kubeconfig
kubectl set image deployment/python-app python-app=${REGISTRY}/${IMAGE_NAME}:${imageTag} --record
kubectl rollout status deployment/python-app
"""
}
}
}
}
}
post {
always {
cleanWs()
}
success {
echo '🎉 Python应用部署成功!'
}
}
}
</script>
</definition>
<triggers>
<org.jenkinsci.plugins.gwt.GenericTrigger plugin="generic-webhook-trigger">
<genericVariables>
<org.jenkinsci.plugins.gwt.GenericVariable>
<expressionType>JSONPath</expressionType>
<key>GIT_URL</key>
<value>$.repository.clone_url</value>
</org.jenkinsci.plugins.gwt.GenericVariable>
</genericVariables>
<token>python-webhook-token</token>
</org.jenkinsci.plugins.gwt.GenericTrigger>
</triggers>
</flow-definition>'''
// 创建作业
try {
instance.createProjectFromXML("java-spring-boot-pipeline", new ByteArrayInputStream(javaJobXml.getBytes()))
instance.createProjectFromXML("vue3-frontend-pipeline", new ByteArrayInputStream(vue3JobXml.getBytes()))
instance.createProjectFromXML("python-fastapi-pipeline", new ByteArrayInputStream(pythonJobXml.getBytes()))
println "✅ Pipeline作业模板创建完成"
} catch (Exception e) {
println "⚠️ 作业创建部分失败: ${e.message}"
}
// 7. 保存配置
instance.save()
println """
🎉 Jenkins完整自动化配置完成!
📋 配置摘要:
- ✅ 管理员用户: ${adminUsername}
- ✅ 安全策略: 已配置
- ✅ 构建工具: Java, Maven, Gradle, NodeJS, Python
- ✅ Docker Cloud: 动态Agent支持
- ✅ 凭据管理: Gitea, Registry, SSH, K8s
- ✅ Pipeline模板: Java, Vue3, Python
🌐 访问地址: http://localhost:8081
👤 登录信息: ${adminUsername} / ${adminPassword}
🚀 Webhook URLs:
- Java: http://localhost:8081/generic-webhook-trigger/invoke?token=java-webhook-token
- Vue3: http://localhost:8081/generic-webhook-trigger/invoke?token=vue3-webhook-token
- Python: http://localhost:8081/generic-webhook-trigger/invoke?token=python-webhook-token
📚 下一步:
1. 更新凭据中的实际Token和密钥
2. 在Gitea中配置Webhook URL
3. 测试CI/CD流程
4. 根据需要调整Pipeline
"""
-85
View File
@@ -1,85 +0,0 @@
#!/usr/bin/env groovy
// Jenkins简化自动化配置脚本
import jenkins.model.*
import hudson.security.*
import hudson.util.Secret
import jenkins.security.s2m.AdminWhitelistRule
import hudson.security.csrf.DefaultCrumbIssuer
def instance = Jenkins.getInstance()
println "🚀 开始Jenkins自动化配置..."
// 1. 基础安全配置
def hudsonRealm = new HudsonPrivateSecurityRealm(false)
def adminUsername = System.getenv('JENKINS_ADMIN_ID') ?: 'admin'
def adminPassword = System.getenv('JENKINS_ADMIN_PASSWORD') ?: 'admin123'
// 创建管理员用户
if (!hudsonRealm.getAllUsers().find { it.getId() == adminUsername }) {
hudsonRealm.createAccount(adminUsername, adminPassword)
instance.setSecurityRealm(hudsonRealm)
println "✅ 创建管理员用户: ${adminUsername}"
}
// 设置授权策略
def strategy = new FullControlOnceLoggedInAuthorizationStrategy()
strategy.setAllowAnonymousRead(false)
instance.setAuthorizationStrategy(strategy)
// 启用CSRF保护
instance.setCrumbIssuer(new DefaultCrumbIssuer(true))
// 设置代理安全
instance.getInjector().getInstance(AdminWhitelistRule.class).setMasterKillSwitch(false)
println "✅ 安全配置完成"
// 2. 系统配置
instance.setNumExecutors(4)
instance.setSystemMessage("""
🎉 Jenkins CI/CD服务器 - 完全自动化配置
📦 插件: 自动安装30+核心插件
🔧 工具: Maven, Gradle, NodeJS, Docker自动配置
🔐 凭据: Gitea, Registry认证模板
📋 作业: 多平台构建演示
📚 文档: docs/jenkins-persistence-guide.md
🌐 访问地址: http://localhost:8081
👤 登录账号: ${adminUsername} / ${adminPassword}
""")
// 设置Jenkins URL
def location = instance.getDescriptor("jenkins.model.JenkinsLocationConfiguration")
location.setUrl("http://localhost:8081/")
location.setAdminAddress("admin@example.com")
location.save()
println "✅ 系统配置完成"
// 3. 保存配置
instance.save()
// 4. 跳过设置向导
def setupWizard = instance.getSetupWizard()
if (setupWizard != null) {
setupWizard.completeSetup()
println "✅ 跳过设置向导"
}
println """
🎉 Jenkins基础自动化配置完成!
📋 配置摘要:
- ✅ 管理员用户: ${adminUsername}
- ✅ 安全策略: 已配置
- ✅ 系统消息: 已设置
- ✅ 设置向导: 已跳过
🌐 访问地址: http://localhost:8081
👤 登录信息: ${adminUsername} / ${adminPassword}
📚 下一步: 访问Web界面完成剩余配置
"""
@@ -1,67 +0,0 @@
# 基础核心插件
ant
build-timeout
credentials-binding
timestamper
ws-cleanup
workflow-aggregator
pipeline-stage-view
git
ssh-slaves
matrix-auth
pam-auth
ldap
email-ext
mailer
# Docker支持
docker-plugin
docker-workflow
docker-commons
docker-build-step
# 代码管理
git-parameter
generic-webhook-trigger
workflow-scm-step
# 构建工具
maven-plugin
gradle
nodejs
# 测试和质量
junit
warnings-ng
# 部署和云
kubernetes
ssh-agent
# UI和可视化
blueocean
pipeline-graph-analysis
pipeline-rest-api
# 安全
role-strategy
authorize-project
# 系统管理
configuration-as-code
job-dsl
script-security
# 多分支
workflow-multibranch
# 参数化构建
parameterized-trigger
# 国际化
localization-support
localization-zh-cn
# 主题
dark-theme
theme-manager
@@ -1,135 +0,0 @@
# Jenkins完整插件列表 - 支持多语言CI/CD
# 核心插件
ant:475.vf34069fef73c
build-timeout:1.34
credentials-binding:681.vf91669a_32e45
timestamper:1.27
ws-cleanup:0.47
gradle:2.14
workflow-aggregator:625.vee5bb58a_5d5b
github-organization-folders:1.6
pipeline-github-lib:45.v0b_560dd72c8c
pipeline-stage-view:2.34
git:5.6.0
ssh-slaves:2.973.v0ce9c1c45c87
matrix-auth:3.2.2
pam-auth:1.12
ldap:750.v72277508b_1de
email-ext:817.v960e1ca_d31ad
mailer:472.vf7c289a_4b_420
# Docker支持
docker-plugin:1.6.2
docker-workflow:580.vc0c340686b_54
docker-commons:439.va_3cb_0a_6a_fb_29
docker-build-step:2.11
# 代码管理
git-parameter:0.9.19
gitea:1.4.8
generic-webhook-trigger:2.2.2
workflow-scm-step:427.v4ca_6512e7df1
# 构建工具
maven-plugin:3.23
gradle:2.14
nodejs:1.6.1
ant:475.vf34069fef73c
# 测试和质量
junit:1304.vd94b_8e39b_250
test-results-analyzer:0.4.0
warnings-ng:12.6.0
coverage:1.11.1
cobertura:1.18
jacoco:3.3.6
# 部署和云
kubernetes:4316.v7b_80b_132c_505
kubernetes-cli:1.12.1
kubernetes-cd:2.4.1
ssh-agent:371.v006c8c451a_7b_
publish-over-ssh:1.26
# UI和可视化
blueocean:1.27.14
pipeline-graph-analysis:216.vfd8b_ece330ca_
pipeline-rest-api:2.34
handlebars:3.0.8
momentjs:1.1.1
jquery-detached:1.2.1
ace-editor:1.1
# 通知
slack:746.v55b_61c845e9f
teams-notification:1.1.0
email-ext:817.v960e1ca_d31ad
# 安全
role-strategy:727.vd344b_eec783d
matrix-auth:3.2.2
authorize-project:1.8.0
# 系统管理
configuration-as-code:1810.v9b_c30a_249a_4c
job-dsl:1.87
script-security:1362.v47c6302f4f9d
command-launcher:115.vd8b_301cc15d0
jdk-tool:73.vddf737284550
# 监控和日志
monitoring:1.98.0
metrics:4.2.21
build-metrics:1.3
log-parser:2.25
# 工具集成
sonar:2.17.2
checkstyle:5.0.0
pmd:5.0.0
findbugs:5.0.0
# 多分支和组织
workflow-multibranch:795.ve0cb_1f45ca_9a_
github-branch-source:1797.v86fdb_4d57d43
gitea-multibranch:1.0.8
# 参数化构建
build-user-vars-plugin:1.9
build-name-setter:2.4.2
parameterized-trigger:2.47
rebuild:330.v645b_7df10e2a_
# 文件操作
copyartifact:722.v0662a_9b_e22a_c
artifact-deployer:1.2
publish-over-ftp:1.16
workspace-cleanup:0.47
# 报告
htmlpublisher:1.36
xunit:3.1.2
performance:3.21
plot:2.1.12
# 国际化
localization-support:1.1
localization-zh-cn:1.0.33
# 主题
dark-theme:481.vb_5fd46b_b_f2f5
theme-manager:263.v0bb_feaf_7e52c
# 实用工具
build-blocker-plugin:1.7.8
conditional-buildstep:1.4.3
envinject:2.906.v77016b_9d7a_c2
flexible-publish:0.16.1
zentimestamp:4.2
# Pipeline扩展
pipeline-input-step:495.ve9c153f6067b_
pipeline-milestone-step:111.v449306f708b_7
pipeline-build-step:516.vd9b_ccd1d2ef7
pipeline-stage-step:312.v8cd10304c27a_
-43
View File
@@ -1,43 +0,0 @@
# Jenkins核心自动配置插件列表
configuration-as-code:latest
# Pipeline和CI/CD核心
workflow-aggregator:latest
pipeline-stage-view:latest
pipeline-utility-steps:latest
build-timeout:latest
timestamper:latest
ws-cleanup:latest
# SCM
git:latest
gitea:latest
ssh-credentials:latest
credentials-binding:latest
# Docker
docker-plugin:latest
docker-workflow:latest
docker-commons:latest
# 构建工具
maven-plugin:latest
gradle:latest
nodejs:latest
# UI
blueocean:latest
dashboard-view:latest
# 系统
ansicolor:latest
antisamy-markup-formatter:latest
job-dsl:latest
# 通知
email-ext:latest
generic-webhook-trigger:latest
# 质量
warnings-ng:latest
junit:latest
@@ -1,45 +0,0 @@
package org.example
class Utils {
static def getGitCommitInfo(script) {
def commit = script.sh(
script: 'git rev-parse HEAD',
returnStdout: true
).trim()
def shortCommit = script.sh(
script: 'git rev-parse --short HEAD',
returnStdout: true
).trim()
def author = script.sh(
script: 'git log -1 --pretty=format:"%an"',
returnStdout: true
).trim()
def message = script.sh(
script: 'git log -1 --pretty=format:"%s"',
returnStdout: true
).trim()
return [
commit: commit,
shortCommit: shortCommit,
author: author,
message: message
]
}
static def generateImageTag(buildNumber, gitCommit) {
return "${buildNumber}-${gitCommit[0..7]}"
}
static def cleanupOldImages(script, registry, appName, keepCount = 5) {
script.sh """
images=\$(docker images ${registry}/${appName} --format "{{.Tag}}" | grep -E '^[0-9]+-[a-f0-9]{8}\$' | sort -nr | tail -n +${keepCount + 1})
for img in \$images; do
docker rmi ${registry}/${appName}:\$img || true
done
"""
}
}
@@ -1,19 +0,0 @@
def call(Map config) {
def registry = config.registry ?: 'localhost:5001'
def appName = config.appName ?: env.JOB_NAME.split('/')[0]
def imageTag = config.imageTag ?: "${env.BUILD_NUMBER}-${env.GIT_COMMIT[0..7]}"
def credentialsId = config.credentialsId ?: 'registry-auth'
echo "构建Docker镜像: ${registry}/${appName}:${imageTag}"
script {
def image = docker.build("${registry}/${appName}:${imageTag}")
docker.withRegistry("http://${registry}", credentialsId) {
image.push()
image.push("latest")
}
return image
}
}
@@ -1,56 +0,0 @@
#!/usr/bin/env groovy
def call(Map config) {
def imageName = config.imageName ?: error("imageName is required")
def platforms = config.platforms ?: "linux/amd64,linux/arm64"
def dockerfile = config.dockerfile ?: "Dockerfile"
def buildContext = config.buildContext ?: "."
def pushImage = config.pushImage ?: true
def registryCredentialsId = config.registryCredentialsId ?: ""
def buildArgs = config.buildArgs ?: [:]
echo "🔨 构建多平台镜像: ${imageName}"
echo "📋 平台: ${platforms}"
script {
// 构建参数
def buildArgsStr = ""
buildArgs.each { key, value ->
buildArgsStr += "--build-arg ${key}=${value} "
}
if (pushImage && registryCredentialsId) {
withCredentials([usernamePassword(credentialsId: registryCredentialsId,
usernameVariable: 'REGISTRY_USER',
passwordVariable: 'REGISTRY_PASS')]) {
// 登录到镜像仓库
sh """
echo "\${REGISTRY_PASS}" | docker login -u "\${REGISTRY_USER}" --password-stdin \$(echo "${imageName}" | cut -d'/' -f1)
"""
// 构建并推送
sh """
docker buildx build \\
--platform ${platforms} \\
--file ${dockerfile} \\
${buildArgsStr} \\
--tag ${imageName} \\
--push \\
${buildContext}
"""
}
} else {
// 仅构建,不推送
sh """
docker buildx build \\
--platform ${platforms} \\
--file ${dockerfile} \\
${buildArgsStr} \\
--tag ${imageName} \\
${buildContext}
"""
}
}
echo "✅ 多平台镜像构建完成: ${imageName}"
}
@@ -1,21 +0,0 @@
def call(Map config) {
def environment = config.environment ?: 'test'
def appName = config.appName ?: env.JOB_NAME.split('/')[0]
def imageTag = config.imageTag ?: "${env.BUILD_NUMBER}-${env.GIT_COMMIT[0..7]}"
def registry = config.registry ?: 'localhost:5001'
def port = config.port ?: 8080
echo "部署到${environment}环境..."
sh """
docker stop ${appName}-${environment} || true
docker rm ${appName}-${environment} || true
docker run -d --name ${appName}-${environment} -p ${port}:5000 ${registry}/${appName}:${imageTag}
"""
// 健康检查
sh """
sleep 10
curl -f http://localhost:${port}/health || echo "健康检查失败"
"""
}
@@ -1,98 +0,0 @@
#!/usr/bin/env groovy
// K8s部署共享库
def call(Map config) {
def namespace = config.namespace ?: 'default'
def appName = config.appName ?: env.JOB_NAME.toLowerCase()
def image = config.image
def manifests = config.manifests ?: 'k8s/'
def kubeconfig = config.kubeconfig ?: 'k8s-config'
def dryRun = config.dryRun ?: false
def waitForRollout = config.waitForRollout != false
def timeout = config.timeout ?: '300s'
if (!image) {
error "❌ 必须指定镜像地址"
}
echo "🚀 开始K8s部署"
echo "Namespace: ${namespace}"
echo "App: ${appName}"
echo "Image: ${image}"
echo "Manifests: ${manifests}"
withCredentials([string(credentialsId: kubeconfig, variable: 'KUBECONFIG_CONTENT')]) {
try {
// 创建kubeconfig文件
writeFile file: 'kubeconfig', text: env.KUBECONFIG_CONTENT
// 设置环境变量
env.KUBECONFIG = "${env.WORKSPACE}/kubeconfig"
// 检查集群连接
sh 'kubectl cluster-info'
// 创建命名空间(如果不存在)
sh """
kubectl create namespace ${namespace} --dry-run=client -o yaml | \
kubectl apply -f -
"""
// 更新镜像标签
if (fileExists(manifests)) {
sh """
find ${manifests} -name "*.yaml" -o -name "*.yml" | \
xargs sed -i '' 's|image:.*${appName}.*|image: ${image}|g'
"""
}
// 执行部署
def deployCmd = "kubectl apply -f ${manifests} -n ${namespace}"
if (dryRun) {
deployCmd += " --dry-run=client"
}
sh deployCmd
if (!dryRun && waitForRollout) {
// 等待部署完成
sh """
kubectl rollout status deployment/${appName} -n ${namespace} --timeout=${timeout} || \
kubectl rollout status statefulset/${appName} -n ${namespace} --timeout=${timeout} || \
echo "等待部署完成..."
"""
// 验证Pod状态
sh """
kubectl get pods -n ${namespace} -l app=${appName} -o wide
kubectl describe pods -n ${namespace} -l app=${appName} | grep -A 5 Events: || true
"""
}
echo "✅ K8s部署成功"
return [
namespace: namespace,
appName: appName,
image: image,
deployed: !dryRun
]
} catch (Exception e) {
echo "❌ K8s部署失败: ${e.message}"
// 显示调试信息
sh """
echo "=== Pod状态 ==="
kubectl get pods -n ${namespace} -l app=${appName} || true
echo "=== Events ==="
kubectl get events -n ${namespace} --sort-by='.lastTimestamp' | tail -10 || true
"""
throw e
} finally {
// 清理kubeconfig
sh 'rm -f kubeconfig'
}
}
}
@@ -1,33 +0,0 @@
def call(Map config = [:]) {
def testType = config.testType ?: 'unit'
def testPath = config.testPath ?: 'tests/'
def coverage = config.coverage ?: false
echo "运行${testType}测试..."
sh """
python -m venv venv || true
. venv/bin/activate
pip install -r requirements.txt
if [ "${coverage}" == "true" ]; then
pip install coverage
coverage run -m pytest ${testPath} -v
coverage report
coverage html
else
python -m pytest ${testPath} -v
fi
"""
if (coverage) {
publishHTML([
allowMissing: false,
alwaysLinkToLastBuild: true,
keepAll: true,
reportDir: 'htmlcov',
reportFiles: 'index.html',
reportName: 'Coverage Report'
])
}
}
@@ -1,49 +0,0 @@
#!/usr/bin/env groovy
def call(Map config) {
def status = config.status ?: currentBuild.result ?: 'SUCCESS'
def title = config.title ?: "${env.JOB_NAME} #${env.BUILD_NUMBER}"
def message = config.message ?: "构建状态: ${status}"
def channels = config.channels ?: ['slack', 'dingtalk', 'email']
def color = status == 'SUCCESS' ? 'good' : 'danger'
def emoji = status == 'SUCCESS' ? '✅' : '❌'
channels.each { channel ->
try {
switch(channel) {
case 'slack':
if (env.SLACK_TOKEN) {
slackSend(
color: color,
message: "${emoji} ${title}\n${message}\n构建详情: ${env.BUILD_URL}"
)
}
break
case 'dingtalk':
if (env.DINGTALK_WEBHOOK) {
dingtalk(
robot: env.DINGTALK_WEBHOOK,
type: 'MARKDOWN',
title: title,
text: "## ${emoji} ${title}\n\n${message}\n\n[查看详情](${env.BUILD_URL})"
)
}
break
case 'email':
emailext(
subject: "${emoji} ${title}",
body: "${message}\n\n构建详情: ${env.BUILD_URL}",
to: "${env.CHANGE_AUTHOR_EMAIL ?: 'admin@example.com'}"
)
break
}
echo "✅ 通知已发送到 ${channel}"
} catch (Exception e) {
echo "⚠️ 发送 ${channel} 通知失败: ${e.message}"
}
}
}
@@ -1,17 +0,0 @@
FROM openjdk:11-jre-slim
# 设置工作目录
WORKDIR /app
# 复制JAR文件
COPY target/*.jar app.jar
# 暴露端口
EXPOSE 8080
# 设置健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:8080/actuator/health || exit 1
# 运行应用
CMD ["java", "-jar", "app.jar"]
@@ -1,54 +0,0 @@
# Java21 ljwx-boot 多平台构建
FROM --platform=$BUILDPLATFORM maven:3.9-eclipse-temurin-21 AS builder
WORKDIR /app
# 复制maven配置和依赖文件
COPY pom.xml ./
COPY .mvn .mvn/
COPY mvnw ./
# 下载依赖(利用缓存层)
RUN mvn dependency:go-offline -B
# 复制源代码
COPY src ./src/
# 构建应用
RUN mvn clean package -DskipTests -B
# 生产镜像
FROM --platform=$TARGETPLATFORM eclipse-temurin:21-jre-alpine
# 安装必要工具
RUN apk add --no-cache curl tzdata && \
cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
echo "Asia/Shanghai" > /etc/timezone
# 创建应用用户
RUN addgroup -g 1001 spring && adduser -S -u 1001 -G spring spring
WORKDIR /app
# 复制jar文件
COPY --from=builder /app/target/*.jar app.jar
# 设置权限
RUN chown spring:spring app.jar
USER spring
# JVM调优参数
ENV JAVA_OPTS="-Xms512m -Xmx1g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -XX:+DisableExplicitGC"
# 应用配置
ENV SPRING_PROFILES_ACTIVE=prod
ENV SERVER_PORT=8080
EXPOSE 8080
# 健康检查
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
CMD curl -f http://localhost:8080/actuator/health || exit 1
ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -jar app.jar"]
@@ -1,23 +0,0 @@
FROM node:18-alpine
# 设置工作目录
WORKDIR /app
# 复制package文件
COPY package*.json ./
# 安装依赖
RUN npm ci --only=production
# 复制应用代码
COPY . .
# 暴露端口
EXPOSE 3000
# 设置健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/health || exit 1
# 运行应用
CMD ["npm", "start"]
@@ -1,57 +0,0 @@
# Python ljwx-bigscreen 多平台构建
FROM --platform=$BUILDPLATFORM python:3.11-slim AS builder
WORKDIR /app
# 安装系统依赖
RUN apt-get update && apt-get install -y \
gcc \
g++ \
libffi-dev \
&& rm -rf /var/lib/apt/lists/*
# 升级pip并安装依赖
COPY requirements.txt ./
RUN pip install --no-cache-dir --upgrade pip && \
pip install --no-cache-dir -r requirements.txt
# 复制应用代码
COPY . .
# 生产镜像
FROM --platform=$TARGETPLATFORM python:3.11-slim
# 安装运行时依赖
RUN apt-get update && apt-get install -y \
curl \
&& rm -rf /var/lib/apt/lists/* \
&& apt-get clean
# 创建用户
RUN groupadd -r app && useradd -r -g app app
WORKDIR /app
# 复制Python环境和应用
COPY --from=builder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages
COPY --from=builder /usr/local/bin /usr/local/bin
COPY --from=builder /app .
# 设置权限
RUN chown -R app:app /app
USER app
# 环境变量
ENV PYTHONPATH=/app
ENV PYTHONUNBUFFERED=1
ENV FLASK_ENV=production
ENV FLASK_APP=app.py
EXPOSE 5000
# 健康检查
HEALTHCHECK --interval=30s --timeout=10s --start-period=30s --retries=3 \
CMD curl -f http://localhost:5000/health || exit 1
CMD ["python", "-m", "flask", "run", "--host=0.0.0.0", "--port=5000"]
@@ -1,61 +0,0 @@
# Vue3 ljwx-admin 多平台构建
FROM --platform=$BUILDPLATFORM node:22-alpine AS builder
WORKDIR /app
# 复制package文件并安装依赖
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force
# 复制源代码并构建
COPY . .
RUN npm run build
# 生产镜像 - 使用nginx
FROM --platform=$TARGETPLATFORM nginx:alpine
# 创建nginx用户和目录
RUN addgroup -g 1001 -S nginx && adduser -S nginx -G nginx
# 复制构建产物
COPY --from=builder /app/dist /usr/share/nginx/html
# 自定义nginx配置
COPY <<EOF /etc/nginx/conf.d/default.conf
server {
listen 80;
server_name localhost;
root /usr/share/nginx/html;
index index.html;
# Gzip压缩
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml text/javascript;
# 处理SPA路由
location / {
try_files \$uri \$uri/ /index.html;
}
# 静态资源缓存
location /assets/ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# API代理(如果需要)
location /api/ {
proxy_pass http://ljwx-boot:8080;
proxy_set_header Host \$host;
proxy_set_header X-Real-IP \$remote_addr;
}
}
EOF
EXPOSE 80
# 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost/ || exit 1
CMD ["nginx", "-g", "daemon off;"]
@@ -1,150 +0,0 @@
@Library('jenkins-shared-library') _
pipeline {
agent any
environment {
REGISTRY = "${env.DOCKER_REGISTRY ?: 'localhost:5001'}"
IMAGE_NAME = "${env.JOB_NAME.toLowerCase()}"
MAVEN_OPTS = '-Dmaven.repo.local=.m2/repository'
}
tools {
maven 'Maven-3.9'
jdk 'JDK-17'
}
stages {
stage('检出代码') {
steps {
checkout scm
script {
env.BUILD_VERSION = sh(
script: "echo '1.0.${BUILD_NUMBER}'",
returnStdout: true
).trim()
}
}
}
stage('代码分析') {
parallel {
stage('编译') {
steps {
sh 'mvn clean compile -DskipTests'
}
}
stage('代码检查') {
steps {
sh 'mvn checkstyle:check'
}
post {
always {
publishHTML([
allowMissing: false,
alwaysLinkToLastBuild: true,
keepAll: true,
reportDir: 'target/site',
reportFiles: 'checkstyle.html',
reportName: 'Checkstyle Report'
])
}
}
}
}
}
stage('单元测试') {
steps {
sh 'mvn test'
}
post {
always {
junit 'target/surefire-reports/**/*.xml'
publishHTML([
allowMissing: false,
alwaysLinkToLastBuild: true,
keepAll: true,
reportDir: 'target/site/jacoco',
reportFiles: 'index.html',
reportName: 'Coverage Report'
])
}
}
}
stage('构建应用') {
steps {
sh 'mvn package -DskipTests'
archiveArtifacts artifacts: 'target/*.jar', fingerprint: true
}
}
stage('构建镜像') {
steps {
script {
def imageName = "${env.REGISTRY}/${env.IMAGE_NAME}:${env.BUILD_VERSION}"
buildMultiPlatformImage {
imageName = imageName
platforms = "linux/amd64,linux/arm64"
dockerfile = 'Dockerfile'
pushImage = true
registryCredentialsId = 'docker-registry-auth'
buildArgs = [
'JAR_FILE': 'target/*.jar',
'BUILD_VERSION': env.BUILD_VERSION
]
}
}
}
}
stage('部署测试') {
when {
branch 'develop'
}
steps {
script {
// 这里添加部署到测试环境的逻辑
echo "部署到测试环境: ${env.REGISTRY}/${env.IMAGE_NAME}:${env.BUILD_VERSION}"
}
}
}
stage('部署生产') {
when {
branch 'main'
}
steps {
script {
// 添加人工确认
timeout(time: 5, unit: 'MINUTES') {
input message: '是否部署到生产环境?',
parameters: [choice(choices: ['Deploy', 'Abort'], description: '选择操作', name: 'ACTION')]
}
echo "部署到生产环境: ${env.REGISTRY}/${env.IMAGE_NAME}:${env.BUILD_VERSION}"
}
}
}
}
post {
always {
cleanWs()
sendNotification {
status = currentBuild.result ?: 'SUCCESS'
title = "${env.JOB_NAME} #${env.BUILD_NUMBER}"
message = "Java 应用构建完成\n版本: ${env.BUILD_VERSION}\n分支: ${env.BRANCH_NAME}"
}
}
success {
echo "✅ Java 应用构建成功"
}
failure {
echo "❌ Java 应用构建失败"
}
}
}
@@ -1,119 +0,0 @@
@Library('jenkins-shared-library') _
pipeline {
agent any
environment {
REGISTRY = "${env.DOCKER_REGISTRY ?: 'localhost:5001'}"
IMAGE_NAME = "${env.JOB_NAME.toLowerCase()}"
NODE_ENV = 'production'
}
tools {
nodejs 'NodeJS-20'
}
stages {
stage('检出代码') {
steps {
checkout scm
script {
env.BUILD_VERSION = sh(
script: "node -p \"require('./package.json').version\"",
returnStdout: true
).trim()
}
}
}
stage('安装依赖') {
steps {
sh 'npm ci'
}
}
stage('代码分析') {
parallel {
stage('ESLint') {
steps {
sh 'npm run lint || true'
}
post {
always {
publishHTML([
allowMissing: true,
alwaysLinkToLastBuild: true,
keepAll: true,
reportDir: 'reports',
reportFiles: 'eslint.html',
reportName: 'ESLint Report'
])
}
}
}
stage('类型检查') {
steps {
sh 'npm run type-check || true'
}
}
}
}
stage('单元测试') {
steps {
sh 'npm test -- --coverage'
}
post {
always {
publishHTML([
allowMissing: false,
alwaysLinkToLastBuild: true,
keepAll: true,
reportDir: 'coverage/lcov-report',
reportFiles: 'index.html',
reportName: 'Coverage Report'
])
}
}
}
stage('构建应用') {
steps {
sh 'npm run build'
archiveArtifacts artifacts: 'dist/**/*', fingerprint: true
}
}
stage('构建镜像') {
steps {
script {
def imageName = "${env.REGISTRY}/${env.IMAGE_NAME}:${env.BUILD_VERSION}"
buildMultiPlatformImage {
imageName = imageName
platforms = "linux/amd64,linux/arm64"
dockerfile = 'Dockerfile'
pushImage = true
registryCredentialsId = 'docker-registry-auth'
buildArgs = [
'NODE_ENV': env.NODE_ENV,
'BUILD_VERSION': env.BUILD_VERSION
]
}
}
}
}
}
post {
always {
cleanWs()
sendNotification {
status = currentBuild.result ?: 'SUCCESS'
title = "${env.JOB_NAME} #${env.BUILD_NUMBER}"
message = "Node.js 应用构建完成\n版本: ${env.BUILD_VERSION}\n分支: ${env.BRANCH_NAME}"
}
}
}
}
@@ -1,122 +0,0 @@
pipeline {
agent any
environment {
DOCKER_REGISTRY = 'localhost:5001'
APP_NAME = 'my-app'
APP_VERSION = "${BUILD_NUMBER}"
REGISTRY_CREDENTIALS = 'registry-auth'
}
options {
buildDiscarder(logRotator(numToKeepStr: '10'))
timeout(time: 30, unit: 'MINUTES')
timestamps()
}
stages {
stage('检出代码') {
steps {
checkout scm
script {
env.GIT_COMMIT_SHORT = sh(
script: 'git rev-parse --short HEAD',
returnStdout: true
).trim()
env.IMAGE_TAG = "${APP_VERSION}-${GIT_COMMIT_SHORT}"
}
}
}
stage('构建Docker镜像') {
steps {
script {
def imageName = "${DOCKER_REGISTRY}/${APP_NAME}:${IMAGE_TAG}"
def latestName = "${DOCKER_REGISTRY}/${APP_NAME}:latest"
echo "构建镜像: ${imageName}"
// 构建镜像
sh """
docker build -t ${imageName} .
docker tag ${imageName} ${latestName}
"""
// 推送镜像
withCredentials([usernamePassword(
credentialsId: REGISTRY_CREDENTIALS,
usernameVariable: 'REGISTRY_USER',
passwordVariable: 'REGISTRY_PASS'
)]) {
sh """
echo \$REGISTRY_PASS | docker login ${DOCKER_REGISTRY} -u \$REGISTRY_USER --password-stdin
docker push ${imageName}
docker push ${latestName}
"""
}
}
}
}
stage('镜像安全扫描') {
steps {
echo '执行镜像安全扫描...'
sh """
echo "扫描镜像: ${DOCKER_REGISTRY}/${APP_NAME}:${IMAGE_TAG}"
# 这里可以集成Trivy等安全扫描工具
"""
}
}
stage('部署到测试环境') {
when {
branch 'develop'
}
steps {
script {
echo '部署到测试环境...'
sh """
docker stop ${APP_NAME}-test || true
docker rm ${APP_NAME}-test || true
docker run -d --name ${APP_NAME}-test -p 8080:5000 ${DOCKER_REGISTRY}/${APP_NAME}:${IMAGE_TAG}
"""
}
}
}
stage('部署到生产环境') {
when {
anyOf {
branch 'main'
branch 'master'
}
}
steps {
script {
echo '部署到生产环境...'
sh """
docker stop ${APP_NAME}-prod || true
docker rm ${APP_NAME}-prod || true
docker run -d --name ${APP_NAME}-prod -p 8081:5000 ${DOCKER_REGISTRY}/${APP_NAME}:${IMAGE_TAG}
"""
}
}
}
}
post {
always {
echo 'Pipeline执行完成'
sh """
docker logout ${DOCKER_REGISTRY} || true
docker system prune -f || true
"""
}
success {
echo '✅ 构建成功!'
}
failure {
echo '❌ 构建失败!'
}
}
}
@@ -1,356 +0,0 @@
@Library('jenkins-shared-library') _
pipeline {
agent any
environment {
REGISTRY = "${env.DOCKER_REGISTRY ?: 'localhost:5001'}"
APP_NAME = "${env.JOB_NAME.split('/')[0].toLowerCase()}"
GIT_SHORT_COMMIT = sh(returnStdout: true, script: 'git rev-parse --short HEAD').trim()
IMAGE_TAG = "${env.BUILD_NUMBER}-${GIT_SHORT_COMMIT}"
PLATFORMS = 'linux/amd64,linux/arm64'
KUBECONFIG_ID = 'k8s-config'
}
parameters {
choice(
name: 'DEPLOY_ENV',
choices: ['dev', 'staging', 'prod'],
description: '部署环境'
)
booleanParam(
name: 'SKIP_TESTS',
defaultValue: false,
description: '跳过测试阶段'
)
booleanParam(
name: 'DEPLOY_TO_K8S',
defaultValue: true,
description: '部署到K8s集群'
)
}
options {
buildDiscarder(logRotator(numToKeepStr: '50', daysToKeepStr: '30'))
timeout(time: 60, unit: 'MINUTES')
timestamps()
ansiColor('xterm')
skipDefaultCheckout(false)
}
stages {
stage('🔍 环境检查') {
steps {
script {
echo "=== 构建信息 ==="
echo "App: ${env.APP_NAME}"
echo "Tag: ${env.IMAGE_TAG}"
echo "Registry: ${env.REGISTRY}"
echo "Environment: ${params.DEPLOY_ENV}"
echo "Git Commit: ${env.GIT_SHORT_COMMIT}"
// 检查必要工具
sh '''
echo "=== 工具版本检查 ==="
docker --version
docker buildx version || echo "❌ buildx not available"
kubectl version --client || echo "⚠️ kubectl not available"
git --version
'''
// 检查Registry连接
sh 'curl -f ${REGISTRY}/v2/ || echo "⚠️ Registry连接检查"'
}
}
}
stage('📥 代码检出') {
steps {
checkout scm
script {
env.GIT_COMMIT = sh(returnStdout: true, script: 'git rev-parse HEAD').trim()
env.GIT_BRANCH = sh(returnStdout: true, script: 'git rev-parse --abbrev-ref HEAD').trim()
// 检测项目类型
if (fileExists('package.json')) {
env.PROJECT_TYPE = 'nodejs'
} else if (fileExists('pom.xml')) {
env.PROJECT_TYPE = 'maven'
} else if (fileExists('build.gradle')) {
env.PROJECT_TYPE = 'gradle'
} else if (fileExists('requirements.txt')) {
env.PROJECT_TYPE = 'python'
} else {
env.PROJECT_TYPE = 'docker'
}
echo "项目类型: ${env.PROJECT_TYPE}"
}
}
}
stage('🔧 依赖安装') {
when { not { params.SKIP_TESTS } }
steps {
script {
switch(env.PROJECT_TYPE) {
case 'nodejs':
sh 'npm ci --production=false'
break
case 'maven':
sh 'mvn dependency:resolve'
break
case 'gradle':
sh './gradlew dependencies'
break
case 'python':
sh 'pip install -r requirements.txt'
break
default:
echo "跳过依赖安装,项目类型: ${env.PROJECT_TYPE}"
}
}
}
}
stage('🧪 代码检查') {
when { not { params.SKIP_TESTS } }
parallel {
stage('语法检查') {
steps {
script {
switch(env.PROJECT_TYPE) {
case 'nodejs':
sh 'npm run lint || echo "无lint脚本"'
break
case 'python':
sh 'flake8 . || echo "无flake8检查"'
break
default:
echo "跳过语法检查"
}
}
}
}
stage('安全扫描') {
steps {
script {
// 依赖安全扫描
switch(env.PROJECT_TYPE) {
case 'nodejs':
sh 'npm audit --audit-level=high || echo "发现安全问题"'
break
case 'python':
sh 'safety check || echo "安全检查完成"'
break
default:
echo "跳过安全扫描"
}
}
}
}
}
}
stage('🧪 单元测试') {
when { not { params.SKIP_TESTS } }
steps {
script {
switch(env.PROJECT_TYPE) {
case 'nodejs':
sh 'npm test || echo "测试执行完成"'
break
case 'maven':
sh 'mvn test'
break
case 'gradle':
sh './gradlew test'
break
case 'python':
sh 'python -m pytest || echo "测试执行完成"'
break
default:
echo "跳过单元测试,项目类型: ${env.PROJECT_TYPE}"
}
}
}
post {
always {
// 发布测试结果
publishTestResults(
testResultsPattern: '**/test-results.xml,**/TEST-*.xml',
allowEmptyResults: true
)
}
}
}
stage('🐳 多平台构建') {
steps {
script {
// 确保Dockerfile存在
if (!fileExists('Dockerfile')) {
echo "创建默认Dockerfile..."
writeFile file: 'Dockerfile', text: """
FROM alpine:latest
RUN apk add --no-cache curl
COPY . /app
WORKDIR /app
EXPOSE 8080
CMD echo "Hello from ${env.APP_NAME}"
"""
}
// 使用共享库构建多平台镜像
def buildResult = buildMultiPlatformImage([
registry: env.REGISTRY,
imageName: env.APP_NAME,
platforms: env.PLATFORMS,
tags: ['latest', env.IMAGE_TAG, "branch-${env.GIT_BRANCH}"],
push: true
])
env.BUILT_IMAGE = "${buildResult.registry}/${buildResult.imageName}:${env.IMAGE_TAG}"
echo "✅ 镜像构建完成: ${env.BUILT_IMAGE}"
}
}
}
stage('🔒 镜像扫描') {
when {
expression { params.DEPLOY_ENV == 'prod' }
}
steps {
script {
echo "执行生产环境镜像安全扫描..."
sh """
docker run --rm -v /var/run/docker.sock:/var/run/docker.sock \\
aquasec/trivy image --exit-code 0 --severity HIGH,CRITICAL \\
${env.BUILT_IMAGE} || echo "扫描完成"
"""
}
}
}
stage('🚀 部署') {
parallel {
stage('K8s部署') {
when {
expression { params.DEPLOY_TO_K8S && fileExists('k8s/') }
}
steps {
script {
def deployResult = deployToK8s([
namespace: "${env.APP_NAME}-${params.DEPLOY_ENV}",
appName: env.APP_NAME,
image: env.BUILT_IMAGE,
manifests: 'k8s/',
kubeconfig: env.KUBECONFIG_ID,
dryRun: false,
waitForRollout: true
])
echo "✅ K8s部署完成: ${deployResult.namespace}/${deployResult.appName}"
}
}
}
stage('Docker Swarm部署') {
when {
expression { !params.DEPLOY_TO_K8S && fileExists('docker-compose.prod.yml') }
}
steps {
script {
echo "部署到Docker Swarm..."
sh """
export IMAGE=${env.BUILT_IMAGE}
docker stack deploy --compose-file docker-compose.prod.yml ${env.APP_NAME}-${params.DEPLOY_ENV}
"""
}
}
}
}
}
stage('✅ 部署验证') {
steps {
script {
echo "执行部署验证..."
if (params.DEPLOY_TO_K8S) {
// K8s健康检查
sh """
kubectl get pods -n ${env.APP_NAME}-${params.DEPLOY_ENV} -l app=${env.APP_NAME}
kubectl top pods -n ${env.APP_NAME}-${params.DEPLOY_ENV} -l app=${env.APP_NAME} || echo "资源使用情况"
"""
} else {
// Docker容器健康检查
sh "docker service ls | grep ${env.APP_NAME}-${params.DEPLOY_ENV} || echo '服务状态检查'"
}
// 应用健康检查
sh 'curl -f http://localhost:8080/health || echo "应用健康检查"'
}
}
}
}
post {
always {
echo "=== 构建统计 ==="
echo "构建时长: ${currentBuild.durationString}"
echo "构建结果: ${currentBuild.currentResult}"
// 清理工作空间
cleanWs(
cleanWhenAborted: true,
cleanWhenFailure: false,
cleanWhenNotBuilt: false,
cleanWhenSuccess: true,
cleanWhenUnstable: false,
deleteDirs: true
)
}
success {
echo "🎉 Pipeline执行成功!"
// 发送成功通知
script {
if (env.SLACK_WEBHOOK) {
slackSend(
color: 'good',
message: """✅ 部署成功
App: ${env.APP_NAME}
Environment: ${params.DEPLOY_ENV}
Image: ${env.BUILT_IMAGE}
Duration: ${currentBuild.durationString}"""
)
}
}
}
failure {
echo "❌ Pipeline执行失败!"
// 发送失败通知
script {
if (env.SLACK_WEBHOOK) {
slackSend(
color: 'danger',
message: """❌ 部署失败
App: ${env.APP_NAME}
Environment: ${params.DEPLOY_ENV}
Branch: ${env.GIT_BRANCH}
Build: ${env.BUILD_URL}"""
)
}
}
}
unstable {
echo "⚠️ Pipeline执行不稳定"
}
}
}
@@ -1,91 +0,0 @@
@Library('jenkins-shared-library') _
pipeline {
agent any
environment {
DOCKER_REGISTRY = 'localhost:5001'
SERVICE_NAME = 'microservice'
REGISTRY_CREDENTIALS = 'registry-auth'
}
stages {
stage('检出代码') {
steps {
checkout scm
script {
env.IMAGE_TAG = "${BUILD_NUMBER}-${GIT_COMMIT[0..7]}"
}
}
}
stage('并行构建') {
parallel {
stage('单元测试') {
steps {
runTests([testType: 'unit'])
}
}
stage('API测试') {
steps {
runTests([testType: 'api', testPath: 'tests/api/'])
}
}
stage('性能测试') {
steps {
sh 'echo "运行性能测试..." && sleep 3'
}
}
}
}
stage('构建服务镜像') {
steps {
script {
buildDockerImage([
appName: env.SERVICE_NAME,
imageTag: env.IMAGE_TAG
])
}
}
}
stage('服务部署') {
parallel {
stage('部署到测试环境') {
when { branch 'develop' }
steps {
deployToEnvironment([
environment: 'test',
appName: env.SERVICE_NAME,
port: 8080
])
}
}
stage('部署到预发环境') {
when { branch 'release/*' }
steps {
deployToEnvironment([
environment: 'staging',
appName: env.SERVICE_NAME,
port: 8081
])
}
}
stage('部署到生产环境') {
when { branch 'main' }
steps {
script {
input message: '确认部署到生产环境?'
deployToEnvironment([
environment: 'prod',
appName: env.SERVICE_NAME,
port: 8082
])
}
}
}
}
}
}
}
@@ -1,239 +0,0 @@
@Library('jenkins-shared-library') _
pipeline {
agent any
environment {
DOCKER_REGISTRY = 'localhost:5001'
GITEA_URL = 'http://192.168.1.6:3000'
REGISTRY_CREDENTIALS = 'registry-auth'
PLATFORMS = 'linux/amd64,linux/arm64'
}
options {
buildDiscarder(logRotator(numToKeepStr: '20', daysToKeepStr: '30'))
timeout(time: 60, unit: 'MINUTES')
timestamps()
ansiColor('xterm')
}
stages {
stage('环境准备') {
steps {
script {
// 获取项目信息
env.APP_NAME = env.JOB_NAME.split('/')[0]
env.GIT_COMMIT_SHORT = sh(returnStdout: true, script: 'git rev-parse --short HEAD').trim()
env.IMAGE_TAG = "${env.BUILD_NUMBER}-${env.GIT_COMMIT_SHORT}"
// 检测项目类型
if (fileExists('package.json')) {
env.PROJECT_TYPE = 'vue3'
} else if (fileExists('pom.xml') || fileExists('build.gradle')) {
env.PROJECT_TYPE = 'java'
} else if (fileExists('requirements.txt') || fileExists('setup.py')) {
env.PROJECT_TYPE = 'python'
} else if (fileExists('Dockerfile')) {
env.PROJECT_TYPE = 'docker'
}
echo "项目类型: ${env.PROJECT_TYPE}, 应用名: ${env.APP_NAME}"
}
}
}
stage('代码检查') {
parallel {
stage('语法检查') {
steps {
script {
switch(env.PROJECT_TYPE) {
case 'vue3':
sh 'npm run lint || echo "Lint检查完成"'
break
case 'java':
sh 'mvn compile || echo "编译检查完成"'
break
case 'python':
sh 'python -m py_compile src/ || echo "语法检查完成"'
break
default:
echo "跳过语法检查"
}
}
}
}
stage('安全扫描') {
steps {
sh 'echo "执行安全扫描..." && sleep 2'
}
}
}
}
stage('单元测试') {
steps {
script {
switch(env.PROJECT_TYPE) {
case 'vue3':
sh 'npm test || echo "测试完成"'
break
case 'java':
sh 'mvn test || echo "测试完成"'
break
case 'python':
sh 'pytest || echo "测试完成"'
break
default:
echo "跳过单元测试"
}
}
}
}
stage('构建多平台镜像') {
when {
anyOf {
branch 'main'
branch 'develop'
branch 'feature/*'
}
}
steps {
script {
def imageName = "${DOCKER_REGISTRY}/${env.APP_NAME}:${env.IMAGE_TAG}"
def latestName = "${DOCKER_REGISTRY}/${env.APP_NAME}:latest"
echo "构建多平台镜像: ${imageName}"
echo "支持平台: ${PLATFORMS}"
withCredentials([usernamePassword(
credentialsId: REGISTRY_CREDENTIALS,
usernameVariable: 'REGISTRY_USER',
passwordVariable: 'REGISTRY_PASS'
)]) {
sh """
echo \$REGISTRY_PASS | docker login ${DOCKER_REGISTRY} -u \$REGISTRY_USER --password-stdin
# 创建buildx实例
docker buildx create --use --name multiarch-builder --driver docker-container || true
docker buildx inspect --bootstrap
# 构建并推送多平台镜像
docker buildx build \\
--platform ${PLATFORMS} \\
--tag ${imageName} \\
--tag ${latestName} \\
--push .
echo "✅ 多平台镜像构建完成"
"""
}
}
}
}
stage('镜像测试') {
parallel {
stage('AMD64测试') {
steps {
sh """
echo "测试AMD64镜像..."
docker run --rm --platform linux/amd64 ${DOCKER_REGISTRY}/${env.APP_NAME}:${env.IMAGE_TAG} echo "AMD64 OK"
"""
}
}
stage('ARM64测试') {
steps {
sh """
echo "测试ARM64镜像..."
docker run --rm --platform linux/arm64 ${DOCKER_REGISTRY}/${env.APP_NAME}:${env.IMAGE_TAG} echo "ARM64 OK"
"""
}
}
}
}
stage('部署测试') {
when {
branch 'develop'
}
steps {
deployToEnvironment([
environment: 'test',
appName: env.APP_NAME,
imageTag: env.IMAGE_TAG,
port: 8080,
platform: 'linux/amd64' # 测试环境使用AMD64
])
}
}
stage('部署生产') {
when {
anyOf {
branch 'main'
branch 'master'
}
}
steps {
script {
input message: '确认部署到生产环境?', ok: '部署'
// 生产环境支持多平台部署选择
def targetPlatform = input(
message: '选择部署平台:',
parameters: [
choice(choices: ['linux/amd64', 'linux/arm64', 'auto'], description: '目标平台', name: 'PLATFORM')
]
)
deployToEnvironment([
environment: 'prod',
appName: env.APP_NAME,
imageTag: env.IMAGE_TAG,
port: 8081,
platform: targetPlatform
])
}
}
}
}
post {
always {
script {
// 清理buildx实例
sh 'docker buildx rm multiarch-builder || true'
// 清理本地镜像
sh """
docker logout ${DOCKER_REGISTRY} || true
docker system prune -f
"""
}
}
success {
echo "✅ 多平台构建成功!"
script {
// 发送成功通知
sendNotification([
status: 'success',
message: "多平台构建成功 - ${env.APP_NAME}:${env.IMAGE_TAG}",
platforms: PLATFORMS
])
}
}
failure {
echo "❌ 多平台构建失败!"
script {
// 发送失败通知
sendNotification([
status: 'failure',
message: "多平台构建失败 - ${env.APP_NAME}:${env.IMAGE_TAG}",
error: "${env.BUILD_URL}"
])
}
}
}
}
@@ -1,54 +0,0 @@
pipeline {
agent any
environment {
DOCKER_REGISTRY = 'localhost:5001'
APP_NAME = 'my-app'
REGISTRY_CREDENTIALS = 'registry-auth'
}
stages {
stage('并行构建') {
parallel {
stage('单元测试') {
steps {
sh 'echo "执行单元测试..."'
}
}
stage('代码检查') {
steps {
sh 'echo "执行代码检查..."'
}
}
stage('安全扫描') {
steps {
sh 'echo "执行安全扫描..."'
}
}
}
}
stage('构建多架构镜像') {
steps {
script {
def platforms = ['linux/amd64', 'linux/arm64']
def imageName = "${DOCKER_REGISTRY}/${APP_NAME}:${BUILD_NUMBER}"
echo "构建多架构镜像: ${imageName}"
withCredentials([usernamePassword(
credentialsId: REGISTRY_CREDENTIALS,
usernameVariable: 'REGISTRY_USER',
passwordVariable: 'REGISTRY_PASS'
)]) {
sh """
echo \$REGISTRY_PASS | docker login ${DOCKER_REGISTRY} -u \$REGISTRY_USER --password-stdin
docker buildx create --use --name multiarch-builder || true
docker buildx build --platform ${platforms.join(',')} -t ${imageName} --push .
"""
}
}
}
}
}
}
@@ -1,157 +0,0 @@
@Library('jenkins-shared-library') _
pipeline {
agent any
environment {
DOCKER_REGISTRY = 'localhost:5001'
APP_NAME = 'webapp'
REGISTRY_CREDENTIALS = 'registry-auth'
}
options {
buildDiscarder(logRotator(numToKeepStr: '20', daysToKeepStr: '30'))
timeout(time: 45, unit: 'MINUTES')
timestamps()
ansiColor('xterm')
}
stages {
stage('检出代码') {
steps {
checkout scm
script {
def gitInfo = org.example.Utils.getGitCommitInfo(this)
env.GIT_COMMIT = gitInfo.commit
env.GIT_COMMIT_SHORT = gitInfo.shortCommit
env.GIT_AUTHOR = gitInfo.author
env.GIT_MESSAGE = gitInfo.message
env.IMAGE_TAG = org.example.Utils.generateImageTag(env.BUILD_NUMBER, env.GIT_COMMIT)
}
}
}
stage('代码质量检查') {
parallel {
stage('语法检查') {
steps {
sh 'find . -name "*.py" -exec python -m py_compile {} \\; || echo "语法检查完成"'
}
}
stage('安全扫描') {
steps {
sh 'echo "执行安全扫描..." && sleep 2'
}
}
stage('依赖检查') {
steps {
sh 'pip list --outdated || echo "依赖检查完成"'
}
}
}
}
stage('运行测试') {
steps {
runTests([
testType: 'unit',
testPath: 'tests/',
coverage: true
])
}
}
stage('构建镜像') {
when {
anyOf {
branch 'main'
branch 'develop'
branch 'feature/*'
}
}
steps {
script {
buildDockerImage([
registry: env.DOCKER_REGISTRY,
appName: env.APP_NAME,
imageTag: env.IMAGE_TAG,
credentialsId: env.REGISTRY_CREDENTIALS
])
}
}
}
stage('部署测试') {
when {
branch 'develop'
}
steps {
deployToEnvironment([
environment: 'test',
appName: env.APP_NAME,
imageTag: env.IMAGE_TAG,
port: 8080
])
}
}
stage('集成测试') {
when {
branch 'develop'
}
steps {
sh '''
echo "运行集成测试..."
sleep 5
curl -f http://localhost:8080/health || echo "集成测试失败"
'''
}
}
stage('部署生产') {
when {
anyOf {
branch 'main'
branch 'master'
}
}
steps {
script {
input message: '确认部署到生产环境?', ok: '部署'
deployToEnvironment([
environment: 'prod',
appName: env.APP_NAME,
imageTag: env.IMAGE_TAG,
port: 8081
])
}
}
}
}
post {
always {
script {
org.example.Utils.cleanupOldImages(this, env.DOCKER_REGISTRY, env.APP_NAME, 5)
}
}
success {
sendNotification([
status: 'SUCCESS',
message: "✅ 构建成功! 提交: ${env.GIT_COMMIT_SHORT} by ${env.GIT_AUTHOR}"
])
}
failure {
sendNotification([
status: 'FAILURE',
message: "❌ 构建失败! 提交: ${env.GIT_COMMIT_SHORT} by ${env.GIT_AUTHOR}"
])
}
unstable {
sendNotification([
status: 'UNSTABLE',
message: "⚠️ 构建不稳定! 提交: ${env.GIT_COMMIT_SHORT} by ${env.GIT_AUTHOR}"
])
}
}
}
-60
View File
@@ -1,60 +0,0 @@
services:
ljwx-jenkins:
build:
context: ./jenkins/setup
dockerfile: Dockerfile-basic
image: ljwx-jenkins:latest
container_name: ljwx-jenkins
restart: unless-stopped
ports:
- "8081:8080"
- "50000:50000"
volumes:
- ljwx-jenkins-data:/var/jenkins_home
- /var/run/docker.sock:/var/run/docker.sock
environment:
- JENKINS_OPTS=--httpPort=8080
- JAVA_OPTS=-Xmx2g -Xms1g -XX:+UseG1GC -XX:MaxGCPauseMillis=200
- JENKINS_ADMIN_ID=admin
- JENKINS_ADMIN_PASSWORD=admin123
- DOCKER_REGISTRY=localhost:5003
- GITEA_URL=http://gitea:3000
- TZ=Asia/Shanghai
user: root
networks:
- cicd-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/login"]
interval: 30s
timeout: 10s
retries: 5
start_period: 300s
labels:
- "project=ljwx"
- "service=jenkins"
ljwx-registry:
image: registry:2
container_name: ljwx-registry
restart: unless-stopped
ports:
- "5003:5000"
volumes:
- ljwx-registry-data:/var/lib/registry
environment:
- REGISTRY_STORAGE_DELETE_ENABLED=true
networks:
- cicd-network
networks:
cicd-network:
driver: bridge
name: ljwx-cicd-network
volumes:
ljwx-jenkins-data:
driver: local
name: ljwx-jenkins-data
ljwx-registry-data:
driver: local
name: ljwx-registry-data
-143
View File
@@ -1,143 +0,0 @@
services:
ljwx-jenkins:
build:
context: ./jenkins/setup
dockerfile: Dockerfile-complete
image: ljwx-jenkins:latest
container_name: ljwx-jenkins
restart: unless-stopped
ports:
- "8081:8080"
- "50000:50000"
volumes:
- ljwx-jenkins-data:/var/jenkins_home
- /var/run/docker.sock:/var/run/docker.sock
- /usr/bin/docker:/usr/bin/docker:ro
- ljwx-jenkins-cache:/var/jenkins_home/.cache
- ljwx-jenkins-m2:/var/jenkins_home/.m2
- ljwx-jenkins-gradle:/var/jenkins_home/.gradle
- ljwx-jenkins-npm:/var/jenkins_home/.npm
environment:
- JENKINS_OPTS=--httpPort=8080
- JAVA_OPTS=-Xmx4g -Xms2g -XX:+UseG1GC -XX:MaxGCPauseMillis=200
- JENKINS_ADMIN_ID=admin
- JENKINS_ADMIN_PASSWORD=admin123
- DOCKER_REGISTRY=localhost:5001
- GITEA_URL=http://gitea:3000
- KUBERNETES_MASTER=https://kubernetes.docker.internal:6443
- TZ=Asia/Shanghai
user: root
privileged: true
networks:
- cicd-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/login"]
interval: 30s
timeout: 10s
retries: 5
start_period: 300s
labels:
- "project=ljwx"
- "service=jenkins"
- "version=complete"
ljwx-registry:
image: registry:2
container_name: ljwx-registry
restart: unless-stopped
ports:
- "5001:5000"
volumes:
- ljwx-registry-data:/var/lib/registry
- ./registry-config.yml:/etc/docker/registry/config.yml:ro
environment:
- REGISTRY_STORAGE_DELETE_ENABLED=true
- REGISTRY_HTTP_ADDR=0.0.0.0:5000
- REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY=/var/lib/registry
networks:
- cicd-network
labels:
- "project=ljwx"
- "service=registry"
ljwx-registry-ui:
image: joxit/docker-registry-ui:latest
container_name: ljwx-registry-ui
restart: unless-stopped
ports:
- "5002:80"
environment:
- SINGLE_REGISTRY=true
- REGISTRY_TITLE=LJWX Docker Registry
- DELETE_IMAGES=true
- SHOW_CONTENT_DIGEST=true
- NGINX_PROXY_PASS_URL=http://ljwx-registry:5000
- SHOW_CATALOG_NB_TAGS=true
- CATALOG_MIN_BRANCHES=1
- CATALOG_MAX_BRANCHES=1
- TAGLIST_PAGE_SIZE=100
- REGISTRY_SECURED=false
- CATALOG_ELEMENTS_LIMIT=1000
networks:
- cicd-network
depends_on:
- ljwx-registry
labels:
- "project=ljwx"
- "service=registry-ui"
networks:
cicd-network:
driver: bridge
name: ljwx-cicd-network
labels:
- "project=ljwx"
volumes:
ljwx-jenkins-data:
driver: local
name: ljwx-jenkins-data
labels:
- "project=ljwx"
- "service=jenkins"
- "type=data"
ljwx-jenkins-cache:
driver: local
name: ljwx-jenkins-cache
labels:
- "project=ljwx"
- "service=jenkins"
- "type=cache"
ljwx-jenkins-m2:
driver: local
name: ljwx-jenkins-m2
labels:
- "project=ljwx"
- "service=jenkins"
- "type=maven"
ljwx-jenkins-gradle:
driver: local
name: ljwx-jenkins-gradle
labels:
- "project=ljwx"
- "service=jenkins"
- "type=gradle"
ljwx-jenkins-npm:
driver: local
name: ljwx-jenkins-npm
labels:
- "project=ljwx"
- "service=jenkins"
- "type=npm"
ljwx-registry-data:
driver: local
name: ljwx-registry-data
labels:
- "project=ljwx"
- "service=registry"
- "type=data"
-63
View File
@@ -1,63 +0,0 @@
services:
ljwx-jenkins:
build:
context: ./jenkins/setup
dockerfile: Dockerfile-simple
image: ljwx-jenkins:latest
container_name: ljwx-jenkins
restart: unless-stopped
ports:
- "8081:8080"
- "50000:50000"
volumes:
- ljwx-jenkins-data:/var/jenkins_home
- /var/run/docker.sock:/var/run/docker.sock
environment:
- JENKINS_OPTS=--httpPort=8080
- JAVA_OPTS=-Xmx2g -Xms1g -XX:+UseG1GC -XX:MaxGCPauseMillis=200
- JENKINS_ADMIN_ID=admin
- JENKINS_ADMIN_PASSWORD=admin123
- DOCKER_REGISTRY=localhost:5001
- GITEA_URL=http://gitea:3000
- TZ=Asia/Shanghai
user: root
networks:
- cicd-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/login"]
interval: 30s
timeout: 10s
retries: 5
start_period: 300s
labels:
- "project=ljwx"
- "service=jenkins"
ljwx-registry:
image: registry:2
container_name: ljwx-registry
restart: unless-stopped
ports:
- "5001:5000"
volumes:
- ljwx-registry-data:/var/lib/registry
environment:
- REGISTRY_STORAGE_DELETE_ENABLED=true
networks:
- cicd-network
labels:
- "project=ljwx"
- "service=registry"
networks:
cicd-network:
driver: bridge
name: ljwx-cicd-network
volumes:
ljwx-jenkins-data:
driver: local
name: ljwx-jenkins-data
ljwx-registry-data:
driver: local
name: ljwx-registry-data

Some files were not shown because too many files have changed in this diff Show More