「12.Maintenance and Troubleshooting」

在本章的各节中,我们将介绍「应用级别」和「集群级别」的维护。

我们还将从多个角度介绍「故障排除」,包括调试pod和容器,测试服务的连接性,解读资源的状态,以及节点维护。

最后我们还将介绍如何使用etcd,即 Kubernetes的控制层面的存储组件。

本章主要面向集群管理员和应用开发人员。

12.2. Removing a Pod from a Service

对于定义良好并由几个pod支持的服务(请参阅5.1节),如果其中一个pod出现了问题,如何将这个pod从访问点列表中移除,以便稍后再进行检查?

可以使用–overwrite-参数重新标记该pod,通过该参数可以改写pod上run命令的标签。通过改写标签,可以确保该pod不会被服务选择器(请参阅5.1节)选中,并从访问点列表中移除该pod同时,负责监视pod的副本集会发现一个pod消失不见了,从而启动一个新的副本。

(1)首先使用 kubectl run(参阅4.4节)生成一个简单的部署: kubectl run nginx –image nginx –replicas 4

(2)当查看pod时,请注意观察字段run中显示的标签,你会看到有4个pod的值为 nginx (run=nginx是 kubectl run命令自动生成的标签):

# kubectl get pods -Lrun

(3)然后为这个部署建立一个服务并查看访问点(每个访问点对应于各自的podIP地址):

# kubectl expose deployments nginx –port 80

# kubectl get endpoints

(4)接下来,可以通过一个简单的命令将第一个pod从服务列表中删除:

# kubectl label pods “nginx-d5dc44cf7-5845r” run=notworking –overwrite

(!!!本质上就是修改了LABEL,使得Service不再选择该Pod!!!)

为了找到pod的IP地址,你可以通过JSON格式查看pod清单文件并运行一个 JQuery查询:

#kubectl get pods nginx-d5dc44cf7-5845r -o json | jq-r. status.podIP

一个新的标记为run=nginx的Pod出现在列表中, notworking的pod依然存在,但是不会再出现在服务访问点列表中:

12.3. Accessing a ClusterIP Service Outside the Cluster

如果内部服务出现问题,如何在不公开到外部的情况下,测试它在本地能否工作正常?

可以通过 kubectl proxy Kubernetes的API服务器建立代理。

从 Kubernetes集群外部无法访问该服务。但是可以在另外一个终端窗口运行代理,然后在 localhost上访问该服务。

首先在另外一个终端窗口运行代理:kubectl proxy # 通过–port参数在指定的端口上运行代理

然后,在先前的终端窗口中使用浏览器或curl访问该服务开放的应用程序。请注意需要在访问该服务的路径中加入“/proxy”,否则只能得到代表该服务的JSON对象:

# curl http: //1ocalhost: 8001/api/v1/proxynamespaces/default/services/nginx/

请注意你可以通过curl访问 localhost Kubernetes的 API.

12.4. Understanding and Parsing Resource Statuses

如何在脚本或另外一个自动化环境。例如:持续集成和持续交付管道中,根据资源(比如pod)的状态进行相应的操作?

可以使用kubectl get $KIND/$NAME -o json,并使用下述的方法解析json输出结果。

如果你安装了JSON查询工具jq,那么可以使用它解析资源的状态。假设有一个叫做jump的pod,现在要了解该pod的服务质量(Quality of Service,QoS)水平:

# kubectl get po/jump -o json | jq –raw-output .status. qosClass

再举一个关于查询事件或状态变化的例子:

# kubectl get po/jump -o json | jq .status.conditions

当然,这些查询不仅限于pod,你可以用这些技巧查询任何资源。例如,可以查询部署的改版信息:

# kubectl get deploy/prom -o json | jq .metadataannotations

或者可以查询构成服务的所有访问点:

# kubectl get ep/prom-svc -o json | jq ‘.subsets’

以上是jq的介绍,现在我们再来看看一个不需要外部工具的方法,即使用Go模板的自带功能。
Go编程语言可以在名为text/template的包内定义模板,而这些模板可以用于任何类型的数据转换,且 kubectl1自带对这种模板的支持。例如,可以通过如下命令,查看当前命名空间中的所有容器映像:

#!/bin/sh

kubectl get pods -o go-template \
			--template="range. itemsrange .spec.containers.image endend \
			busybox prom/prometheus

jq指南(htts: . jq tm(https: /stedolan.github.io/jqlmanual/) ..ojmna)

·jq练习环境,无需安装jq也可以练习查询 . jqym, Ek#jq t uClAEia(https: ljqplay.org/).

Go语言的包模板(htts: . Go iawett(https: /golang.org/pkg/text/template/)..org/pkg/text/templte)。

12.5. Debugging Pods

如果遇到pod无法按照预期启动,或在一段时间后发生故障的情况,应当如何处理?

为了系统地发现并修复问题产生的原因,我们需要采用OODA循环流程:

1.观察(Oberve)。容器日志中有什么?发生了什么事件?网络连通性如何?

2.调整(Orient)。制定一套合理的假设,尽可能大胆地设想,但不要急于下结论。

3.决定(Decide)。选择其中一种假设。

4.行动(Act)。测试选择的假设。如果得到证实,那么问题就解决了;否则重回第一步。

让我们来看一个pod发生故障的实例。首先创建一个明文 unhappy–pod.yaml的清单文件,内容略过:

现在启动该部署,并看看创建的pod,会发现结果不太顺利:

# kubectl create -f unhappy-podyaml

# kubectl get po

# kubectl describe po/unhappy-3626010456-4j251

Kubernetes认为该pod没有准备好服务访问,因为它遇到了一个 error syncing pod”的错误。

另一种查看上述信息的方式是使用 Kubernetes的仪表盘,查看部暑(见图12-1)以及监控的副本集与pod(见图12-2)。

导致pod故障或节点行为异常的原因可能不尽相同。在怀疑软件bug之前请先检查以下若千事项:

清单文件正确吗?请结合Kubernetes的JSON结构(atp:/github.comgareth/ kubernetes-json-schema)进行排査。

容器是独立运行的吗?是在本地(也就是在 Kubernetes之外)运行的吗?Kubernetes可以访问容器的注册,以及查看容器的映像吗?

节点之间可以互相对话吗?

节点可以访问主节点吗

集群的DNS工作正常吗?

节点上有足够的资源吗?

容器的资源使用是否受限

Kubernetes故障排除应用程序文档
(htps:/ kubernetes. ioldocs/tasks/debugapplication-cluster/debug-application/)

应用程序的自我检査和调试
(https:/kubernetes.io/docs//tasks/debugapplication-cluster/debug-application-introspection/

调试pod和副本控制器
https://kubernetes.io/docs/tasks/debug-applicationcluster/debug-pod-replication-controller/%EF%BC%89
调试服务
(htps:/ kubernetes.io/ docs/tasks/debug- application- cluster/debugservice/)。

集群的故障排除
(hipi:/ kubernetes.io/ docs/tasks/. debug- applicationclusterldebug-cluster/)

12.6. Getting a Detailed Snapshot of the Cluster State

如何才能获得整个集群状态的详细快照,以便于调整、检查或排除故障?

使用 kubectl clusterinfo dump命令。例如,在子目录 cluster-state–2017-08-13中创建集群状态的转储,如下所示:

# kubectl cluster-info dump –all-namespaces –output-directory=$PWD/cluster-state-2017-08-13

# tree. /cluster-state-2017-08-13

12.7. Adding Kubernetes Worker Nodes

如何向 Kubernetes集群添加工作节点?

根据环境的需要(例如,在裸金属裸机环境中需要在机架上安装一台新服务器,或在公有云环境中,需要建立新的虚拟机等)准备一台新的服务器,然后安装三个组件建立 Kubernetes的工作节点:

# kubelet,kubelet是节点管理员,负责监控所有的pod,无论是API服务器控制的pod,还是在本地运行的静态pod

请注意 kubelet是最后的仲裁者,可以决定哪些pod可以在节点上运行,哪些不可以,并负责:

向API服务器报告节点和pod的状态。

定期地执行存活探针

挂载pod卷并下载secret

控制容器的运行时。

# 容器的运行时,负责下载容器映像以及运行容器。最初它是 Docker引擎固有的功能,但容器的运行时

是如今它是基于容器运行时接口(Container Runtime Interface,Cri)的插件系统,所以可以使用CRI-O等代替 Docker

# kube-proxy,此进程可以根据节点的规则自动配置 iptables Kubernetes kube-proxy服务的抽象层(将VIP重新指向一个或多个代表该服务的pod访问点)。

这些组件的安装要根据实际的环境情况以及选用的安装方法(云端、kubeadm等)决定。可选的参数列表,请参照 kubelet参考手册kubeernets.io/docs/reference/generated/kubelet,以及kube-proxy的参考手册 kubernetes.iol/docs/referencelgenerated/kube-proxy)o

工作节点与Kubernetes部署或服务不同,并非由Kubernetes管理中心直接创建, Kubernetes只负责管理。。这也就意味着,Kubernetes中创建节点的时候,实际上仅创建了代表工作节点的对象。 Kubernetes根据节点的 metadata.name字段进行健康检查,从而判断节点的合法性,如果节点合法(即所有必要的组件都处于运行状态),将其归为集群的一部分;否则,所有的集群活动都会忽略此节点,直到节点合法。

KubernetesKubernetes节点
github.com/kubernetes/community/blob/master/contributors/design-proposals/ architecturelarchitecture. md#the-kubernetes-node)

主节点的交流 .
(https: //kubernetes.ioldocs/coi /architecture/master- node-communication/).

静态Pod: (https: //kubernetes.ioldocs/tasks/adm/static-pod)。

12.8. Draining Kubernetes Nodes for Maintenance

如何对节点实施维护工作,例如打安全补丁或升级操作系统?

可以使用 kubectl drain实施维护: kubectl drain 123-worker

在准备将节点放回服务的时候,可以使用 kubectl uncordon 123-worker命令,节点就可以被调度了。

kubectl drain命令所做的工作包括:首先将指定的节点标记为不可调度,从而阻止新pod被分配到节点上(实质上是 kubect1 codon),然后如果API服务器支持则收回所有pod。否则就使用常见的 kubectl delete命令删除pod。 Kubernetes的文档详细描绘了这些步骤的时序图,如图12-3所示API服务器

kubectl drain命令会回收或删除所有的pod,除了镜像pod(API服务器无法删除镜像pod)。对于由 DaemonSet ignore daemonsets drain命令则无法执行,且无论怎样它都不会删除任何由 DaemonSet DaemonSet制器立即替换,所以会忽略不可调度的标记)。

drain命令会等待正常的结束,所以在kubect1 drain命令结束前不应该操作该节点。请注意 kubectl drain $NODE –force也可以收回pod,除非、pod由RC、RS、工作、DaemonSet、StatefulSet管理。

·在考虑应用程序SLO的同时安全的抽出节点
//kubernetes.ioldocs/ tasks/administer-cluster/safely-drain-node/).

kubectl&yxt(https: //kubernetes.ioldo/reference/generated/的参考文档(https:1/kuberntes.ioldocslreferencelgenerated/ kubectl/kubectl-commands#drain).

12.9. Managing etcd

如何访问etcd以进行备份,或直接检验集群的状态?

可以使用curl或 etcdctl Minikube中(假设安装了jq):

# minitube ssh

# curl 127.0.0.1:2379/v2/keys/registry | jq .

这个方法适用于任何加载了 etcd v22API的环境。

etcd是 Kubernetes控制中心的组件。API服务器(请参阅6.1节)是无状态的,且是唯一可以直接与etcd交流的 Kubernetes组件,etcd是管理集群的状态的分布式存储组件。本质上,etcd是以键值的形式保存的,在etcd2中键组成了层次结构,但是根据etcd3的介绍,存储方式改为了扁平化结构(并向后兼容层次结构的键)。

一般来讲,理应由集群管理员负责管理etc,即负责升级并备份数据。在特定环境中,如果由控制中心管理etcd,比如 Google Kubernetes引擎,那就无法直接访问etcd。这是设计上的考虑,没有其他方法可以解决这个问题。

# 相关连接

Etcd v22集群管理员指南
(https: //coreos. com/etcdldocs/latest/v2/admin_guide.html

Etcd v33灾难恢复指南
https: //coreos.com/etcd/docs/latest/op-guidel recovery.html

·操控 kubernetes etcd 集群
(https: //kubernetes.io/docs/tasks/administer-cluster/configure-upgrade-etcd/)

minikube文档中“从pod内部访问Localkube资源:etcd实例”
(https:/ github. com/kubernetes/minikubelblob/master/docs/accessing_etcd. md)

Stefan Schimanski Michael Hausenblas的博文“深度探索 Kubernetes:API服务器之二 api E&&z-
(https://blog.openshift. com/kubernet- server–part-2/)。

Michael Hausenblas ttxM etcd2 Fetcd3EA”的博文“从etcd2转换到etcd3的注意点”
(https: hackernoon. com/notes-on-moving-from-etcd2-to-etcd3).