64

对 Kubernetes 应用程序进行调试和记录

 5 years ago
source link: http://www.ibm.com/developerworks/cn/cloud/library/debug-and-log-your-kubernetes-app/index.html?ca=drs-&%3Butm_source=tuicool&%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

免费试用 IBM Cloud

利用IBM Cloud Lite 快速轻松地构建您的下一个应用程序。您的免费帐户从不过期,而且您会获得 256 MB 的 Cloud Foundry 运行时内存和包含 Kubernetes 集群的 2 GB 存储空间。了解所有细节并确定如何开始。如果您不熟悉 IBM Cloud,请查阅 developerWorks 上的 IBM Cloud Essentials 课程

Kubernetes 是用于管理多个主机间的容器化应用程序的开源系统,它为应用程序部署、维护和扩展提供了基本机制。开源项目由 云原生计算基金会 托管,在本教程中,托管在 IBM Cloud Kubernetes Service 上。

学习目标

本教程面向希望深入了解Kubernetes 集群以及应用程序调试方式和日志获取方式的开发者。

前提条件

开始本教程前,您需要:

预估时间

完成本教程大约需要 20 分钟。

步骤

容器日志

检验和调试 pod

让我们来聊聊应用程序部署。有时部署会很顺利,您会看到 deployment <your-app-name> created 消息!但如果应用程序部署失败该怎么办?您可以执行以下几个步骤:收集信息、制定修复计划、测试并执行。先来看下信息收集,可用于信息收集的工具和方法多种多样。

  1. 要获取 pod 的基本信息,可以使用以下简单命令:
    $ kubectl get pods
    NAME                         READY     STATUS    RESTARTS   AGE
    guestbook-75786d799f-fg72k   1/1       Running   0          7m
  2. 如果对特定 pod 加以描述,就可获得更详细的信息,如下所示:
    $ kubectl describe pod <your-pod-name> 
      Name:           guestbook-75786d799f-fg72k
      Namespace:      default
      Node:           10.47.84.98/10.47.84.98
      Start Time:     Sun, 19 Aug 2018 12:56:23 +0300
      Labels:         pod-template-hash=3134283559
      					run=guestbook
      Annotations:    kubernetes.io/psp=ibm-privileged-psp
      Status:         Running
      ...

在上例中,您可看到容器和 pod 的相关配置信息(标签、资源需求等)以及容器和 pod 的相关状态信息(状态、准备情况、重新启动计数、事件等)。

有时使用这些基本命令应已足矣。例如,通过查看 kubectl describe,您可以发现镜像提取错误,您只是忘记了放入部分信息(如镜像提取密钥)。或者可能您使用了最新版本的镜像,但它未能正常运行,因此您想要切换回较低版本。

但如果我们未找到任何错误并需要深入挖掘日志,那么会发生什么?许多开发者不知道的是, 事件 (kubectl get events) 实际上是 Kubernetes 中的一种资源类型。因此,执行此命令时,它将列出各种事件,就像列出任何其他资源一样,并提供汇总视图。应记住,事件资源按名称空间划分,因此如果要获取特定事件,应注明要获取的事件所属的名称空间,或者留空即可获取所有事件。

  1. 使用以下命令获取 pod 的事件列表:
$kubectl get events [--namespace=default]
		LASTSEEN   FIRSTSEEN   COUNT     NAME                         KIND         SUBOBJECT                    TYPE      REASON                  SOURCE                  MESSAGE
		3m         3m          1         guestbook-75786d799f-r6mxl   Pod                                       Normal    Scheduled               default-scheduler       Successfully assigned guestbook-75786d799f-r6mxl to 10.77.155.84
		3m         3m          1         guestbook-75786d799f-r6mxl   Pod                                       Normal    SuccessfulMountVolume   kubelet, 10.77.155.84   MountVolume.SetUp succeeded for volume "default-token-5rlxc"
		3m         3m          1         guestbook-75786d799f-r6mxl   Pod          spec.containers{guestbook}   Normal    Pulled                  kubelet, 10.77.155.84   Container image "ibmcom/guestbook:v1" already present on machine
		3m         3m          1         guestbook-75786d799f-r6mxl   Pod          spec.containers{guestbook}   Normal    Created                 kubelet, 10.77.155.84   Created container
		3m         3m          1         guestbook-75786d799f-r6mxl   Pod          spec.containers{guestbook}   Normal    Started                 kubelet, 10.77.155.84   Started container
		3m         3m          1         guestbook-75786d799f-xvpvv   Pod          spec.containers{guestbook}   Normal    Killing                 kubelet, 10.77.155.84   Killing container with id docker://guestbook:Need to kill Pod
		3m         3m          1         guestbook-75786d799f         ReplicaSet                                Normal    SuccessfulDelete        replicaset-controller   Deleted pod: guestbook-75786d799f-xvpvv
		3m         3m          1         guestbook-75786d799f         ReplicaSet                                Normal    SuccessfulCreate        replicaset-controller   Created pod: guestbook-75786d799f-r6mxl
		3m         3m          1         guestbook                    Deployment                                Normal    ScalingReplicaSet       deployment-controller   Scaled down replica set guestbook-75786d799f to 0
		3m         3m          1         guestbook                    Deployment                                Normal    ScalingReplicaSet       deployment-controller   Scaled up replica set guestbook-75786d799f to 1

通过事件通常检测到的一种情况是,创建的 pod 并不适用于任何节点,它将保持 "Pending" 状态,发生这种情况的原因可能是缺少资源等,您可在“事件”部分中查看问题。 让我们看一下重要事件参数,您会发现事件记录中包含如下信息:

  • KIND 指示事件相关资源的类型(Pod、ReplicaSet、Deployment 等)。
  • TYPE 即事件的状态。它可标记为 "Normal" 或 "Warning",将来可能添加新类型。
  • REASON 表示转换为对象当前状态的原因。
  • SOURCE 表示报告此事件的组件来源。
  • MESSAGE 指示这是事件的人类可读描述。

此外,还有更多参数未显示在以上列表中,这些参数可能对您很有用,如 METADATA ,即标准对象元数据。EVENTTIME 是首次观察到事件的时间。ACTION 是针对对象已执行或已失败的特定操作。

有关更多信息,您可以 在此处阅读了解事件

获取应用程序日志

应用程序和系统日志可帮助您深入了解集群内发生的状况。您可获取特定 pod 的日志,如果此 pod 包含多个容器,那么您可指定所需的容器。

查看日志

要查看日志,可运行以下简单命令:

$ kubectl logs <your-pod-name>
[negroni] listening on :3000
[negroni] 2018-08-19T11:55:39Z | 200 |   332.277µs | 173.193.106.55:32412 | GET /
[negroni] 2018-08-19T11:55:39Z | 200 |   140.407µs | 173.193.106.55:32412 | GET /style.css
[negroni] 2018-08-19T11:55:39Z | 200 |   123.595µs | 173.193.106.55:32412 | GET /script.js
[negroni] 2018-08-19T11:55:39Z | 200 |   87.508µs | 173.193.106.55:32412 | GET /lrange/guestbook
[negroni] 2018-08-19T11:55:39Z | 404 |   74.307µs | 173.193.106.55:32412 | GET /favicon.ico
[negroni] 2018-08-19T11:57:30Z | 304 |   89.418µs | 173.193.106.55:32412 | GET /
[negroni] 2018-08-19T11:57:30Z | 200 |   60.671µs | 173.193.106.55:32412 | GET /lrange/guestbook
[negroni] 2018-08-19T12:06:23Z | 304 |   152.557µs | 173.193.106.55:32412 | GET /
[negroni] 2018-08-19T12:06:23Z | 200 |   94.091µs | 173.193.106.55:32412 | GET
/lrange/guestbook

注意:要打印到日志中,从应用程序写入 stdout/stderr。此外,还应注意的一点是,日志命令中没有 get,这表示日志并非类似事件的资源。

为帮助您从日志中获取更好的结果,您可使用 "kubetail",这是为每种类型的日志添加不同颜色的开源项目。链接如下: https://github.com/johanhaleby/kubetail。

先前日志

您始终可使用 --previous 标志请求获取先前日志,但应知晓另外两种日志级别:节点级别和集群级别。这两种日志级别之间也存在较大差异。让我们来了解下它们的差异:

  • 节点级别 :容器化应用程序写入由容器引擎处理的 stdout 和 stderr。容器引擎将这两种流重定向至日志记录驱动程序,在 Kubernetes 中将此驱 动程序配置为写入 JSON 格式的文件。JSON 日志记录驱动程序将每一行都作为一条独立消息来处理。使用日志记录驱动程序时,不会直接支持多行消息。您需要在日志记录代理程序级别或更高级别来处理多行消息。 默认情况下,如果某个容器重新启动,kubelet 会保留一个已终止的容器及其日志。如果从节点收回某个 pod,那么将同时收回所有对应的容器及其日志。
  • 集群级别 :虽然 Kubernetes 并没有为集群级别日志记录提供本机解决方案,但还是有多种常用方法可供您考虑。以下是部分可供选择的方法:
    • 使用在每个节点上运行的节点级别日志记录代理程序。
    • 在应用程序 pod 中包含一个专用伴生容器用于日志记录。
    • 将日志从应用程序内直接推送至后端。

要获取有关这些方法的更多信息,可以阅读本 指南

在运行中的容器内使用 shell

大部分情况下,您的容器日志即 pod 日志,尤其是当 pod 中仅有一个容器时。如果集群中确实出现问题,并且您无法使用 kubectl 从 pod 中获取日志,那么您可能必须进入容器并获取日志(调试容器),这样才能完全掌控容器内发生的状况。您可以使用 kubectl exec 来访问容器中运行的 shell,识别容器中哪部分流程出现问题,这样才能更准确地调试容器。

但应记住,仅当您的容器内包含 Shell exec 时,才能执行此操作。如果您构建容器时所使用的镜像不包含 Shell exec,那么您将无法使用 exec 命令。Shell exec 可能会占用一些空间,导致增加容器负载,因此您可能会问:“我为何要把它放在容器内?使用容器的最大优势不就是负载轻吗?”在生产环境中,您可能希望最大限度提升性能,因此不应将 shell 放入镜像。而在测试环境中,您可能乐于在运行容器时访问 shell 以运行测试。

  1. 为实现此目的,我们需要使用 /bin/bash 创建新 pod:
    $ kubectl create -f https://k8s.io/examples/application/shell-demo.yaml
  2. 将 shell 放入容器:
    $ kubectl exec -it shell-demo -- /bin/bash
  3. 现在,列出根目录:
    root@shell-demo:/# ls /
    bin   dev  home  lib64  mnt  proc  run   srv  tmp
    boot  etc  lib   media  opt  root  sbin  sys  usr

集群联网问题

联网问题是最常见的问题,因为您无法参照任何要点来按步骤解决所有问题,您必须了解集群网络中出现的具体问题。为帮助您找到这些问题,我列出了当您怀疑网络出现问题时应查看的关键领域。 延伸阅读:要获取有关 Kubernetes 联网的部分指南,可查看 Kubernetes Networking: A lab on basic networking concepts

调试服务

新安装 Kubernetes 时常见的一个问题是服务无法正常运行,即您运行自己的部署并创建服务,但仍无法获取任何响应。在本部分中,我们将查看一些可能有助于您找出问题的命令。

有时,我们忘记为 pod 创建服务,因为服务是必需的,所以,我们将无法访问 pod,并收到错误。

  1. 要查看所有服务,可通过使用如下简单命令来查看所有 pod:
    $ kubectl get svc
    NAME        CLUSTER-IP      EXTERNAL-IP   PORT(S)          AGE
    guestbook   172.21.30.218   <nodes> 3000:32412/TCP 45m
  2. 如果您要查找的服务不存在,那么可使用以下命令来创建此服务:

    $ kubectl expose deployment <your-deployment-name> --type="NodePort" --port=3000
     service "guestbook" exposed

    如果您已有服务,则应查看其配置是否存在问题。

  3. 让我们来试着获取有关此服务的更多信息:

    $ kubectl describe service <your-service-name> 
                 Name: guestbook 
                 Namespace: default 
                 Labels: run=guestbook 
                 Annotations: <none> 
                 Selector: run=guestbook 
                 Type: NodePort 
                 IP: 172.21.138.209 
                 Port: <unset> 3000/TCP 
                 NodePort: <unset> 31235/TCP 
                 Endpoints: 172.30.87.71:3000 
                 Session Affinity: None 
                 Events: <none>

    检查您用于访问容器的 NodePort 是否正确,确保端点已存在。 如果找到错误信息(如无端点),可尝试重新创建服务,并使用 kubectl expose 命令再次核查是否存在错误。

  4. 您还可获取 JSON 格式的信息:

    $ kubectl get service <your-service-name> -o json
    {
      		"apiVersion": "v1",
      		"kind": "Service",
      		"metadata": {
      			"creationTimestamp": "2018-08-19T11:55:12Z",
      			"labels": {
      				"run": "guestbook"
      			},
      			"name": "guestbook",
      			"namespace": "default",
      			"resourceVersion": "1118",
      			"selfLink": "/api/v1/namespaces/default/services/guestbook",
      			"uid": "baa2e98d-a3a6-11e8-a994-f20601bb534c"
      		},
      		"spec": {
      			"clusterIP": "172.21.30.218",
      			"externalTrafficPolicy": "Cluster",
      			"ports": [
      				{
      					"nodePort": 32412,
      					"port": 3000,
      					"protocol": "TCP",
      					"targetPort": 3000
      				}
      			],
      			"selector": {
      				"run": "guestbook"
      			},
      			"sessionAffinity": "None",
      			"type": "NodePort"
      		},
      		"status": {
      			"loadBalancer": {}
      		}
    }

    您应始终仔细检查可能导致问题的配置,如确认 spec.ports 是否是对应于您的 pod 的正确 targetPort。服务与 pod 使用的协议是否相同?

  5. 此外,还有其他一些方法可用于检验您的服务。您可阅读 此处 ,获取更多信息。

检查 DNS

部分网络问题可能是由 DNS 配置或错误所导致的。因此,您首先需要检查 DNS 是否正常工作。

  1. 使用 get pods 命令获取 pod 名称:
    $ kubectl get pods
    NAME                         READY     STATUS    RESTARTS   AGE
    guestbook-75786d799f-brrhf   1/1       Running   0          47m
  2. 使用以下命令检查 pod DNS:

    $ kubectl exec -ti <your-pod-name> -- nslookup kubernetes.default 
    Server:    172.21.0.10
    Address 1: 172.21.0.10 kube-dns.kube-system.svc.cluster.local
    
    Name:      kubernetes.default
    Address 1: 172.21.0.1 kubernetes.default.svc.cluster.local

    应注意,如果您不使用 "default" 名称空间,那么应根据集群名称空间尝试使用其他名称。如果您的 pod 与服务位于不同名称空间内,尝试使用名称空间限定的名称 (default) - 但您需要将自己的应用调整为使用跨名称空间的名称,或者 在相同名称空间内运行您的应用和服务。如果仍失败,尝试使用标准名称(例如,default.svc.cluster.local)。如果 nslookup 命令失败,应在配置中执行一些检查或查找错误。nslookup:can't resolve 'kubernetes.default' 之类的错误可能指示 coredns/kube-dns 附加组件或关联服务中存在问题。

    如果您能够执行标准名称查找,但不能执行相对名称查找,那么就需要检查 /etc/resolv.conf 文件是否正确。

  3. 进入 resolv.conf 文件,查看参数是否正确:
    $ kubectl exec <your-pod-name> cat /etc/resolv.conf
    nameserver 172.21.0.10
    search default.svc.cluster.local svc.cluster.local cluster.local
    options ndots:5

确保 nameserver 行指示您的集群 DNS 服务;使用 --cluster-dns 标志将此内容传递到 kubelet 中。search 行必须包含相应的后缀,供您查找服务名称。在此例中,将查找本地名称空间中的服务 (default.svc.cluster.local)、所有名称空间中的服务 (svc.cluster.local) 和集群 (cluster.local)。根据您自己的安装,您可能还有其他记录。使用 --cluster-domain 标志将集群后缀传递到 kubelet 中。options 行必须将 ndots 设置为足够高的值,以便 DNS 客户机库考虑搜索路径。默认情况下,Kubernetes 将其设置为 5 ,该值足以涵盖它生成的所有 DNS 名称。

如果以上所有操作均告失败,您可能需要检查 kube-proxy

网络策略

NetworkPolicy 可定义允许 pod 彼此通信以及与其他网络端点进行通信的方式。NetworkPolicy 使用标签来管理 pod 之间的流量。如果您无法与 pod 进行通信,那么可检查网络策略,看看是否不允许此 pod 获取任何请求。默认情况下,pod 不会被隔离,它们可以接受流量。但为 NetworkPolicy 选择特定 pod 后,就会拒绝通过未经授权的连接进行任何通信。

让我们来看一个 NetworkPolicy 示例:

kind: NetworkPolicy
  	apiVersion: networking.k8s.io/v1
  	metadata:
  	  name: access-nginx
  	spec:
  	  podSelector:
  		matchLabels:
  		  run: nginx
  	  policyTypes:
  	  - Ingress
  	  - Egress
  	  ingress:
  	  - from:
  		- podSelector:
  			matchLabels:
  			  access: "true"
  	  egress:
  	  - to:
  		- ipBlock:
  			cidr: 10.0.0.0/24
  		ports:
  		- protocol: TCP
  		  port: 5978

就像所有其他 Kubernetes 配置一样,NetworkPolicy 具有 kind、apiVersion 和 metadata 参数,用于提供常规信息。您可在以上示例中看到 spec 内包含 podSelector,用于选择要在此 NetworkPolicy 中包含的 pod。在此示例中,将包含所有 nginx pod。 注意: 如果 podSelector 为空,此 NetworkPolicy 将影响相同名称空间内的所有 pod!

您需要检查的另外两个重要参数是 ingress 和 egress;这两个参数会影响与 podSelector 中的 pod 通信时支持的传入和传出网络。您应仔细核对这些参数,确保插入正确的标签、IP 和端口,以便允许 pod 进行通信,避免其遭到阻止。

使用 Weave Scope

Weave Scope 是用于 Docker 和 Kubernetes 的开源可视化和监视工具。它提供了您的应用和整个基础架构的自上而下的视图,并且支持您在将分布式容器化应用部署到云提供者时,实时诊断其中存在的任何问题。要在 Kubernetes 集群上安装 Weave Cope, 可在此处查找说明 。如果不使用 Weave Scope,我非常鼓励您使用一个类似的监视工具,轻松显示容器正在执行的操作以及执行相应操作的原因。

使用 Grafana

Grafana 是一个开源的通用仪表板和图形编辑器,作为 Web 应用程序运行。您可使用 Grafana 来获取集群和 pod 的 CPU、内存及负载指标。每位 IBM Cloud 用户都会自动获得 Grafana 访问权和帐户。要开始使用 Grafana,可阅读此处教程。要了解如何使用 Grafana 并为 Kubernetes 集群创建仪表板, 可在此处阅读了解更多信息

结束语

既然您已学习了 Kubernetes 应用程序的日志记录和调试方面的基础知识,现在就可以尝试使用并探索其他一些工具:

参考资源

本文翻译自: Debug and log your Kubernetes applications (2019-02-04)


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK