目录

    本篇主要介绍如何运维 DevOps 流水线,怎么解决一些常见的问题。问题主要分为两大类,一类是 Kubernetes 相关的,具有一定通用性;另一类是与业务相关,需要对领域有所了解,解决问题时才能事半功倍。文档内容,会不断滚动更新。

    1. Kubernetes 问题排查

    1.1 基本的创建流程

    如上图所示,是用户创建一个 Deployment 的简单流程。主要分为以下步骤:

    1. kubectl 根据用户输入的命令,填充相关字段,将 deployment/pvc 对象发送给 kube-apiserver
    2. kube-apiserver 会有一系列的权限/准入控制,最终将数据序列化存储在 etcd 中
    3. kube-controller-manager 包含大量的控制器,这些控制器会生成 replicaset/pod 对象存储在 etcd 中。pvc 需要绑定到 pv 上,如果没有满足要求的 pv,则通过 Storage Class 动态创建一个 pv 。
    4. kube-sheduler 负责给 pod 选择运行的 node 节点,然后将 NodeName 字段写入 pod 对象中。
    5. kubelet 发现当前 node 节点有待创建的 pod,然后开始调用 CRI 接口去管理 pod 的生命周期。如果有 pvc,还需要将远程磁盘挂载到宿主机目录。

    了解基本的创建流程,有利于排查各种可能的故障。故障可以理解为集群生命周期中的一个状态,而创建是整个生命周期的起点。同时,重置、重启都是非常快速地解决问题的方法,都涉及创建。

    1.2 解决集群故障的思路

    如上图所示,是我的集群故障修复思路。主要分为以下步骤:

    1. kubectl get 检查 node、pod 等资源是否符合预期
    2. kubectl describe 查看 Kubernetes 中的事件信息,包括 kube-sheduler 的调度、拉取镜像、启动是否成功等。通常能解决大部分的问题。
    3. kubectl logs 查看负载的日志。当 pod 处于 running,但是又无法正常提供服务时,logs 信息能够给出有用的提示。有时无法查看 pod 中容器的日志,那么需要去 pod 所在的节点查看 docker 的日志。journal 通过 -u 参数指定服务,通过 -f 查看滚动的最新日志,也十分有用。
    4. 如果上面两种思路还不能解决问题,那么恭喜你,又有机会提高自己了。检查底层服务,也就是检查集群的基础环境,包括磁盘、允许的协议、允许的端口、防火墙、网络等。最终能不能解决,取决于你的积累和检索问题答案的能力。

    1.3 必要的检查项

    这里列举一些必要的检查项,可以辅助排查问题。

    • node 负载

    node 负载过高时,有可能导致节点 NotReady。

    • node 磁盘

    磁盘包括两部分,大小和 inode。

    • swap、firewall

    安装集群时的配置,在重启机器之后,可能会失效。

    • 跨 node 的 pod 通信

    跨节点通信异常时,会导致服务无法访问。

    • node 节点上 kubelet、docker 的状态

    systemctl status kubeletsystemctl status docker 查看组件的状态。

    • 检查 kubelet 、docker 的配置

    ps aux|grep kubeletdocker info 查看相关配置是否符合预期。

    • 查看存储 CSI 存储插件日志

    通常 StorageClass 是通过 CSI 插件提供存储服务的,可以查看相关日志,检查是否有异常输出。

    • 检查 ip 转发功能

    执行命令 cat /proc/sys/net/ipv4/ip_forward ,如果输出 0 则表示未开启。ip 转发允许将一个端口的包转发到另外一个端口。未开启时,会导致网络访问失败,tcpdump 中发送了大量 syn 数据包,但是没有 ack 。

    • 检查 Pod CIDR 与主机网段是否冲突

    可以先查看 Pod 的 ip,检查其与主机、VPC 的 ip 是否有重叠。如果发生冲突,将会导致服务不可访问,提示 No route to host 类似的错误,需要修改 CIDR 。

    2. 安装问题

    如上图所示,是 installer 在执行安装 DevOps 时的依赖关系。DevOps 主要有两个核心组件 S2I 和 Jenkins 。S2I 依赖于 minio 存储文件,Jenkins 依赖于 uc 提供插件下载、依赖 openldap 打通账户体系。

    安装时,比较常见的是 minio 安装失败,导致 DevOps 无法继续安装。而 minio 安装失败通常又是存储和网络导致。

    3. Jenkins 运维问题

    3.1 修改默认配置导致异常

    DevOps 允许用户自定义配置,但 Jenkins /configureSecurity/ 页面中鉴权和 CSRF Protection 不要修改。

    修改上图,红色框中的内容,会导致流水线无法使用。

    3.2 大量多分支流水线占满磁盘空间

    多分支流水线扫描时,会将仓库拉取到 /var/jenkins_home/cache 中,查找 jenkinsfile 文件。

    如果大量实践多分支流水线扫描,请将 Jenkins 的 pv 设置大一些,50 GB 以上。

    3.3 Lightweight 问题导致并发流水线冲突

    具体可以参考文档: Jenkins 中 Lightweight 拉取代码问题分析

    3.4 多节点集群,无法创建流水线

    节点之间通信问题,可以将 ks-controller-manager 和 ks-jenkins 调度到一个节点进行验证。

    如果能够创建成功,那么 Pod 的跨节点通信有问题。

    3.5 流水线并发数量少

    调整 ks-jenkins 的 cpu 和 memory 限制,还有 Xms、Xmx 值。

    具体调整可以参考文档: Kubernetes 动态创建 Jenkins Agent 压力测试

    3.6 流水线部署报错 ended with HasError

    Jenkins 的 Kubernetes Deploy 插件提示可读性不是十分友好,可能的原因有:

    • apiVersion 版本不支持
    • yaml 本身有问题
    • 凭证有问题

    可以在节点上直接执行 kubectl apply 进行验证。怀疑凭证有问题时,可以直接使用 admin 的凭证,进行确认。

    3.7 流水线一直 Pending,Kubernetes 无法创建 Pod

    如果流水线无法执行,并且 kubectl -n kubesphere-devops-system get pod 下没有发现为运行流水线新创建的 Pod,那么很有可能是受限于准入控制。

    kube-apiserver 提供了在创建负载时,修改负载相关信息的能力。比如,Istio 通过 webhook 在创建 Pod 时,向其中注入 Sidecar 进行微服务治理。但如果 Istio 组件发生了异常,那么也会导致 Pod 一直等待注入,从而无法创建 Pod 的现象。

    解决办法是,给运行的命名空间加上豁免注入的标签,比如,kubectl label namespace kubesphere-devops-system istio-injection=disabled

    3.8 变量引用不生效或者流水线引用变量报错

    ${env.<ParameterName>}${params.<ParameterName>}${<ParameterName>} 都可以引用变量,也可以用于 Stage 之间传值。在引用变量时,常见的错误是没区分单双引号。单引号并不替换变量,双引号才会替换变量,这与 Shell 一致。

    另外需要注意,作用域。如果提示 groovy.lang.MissingPropertyException: No such property: ,而你又十分确认定义了这个变量,那么很有可能是作用域的问题。只需要带上 envparams 再试一次就行。