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:
@@ -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
|
||||
@@ -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
|
||||
```
|
||||
@@ -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
|
||||
@@ -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
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**节省时间 = 更多咖啡时间 ☕**
|
||||
@@ -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
|
||||
**节省时间 = 更多创造价值的时间** ⚡
|
||||
@@ -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
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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流程。
|
||||
@@ -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
@@ -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
|
||||
**状态**: ✅ 已验证可用
|
||||
@@ -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 流水线吧!**
|
||||
@@ -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流水线,支撑现代化应用开发!🎊
|
||||
@@ -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
|
||||
@@ -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`
|
||||
@@ -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)
|
||||
|
||||

|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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 # 一键部署
|
||||
```
|
||||
|
||||
祝使用愉快!🚀
|
||||
@@ -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!** 🎊
|
||||
@@ -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
File diff suppressed because it is too large
Load Diff
-414
@@ -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 "$@"
|
||||
@@ -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 "$@"
|
||||
@@ -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
|
||||
@@ -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 }}
|
||||
@@ -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
|
||||
@@ -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 流程完成 ==="
|
||||
@@ -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 "$@"
|
||||
@@ -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 ""
|
||||
@@ -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
|
||||
@@ -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 "$@"
|
||||
@@ -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
|
||||
@@ -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 "$@"
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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 # 临时文件
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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}"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -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环境已完全配置就绪!**
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 "=== 健康检查完成 ==="
|
||||
''')
|
||||
}
|
||||
}
|
||||
@@ -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!')
|
||||
@@ -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
|
||||
@@ -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 -> 全局凭据"
|
||||
@@ -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
|
||||
"""
|
||||
@@ -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_
|
||||
@@ -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}"
|
||||
])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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"
|
||||
@@ -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
Reference in New Issue
Block a user