kubernetes Pod无法启动问题排查总结

一:问题描述

本周,通过kubernetes搭建企业级jupyterhub服务的时候,遇到个问题:
通过helm部署jupyterhub的时候,hook-image-puller-b8p5p这个pod一直无法启动,反复于 ErrImagePullImagePullBackOff两个状态,如下

[zhanhaitao@master ~]$ kubectl -n jhub get pods
NAME                       READY   STATUS         RESTARTS   AGE
hook-image-awaiter-qpsw6   1/1     Running        0          68s
hook-image-puller-b8p5p    0/1     ErrImagePull   0          68s

 

二:系统环境

centos:7.1版本
k8s 版本:1.13.2
helm 版本:v2.13.1

k8s集群是参考官网的用户手册通过kubeadm完成搭建的,一个master,一个node

jupyterhub的配置文件:
[zhanhaitao@master ~]$ cat config.yaml
proxy:
  secretToken: ebcf616d2ae617e67bf8d5c93c4b131abb25adf5849d68a5be51bc922ef072c7
  https:
    enabled: false

部署命令:
[zhanhaitao@master ~]$ helm upgrade --install jhub jupyterhub/jupyterhub \
>   --namespace jhub  \
>   --version=0.8.2 \
>   --values config.yaml

 

三:问题分析

status=ErrImagePullImageBackOff,通过字面分析,应该是k8s启动pod时候,拉取镜像失败导致。
ImageBackOffk8s中一个镜像相关的常见问题,一般导致的原因主要有如下几个:
1.镜像是本公司的私服镜像
2.镜像写法不对或者版本不对
3.镜像所在仓库无法访问,或者访问超时

3.1 确定具体的问题镜像

下面来分析是上面哪个原先导致,在k8s中,大部分的问题,都能通过logsdescribe两个命令进行分析和定位

[zhanhaitao@master ~]$ kubectl -n jhub logs hook-image-puller-b8p5p
Error from server (BadRequest): container "pause" in pod "hook-image-puller-b8p5p" is waiting to start: trying and failing to pull image

# 通过logs验证了猜测,问题是pull image导致
# 然后通过describe查明问题所在
# 考虑篇幅,仅仅贴出了关键的信息
[zhanhaitao@master ~]$ kubectl -n jhub describe pod hook-image-puller-b8p5p
Containers:
  pause:
    Container ID:
    Image:          gcr.io/google_containers/pause:3.0
    Image ID:
    Port:           <none>
    Host Port:      <none>
    State:          Waiting
      Reason:       ImagePullBackOff
Events:
  Type     Reason            Age                    From                                      Message
  ----     ------            ----                   ----                                      -------
  Warning  Failed            7m24s (x2 over 7m56s)  kubelet, tx-phxmlp-demo-k8s-staging01.mt  Failed to 
  pull image "gcr.io/google_containers/pause:3.0": rpc error: code = Unknown desc = Error response from daemon: 
  Get https://gcr.io/v2/: net/http: request canceled while waiting for connection (Client.Timeout exceeded while awaiting headers)
  
  # 通过上面的信息,明确了是 gcr.io/google_containers/pause:3.0 镜像拉去失败导致

 

3.2 确定镜像失败原因

镜像明确后,接下来就是分析为什么这个镜像会拉取失败,

如果对docker有一定的了解的话,看到gcr.io这个镜像前缀,就知道原因了,中国大概率是无法访问gcr.io相关镜像网站的

但是,这里我认为可能并不是每个人都知道这个先验知识,可能部分同学就是简单的操作官网的手册,参照着部署的,不一定具备相关的理论知识

下面,我们分析,镜像失败的原因,首先,看前缀,可以确定不是私服导致的,其实pause镜像是k8s的底层基础镜像,第三节会简单介绍下

其次,我们的部署配置config.yaml并没有这个镜像,所以这个镜像也不是我们拼写或者版本写错导致,所以,只能是网络问题

# 通过本地pull下,发现确实是网络问题导致
[zhanhaitao@master ~]$ sudo docker pull gcr.io/google_containers/pause:3.0
Error response from daemon: Get https://gcr.io/v2/: net/http: request canceled while waiting for connection 
(Client.Timeout exceeded while awaiting headers)

 

四:问题解决

4.1 pause 镜像简介

k8s中,服务是运行在一个个的Pod中,一个Pod包含一个或多个containercontainer中则根据指定的docker images运行着具体的服务(runtime container可以不是docker,可以是其他容器技术,这里通过docker举例),podk8s的最小调度单位,如下图示意
kubernetes Pod无法启动问题排查总结_第1张图片

k8s通过kubelet这个组件管理着Pod的生命周期,pause正是每个Pod启动时,最开始加载的镜像,用于管理这个Pod的网络和命名空间,官方介绍如下:
The image whose network/ipc namespaces containers in each pod will use. This docker-specific flag only works when container-runtime is set to docker. (default “k8s.gcr.io/pause:3.1”)

正是这个镜像的拉取失败,导致整个Pod无法启动

4.2 解决办法

问题明确,背景知识也了解后,现在就是怎么解决问题了

1. 通用的解决办法

# 对于docker由于网络问题无法拉取的问题,较为通用的解决方法主要是:
# 本地取其他镜像源下载,然后替换名字,如下所示
# 这样拉取镜像的时候,发现本地有需要的镜像,就直接使用本地镜像了,避免去网上再次拉取
sudo docker pull docker.io/mirrorgooglecontainers/pause:3.0
sudo docker tag mirrorgooglecontainers/pause:3.0 gcr.io/google_containers/pause:3.0
# 看下image是否改成需要的名字,已经成功本地创建了一个同名的镜像了
[zhanhaitao@master ~]$ sudo docker images|grep pause
mirrorgooglecontainers/pause                                     3.0                 99e59f495ffa        3 years ago         747kB
gcr.io/google_containers/pause                                   3.0                 99e59f495ffa        3 years ago         747kB

2. 更为优雅的办法

第一个方法很方便,但是是类似补丁式的修复,治标不治本。一般适合小规模的镜像问题,或者日常使用,或者是团队没有维护镜像的私服

更为优雅的方式是通过配置私服的方式,通过配置 imagePullSecrets这个参数,因为我这次不是通过这种方式,就不展开了

具体可以自行Google或者参考:kubernetes troubleshooting

3. 针对pause这个特殊镜像的解决办法

通过前面的pause镜像介绍知道,它是Pod的基础架构镜像,所以还可以通过其他特定的方式进行解决,

我们知道,k8s是通过kubelet进行Pod管理的,kubelet启动参数有一个参数 --pod-infra-container-image 就是用来知道pause镜像名的,将其换成能够获取到的镜像名即可

# 1. 我们通过 ps -ef 先看下 kubelet的启动命令,发现其默认使用的是 k8s.gcr.io/pause:3.1
[zhanhaitao@master ~]$ ps -ef | grep pause
root      8924     1  0 Oct12 ?        00:12:27 /usr/bin/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf 
--kubeconfig=/etc/kubernetes/kubelet.conf --config=/var/lib/kubelet/config.yaml --cgroup-driver=systemd 
--network-plugin=cni --pod-infra-container-image=k8s.gcr.io/pause:3.1

# 2. kubelet是配置成了系统服务,我们看下它的状态信息,发现其配置文件是/etc/systemd/system/kubelet.service.d下的10-kubeadm.conf
[zhanhaitao@master ~]$ systemctl status kubelet
● kubelet.service - kubelet: The Kubernetes Node Agent
   Loaded: loaded (/etc/systemd/system/kubelet.service; enabled; vendor preset: disabled)
  Drop-In: /etc/systemd/system/kubelet.service.d
           └─10-kubeadm.conf
   Active: active (running) since Sat 2019-10-12 11:48:52 CST; 1 day 2h ago
     Docs: https://kubernetes.io/docs/
 Main PID: 8924 (kubelet)
   Memory: 82.3M
   CGroup: /system.slice/kubelet.service
           └─8924 /usr/bin/kubelet --bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/k...
       
# 3. 查看启动配置文件,已经查看里面配置的环境目录,可以找到pause的版本指定在:/var/lib/kubelet/kubeadm-flags.env 中
[zhanhaitao@master kubelet.service.d]$ cat 10-kubeadm.conf
# Note: This dropin only works with kubeadm and kubelet v1.11+
[Service]
Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf"
Environment="KUBELET_CONFIG_ARGS=--config=/var/lib/kubelet/config.yaml"
# This is a file that "kubeadm init" and "kubeadm join" generates at runtime, populating the KUBELET_KUBEADM_ARGS variable dynamically
EnvironmentFile=-/var/lib/kubelet/kubeadm-flags.env
# This is a file that the user can use for overrides of the kubelet args as a last resort. Preferably, the user should use
# the .NodeRegistration.KubeletExtraArgs object in the configuration files instead. KUBELET_EXTRA_ARGS should be sourced from this file.
EnvironmentFile=-/etc/sysconfig/kubelet
ExecStart=
ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KUBEADM_ARGS $KUBELET_EXTRA_ARGS

# 4. 将pause镜像改为指定的版本
[zhanhaitao@master kubelet.service.d]$ sudo cat /var/lib/kubelet/kubeadm-flags.env
KUBELET_KUBEADM_ARGS=--cgroup-driver=systemd --network-plugin=cni --pod-infra-container-image=docker.io/mirrorgooglecontainers/pause:3.1

# 5. kubelet服务重启
[zhanhaitao@master kubelet.service.d]$ sudo systemctl restart kubelet.service

你可能感兴趣的:(软件开发,kubernetes)