Pod状态异常,挂载configmap显示no such file or directory

$ kubectl get pod -o wide
test-7695dc7fb9-rjxlq                0/1       CrashLoopBackOff   13        17h       192.168.100.20   node1   <none>

CrashLoopBackOff状态需要查看pod的日志,通过kubectl logs可以查看到具体的错误信息。

$ kubectl logs -n test-7695dc7fb9-rjxlq
container_linux.go:345: starting container process caused "process_linux.go:430: container init caused \"rootfs_linux.go:58: mounting \\\"/var/lib/kubelet/pods/ed1b799a-d3a5-11e9-add6-0894ef725f6e/volume-subpaths/test-cm/app-conf/1\\\" to rootfs \\\"/var/lib/docker/overlay/23a69e27f79f84a14b50fbee1e4840836487f8c740423291c2f785da1e7a6820/merged\\\" at \\\"/var/lib/docker/overlay/23a69e27f79f84a14b50fbee1e4840836487f8c740423291c2f785da1e7a6820/merged/etc/app/app.conf\\\" caused \\\"no such file or directory\\\"\""

查看日志发现是挂载的configmap有问题。

猜测原因:该pod采用subPath的方式挂载configmap,怀疑是configmap修改后,未重建pod导致,因此会出现上述no such file or directory的错误。

排查问题

查看异常pod的uid,通过下述的命令我们可以看到当前pod在2019-09-10T08:35:21Z的时间创建,并且uid为ed1b799a-d3a5-11e9-add6-0894ef725f6e

$ kubectl get pod test-7695dc7fb9-rjxlq -o json | jq .metadata
{
  "creationTimestamp": "2019-09-10T08:35:21Z",
  "generateName": "test-7695dc7fb9-",
  "labels": {
    "application": "test",
    "pod-template-hash": "3251873965"
  },
  "name": "test-7695dc7fb9-rjxlq",
  "namespace": "openstack",
  "ownerReferences": [
    {
      "apiVersion": "apps/v1",
      "blockOwnerDeletion": true,
      "controller": true,
      "kind": "ReplicaSet",
      "name": "test-7695dc7fb9",
      "uid": "ece58508-d3a5-11e9-add6-0894ef725f6e"
    }
  ],
  "resourceVersion": "1762165",
  "selfLink": "/api/v1/namespaces/default/pods/test-7695dc7fb9-rjxlq",
  "uid": "ed1b799a-d3a5-11e9-add6-0894ef725f6e"
}

接下来就需要登录到pod所在的节点进行查看。

查看node1节点的kubelet工作目录下该pod的configmap保存路径,路径为/var/lib/kubelet/pods/<uid>/volumes/kubernetes.io~configmap

针对当前的pod该路径为/var/lib/kubelet/pods/ed1b799a-d3a5-11e9-add6-0894ef725f6e/volumes/kubernetes.io~configmap,在这个目录下我们看到有目录为test-cm,该目录即为需要挂载的configmap的内容。因为日志显示为test-cm挂载有问题,因此我们进入该目录下,并查看该目录下所有文件的最后修改时间。

$ cd test-cm/
$ ll -at
total 0
drwxrwxrwx 3 root root 325 Sep 10 16:37 .
drwxr-xr-x 2 root root 272 Sep 10 16:37 ..2019_09_10_08_37_48.156264351
lrwxrwxrwx 1 root root  31 Sep 10 16:37 ..data -> ..2019_09_10_08_37_48.156264351
drwxr-xr-x 4 root root  38 Sep 10 16:35 ..
lrwxrwxrwx 1 root root  27 Sep 10 16:35 app.conf -> ..data/app.conf

我们可以看到在9.10号16:37分的时候,kubelet更新configmap到该目录下,但是容器挂载的是16:35的文件,因此符合我们的猜想,即configmap修改后,未重建整个pod,在pod里的某个容器重启新建的时候,就会有上述no such file or directory

但是目前环境上的问题,是pod在最开始新建的时候,状态就为CrashLoopBackOff,因此怀疑在pod里的容器新建之前,有其他操作导致test这个容器创建的时间在configmap更新之后。

正常的pod新建流程,会由kubelet先把configmap更新到该目录下,然后挂载到容器内,而这个时间很短,在pod第一次启动的时候应该是可以正常Running才对,因此需要进一步排查问题。

我们查看下该pod的内容,发现该pod还有initContainer的操作,我们通过下述命令发现该initContainer的处理时间为2019-09-10T08:35:31Z2019-09-10T08:37:47Z。这个和我们上面看到的configmap时间与猜想是符合的,因为这个说明pod是在第一次configmap创建的时候生成,而test这个容器是在configmap更新之后才创建,而subPath的方式挂载configmap需要在configmap更新后重建整个pod,但是目前环境没有该操作。

$ kubectl get pod test-7695dc7fb9-rjxlq -o json | jq .status.initContainerStatuses
[
  {
    "containerID": "docker://3aaab80f5a4b5349a1444cfb483b2877416cbe877693d62cbae78434ddd48c6f",
    "image": "docker.cloud/pytimer/kubernetes-entrypoint:v0.3.1",
    "imageID": "docker-pullable://docker.cloud/pytimer/kubernetes-entrypoint@sha256:2cad635d9079ee130f7f288b2ffb9c65c90fc7711364dcf438973ddf579b7fed",
    "lastState": {},
    "name": "init",
    "ready": true,
    "restartCount": 0,
    "state": {
      "terminated": {
        "containerID": "docker://3aaab80f5a4b5349a1444cfb483b2877416cbe877693d62cbae78434ddd48c6f",
        "exitCode": 0,
        "finishedAt": "2019-09-10T08:37:47Z",
        "reason": "Completed",
        "startedAt": "2019-09-10T08:35:31Z"
      }
    }
  }
]

通过操作日志记录,发现在16:35:15这个时间点,创建了test这个pod相关的资源,包括configmap。而在16:36:55的时候更新了configmap。我们上面看到这个异常的pod的创建时间在16:35:21,configmap最后更新的时间为16:37分(kubelet会有10s左右的时间延迟更新),因此从kubelet的相关信息和日志操作时间对比,时间点是吻合的,因此确认了该问题确实是因为更新了configmap未重建pod,而pod里的容器又是在configmap更新后新建的,因此会出现状态为CrashLoopBackOff,并且日志为no such file or directory

结论

该现象的发生是由于configmap更新,但是未重建整个pod导致。