18.4.4 制品管理与版本控制
制品管理与版本控制#
制品管理是CI流程的闭环环节,目标是将构建产物以可追溯、可复用、可回滚的方式沉淀到统一仓库。结合版本控制体系,确保每一次构建都能定位到具体源码、依赖、环境与配置,从而支撑发布与问题排查。
原理草图:制品与版本关联
制品类型与范围
- 二进制制品:Jar/War、可执行文件、镜像、压缩包。
- 配置制品:配置文件模板、Helm Chart、清单文件。
- 测试制品:测试报告、覆盖率、静态扫描结果。
- 元数据:构建号、Git提交、依赖清单、构建时间、构建环境。
制品仓库与命名规范
- 使用统一制品仓库(如 Nexus、Artifactory、Harbor)集中管理。
- 命名建议:<项目名>-<环境>-<版本号>-<构建号>。
- 采用不可变制品策略,禁止覆盖同版本制品。
- 区分快照与发布版本:1.2.3-SNAPSHOT 与 1.2.3。
安装与初始化(Nexus 示例)#
安装 Nexus 3
# 1) 下载并解压
cd /opt
wget https://download.sonatype.com/nexus/3/nexus-3.68.1-02-unix.tar.gz
tar -zxf nexus-3.68.1-02-unix.tar.gz
ln -s nexus-3.68.1-02 nexus
# 2) 创建运行用户
useradd -r -s /sbin/nologin nexus
chown -R nexus:nexus /opt/nexus /opt/sonatype-work
# 3) 配置运行
sed -i 's/^#run_as_user=.*/run_as_user="nexus"/' /opt/nexus/bin/nexus.rc
# 4) 启动
/opt/nexus/bin/nexus start
# 预期:访问 http://<IP>:8081
创建 Maven hosted 仓库(REST 简化示例)
# 需管理员账号,首次登录在 /opt/sonatype-work/nexus3/admin.password 获取
curl -u admin:YOUR_PASS -X POST \
http://127.0.0.1:8081/service/rest/v1/repositories/maven/hosted \
-H 'Content-Type: application/json' \
-d '{
"name": "maven-releases",
"online": true,
"storage": {"blobStoreName": "default", "strictContentTypeValidation": true, "writePolicy": "ALLOW_ONCE"},
"maven": {"versionPolicy": "RELEASE", "layoutPolicy": "PERMISSIVE"}
}'
版本控制策略与示例#
语义化版本与分支策略
- 版本号:主版本.次版本.修订号
- 发布版本由 Tag 触发,快照版本由分支触发
- 建议分支:main/master 发布、develop 集成、feature/* 开发
Git Tag 与制品对应
# 创建发布标签并推送
git tag -a v1.2.3 -m "release 1.2.3"
git push origin v1.2.3
# 预期:CI 监听 tag 触发发布构建
制品元数据与可追溯性(build-info)#
构建产物写入元数据示例
# build-info.json(与制品同目录)
cat > build-info.json <<'EOF'
{
"project": "order-service",
"version": "1.2.3",
"buildNumber": "102",
"gitCommit": "a1b2c3d4",
"gitBranch": "main",
"buildTime": "2024-05-12T10:20:30Z",
"builder": "jenkins@ci-01",
"dependencies": [
"org.springframework.boot:spring-boot-starter-web:3.2.0"
]
}
EOF
制品上传与下载(命令完整示例)#
上传制品(curl + Nexus REST)
# 生成制品
mkdir -p dist
echo "hello" > dist/order-service-1.2.3-102.jar
sha256sum dist/order-service-1.2.3-102.jar > dist/order-service-1.2.3-102.jar.sha256
# 上传制品与校验
curl -u admin:YOUR_PASS --upload-file dist/order-service-1.2.3-102.jar \
"http://127.0.0.1:8081/repository/maven-releases/com/example/order-service/1.2.3/order-service-1.2.3-102.jar"
curl -u admin:YOUR_PASS --upload-file dist/order-service-1.2.3-102.jar.sha256 \
"http://127.0.0.1:8081/repository/maven-releases/com/example/order-service/1.2.3/order-service-1.2.3-102.jar.sha256"
下载制品(CD 使用)
mkdir -p /opt/releases/order-service
cd /opt/releases/order-service
curl -O "http://127.0.0.1:8081/repository/maven-releases/com/example/order-service/1.2.3/order-service-1.2.3-102.jar"
curl -O "http://127.0.0.1:8081/repository/maven-releases/com/example/order-service/1.2.3/order-service-1.2.3-102.jar.sha256"
# 校验
sha256sum -c order-service-1.2.3-102.jar.sha256
# 预期:order-service-1.2.3-102.jar: OK
Jenkins Pipeline 示例(含制品与元数据)#
pipeline {
agent any
environment {
APP_NAME = "order-service"
VERSION = "1.2.3"
BUILD_NO = "${env.BUILD_NUMBER}"
NEXUS_URL = "http://127.0.0.1:8081"
REPO = "maven-releases"
}
stages {
stage('Build') {
steps {
sh '''
mkdir -p dist
echo "hello" > dist/${APP_NAME}-${VERSION}-${BUILD_NO}.jar
'''
}
}
stage('Build-Info') {
steps {
sh '''
cat > dist/build-info.json <<EOF
{
"project": "${APP_NAME}",
"version": "${VERSION}",
"buildNumber": "${BUILD_NO}",
"gitCommit": "$(git rev-parse HEAD)",
"gitBranch": "$(git rev-parse --abbrev-ref HEAD)",
"buildTime": "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
}
EOF
'''
}
}
stage('Upload') {
steps {
withCredentials([usernamePassword(credentialsId: 'nexus-cred', usernameVariable: 'U', passwordVariable: 'P')]) {
sh '''
curl -u $U:$P --upload-file dist/${APP_NAME}-${VERSION}-${BUILD_NO}.jar \
${NEXUS_URL}/repository/${REPO}/com/example/${APP_NAME}/${VERSION}/${APP_NAME}-${VERSION}-${BUILD_NO}.jar
curl -u $U:$P --upload-file dist/build-info.json \
${NEXUS_URL}/repository/${REPO}/com/example/${APP_NAME}/${VERSION}/build-info-${BUILD_NO}.json
'''
}
}
}
}
}
安全与合规(示例)#
GPG 签名与校验
# 生成签名
gpg --batch --yes --detach-sign --armor dist/order-service-1.2.3-102.jar
# 校验签名
gpg --verify dist/order-service-1.2.3-102.jar.asc dist/order-service-1.2.3-102.jar
常见排错与诊断#
1) 上传 401/403
# 检查权限与凭据
curl -u admin:YOUR_PASS http://127.0.0.1:8081/service/rest/v1/status
# 预期:返回运行状态 JSON
2) 制品被覆盖
# 仓库 writePolicy 应为 ALLOW_ONCE(禁止覆盖)
curl -u admin:YOUR_PASS http://127.0.0.1:8081/service/rest/v1/repositories/maven/hosted/maven-releases
3) 校验失败
# 重新生成与比对
sha256sum dist/order-service-1.2.3-102.jar
cat dist/order-service-1.2.3-102.jar.sha256
4) Jenkins 构建号与版本不一致
# 检查 Pipeline 环境变量
echo $BUILD_NUMBER
# 预期:与制品命名中的构建号一致
练习#
- 在本地安装 Nexus,创建
maven-snapshots与maven-releases仓库并验证上传/下载。 - 使用 Git Tag 触发 Jenkins 发布构建,并在 Nexus 中找到对应版本制品与 build-info。
- 将制品校验加入 Pipeline,失败时阻断发布。
- 模拟上传重复版本,验证仓库拒绝覆盖策略是否生效。