应用自测与调试

运行应用时,不可避免的需要定位问题。 前面我们介绍了如何使用 kubectl get pods 来查询 pod 的简单信息。 除此之外,还有一系列的方法来获取应用的更详细信息。

使用 kubectl describe pod 命令获取 Pod 详情

与之前的例子类似,我们使用一个 Deployment 来创建两个 Pod。

application/nginx-with-request.yaml 应用自测与调试 - 图1

  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. name: nginx-deployment
  5. spec:
  6. selector:
  7. matchLabels:
  8. app: nginx
  9. replicas: 2
  10. template:
  11. metadata:
  12. labels:
  13. app: nginx
  14. spec:
  15. containers:
  16. - name: nginx
  17. image: nginx
  18. resources:
  19. limits:
  20. memory: "128Mi"
  21. cpu: "500m"
  22. ports:
  23. - containerPort: 80

使用如下命令创建 Deployment:

  1. kubectl apply -f https://k8s.io/examples/application/nginx-with-request.yaml
  1. deployment.apps/nginx-deployment created

使用如下命令查看 Pod 状态:

  1. kubectl get pods
  1. NAME READY STATUS RESTARTS AGE
  2. nginx-deployment-1006230814-6winp 1/1 Running 0 11s
  3. nginx-deployment-1006230814-fmgu3 1/1 Running 0 11s

我们可以使用 kubectl describe pod 命令来查询每个 Pod 的更多信息,比如:

  1. kubectl describe pod nginx-deployment-1006230814-6winp
  1. Name: nginx-deployment-1006230814-6winp
  2. Namespace: default
  3. Node: kubernetes-node-wul5/10.240.0.9
  4. Start Time: Thu, 24 Mar 2016 01:39:49 +0000
  5. Labels: app=nginx,pod-template-hash=1006230814
  6. Annotations: kubernetes.io/created-by={"kind":"SerializedReference","apiVersion":"v1","reference":{"kind":"ReplicaSet","namespace":"default","name":"nginx-deployment-1956810328","uid":"14e607e7-8ba1-11e7-b5cb-fa16" ...
  7. Status: Running
  8. IP: 10.244.0.6
  9. Controllers: ReplicaSet/nginx-deployment-1006230814
  10. Containers:
  11. nginx:
  12. Container ID: docker://90315cc9f513c724e9957a4788d3e625a078de84750f244a40f97ae355eb1149
  13. Image: nginx
  14. Image ID: docker://6f62f48c4e55d700cf3eb1b5e33fa051802986b77b874cc351cce539e5163707
  15. Port: 80/TCP
  16. QoS Tier:
  17. cpu: Guaranteed
  18. memory: Guaranteed
  19. Limits:
  20. cpu: 500m
  21. memory: 128Mi
  22. Requests:
  23. memory: 128Mi
  24. cpu: 500m
  25. State: Running
  26. Started: Thu, 24 Mar 2016 01:39:51 +0000
  27. Ready: True
  28. Restart Count: 0
  29. Environment: <none>
  30. Mounts:
  31. /var/run/secrets/kubernetes.io/serviceaccount from default-token-5kdvl (ro)
  32. Conditions:
  33. Type Status
  34. Initialized True
  35. Ready True
  36. PodScheduled True
  37. Volumes:
  38. default-token-4bcbi:
  39. Type: Secret (a volume populated by a Secret)
  40. SecretName: default-token-4bcbi
  41. Optional: false
  42. QoS Class: Guaranteed
  43. Node-Selectors: <none>
  44. Tolerations: <none>
  45. Events:
  46. FirstSeen LastSeen Count From SubobjectPath Type Reason Message
  47. --------- -------- ----- ---- ------------- -------- ------ -------
  48. 54s 54s 1 {default-scheduler } Normal Scheduled Successfully assigned nginx-deployment-1006230814-6winp to kubernetes-node-wul5
  49. 54s 54s 1 {kubelet kubernetes-node-wul5} spec.containers{nginx} Normal Pulling pulling image "nginx"
  50. 53s 53s 1 {kubelet kubernetes-node-wul5} spec.containers{nginx} Normal Pulled Successfully pulled image "nginx"
  51. 53s 53s 1 {kubelet kubernetes-node-wul5} spec.containers{nginx} Normal Created Created container with docker id 90315cc9f513
  52. 53s 53s 1 {kubelet kubernetes-node-wul5} spec.containers{nginx} Normal Started Started container with docker id 90315cc9f513

这里可以看到容器和 Pod 的标签、资源需求等配置信息,还可以看到状态、就绪态、 重启次数、事件等状态信息。

容器状态是 Waiting、Running 和 Terminated 之一。 根据状态的不同,还有对应的额外的信息 —— 在这里你可以看到, 对于处于运行状态的容器,系统会告诉你容器的启动时间。

Ready 指示是否通过了最后一个就绪态探测。 (在本例中,容器没有配置就绪态探测;如果没有配置就绪态探测,则假定容器已经就绪。)

Restart Count 告诉你容器已重启的次数; 这些信息对于定位配置了 “Always” 重启策略的容器持续崩溃问题非常有用。

目前,唯一与 Pod 有关的状态是 Ready 状况,该状况表明 Pod 能够为请求提供服务, 并且应该添加到相应服务的负载均衡池中。

最后,你还可以看到与 Pod 相关的近期事件。 系统通过指示第一次和最后一次看到事件以及看到该事件的次数来压缩多个相同的事件。 “From” 标明记录事件的组件, “SubobjectPath” 告诉你引用了哪个对象(例如 Pod 中的容器), “Reason” 和 “Message” 告诉你发生了什么。

例子: 调试 Pending 状态的 Pod

可以使用事件来调试的一个常见的场景是,你创建 Pod 无法被调度到任何节点。 比如,Pod 请求的资源比较多,没有任何一个节点能够满足,或者它指定了一个标签,没有节点可匹配。 假定我们创建之前的 Deployment 时指定副本数是 5(不再是 2),并且请求 600 毫核(不再是 500), 对于一个 4 个节点的集群,若每个节点只有 1 个 CPU,这时至少有一个 Pod 不能被调度。 (需要注意的是,其他集群插件 Pod,比如 fluentd、skydns 等等会在每个节点上运行, 如果我们需求 1000 毫核,将不会有 Pod 会被调度。)

  1. kubectl get pods
  1. NAME READY STATUS RESTARTS AGE
  2. nginx-deployment-1006230814-6winp 1/1 Running 0 7m
  3. nginx-deployment-1006230814-fmgu3 1/1 Running 0 7m
  4. nginx-deployment-1370807587-6ekbw 1/1 Running 0 1m
  5. nginx-deployment-1370807587-fg172 0/1 Pending 0 1m
  6. nginx-deployment-1370807587-fz9sd 0/1 Pending 0 1m

为了查找 Pod nginx-deployment-1370807587-fz9sd 没有运行的原因,我们可以使用 kubectl describe pod 命令描述 Pod,查看其事件:

  1. kubectl describe pod nginx-deployment-1370807587-fz9sd
  1. Name: nginx-deployment-1370807587-fz9sd
  2. Namespace: default
  3. Node: /
  4. Labels: app=nginx,pod-template-hash=1370807587
  5. Status: Pending
  6. IP:
  7. Controllers: ReplicaSet/nginx-deployment-1370807587
  8. Containers:
  9. nginx:
  10. Image: nginx
  11. Port: 80/TCP
  12. QoS Tier:
  13. memory: Guaranteed
  14. cpu: Guaranteed
  15. Limits:
  16. cpu: 1
  17. memory: 128Mi
  18. Requests:
  19. cpu: 1
  20. memory: 128Mi
  21. Environment Variables:
  22. Volumes:
  23. default-token-4bcbi:
  24. Type: Secret (a volume populated by a Secret)
  25. SecretName: default-token-4bcbi
  26. Events:
  27. FirstSeen LastSeen Count From SubobjectPath Type Reason Message
  28. --------- -------- ----- ---- ------------- -------- ------ -------
  29. 1m 48s 7 {default-scheduler } Warning FailedScheduling pod (nginx-deployment-1370807587-fz9sd) failed to fit in any node
  30. fit failure on node (kubernetes-node-6ta5): Node didn't have enough resource: CPU, requested: 1000, used: 1420, capacity: 2000
  31. fit failure on node (kubernetes-node-wul5): Node didn't have enough resource: CPU, requested: 1000, used: 1100, capacity: 2000

这里你可以看到由调度器记录的事件,它表明了 Pod 不能被调度的原因是 FailedScheduling(也可能是其他值)。 其 message 部分表明没有任何节点拥有足够多的资源。

要纠正这种情况,可以使用 kubectl scale 更新 Deployment,以指定 4 个或更少的副本。 (或者你可以让 Pod 继续保持这个状态,这是无害的。)

你在 kubectl describe pod 结尾处看到的事件都保存在 etcd 中, 并提供关于集群中正在发生的事情的高级信息。 如果需要列出所有事件,可使用命令:

  1. kubectl get events

但是,需要注意的是,事件是区分名字空间的。 如果你对某些名字空间域的对象(比如 my-namespace 名字下的 Pod)的事件感兴趣, 你需要显式地在命令行中指定名字空间:

  1. kubectl get events --namespace=my-namespace

查看所有 namespace 的事件,可使用 --all-namespaces 参数。

除了 kubectl describe pod 以外,另一种获取 Pod 额外信息(除了 kubectl get pod)的方法 是给 kubectl get pod 增加 -o yaml 输出格式参数。 该命令将以 YAML 格式为你提供比 kubectl describe pod 更多的信息 —— 实际上是系统拥有的关于 Pod 的所有信息。 在这里,你将看到注解(没有标签限制的键值元数据,由 Kubernetes 系统组件在内部使用)、 重启策略、端口和卷等。

  1. kubectl get pod nginx-deployment-1006230814-6winp -o yaml
  1. apiVersion: v1
  2. kind: Pod
  3. metadata:
  4. annotations:
  5. kubernetes.io/created-by: |
  6. {"kind":"SerializedReference","apiVersion":"v1","reference":{"kind":"ReplicaSet","namespace":"default","name":"nginx-deployment-1006230814","uid":"4c84c175-f161-11e5-9a78-42010af00005","apiVersion":"extensions","resourceVersion":"133434"}}
  7. creationTimestamp: 2016-03-24T01:39:50Z
  8. generateName: nginx-deployment-1006230814-
  9. labels:
  10. app: nginx
  11. pod-template-hash: "1006230814"
  12. name: nginx-deployment-1006230814-6winp
  13. namespace: default
  14. resourceVersion: "133447"
  15. uid: 4c879808-f161-11e5-9a78-42010af00005
  16. spec:
  17. containers:
  18. - image: nginx
  19. imagePullPolicy: Always
  20. name: nginx
  21. ports:
  22. - containerPort: 80
  23. protocol: TCP
  24. resources:
  25. limits:
  26. cpu: 500m
  27. memory: 128Mi
  28. requests:
  29. cpu: 500m
  30. memory: 128Mi
  31. terminationMessagePath: /dev/termination-log
  32. volumeMounts:
  33. - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
  34. name: default-token-4bcbi
  35. readOnly: true
  36. dnsPolicy: ClusterFirst
  37. nodeName: kubernetes-node-wul5
  38. restartPolicy: Always
  39. securityContext: {}
  40. serviceAccount: default
  41. serviceAccountName: default
  42. terminationGracePeriodSeconds: 30
  43. volumes:
  44. - name: default-token-4bcbi
  45. secret:
  46. secretName: default-token-4bcbi
  47. status:
  48. conditions:
  49. - lastProbeTime: null
  50. lastTransitionTime: 2016-03-24T01:39:51Z
  51. status: "True"
  52. type: Ready
  53. containerStatuses:
  54. - containerID: docker://90315cc9f513c724e9957a4788d3e625a078de84750f244a40f97ae355eb1149
  55. image: nginx
  56. imageID: docker://6f62f48c4e55d700cf3eb1b5e33fa051802986b77b874cc351cce539e5163707
  57. lastState: {}
  58. name: nginx
  59. ready: true
  60. restartCount: 0
  61. state:
  62. running:
  63. startedAt: 2016-03-24T01:39:51Z
  64. hostIP: 10.240.0.9
  65. phase: Running
  66. podIP: 10.244.0.6
  67. startTime: 2016-03-24T01:39:49Z

示例:调试宕机或无法联系的节点

有时候,在调试时,查看节点的状态是很有用的 —— 例如,因为你已经注意到节点上运行的 Pod 的奇怪行为, 或者想了解为什么 Pod 不会调度到节点上。 与 Pod 一样,你可以使用 kubectl describe nodekubectl get node -o yaml 来查询节点的详细信息。 例如,如果某个节点宕机(与网络断开连接,或者 kubelet 挂掉无法重新启动等等),你将看到以下情况。 请注意显示节点未就绪的事件,也请注意 Pod 不再运行(它们在5分钟未就绪状态后被驱逐)。

  1. kubectl get nodes
  1. NAME STATUS ROLES AGE VERSION
  2. kubernetes-node-861h NotReady <none> 1h v1.13.0
  3. kubernetes-node-bols Ready <none> 1h v1.13.0
  4. kubernetes-node-st6x Ready <none> 1h v1.13.0
  5. kubernetes-node-unaj Ready <none> 1h v1.13.0
  1. kubectl describe node kubernetes-node-861h
  1. Name: kubernetes-node-861h
  2. Role
  3. Labels: kubernetes.io/arch=amd64
  4. kubernetes.io/os=linux
  5. kubernetes.io/hostname=kubernetes-node-861h
  6. Annotations: node.alpha.kubernetes.io/ttl=0
  7. volumes.kubernetes.io/controller-managed-attach-detach=true
  8. Taints: <none>
  9. CreationTimestamp: Mon, 04 Sep 2017 17:13:23 +0800
  10. Phase:
  11. Conditions:
  12. Type Status LastHeartbeatTime LastTransitionTime Reason Message
  13. ---- ------ ----------------- ------------------ ------ -------
  14. OutOfDisk Unknown Fri, 08 Sep 2017 16:04:28 +0800 Fri, 08 Sep 2017 16:20:58 +0800 NodeStatusUnknown Kubelet stopped posting node status.
  15. MemoryPressure Unknown Fri, 08 Sep 2017 16:04:28 +0800 Fri, 08 Sep 2017 16:20:58 +0800 NodeStatusUnknown Kubelet stopped posting node status.
  16. DiskPressure Unknown Fri, 08 Sep 2017 16:04:28 +0800 Fri, 08 Sep 2017 16:20:58 +0800 NodeStatusUnknown Kubelet stopped posting node status.
  17. Ready Unknown Fri, 08 Sep 2017 16:04:28 +0800 Fri, 08 Sep 2017 16:20:58 +0800 NodeStatusUnknown Kubelet stopped posting node status.
  18. Addresses: 10.240.115.55,104.197.0.26
  19. Capacity:
  20. cpu: 2
  21. hugePages: 0
  22. memory: 4046788Ki
  23. pods: 110
  24. Allocatable:
  25. cpu: 1500m
  26. hugePages: 0
  27. memory: 1479263Ki
  28. pods: 110
  29. System Info:
  30. Machine ID: 8e025a21a4254e11b028584d9d8b12c4
  31. System UUID: 349075D1-D169-4F25-9F2A-E886850C47E3
  32. Boot ID: 5cd18b37-c5bd-4658-94e0-e436d3f110e0
  33. Kernel Version: 4.4.0-31-generic
  34. OS Image: Debian GNU/Linux 8 (jessie)
  35. Operating System: linux
  36. Architecture: amd64
  37. Container Runtime Version: docker://1.12.5
  38. Kubelet Version: v1.6.9+a3d1dfa6f4335
  39. Kube-Proxy Version: v1.6.9+a3d1dfa6f4335
  40. ExternalID: 15233045891481496305
  41. Non-terminated Pods: (9 in total)
  42. Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits
  43. --------- ---- ------------ ---------- --------------- -------------
  44. ......
  45. Allocated resources:
  46. (Total limits may be over 100 percent, i.e., overcommitted.)
  47. CPU Requests CPU Limits Memory Requests Memory Limits
  48. ------------ ---------- --------------- -------------
  49. 900m (60%) 2200m (146%) 1009286400 (66%) 5681286400 (375%)
  50. Events: <none>
  1. kubectl get node kubernetes-node-861h -o yaml
  1. apiVersion: v1
  2. kind: Node
  3. metadata:
  4. creationTimestamp: 2015-07-10T21:32:29Z
  5. labels:
  6. kubernetes.io/hostname: kubernetes-node-861h
  7. name: kubernetes-node-861h
  8. resourceVersion: "757"
  9. selfLink: /api/v1/nodes/kubernetes-node-861h
  10. uid: 2a69374e-274b-11e5-a234-42010af0d969
  11. spec:
  12. externalID: "15233045891481496305"
  13. podCIDR: 10.244.0.0/24
  14. providerID: gce://striped-torus-760/us-central1-b/kubernetes-node-861h
  15. status:
  16. addresses:
  17. - address: 10.240.115.55
  18. type: InternalIP
  19. - address: 104.197.0.26
  20. type: ExternalIP
  21. capacity:
  22. cpu: "1"
  23. memory: 3800808Ki
  24. pods: "100"
  25. conditions:
  26. - lastHeartbeatTime: 2015-07-10T21:34:32Z
  27. lastTransitionTime: 2015-07-10T21:35:15Z
  28. reason: Kubelet stopped posting node status.
  29. status: Unknown
  30. type: Ready
  31. nodeInfo:
  32. bootID: 4e316776-b40d-4f78-a4ea-ab0d73390897
  33. containerRuntimeVersion: docker://Unknown
  34. kernelVersion: 3.16.0-0.bpo.4-amd64
  35. kubeProxyVersion: v0.21.1-185-gffc5a86098dc01
  36. kubeletVersion: v0.21.1-185-gffc5a86098dc01
  37. machineID: ""
  38. osImage: Debian GNU/Linux 7 (wheezy)
  39. systemUUID: ABE5F6B4-D44B-108B-C46A-24CCE16C8B6E

接下来

了解更多的调试工具: