DevOps 入门系列 :CI_CD 故障排查与容器运维核心原理
CI/CD 故障排查与容器运维核心原理
1.1 容器核心机制:PID1 与退出码
1.1.1 什么是 PID1?
在 Linux 系统中,所有进程拥有唯一进程编号(PID),PID1 是操作系统初始化第一个进程,负责收养孤儿进程、统一处理系统信号。
在 Docker 容器运行环境中:PID1 = Dockerfile 内 CMD/ENTRYPOINT 定义的启动进程。
运行规则
容器生命周期完全依附 PID1:PID1 持续运行 → 容器存活;PID1 执行结束 / 异常崩溃 → 容器立刻销毁。
容器启动
│
▼
启动 PID1(如 python app.py)
│
├── 如果 PID1 持续运行 → 容器活着
│
└── 如果 PID1 执行完毕或崩溃 → 容器停止
1.1.2 为什么容器一启动就退出?
高频故障原因
-
启动进程为一次性任务:进程执行完毕无驻留逻辑,运行结束直接退出
-
应用启动异常:依赖缺失、端口占用、配置文件丢失导致程序崩溃
-
Shell 包装启动命令:
sh -c执行单次指令,命令结束后 PID1 消亡
代码示例
❌ 错误写法(执行完立即退出)
CMD ["echo", "Hello"]
✅ 正确写法(前台常驻进程)
CMD ["python", "-u", "app.py"]
补充:Flask 项目需在代码内配置
app.run(host='0.0.0.0')保持前台运行;Nginx 官方镜像默认前台运行,无需额外改造。
1.1.3 退出码的含义
执行 docker ps -a 可查看容器退出状态,通过退出码快速分类故障:
| 退出码 | 含义 | 常见场景 |
|---|---|---|
| 0 | 正常退出 | 批处理脚本执行完成;docker stop 停机 |
| 1 | 运行异常 | 依赖缺失、端口冲突、代码语法错误 |
| 137 | 进程被 SIGKILL 强制杀死 | 容器内存溢出 OOM;手动执行 docker kill |
| 143 | 进程被 SIGTERM 终止 | 正常执行 docker stop 停止容器 |
排查要点
-
Exited (1):优先通过docker logs查看应用报错日志 -
Exited (137):核查容器内存配额,排查 OOM 问题 -
Exited (0)但预期常驻:启动命令为一次性任务,修改 CMD 为常驻进程
1.2 --restart 策略:容器崩溃后自动恢复
1.2.1 策略详解
--restart 用于定义容器退出后的自动重启逻辑,共 4 种配置:
| 策略 | 行为 | 适用场景 |
|---|---|---|
| no(默认) | 容器退出后永不自动重启 | 一次性批处理、数据库迁移脚本 |
| always | 无论退出码,永久自动重启 | 核心基础中间件服务 |
| unless-stopped | 除手动docker stop外,异常退出自动重启 |
生产业务容器(生产推荐) |
| on-failure[:max-retries] | 仅非 0 退出码时重启,可限制重试次数 | 间歇性故障测试任务 |
启动示例
docker run -d --name myapp --restart=unless-stopped myapp:latest
注意事项:
always策略下,服务器重启 / Docker 守护进程重启后容器会自动拉起;unless-stopped手动停机后不会随 Docker 重启自启,更贴合运维习惯。
1.2.2 在 CI 部署中怎么用?
在流水线部署脚本的 docker run 追加重启参数:
docker run -d --name myapp --restart=unless-stopped -p 5000:5000 myapp:ci-123
补充:若容器陷入无限重启循环,说明应用存在根本性代码 BUG,需查看日志定位根源。
1.3 部署假阳性:流水线绿了,但服务不可用
1.3.1 现象描述
CI/CD Job 执行返回 0、流水线状态 Passed(绿色),但业务访问返回 502 / 连接失败。
故障诱因
-
docker run命令执行成功(返回码 0),但容器内部应用启动失败 -
应用启动耗时长(数据库连接、配置加载),部署完成后未就绪
-
服务器防火墙 / 安全组未放行容器映射端口
1.3.2 解决方案:部署后健康检查
在部署阶段脚本新增应用端口健康探测,探测失败主动让 Job 异常退出,流水线标红阻断发布。
# 最多等待10秒,每2秒探测一次,共探测5次
for i in 1 2 3 4 5; do
if curl -s http://localhost:5000/health > /dev/null; then
echo "应用启动成功"
exit 0
fi
echo "等待应用启动... ($i/5)"
sleep 2
done
echo "健康检查失败"
exit 1
配置要点
-
业务代码需实现
/health健康接口,正常状态返回 HTTP 200 -
应用冷启动耗时过长可增大循环次数或 sleep 间隔
-
探测失败执行
exit 1,让部署 Job 失败,避免无效上线
1.4 容器排错三板斧
容器异常(启动失败、循环重启、网络不通)优先使用以下三条命令逐层排查。
第一斧:docker ps -a 查看全量容器状态
docker ps -a
状态识别:
-
Up X minutes:容器正常运行 -
Exited (数字):容器异常退出,结合退出码 + 日志排错 -
Restarting (数字):容器持续循环重启,应用启动失败
第二斧:docker logs [容器名/ID] 查看标准输出 & 错误日志
# 查看全量日志
docker logs myapp
# 只查看末尾100行日志
docker logs --tail 100 myapp
# 实时滚动跟踪日志
docker logs -f myapp
示例报错:
ModuleNotFoundError: No module named 'flask'→ 项目依赖缺失,构建镜像阶段未安装依赖。
第三斧:docker inspect 读取容器结构化详情(JSON)
支持格式化输出关键字段,常用于 CI 自动化校验:
# 查询容器运行状态
docker inspect myapp --format='{{.State.Status}}'
# 查询容器退出码
docker inspect myapp --format='{{.State.ExitCode}}'
可拓展查询:端口映射、挂载目录、容器环境变量、网络配置等信息。
1.5 GitLab CI 变量安全机制
1.5.1 明文密码写入 yml 的安全隐患
❌ 高危错误写法(密钥硬编码进配置文件,仓库可见人员均可窃取密码)
script:
- docker login -u myuser -p mypassword registry.com
1.5.2 解决方案:GitLab CI/CD 项目变量配置
配置路径:项目 → Settings → CI/CD → Variables → Add variable
-
Key:自定义变量名(如
ALIYUN_PASSWORD) -
Value:填写真实密钥、密码
-
Mask variable(掩码变量):日志中自动将原值替换为
[MASKED] -
Protect variable(受保护变量):仅受保护分支可读取变量
使用方式:.gitlab-ci.yml脚本中直接引用$ALIYUN_PASSWORD。
1.5.3 掩码变量使用注意事项
-
掩码仅全值匹配隐藏:密码
abc123完整出现才会脱敏,片段abc不会被掩码 -
掩码变量不可在
variables:区块嵌套拼接生成新变量,避免密钥泄漏 -
禁止将变量拼接至 URL 参数、日志输出字符串
1.5.4 受保护变量配置规范
-
路径:
Settings → Repository → Protected branches,将生产分支(main/master)设置为受保护分支 -
生产密钥勾选
Protect variable,dev/feature 等非生产分支流水线无法读取密钥 -
隔离测试环境与生产环境密钥,避免测试分支误触发生产部署
1.6 常见 CI/CD 故障场景与排查思路
| 故障症状 | 可能原因 | 排查步骤 |
|---|---|---|
| 流水线任务 Pending 阻塞 | 无可用运行中的 GitLab Runner | 项目 CI/CD 配置核对,绑定可用共享 / 私有 Runner |
| 脚本报错:docker: command not found | Job 运行镜像不含 Docker 客户端 | 配置image: docker:24.0.7,启用 DinD 容器架构 |
| 拉镜像 / 安装依赖报 dial tcp: i/o timeout | 构建环境外网网络超时 | 配置 Docker 国内镜像加速器、切换国内 Pip/Yum 源 |
| 本地代码测试正常,CI 测试 Job 报错 | 环境依赖 / 版本不一致 | before_script 中打印 Python/JDK 版本、依赖清单对比 |
| 部署后容器不停重启 | 应用内部启动异常 | docker logs查看程序报错,核对端口、配置文件 |
| 版本回滚提示 No previous version | 旧版本信息落地失败 | 检查部署后置 after_script 执行状态、服务器目录读写权限 |
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐


所有评论(0)