文章章节
前言
背景问题分析
一、整体架构设计
1.1 核心组件
1.2 部署流程总览
二、Jenkins集成方案
2.1 Jenkins Pipeline配置
2.2 Jenkins凭证配置
三、核心脚本详解
3.1 ai_cice.sh – 主部署流程
3.2 start.sh – 智能启动与增量构建
3.3 cleanup_docker.sh – 资源清理
四、零宕机部署原理
4.1 容器切换
4.2 回滚机制
五、磁盘空间管理
5.1 监控告警
5.2 清理策略
六、实践建议
6.1 Dockerfile健康检查配置
6.2 Jenkins定时清理
6.3 镜像版本管理
6.4 日志管理
七、常见的故障排查手段
7.1 常见问题
7.2 监控指标
八、总结
前言
在如今各种项目快速迭代中,服务的持续部署是日常运维的核心工作。如何在保证服务不中断的前提下完成新版本的发布,是每个负责环境维护的同学都会面对到的挑战。本文将详细介绍一套完全独立的零宕机部署方案,通过Jenkins触发部署脚本,实现从代码拉取、容器构建、平滑切换到资源清理的全流程自动化。
背景问题分析
原始问题:
- /dev/vda1 使用率99% (50G/50G),空间紧张
- /dev/vdb 仅使用4% (3.2G/99G),浪费严重
- 部署后历史镜像和容器未清理
- 部署过程会导致服务中断
根本原因:
- 项目部署在 /home/user/ai,占用根分区
- 缺少自动清理机制
- 部署流程先停止旧容器再启动新容器
- Docker数据可能也在根分区
因在项目初期,只为了能支持jenkins部署,快速搭建了部署流程,并没有针对性考虑其他优化或体验的问题,所以在部署项目的过程中,常常遇到以上问题,就想着重新设计一下部署流程,故输出以下方案:
一、整体架构设计
1.1 核心组件
本方案涉及四个核心脚本,各司其职:
ai_cicd.sh:主部署脚本,负责代码拉取、镜像构建和容器启动
start.sh:智能启动脚本,支持增量构建和零宕机切换
cleanup_docker.sh:资源清理脚本,定期清理冗余镜像和容器
check_disk_space.sh:磁盘监控脚本,预防存储空间不足
1.2 部署流程总览
二、Jenkins集成方案
2.1 Jenkins Pipeline配置
在Jenkins中创建Pipeline任务,配置如下:
pipeline {
agent any
parameters {
choice(name:'PROJECT_NAME',
choices: [‘ai_xxx_analysis’, ‘qa_xxx_server’, ‘ai_xxx’],
description:’选择要部署的项目’)
choice(name:’BRANCH’,
choices: [‘main’, ‘develop’, ‘test’],
description:’选择要部署的分支’)
booleanParam(name:’CHECK_DISK’,
defaultValue:true,
description:’部署前检查磁盘空间’)
}
stages {
stage('磁盘空间检查') {
when {
expression { params.CHECK_DISK }
}
steps {
script {
sh '''
cd /opt/ai
bash check_disk_space.sh
'''
}
}
}
stage('执行部署') {
steps {
script {
sh """
cd /opt/ai
bash ai_cicd.sh ${params.PROJECT_NAME} ${params.BRANCH}
"""
}
}
}
stage('验证部署') {
steps {
script {
// 等待服务启动
sleep 10
// 健康检查
def containerName = params.PROJECT_NAME.replace(‘-‘, ‘_’)
sh “””
docker ps -f name=${containerName} –format ‘{{.Status}}’ | grep ‘Up’
“””
}
}
}
}
post {
success {
echo "✅ 部署成功!项目: ${params.PROJECT_NAME}, 分支: ${params.BRANCH}"
}
failure {
echo "❌ 部署失败,请检查日志"
}
}
}
2.2 Jenkins凭证配置
确保Jenkins有足够的权限:
Docker权限:将jenkins用户加入docker组
目录权限:确保/opt/ai目录对jenkins可读写
Git凭证:配置Git仓库的访问凭证
三、核心脚本详解
3.1 ai_cicd.sh – 主部署流程
关键代码逻辑:
1. 代码拉取
git fetch –all
git reset –hard origin/$BRANCH
git pull origin $BRANCH
2. 构建新镜像(使用时间戳版本)
VERSION_TAG=$(date +%Y%m%d_%H%M%S)
NEW_IMAGE_NAME=”${PROJECT_NAME}:${VERSION_TAG}”
docker build -t $NEW_IMAGE_NAME -t ${PROJECT_NAME}:latest .
3. 零宕机切换
OLD_CONTAINER_ID=$(docker ps -q -f name=$CONTAINER_NAME)
if [ -n “$OLD_CONTAINER_ID” ]; then
docker stop $CONTAINER_NAME# 停止旧容器释放端口
fi
4. 启动新容器
docker run -d –name $CONTAINER_NAME –network host $NEW_IMAGE_NAME
5. 健康检查
MAX_WAIT=60
while [ $WAITED -lt $MAX_WAIT ]; do
HEALTH_STATUS=$(docker inspect –format='{{.State.Health.Status}}’$CONTAINER_NAME)
if [ “$HEALTH_STATUS” = “healthy” ]; then
docker rm$OLD_CONTAINER_ID# 删除旧容器
break
fi
done
6. 调度清理任务
(sleep 60 && bash cleanup_docker.sh $PROJECT_NAME) &
3.2 start.sh – 智能启动与增量构建
增量构建优化:
检查是否需要构建
check_build_needed() {
1. 检查镜像是否存在
if [ -z “$(docker images -q $IMAGE_NAME)” ]; then
echo”true:true:镜像不存在”
return
fi
2. 检查requirements.txt变化(强制重建)
current_req_hash=$(md5sum requirements.txt | cut -d' ' -f1)
if [ “$(cat $LAST_REQ_HASH_FILE)” != “$current_req_hash” ]; then
echo”true:true:依赖文件有变更”
return
fi
3. 检查代码变化(增量构建)
current_commit=$(git rev-parse HEAD)
if [ “$(cat $LAST_COMMIT_FILE)” != “$current_commit” ]; then
echo”true:false:代码有变更”
return
fi
echo”false:false:无需构建”
}
零宕机切换策略:
1. 记录旧容器
OLD_CONTAINER_ID=$(docker ps -q -f name=$CONTAINER_NAME)
2. 使用临时端口启动新容器
if [ -n “$OLD_CONTAINER_ID” ]; then
TEMP_PORT=$((HOST_PORT + 1)) # 端口+1
docker run -d –name ${CONTAINER_NAME}_new -p $TEMP_PORT:$PORT$NEW_IMAGE
fi
3. 健康检查通过后
if [ “$health_status” = “healthy” ]; then
docker stop $CONTAINER_NAME# 停止旧容器
docker rm${CONTAINER_NAME}_new # 删除临时容器
4. 使用正确端口重启
docker run -d --name $CONTAINER_NAME -p $HOST_PORT:$PORT$NEW_IMAGE
fi
最终部署效果:
……
14 3.408 [notice] A new release of pip is available: 25.0.1 -> 25.3
14 3.408 [notice] To update, run: pip install –upgrade pip
14 DONE 3.5s
15 exporting to image
15 exporting layers
15 exporting layers 4.2s done
15 preparing layers for inline cache 0.1s done
15 writing image sha256:d1e29bbf5e12da9aca860155083xxxxxxxxxxxxxxx done
15 naming to docker.io/library/ai_xxx:20251230_154637 0.1s done
15 naming to docker.io/library/ai_xxx:latest done
15 DONE 4.4s
镜像构建成功: ai_xxx:20251230_154637
清理 Docker 资源…
清理构建缓存…
✓ 构建缓存已清理(保留24小时内)
✓ Docker 资源清理完成
启动新容器: ai_xxx (端口: 5000)
8195b6b53e06186ef74bb93b8149xxxxxxxxx
等待容器启动…
等待服务就绪…
⏳ 等待 Gunicorn 启动… (已等待 3s / 最多 120s)
执行部署后清理…
当前 Docker 资源使用:
TYPE TOTAL SIZE RECLAIMABLE
Images 1 2.74GB 0B (0%)
Containers 1 0B 0B
Local Volumes 0 0B 0B
Build Cache 16 2.602GB 2.602GB
=========================================
部署成功!
服务地址: http://0.0.0.0:5000
容器名称: ai_xxx
容器IP: 1xx.1x.0.2
健康状态: healthy
镜像版本: ai_xxx:20251230_154637
容器已在后台运行,可以使用以下命令查看日志:
docker logs -f ai_xxx
要停止服务,请使用:
docker stop ai_xxx
调度自动清理任务(60秒后执行)…
✓ 清理任务已调度
3.3 cleanup_docker.sh – 资源清理
清理策略配置:
使用方法
bash cleanup_docker.sh ai_xxx –keep-images 3
bash cleanup_docker.sh –aggressive # 激进模式
bash cleanup_docker.sh –dry-run # 预览模式
核心清理逻辑
1. 按时间排序,保留最新N个版本
ALL_IMAGES=$(docker images –format “{{.ID}}|{{.CreatedAt}}” |
grep “$PROJECT_NAME” |
grep -v “latest” |
sort -t’|’ -k2 -r)
OLD_IMAGES=$(echo”$ALL_IMAGES” | tail -n +$((KEEP_IMAGES + 1)))
2. 清理旧版本
for IMAGE_ID in$OLD_IMAGES; do
docker rmi -f $IMAGE_ID
done
3. 清理7天前的日志
find logs/ -name “.log.” -mtime +7 -delete
四、零宕机部署原理
4.1 容器切换
4.2 回滚机制
健康检查失败时自动回滚
if [ “$HEALTH_STATUS” = “unhealthy” ]; then
echo”新容器健康检查失败,开始回滚…”
1. 停止并删除新容器
docker stop $TEMP_CONTAINER_NAME
docker rm$TEMP_CONTAINER_NAME
2. 重启旧容器(如果还在)
if [ -n “$OLD_CONTAINER_ID” ]; then
docker start $OLD_CONTAINER_ID
echo”已回滚到旧版本”
fi
exit 1
fi
五、磁盘空间管理
5.1 监控告警
check_disk_space.sh 关键逻辑
WARNING_THRESHOLD=70 # 警告阈值
CRITICAL_THRESHOLD=85 # 严重告警阈值
VDA1_USAGE=$(df -h | grep ‘/dev/vda1’ | awk ‘{print $5}’ | sed ‘s/%//’)
if [ “$VDA1_USAGE” -ge “$CRITICAL_THRESHOLD” ]; then
echo”❌ 严重警告: 磁盘使用率 ${VDA1_USAGE}%”
可以在这里集成告警通知(钉钉、邮件等)
exit 1
fi
5.2 清理策略
资源类型
清理条件
保留策略
停止的容器
status=exited
全部清理
旧镜像版本
非latest标签
保留最新1个
悬空镜像
dangling=true
全部清理
日志文件
.log.
保留7天
构建缓存
普通模式
保留24小时
Python缓存
pycache
全部清理
六、实践建议
6.1 Dockerfile健康检查配置
HEALTHCHECK –interval=5s –timeout=3s –start-period=30s –retries=10 \
CMD curl -f http://localhost:${PORT}/health || exit 1
6.2 Jenkins定时清理
在Jenkins中配置定时任务:
// 每天凌晨2点执行清理
pipeline {
triggers {
cron(‘0 2 * * *’)
}
stages {
stage('Docker资源清理') {
steps {
sh 'bash /opt/ai/cleanup_docker.sh --keep-images 2'
}
}
stage('磁盘空间检查') {
steps {
sh 'bash /opt/ai/check_disk_space.sh'
}
}
}
}
6.3 镜像版本管理
使用语义化版本标签
VERSION_TAG=$(date +%Y%m%d_%H%M%S) # 时间戳版本
或者使用Git commit
VERSION_TAG=$(git rev-parse –short HEAD)
同时打上多个标签
docker build \
-t ${PROJECT_NAME}:${VERSION_TAG} \
-t ${PROJECT_NAME}:latest \
-t ${PROJECT_NAME}:${BRANCH} \
.
6.4 日志管理
限制Docker容器日志大小
docker run \
–log-opt max-size=100m \
–log-opt max-file=3 \
$IMAGE_NAME
定期清理历史日志
find /opt/ai//logs -name “.log.*” -mtime +7 -delete
七、常见的故障排查手段
7.1 常见问题
- 端口被占用
检查端口占用
lsof -i :5000
强制清理
docker stop $(docker ps -q -f name=ai_xxx)
- 磁盘空间不足
紧急清理
docker system prune -a -f
bash cleanup_docker.sh –aggressive
- 健康检查失败
查看容器日志
docker logs –tail 100 $CONTAINER_NAME
进入容器排查
docker exec -it $CONTAINER_NAME bash
7.2 监控指标
建议在Jenkins中集成以下监控:
部署成功率
部署耗时
磁盘使用率趋势
容器健康状态
镜像数量变化
八、总结
通过四个核心脚本的协同工作,实现了完整的自动化部署流程:
ai_cicd.sh
作为主入口,协调整个部署流程
start.sh
提供智能的增量构建和零宕机切换
cleanup_docker.sh
确保磁盘空间不会耗尽
check_disk_space.sh
提供预警机制
核心实现:
✅ 零宕机:临时端口验证后再切换
✅ 自动回滚:健康检查失败自动恢复
✅ 增量构建:智能检测变更,节省构建时间
✅ 资源清理:自动清理冗余资源,防止磁盘爆满
✅ 易于集成:Jenkins Pipeline即可接入
通过这套方案,可以实现从代码提交到服务上线的全流程自动化,提高了部署效率和系统可靠性。
以上为个人的经验总结,还达不到专业运维的全流水线的部署操作,但若是运用于个人项目或都独立环境的部署,是完全足够的,主要解决的目标就是要快且稳!
作者简介:庄锦弟,主要负责测试平台基建
声明:来自转转QA,仅代表创作者观点。链接:http://eyangzhen.com/5089.html