KubeSphere DevOps 3.0 流水线运维指南

2023年 1月 4日 76.5k 0

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

1. Kubernetes 问题排查

1.1 基本的创建流程

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

  • kubectl 根据用户输入的命令,填充相关字段,将 deployment/pvc 对象发送给 kube-apiserver
  • kube-apiserver 会有一系列的权限/准入控制,最终将数据序列化存储在 etcd 中
  • kube-controller-manager 包含大量的控制器,这些控制器会生成 replicaset/pod 对象存储在 etcd 中。pvc 需要绑定到 pv 上,如果没有满足要求的 pv,则通过 Storage Class 动态创建一个 pv 。
  • kube-sheduler 负责给 pod 选择运行的 node 节点,然后将 NodeName 字段写入 pod 对象中。
  • kubelet 发现当前 node 节点有待创建的 pod,然后开始调用 CRI 接口去管理 pod 的生命周期。如果有 pvc,还需要将远程磁盘挂载到宿主机目录。
  • 了解基本的创建流程,有利于排查各种可能的故障。故障可以理解为集群生命周期中的一个状态,而创建是整个生命周期的起点。同时,重置、重启是非常快速地解决问题的方法,都涉及创建。

    1.2 解决集群故障的思路

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

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

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

    • apiVersion 版本不支持
    • namespace 没有提前创建
    • yaml 本身有问题
    • 凭证有问题
    • 创建的凭证和使用的凭证 ID 不一致

    可以在节点上直接执行 kubectl apply 进行验证。怀疑凭证有问题时,可以直接使用 admin 的凭证,进行确认。如果是 EKS 集群,请参考 https://github.com/kubesphere/community/issues/165 单独生成凭证。EKS 上使用 DevOps 进行部署,需要的是 token 类型的凭证,证书类型的凭证没有足够的权限。简单点,可以直接使用 kubectl -n kubesphere-system get secret kubesphere-token-xxx -o jsonpath={.data.token} | base64 -d 拿到 token,替换至 kubeconfig 。

    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 再试一次就行。

    3.9 图形化编辑时,报错 至少需要一个嵌套步骤

    API 提示报错 instance failed to match at least one schema 。流水线部分,前端页面图形化与后端数据模型是通过 pipeline-model-api 插件相互转换的。具体接口是 /tojson/tojenkinsfile ,前端编辑的是 json ,后端需要的是 jenkinsfile 。例如,下面这个示例:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    
    pipeline {
      agent any
      stages {
          stage ('Hello') {
              steps {
                  echo "Hello"
              }
          }
      }
    }
    

    将被转换为如下内容:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    
    "pipeline":{
      "stages": [
        {
        "branches": [
          {
          "name": "default",
          "steps": [
            {
            "arguments": [
              {
              "key": "message",
              "value": {
                "isLiteral": true,
                "value": "Hello"
              }
              }
            ],
            "name": "echo"
            }
          ]
          }
        ],
        "name": "Hello"
        }
      ],
      "agent": {
        "type": "any"
      },
      "parameters": {}
    }
    

    json 格式的流水线对前端十分友好,scheme 非常简单,极大降低实现图形化编辑的难度。转换失败时,页面会展示错误提示。如果返回错误提示为空,那么页面会展示 当前 Jenkinsfile 不是标准的声明式 Jenkinsfile,无法进行图形化显示 。前端只覆盖了常见的几种情况,提示不是十分准确,例如,当 defaultValue 为空字符串时,提示 至少需要一个嵌套步骤 ,不知所云。最好能够直接参考 /tojson 接口的返回进行处理。

    3.10 构建镜像时,无法访问外部服务,报错 timeout

    在 Jenkinsfile 中执行 docker build 命令时,由于是 Docker in Docker 网络,使用的是 Node 节点上的 Docker Daemon 进行构建。看着是动态创建的 Pod 无法访问外网,其实是 Node 节点无法访问指定外部服务。这很有可能是,对网络要求严格的运行环境,禁止了主机访问外网所致。使用 iptables 命令,添加白名单即可。

    3.11 升级时,PVC 报错

    常见的两种报错提示是 The PersistentVolumeClaim "pvc1" is invalid: spec: Forbidden: is immutable after creation except resources.requests for bound claimsError: UPGRADE FAILED: cannot patch "mysql" with kind PersistentVolumeClaim: persistentvolumeclaims "mysql" is forbidden: only dynamically provisioned pvc can be resized and the storageclass that provisions the pvc must support resize 。报错原因是 StorageClass 不支持动态扩容,需要保持升级前后 PVC 容量一致。在升级之前,可以通过 describe 命令检查 StorageClass 是否支持动态扩容。如果 AllowVolumeExpansion 被设置,则代表支持;否则不支持。

    3.12 安装不兼容的插件之后,Jenkins 无法启动

    处理办法是进入 Jenkins 运行的 Pod,删掉不兼容的插件。首先 exec 进入 Pod

    1
    
    kubectl -n kubesphere-devops-system exec -it ks-jenkins-xxx bash
    

    然后进入 /var/jenkins_home/plugins 目录,删掉 Jenkins Pod 日志中提到的引发错误的插件。如果你安装了大量的插件,这里有一个技巧是按照日期删除。有时候,插件之间具有复杂依赖,还有一个救急的方式是直接清空 /var/jenkins_home/plugins ,Jenkins 会根据 /var/jenkins_home/plugins.txt 从 UC 中下载插件,恢复至初始状态。

    3.13 修改鉴权策略之后,无法登陆

    处理办法是进入 Jenkins 运行的 Pod,将 useSecurity 改为 false,登陆之后改回原来的值。useSecurity 在 /var/jenkins_home/config.xml 中进行配置。

    3.14 Jenkins 找不到用户,LDAP 报错(重置密码)

    提示信息类似:

    1
    2
    
    org.acegisecurity.userdetails.UsernameNotFoundException: User admin not found in directory.
    at hudson.security.LDAPSecurityRealm$LDAPUserDetailsService.loadUserByUsername(LDAPSecurityRealm.java:1314)
    

    Jenkins 用户来源于 OpenLdap 组件,报错信息的含义是在 OpenLdap 组件中找不到 admin 用户。解决这个问题,需要检查两个地方:OpenLdap 组件是否异常、admin 用户是否在 OpenLdap 中。然后,修复组件,重新创建 admin 用户。重建方法从代码 https://github.com/kubesphere/kubesphere/blob/release-3.0/pkg/controller/user/user_controller.go#L537 中可以发现,需要编辑 admin 用户的加密注解。执行命令 kubectl patch users admin --type merge --patch '{"spec":{"password":"[email protected]"}, "metadata":{"annotations":{"iam.kubesphere.io/password-encrypted":"false"}}}' 将 admin 用户登陆密码重置为默认值,触发同步逻辑。此条命令也可以用于重置密码。

    3.15 流水线创建之后,在页面查看不到

    在 3.0.0 中,采用 CRD 对 DevOps 工程和 Pipeline 进行管理,最终同步到 Jenkins 中。流水线创建之后,在页面无法查看到,是没有完成同步。没有完成同步的可能性很多,ks-controller-manager 中的日志将会帮到你。可能是节点之间的网络通信问题,也有可能是 Jenkins 服务发生了异常,需要根据错误日志排查。

    3.16 找不到 Docker 命令

    首先得了解 Jenkins 创建 Agent 运行流水线的过程:

  • agent 模板中, 需要挂载 docker.socket 文件
  • 运行流水线时, Jenkins 通 label 选中一个 agent
  • Kubernetes 会以 agent 的配置作为模板,创建一个 Pod
  • 执行 docker 时,需要在 container 包裹下执行(否则使用默认容器 jnlp)
  • 如果执行流水线时,提示找不到 Docker 命令,那么可能是使用了 jnlp 容器。请检查步骤 4, 选中一个包含 docker 命令,并挂载了 docker.socket 的容器。

    相关文章

    KubeSphere 部署向量数据库 Milvus 实战指南
    探索 Kubernetes 持久化存储之 Longhorn 初窥门径
    征服 Docker 镜像访问限制!KubeSphere v3.4.1 成功部署全攻略
    那些年在 Terraform 上吃到的糖和踩过的坑
    无需 Kubernetes 测试 Kubernetes 网络实现
    Kubernetes v1.31 中的移除和主要变更

    发布评论