[toc]
0x00 前言简述 前面简单的介绍了Kubernetes基础知识以及单节点和高可以用集群的搭建, 本章将从实操来介绍Kubernetes概念和术语以及控制器,便于各位读者进行学习;
0x01 资源清单 Q: 什么是资源?
答: K8s中所有的内容都抽象为资源在资源实例化(容器被执行
)之后叫做对象;
Q: 什么是Kubernetes对象?
答:Kubernetes对象指的是Kubernetes系统的持久化实体,所有这些对象合起来代表了你集群的实际情况。创建一个k8s对象就是告诉Kubernetes,您需要的集群中的工作负载是什么(集群的目标状态), 因为一个Kubernetes对象代表着用户的一个意图(a record of intent),一旦您创建了一个Kubernetes对象,Kubernetes将持续工作以尽量实现此用户的意图。
常规的应用里我们把应用程序的数据存储在数据库中,Kubernetes将其数据以Kubernetes对象的形式通过 api server
存储在 etcd 中; Kubernetes对象数据描述的信息:
集群中运行了哪些容器化应用程序(以及在哪个节点上运行)
集群中对应用程序可用的资源
应用程序相关的策略定义,例如,重启策略、升级策略、容错策略
其他Kubernetes管理应用程序时所需要的信息
如何进行Kubernetes对象的CURD呢?
答:自带的kubectl命令或者一些管理k8s的图形化界面工具比如Kuboard或者Kubedash;
PS: kubectl、kuboard 最终都通过调用 kubernetes API 来实现对 Kubernetes 对象的操作。您也可以直接在自己的程序中调用 Kubernetes API,此时您可能要有用到 Client Libraries
基础补充:
1.名称空间级别资源 (Namespace Level): 仅在此名称空间下生效k8s的系统组件是默认放在kube-system名称空间下
的,而kubectl get pod等价于kubectl get pod -n default,因此查看不到k8s的系统组件。
工作负载型资源(workload):Pod、ReplicaSet(调度器控制器通过标签保证Pod的副本数以及创建Pod)、Deployment、StatefulSet(有状态服务的控制器)、DaemonSet(可以在每个节点都运行一个Pod的组件)、Job、CronJob(ReplicationController在v1.11版本被废弃)
服务发现及负载均衡型资源(Service Discovery LoadBalance):Service、Ingress、…
配置与存储型资源:Volume(存储卷)、CSI(容器存储接口可以扩展各种各样的第三方存储卷)
特殊类型的存储卷:ConfigMap(当配置中心来使用的资源类型可以达到热更新)、Secret(保存敏感数据)、DownwardAPI(把外部环境中的信息输出给容器)
2.集群级资源:不管在任何名称空间下定义,在其他的名称空间下都能看得到,在定义的时候无需指定名称空间
Namespace、Node、Role、ClusterRole、RoleBinding、ClusterRoleBinding
3.元数据型资源:提供一个指标,不像是名称空间类型又不像集群级别,本质上更像是在两者之间,但是它有自己的特点,所以更应该作为一个单独的分类,例如HPA【通过cpu的利用率进行平滑扩展】就是一个很明显的元数据类型,通过指标进行操作。
HPA、PodTemplate、LimitRange(根据指标进行相对应的操作)
Q: 什么是资源清单?
答: 您可以将其理解为剧本,里面规定了每一步如何操作,Kubernets只需要按照要求去做即可; 在 K8s 中一般使用Yaml格式或者Json格式的文件来创建符合我们预期期望的Pod,该yaml文件我们称为资源清单;
Q: 如何编辑资源清单?
答: 在编写清单时候必须对Kubernetes定义Pod以及控制器(Controller)的常用字段有一定的了解, 如果忘记对象的资源清单字段可以通过explain命令查看相对应的控制清单编写字段;
资源清单编写帮助: 获取资源的apiVersion的版本信息(以pod为例),该命令同时输出属性设置帮助文档
[toc]
0x00 前言简述 前面简单的介绍了Kubernetes基础知识以及单节点和高可以用集群的搭建, 本章将从实操来介绍Kubernetes概念和术语以及控制器,便于各位读者进行学习;
0x01 资源清单 Q: 什么是资源?
答: K8s中所有的内容都抽象为资源在资源实例化(容器被执行
)之后叫做对象;
Q: 什么是Kubernetes对象?
答:Kubernetes对象指的是Kubernetes系统的持久化实体,所有这些对象合起来代表了你集群的实际情况。创建一个k8s对象就是告诉Kubernetes,您需要的集群中的工作负载是什么(集群的目标状态), 因为一个Kubernetes对象代表着用户的一个意图(a record of intent),一旦您创建了一个Kubernetes对象,Kubernetes将持续工作以尽量实现此用户的意图。
常规的应用里我们把应用程序的数据存储在数据库中,Kubernetes将其数据以Kubernetes对象的形式通过 api server
存储在 etcd 中; Kubernetes对象数据描述的信息:
集群中运行了哪些容器化应用程序(以及在哪个节点上运行)
集群中对应用程序可用的资源
应用程序相关的策略定义,例如,重启策略、升级策略、容错策略
其他Kubernetes管理应用程序时所需要的信息
如何进行Kubernetes对象的CURD呢?
答:自带的kubectl命令或者一些管理k8s的图形化界面工具比如Kuboard或者Kubedash;
PS: kubectl、kuboard 最终都通过调用 kubernetes API 来实现对 Kubernetes 对象的操作。您也可以直接在自己的程序中调用 Kubernetes API,此时您可能要有用到 Client Libraries
基础补充:
1.名称空间级别资源 (Namespace Level): 仅在此名称空间下生效k8s的系统组件是默认放在kube-system名称空间下
的,而kubectl get pod等价于kubectl get pod -n default,因此查看不到k8s的系统组件。
工作负载型资源(workload):Pod、ReplicaSet(调度器控制器通过标签保证Pod的副本数以及创建Pod)、Deployment、StatefulSet(有状态服务的控制器)、DaemonSet(可以在每个节点都运行一个Pod的组件)、Job、CronJob(ReplicationController在v1.11版本被废弃)
服务发现及负载均衡型资源(Service Discovery LoadBalance):Service、Ingress、…
配置与存储型资源:Volume(存储卷)、CSI(容器存储接口可以扩展各种各样的第三方存储卷)
特殊类型的存储卷:ConfigMap(当配置中心来使用的资源类型可以达到热更新)、Secret(保存敏感数据)、DownwardAPI(把外部环境中的信息输出给容器)
2.集群级资源:不管在任何名称空间下定义,在其他的名称空间下都能看得到,在定义的时候无需指定名称空间
Namespace、Node、Role、ClusterRole、RoleBinding、ClusterRoleBinding
3.元数据型资源:提供一个指标,不像是名称空间类型又不像集群级别,本质上更像是在两者之间,但是它有自己的特点,所以更应该作为一个单独的分类,例如HPA【通过cpu的利用率进行平滑扩展】就是一个很明显的元数据类型,通过指标进行操作。
HPA、PodTemplate、LimitRange(根据指标进行相对应的操作)
Q: 什么是资源清单?
答: 您可以将其理解为剧本,里面规定了每一步如何操作,Kubernets只需要按照要求去做即可; 在 K8s 中一般使用Yaml格式或者Json格式的文件来创建符合我们预期期望的Pod,该yaml文件我们称为资源清单;
Q: 如何编辑资源清单?
答: 在编写清单时候必须对Kubernetes定义Pod以及控制器(Controller)的常用字段有一定的了解, 如果忘记对象的资源清单字段可以通过explain命令查看相对应的控制清单编写字段;
资源清单编写帮助: 获取资源的apiVersion的版本信息(以pod为例),该命令同时输出属性设置帮助文档1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 kubectl explain pod kubectl explain pod.apiVersion
查看k8s中有对象可用那些资源的API版本(1.19.6)1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 $ kubectl api-versions apiVersion: apps/v1 apps/v1 v1 admissionregistration.k8s.io/v1 admissionregistration.k8s.io/v1beta1 apiextensions.k8s.io/v1 apiextensions.k8s.io/v1beta1 apiregistration.k8s.io/v1 apiregistration.k8s.io/v1beta1 authentication.k8s.io/v1 authentication.k8s.io/v1beta1 authorization.k8s.io/v1 authorization.k8s.io/v1beta1 autoscaling/v1 autoscaling/v2beta1 autoscaling/v2beta2 batch/v1 batch/v1beta1 certificates.k8s.io/v1beta1 coordination.k8s.io/v1 coordination.k8s.io/v1beta1 crd.projectcalico.org/v1 discovery.k8s.io/v1beta1 events.k8s.io/v1beta1 extensions/v1beta1 networking.k8s.io/v1 networking.k8s.io/v1beta1 node.k8s.io/v1beta1 policy/v1beta1 rbac.authorization.k8s.io/v1 rbac.authorization.k8s.io/v1beta1 scheduling.k8s.io/v1 scheduling.k8s.io/v1beta1 storage.k8s.io/v1 storage.k8s.io/v1beta1
(1) 对象字段 描述: 每个K8s控制器对象都包含了两个重要的字段,即 spec
和 status
字段, Kubernetes通过对应的控制器,不断地使实际状态趋向于您期望的目标状态。
spec 必须由您来提供,描述了您对该对象所期望
的 目标状态
status 只能由 Kubernetes 系统来修改,描述了该对象在 Kubernetes 系统中的 实际状态
例如,一个 Kubernetes Deployment 对象可以代表一个应用程序在集群中的运行状态。当您创建 Deployment 对象时,您可以通过 Deployment 的 spec 字段指定需要运行应用程序副本数(replicas假设为3)。Kubernetes 从 Deployment 的 spec 中读取这些信息,并为您创建指定容器化应用程序的 3 个副本,再将实际的状态更新到 Deployment 的 status 字段。Kubernetes 系统将不断地比较 实际状态 staus 和 目标状态 spec 之间的差异,并根据差异做出对应的调整。 例如,如果任何一个副本运行失败了,Kubernetes 将启动一个新的副本,以替代失败的副本。
apiVersion - 必须 描述: 用来创建对象时所使用的Kubernetes API版本,可通过kubectl api-versions
命令查询可用API版本;1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 kubectl api-versions admissionregistration.k8s.io/v1 apiextensions.k8s.io/v1 apiregistration.k8s.io/v1 apps/v1 authentication.k8s.io/v1 authorization.k8s.io/v1 autoscaling/v1 autoscaling/v2 autoscaling/v2beta1 autoscaling/v2beta2 batch/v1 batch/v1beta1 certificates.k8s.io/v1 coordination.k8s.io/v1 crd.projectcalico.org/v1 discovery.k8s.io/v1 discovery.k8s.io/v1beta1 events.k8s.io/v1 events.k8s.io/v1beta1 flowcontrol.apiserver.k8s.io/v1beta1 flowcontrol.apiserver.k8s.io/v1beta2 networking.k8s.io/v1 node.k8s.io/v1 node.k8s.io/v1beta1 policy/v1 policy/v1beta1 rbac.authorization.k8s.io/v1 scheduling.k8s.io/v1 storage.k8s.io/v1 storage.k8s.io/v1beta1 v1
kind - 必须 描述:被创建对象的类型常用的有Deployment(部署)、Service(服务端口)
描述:用于唯一确定该对象的元数据,包括 name
和 namespace
,如果 namespace 为空,则默认值为 default;1 2 3 metadata: name: nginx-deployment namespace: nginx-app
Annotation - 注解 描述: 从Annotation字面意思理解其用途就是注解,或者有一些小伙伴看到过它,它类使用前面所提到的Label其也是采用Key/Value键值对进行表示;1 2 3 4 metadata: annotation: key1: value1 key2: value2
Q: Annotation 与 Lables 不同之处?
答: Lable 具有更为严格的命令规则,主要用于定义资源对象的元数据(Metadata)并且被Label Seletor使用 Annotation 是用户任意定义的附加信息,便于外部工具查找;
Q: Annotation 记录的信息?
A: Build 信息、Release 信息、Docker Image 信息、Docker Registry地址 A: 开发环境信息、工具名称、版本号等 A: 团队开发信息、电话号码、负责人、以及网站等
spec - 必须 描述:您对该对象的期望状态但是需注意不同类型的 Kubernetes,其 spec 对象的格式不同(含有不同的内嵌字段),通过 API 手册 可以查看 Kubernetes 对象的字段和描述;
例如,假设您想了解 Pod 的 spec 定义,可以在 这里 找到,Deployment 的 spec 定义可以在 这里 找到;
资源清单常用的字段描述:
资源清单格式: 1 2 3 4 5 6 7 8 9 apiVersion: group/apiversion kind: metadata: name: namespace: lables: annotations: spec: status:
示例:以下是创建Pod所定义清单文件内容1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 apiVersion: v1 kind: Pod metadata: name: pod-demo namespace: default 1 abels: app: myapp spec: containers: - name: myapp-1 image: harbor.weiyigeek.top/1ibrary/myapp:v1 - name: busybox-1 image: busybox:latest command: - "/bin/sh" - "-c" - "sleep 3600"
PS: 创建pod时如发生错误可以通过kubectl describe pod myapp-pod-name
和kubectl logs myapp-pod-name
命令查看pod相关信息(注意如果有名称空间则需要加上); PS: 一个Pod内支持多个容器运行所以在定义资源清单的时候,可以在spec.containers
数组中指定多个运行的容器及其镜像;
0x02 NameSpace - 名称空间 描述: Namespace即名称空间,您可能在c++
或者c#
中听说它, 它也是K8s系统中非常重要的一个概念;
Tips : 由于创建多个集群会导致集群资源使用碎片化以及更多的维护成本,可以通过Kubernetes的NameSpace对不同工作组的需求隔离。
Q: namespace 有何作用?
A: 它可以通过不同的资源对象调度到不同的Namespace中, 从逻辑上形成不同项目、小组或用户组,便于不同的分组之间能够共享使用整个集群的资源同时还能分别管理; 简而言之: namespace 能够帮助不同的租户(多租户管理)共享一个k8s集群的资源,使得整个集群的配置非常灵、方便。
Q: namespace 命名规则?
A: 只能包括[a-z0-9]
并且最大长度为63位;
Tips : 默认情况下k8s集群会创建一个默认的名称空间即Default, 如果采用资源对象未指定namespace时,则用户所创建的所有资源对象如Pod、RC、RS、Deployment、Service
都将被分配到default的namespace之中;
namespace 创建查看
Step 1.名称空间创建的两种方式命令行、yaml配置文件
1 2 3 4 5 6 7 8 9 10 11 12 kubectl create namespace dev-ops apiVersion: v1 kind: Namespace metadata: name: dev-ops kubecrl create -f namespace-create.yaml
Step 2.查看名称空间
1 2 3 4 5 6 7 8 9 10 11 12 13 14 ~$ kubectl get ns ~$ kubectl describe ns dev-ops
Step 3.删除名称空间(非常注意删除名称空间是非常注意是该namespace下存在pvc/deployment/rc
等资源对象, 否则删除名称空间后其资源将被销毁)
1 2 kubectl delete namespace dev-ops kubectl delete -f namespace-create.yaml
namespace 配额 描述: 默认情况下创建的namespace并不会对资源进行配额,如果需要对某一个Namespace配额则需要配合ResourceQuota
使用;
基础示例: ResourceQuota 配额管理1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 kubectl create namespace dev-ops cat > K8s/Day1/resource-quote-demo.yaml <<'end' apiVersion: v1 kind: ResourceQuota metadata: name: resource-quote-demo spec: hard: requests.cpu: "1" requests.memory: 1Gi limits.cpu: "2" limits.memory: 2Gi end ~/K8s/Day1$ kubectl create -f resource-quote-demo.yaml -n dev-ops ~/K8s/Day1$ kubectl get resourcequota -n dev-ops ~/K8s/Day1$ kubectl describe resourcequota -n dev-ops ~/K8s/Day1$ kubectl get resourcequota -n dev-ops -o yaml
Tips : 如果此时再创建一个Pod并设置resources.requests.memory
的值为700Mi。则会显示错误由于请求700Mi已经超出剩余的剩余的Memoryquota的值,所以新创建Pod的请求将会被终止;
Tips : 非常建议每个Container设置CPU/Memory的request与limit值(涉及到Qos后文讲述)
Tips :我们不单单可以对Namespace做名称空间资源限制还可以通过其对应Container、Pod数量配额(副本数)、API对象的配额等;
0x03 Pod 基础&进阶 我们知道 Pod 是Kubernetes里最小单元,部署在节点之上包含一组容器(Container)和卷(Volume)
, 同一个Pod中的容器共享同一个网络命名空间即可以通过localhost进行相互通信; 简单的说 Pod 是一组可以在主机上运行的容器,该资源由客户端创建并调度到主机上。
先来提出几个问题&回答:
(1) 如果Pod生命周期是短暂的那么如何才能持久化容器数据,即使在Pod被销毁或者重启到其它机器上存在?
答: k8s支持(Volume,Persistent Volumes)的概念所以可以使用持久化的卷类型;
(2) 如何创建大批量的实例副本?
答: 建议采用 Replication Controller / Replica Set / Deployment / StateSetful
使用Pod模板创建多份拷贝;
(3) 如果Pod生命周期是短暂的那么重建pod后意味着IP地址可能会发生变化,那如何才能从前端容器正确可靠的指向后端容器?
Pod 分类
自助式pod 只要pod退出了,此类型的pod不会被重建,该pod没有管理者,死亡后不会被拉起。
控制器管理的pod【生产环境中大多数都是选择控制器去管理pod】 在控制器的生命周期里始终要维持pod的副本数目
自助式pod与控制器管理的pod有何区别?
答: 其生命周期
被管理的机制不太一致
(1) Pod Template & Controller 描述: 我们一般不会在k8s中直接创建单个Pod,因为其的生命周期是短暂的(即用后即焚的实体),当Pod被创建后都会被k8s调度到集群的Node之上, 直到Pod进程终止被删除, 因为缺少资源而被驱逐或者Node故障之前这个Pod都会一直保持在那个Node上;
注意事项:
1.重启Pod中的容器和重启Pod是两种概念,因为Pod只提供容器运行环境并保持容器的运行状态所有重启容器并不会导致Pod重启, 最外层还有个Pause容器在运行;
2.自助式Pod并不会自愈,如果当Pod运行的Node节点故障或者调度器本身故障该Pod就会被删除,同样的如果Pod所在Node缺少资源或者Pod处于维护状态也将会被驱逐,所以常常使用Controller来管理Pod的。
Controller 可以创建和管理多个Pod并且提供副本管理、滚动升级和集群级别的自愈能力; 例如:当一个Node故障Controller就能自动将该节点上的Pod调度到其他健康的Node上;
常用于创建Pod的控制器列表: 一般来说Pod并不会自动消失,除非是特意将它们进行销毁如人为操作或者控制器操作, 该规则唯一例外的是成功或者失败的Phase超过一段时间(由Master确定操作)的Pod将过期并被自动销毁; 如下列控制器:
Replication Controller
Delopyment
StatefulSet
DaemonSet
Job
Tips : 通常Controller会通过Pod Template
来创建相应的Pod, 而又为什么建议使用控制器创建Pod而非直接创建呢?;
答: 因为单独的Pod在机器故障的情况下没有办法自动复原而控制器则可以按照期望副本数进行构建复原;
什么是Pod模板? 答: Pod 模板是包含了其他对象(例如RC、Jobs和DeamonSets)中的Pod定义。Controller 控制器使用 Pod模板 以及 selector选择器 来创建实际需要的Pod;
(1) Pod 资源配额与限额 描述: 每个Pod都可以对其能使用的服务器上的计算机资源比如CPU和Memory进行设置限额,值得注意的是CPU的资源单位为CPU(Core)的数量是一个绝对值而非相对值,同样Memory也是一个绝对值;
在Kubernets中CPU常以千分之一的CPU配额作为最小的单元通常用m
表示,而Memory配额单位是内存字节数通常用Mi
表示; 例如: 通常一个容器的配额被定义为100~300m即占用0.1~0.3个CPU,由于CPU配额是个绝对值所以说无论是1C或者48C的机器上100m代表的配额都是一样的;1 2 3 4 5 6 7 8 9 resources: limits: cpu: 500m memory: 500Mi requests: cpu: 500m memory: 6Gi
示例.Pod Template & Pod resources1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment namespace: nginx-app labels: app: nginx spec: selector: matchLabels: app: nginx role: master tier: backend replicas: 2 template: metadata: labels: app: nginx role: master tier: backend spec: containers: - name: nginx image: nginx:1.7.9 resources: requests: cpu: 100 m memory: 100 Mi limits: cpu: 800 m memory: 800 Mi ports: - containerPort: 8080
Yaml 配置文件相关操作:1 2 3 kubectl apply -f deployment.yaml kubectl apply -f https://weiyigeek.top/k8s/deployment.yaml
Tips : 可以采用直接 RUN 创建Pod, 实际上不加port也能通过服务进行发现实际工作中一定要加上为了后期问题的排查1 kubectl run nginx --image nginx:latest --port=80 --replicas=2
(2) Static Pod (静态) Q: 什么是静态Pod?
答: 在 k8s 中由kubelet创建并运行的Pod, 该种类型的Pod可以在某个节点上长期运行(即静态Pod)。 简单说静态 pod 是由 kubelet 创建和管理的只在特定node上存在的 pod,并且只在kubelet所在的Node上运行。
静态Pod特点:
1.静态 pod 总是由某个节点上的 kubelet 创建和管理的, 即不能通过 api-server 来管理,所以无法和 RC,RS,Deployment 或者 DaemonSet控制器
进行关联。
2.kubelet 无法对 静态 pod 进行健康检查。
3.如果把 pod 的yaml描述文件放到这个目录中,等kubelet扫描到文件,会自动在本机创建出来 pod;
4.如果把 pod 的yaml文件更改了,kubelet也会识别到,会自动更新 pod;
5.如果把 pod 的yaml文件删除了,kubelet会自动删除掉pod;
6.如果当 kubelet 发现静态Pod停止掉时候,将会重新启动静态Pod;
Tips: 因为静态 pod 不能被 api-server 直接管理,所以它的更新删除操作不能由 kubectl 来执行,只能直接修改或删除文本文件。
静态Pod创建的两种方式:
1.HTTP: kubelet 周期地从采用 --manifest-url
参数指定的地址下载文件,并且将它翻译成JSON/YAML格式的Pod定义(实际与下面差距不大只是增加了下账的步骤)
2.配置文件:kubelet 启动时采用 --pod-manifest-path=/etc/kubernetes/manifests
指定yaml文件存放目录 会定期扫描这个目录,并根据这个目录下的 .yaml 或 .json 文件进行创建和更新操作
例如将static-nginx-web.yaml文件加入到该文件夹之中, 重启 Kubelet 服务或者等待几秒即可创建静态 Pod;1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 sudo tee /etc/kubernetes/manifests/static-pod.yaml <<'EOF' apiVersion: v1 kind: Pod metadata: name: static-nginx-web lables: app: nginx spec: containers: - name : web image: nginx:latest imagePullPolicy: IfNotPresent ports: - name: nginx-port containerPort: 80 protocol: TCP EOF
操作流程:
(3) Pod 生命周期 Q: 主要通过以下层面了解Pod的声明周期;
在Pod被创建后经历的过程及其状态;
Pod中容器探测纠察;
Pod 创建过程与各对象生命周期流程图:
weiyigeek.top-k8s中Pod创建过程与生命周期
简单说明:
1.前面我们讲解了Kubectl、KubeAPI-Server、ETCD、Kubelet、CRI等组件此处不在累述;
2.Pause 容器: Pod 创建之初的创建它是Pod里容器共享网络栈以及存储卷必备的;
3.Init C(初始化容器): Pod 能够具有一个或多个容器,应用运行在容器里面,但是它也可能有一个或多个先于应用容器启动的Init容器。
2.1 Init容器与普通的容器区别: Init容器总是运行到成功完成为止,每个Init容器都必须在下一个Init容器启动之前成功完成(有一定的顺序
)。
2.2 如果Pod的Init容器失败 Kubernetes会不断地重启该Pod,直到Init容器成功为止。但是如果 Pod 对应的 restartPolicy【默认为Always】 设置为Never
,它将不会重新启动。
4.Mian C(主容器 ): 在Pod中可以运行一个多个容器它们都有各自的生命周期, 当Pod中主容器结束退出时Pod将结束;
5.Start / Stop : 在容器启动或者停止时候执行的脚本
6.Readiness : 在主容器启动后进行其应用进程探测,完成后容器的状态将改变成Running;
7.Liveness : 在主容器的生命周期都有它的身影,其作用是在主容器的进程与其检测结果不一致的情况下将执行重启或者删除容器;
Pod Phase 描述: Pod的status字段是保存在一个PodStatus对象中,该 PodStatus 中有一个 phase 字段。 Pod的相位(phase) 是 Pod 在其生命周期中的简单宏观概述。
PS : 该阶段并不是对容器或Pod的综合汇总,也不是为了做为综合状态机, 并且Pod相位的数量和含义是严格指定的。 PS : 除了本文档中列举的状态外不应该在假定Pod有其他的phase值
Pod phase 可能存在的几种状态值:
挂起(Pending):Pod 已被 Kubernetes系统接受,但有一个或者多个容器镜像尚未创建。等待时间包括调度Pod的时间和通过网络下载镜像的时间,这可能需要花点时间
运行中(Running):该Pod 已经绑定到了一个节点上,Pod中所有的容器都已被创建。至少有一个容器正在运行,或者正处于启动或重启状态
成功(Succeeded):Pod中的所有容器都被成功终止,并且不会再重启
失败(Failed):Pod中的所有容器都已终止了,并且至少有一个容器是因为失败终止。也就是说容器以非0状态退出或者被系统终止
未知(Unknown):因为某些原因无法取得Pod的状态,通常是因为与Pod所在主机通信失败
Pod 的生命周期示意图(从图中可以看到Pod状态的变化)
weiyigeek.top-Pod 的生命周期示意图
示例1.Pod Phase 与 Pod 运行状态查看1 2 3 4 5 $ kubectl get pod redis-cluster-operator-6669898858-rwm7s -o yaml | grep " phase" phase: Running $ kubectl describe pod redis-cluster-operator-6669898858-rwm7s | grep "^Status" Status: Running
Pod 重启策略 描述: 当 Pod 中某一个 Container 处于退出状态(Exited)时, Kubelet 会根据 Pod Sepc 中 restartPolicy 字段的取值(Always [缺省]、OnFailure和Never
进行相应的操作;
1 2 3 kubectl explain statefulset.spec.template.spec | grep "restartPolicy" restartPolicy. The name for an init container or normal container must be restartPolicy <string>
重启策略说明:
Always : 默认重启策略只要有一个Container处于Exited时,即会重启
OnFailure : 当容器异常退出或退出状态不为0时,即会重启
Never : 无论如何都不重启
补充说明:
(1) 当一个pod设置重启策略restartPolicy
则适用于Pod 中的所有容器, 触发规则时通过同一节点上的kubelet重新启动容器。 restartPolicy 仅指, 失败的容器由 kubelet 以五分钟为上限的指数退避延迟(10秒,20秒,40秒...) 重新启动
,并在成功执行十分钟后重置。
(2) 不同控制器对不同Pod重启策略的处理机制是不一样的例如
2.1 使用 Job 控制器创建POD运行预期会终止, 如批量计算此时Job仅适用于重启策略为 OnFailure 或 Never 的 Pod;
2.2 使用 RC、RS、Deployment、StatefulSet控制器创建的Pod预期是不会终止的,如Web服务器注意RC仅适用于具有 RestartPolicy 为 Always 的Pod。
2.3 使用 DeamonSet 控制器创建的Pod将会在每台工作节点上运行,提供特定于机器的系统服务;
Tips : 如Pod文档中所述一旦绑定到一个节点,Pod将永远不会重新绑定到另一个节点。
Pod状态示例
⒈Pod 中只有一个容器并且正在运行,容器成功退出
1 2 3 4 5 ·记录事件完成 ·如果restartPolicy为: Always:重启容器; OnFailure: Never:
⒉Pod 中只有一个容器并且正在运行,容器退出失败
1 2 3 4 5 ·记录失败事件 ·如果restartPolicy为: Always:重启容器; OnFailure:重启容器; Never:
⒊Pod 中有两个容器并且正在运行。 如果容器1退出失败
1 2 3 4 5 记录失败事件· 如果restartPolicy为: Always:重启容器; OnFailure:重启容器; Never:不重启容器;
⒎Pod 正在运行,其节点被分段1 2 3 ·节点控制器等待直到超时 ·节点控制器将Pod phase设置为Failed ·如果是用控制器来运行,Pod 将在别处重建
Pod Init 容器 Q: 什么是 Init Container? 描述: 一个Pod中可以有一个或者多个 Init Container 即初始化容器操作, 其启动顺序受yaml文件中描述顺序影响进行启动(串行方式), 这表示了每个容器必须在下一个容器启动之前成功退出,否则将会阻止后续的 init Container 与 app Container 服务启动,例如 init Container 1 -> init Container 2 .. -> init Container n -> app Container
;
Q: Init容器的作用有那些?
答: 因为Init容器具有与应用程序容器分离的单独镜像,所以利用其特征主要作为服务依赖处理
, 例如某个服务A需依赖db或者Memcached, 那么可以利用服务A pod的Init Container判断dbdb或者Memcached是否正常提供服务,如果启动服务失败或者工作异常,则设置init 容器也将启动失败并且pod中的app 容器也将不会运行。
所以它们的启动相关代码具有其它优势:
(1) 它们可以包含并运行实用工具,但是出于安全考虑,是不建议在应用程序容器镜像中包含这些实用工具的 (2) 它们可以包含使用工具和定制化代码来安装,但是不能出现在应用程序镜像中。例如创建镜像没必要FROM另一个镜像,只需要在安装过程中使用类似sed、awk、python或dig这样的工具。 (3) 应用程序镜像可以分离出创建和部署的角色,而没有必要联合它们构建一个单独的镜像。 (4) Init 容器使用Linux Namespace,所以相对应用程序容器来说具有不同的文件系统视图。因此它们能够具有访问Secret的权限而应用程序容器则不能(简单的说 Init Container也可被授权访问应用Container无权访问的内容
)。 (5) 它们必须在应用程序容器启动之前运行完成,而应用程序容器是并行运行的
,所以Init容器能够提供了一种简单的阻塞或延迟应用容器的启动的方法,直到满足了一组先决条件。
init 容器补充说明:
在Pod启动过程中Init 容器会按顺序在网络和数据卷初始化之后启动【即在pause启动之后启动,pod第一个启动的容器并不是Init而是pause, 但pause仅仅只负责初始化网络和数据卷其它什么操作都不能做,我们可操作的空间几乎为0因此不做描述】。
如果由于运行时或失败退出,将导致容器启动失败,它会根据Pod的restart Policy
指定的策略进行重试。然而,如果Pod的restartPolicy设置为Always,Init 容器失败时会使用RestartPolicy 策略
从上面Pod 创建过程与各对象生命周期流程图
中可知Init Container
必须要在Pod状态变成Ready之前完成(其不需要readiness), 以及在资源的request和limits与app container 有些许差别,除以上两种init 容器 与 app 容器 大致相同;
在所有的Init容器没有成功之前,Pod将不会变成Ready状态。Init容器的端口将不会在Service中进行聚集。正在初始化中的Pod处于Pending状态,但应该会将Initializing状态设置为true
如果Pod 重启,所有Init容器必须重新执行,因此Init容器应该配置为幂等的状态。
Init 容器具有应用容器的所有字段。除了readiness Probe因为Init容器无法定义不同于完成(completion)的就绪(readiness)之外的其他状态(会在验证过程中强制执行
)
在 Pod 中的每个app和Init容器的名称必须唯一;与任何其它容器共享同一个名称,会在验证时抛出错误;当然你可以加上一个名称空间来防止冲突;
对Init容器spec的修改被限制在容器image字段,修改其他字段都不会生效。更改Init容器的image字段,等价于重启该Pod1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 $ kubectl edit -n test pod myapp-pod ...... initContainers: - command : - sh - -c - until nslookup myservice;do echo waiting for myservice;sleep 2; done ; image: busybox imagePullPolicy: Always name: init-myservice resources: {} terminationMessagePath: /dev/termination-log terminationMessagePolicy: File volumeMounts: - mountPath: /var/run/secrets/kubernetes.io/serviceaccount name: default-token-bk9vl readOnly: true
Init 容器使用简单示例:
Pod资源清单1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 cat > ~/K8s/Day3/initC.yaml <<'EOF' apiVersion: v1 kind: Namespace metadata: name: test labels: name: test --- kind: Pod apiVersion: v1 metadata: name: myapp-pod namespace: test labels: app: myapp version: v1 author: weiyigeek spec: containers: - name: myapp-main-container image: busybox command : ['sh' ,'-c' ,'echo The app is running!&& sleep 3600' ] initContainers: - name: init-myservice image: busybox command : ['sh' ,'-c' ,'until nslookup myservice;do echo waiting for myservice;sleep 2; done;' ] - name: init-mydb image: busybox command : ['sh' ,'-c' ,'until nslookup mydb;do echo waiting for mydb;sleep 2;done;' ] - name: init-serverA images: busybox command : ['sh' ,'-c' ,"curl --connect-timeout 3 --max-time 5 --retry 10 --retry-delay 5 --retry-max-time 60 http://serverB:port/Path/" ] EOF
Service 资源清单1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 cat > ~/K8s/Day3/dependService.yaml <<'EOF' kind: Service apiVersion: v1 metadata: name: myservice namespace: test spec: selector: app: myapp ports: - protocol: TCP port: 80 targetPort: 9376 --- kind: Service apiVersion: v1 metadata: name: mydb namespace: test spec: selector: author: weiyigeek ports: - protocol: TCP port: 80 targetPort: 9377 EOF
执行部署:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 weiyigeek@ubuntu:~/K8s/Day3$ kubectl create -f initC.yaml weiyigeek@ubuntu:~/K8s/Day3$ kubectl get pod -n test kubectl create -f dependService.yaml weiyigeek@ubuntu:~$ kubectl describe pod -n test myapp-pod ... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled 113s default-scheduler Successfully assigned test /myapp-pod to k8s-node-4 Normal Pulling 113s kubelet Pulling image "busybox" Normal Pulled 108s kubelet Successfully pulled image "busybox" in 4.499850144s Normal Created 108s kubelet Created container init-myservice Normal Started 108s kubelet Started container init-myservice Normal Pulling 40s kubelet Pulling image "busybox" Normal Pulled 34s kubelet Successfully pulled image "busybox" in 5.078096509s Normal Created 34s kubelet Created container init-mydb Normal Started 34s kubelet Started container init-mydb Normal Pulling 28s kubelet Pulling image "busybox" Normal Pulled 25s kubelet Successfully pulled image "busybox" in 3.215811094s Normal Created 25s kubelet Created container myapp-main-container Normal Started 25s kubelet Started container myapp-main-container weiyigeek@ubuntu:~$ kubectl get pod -n test
Tips : 如Pod重启了所有的Init Container将会重新运行,由于K8s禁止init Container使用 readiness
探针, 则可以使用Pod定义 activeDeadineSeconds (包含 init Container 启动时间
) 和 Container 的 livenessProbe
防止 init 容器重复失败
Pod 容器探针 Q: 什么是容器探针(Probe)?
答: 探针是由各个节点(Node)的kubelet对容器执行的定期诊断,而执行诊断时kubelet需调用由容器实现的Handler 处理程序
, 注意它不是在Main C
之内这是为了便于减少主容器运行压力。
Q: 为什么需要探针?
答: 对于线上业务来说保证服务的正常是稳定是重中之重,而对故障服务的及时处理避免影响业务以及快速恢复一直是开发运维的难点。而采用 K8s 提供的两种探针方式(readiness Probe、Liveness Probe)进行健康检查服务,如检测到故障服务将会被及时下线及通过重启服务的方式使服务自动恢复;
Q: readiness Probe英 /ˈredinəs/(准备就绪) 英 /prəʊb/
与 liveness Probe/laivnis/(生存)
探测方式?
readiness Probe
【就绪指针或叫就绪探针-针对于服务】: 指示判断容器是否准备好服务
请求。如果就绪探测失败(服务未加载或工作加载异常),端点控制器将从与 Pod 所匹配的Service 的端点中删除该Pod的IP地址。
简单的说当服务没有Ready时会将其从服务的Load Balancer中移除,并不会再接受或者响应任何请求;
如果容器不提供就绪探针, 则默认状态为Success;初始延迟之前的就绪状态默认为Failure。
liveness Probe
【存活指针或叫存活探针-针对于容器】: 指示判断容器
是否正在运行。如果存活探测失败(服务Crash或者死锁等情况发送时),则kubelet会杀死容器,而容器将受到其重启策略(spec.restartPolicy: Always
)的影响进行重启容器或者分发到其它机器上进行运行;
如果容器不提供存活探针, 则默认状态为Success;
Q: 探针如何实现服务可用性与自动恢复?
1) 如服务的 Readiness Probe 健康检查失败, 则故障服务实例从Service Endpoint中剔除,外部请求将不会转发到该故障服务实例中; 2) 如对该故障服务实例设置了 Liveness 的探针将会失效, 并且该Container会被Kill掉,然后根据restartPolicy策略将会在当前节点重启容器或者其它可用节点重建容器;
Tips : 如此时服务自我恢复了(网络问题导致),其将会自动重新加入Service Endpoint
对外提供服务, 基于上述机制整个服务实现了自身可用与自动恢复;
Probe 探测反馈结果
成功(Success):容器通过了诊断。 失败(Failure):容器未通过诊断。 未知(Unknown):诊断失败因此不会采取任何行动【这将导致容器挂死,因为探针不执行成功的话容器会一直在等待】
Probe 监控检查方式 Probe Handler 处理程序类型:
ExecAction:在容器 Container 内执行指定 Shell 命令。 如果命令退出时返回码为0则认为诊断成功。
TCPSocketAction: 对指定端口上的容器 Container 的IP地址、端口进行TCP检查。如果端口打开则诊断被认为是成功的。
HTTPGetAction: 对指定的端口和路径上的容器 Container 的IP地址、端口、Path路径执行HTTPGet请求。如果响应的状态码大于等于200且小于400 [2xx:成功,3xx:跳转] 则诊断被认为是成功的;
Probe 使用建议
1.建议对全部服务实例同时设置 服务 Readiness 探针
和 容器 Liveiness 探针
进行健康检查; 2.在对端口TCPSocketAction检测的同时一般建议使用ExecAction或者HTTPGetAction去进行健康检查; 3.无论采用哪种类型探针建议Readiness 探针的时间短于 Liveiness 探针时间,当然您也可以设置一致其目的都是为了将故障服务下线并等待恢复;
Probe 使用示例
(1) 就绪指针 or 就绪探针 readinessProbe字段: 定期检查集装箱服务
准备情况(运行状态)1 2 3 4 5 6 7 8 9 10 11 $ kubectl explain pod.spec.containers.readinessProbe | egrep "FIELDS|>" RESOURCE: readinessProbe <Object> FIELDS: exec <Object> httpGet <Object> tcpSocket <Object> initialDelaySeconds <integer > periodSeconds <integer > timeoutSeconds <integer > failureThreshold <integer > successThreshold <integer >
简单实例:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 cat > readinessProbe-httpget.yaml<<'EOF' apiVersion: v1 kind: Pod metadata: name: readiness-httpget-pod namespace: test spec: containers: - name: readiness-httpget-container image: harbor.weiyigeek.top/test /nginx:v2.2 imagePullPolicy: IfNotPresent readinessProbe: httpGet: port: 80 path: /index1.html initialDelaySeconds: 1 timeoutSeconds: 1 periodSeconds: 3 EOF ~/K8s/Day4$ kubectl create -f readinessProbe-httpget.yaml pod/readiness-httpget-pod created ~/K8s/Day4$ kubectl get pod -n test | grep "readiness-httpget-pod" NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES readiness-httpget-pod 1/1 Running 0 40m 10.244.1.14 k8s-node-4 <none> <none> ~/K8s/Day4$ kubectl describe -n test pod readiness-httpget-pod Warning Unhealthy 2m32s (x101 over 7m32s) kubelet Readiness probe failed: HTTP probe failed with statuscode: 404 ~/K8s/Day4$ kubectl exec -n test readiness-httpget-pod -it sh ~/K8s/Day4$ curl http://10.244.1.14/index1.html ~/K8s/Day4$ kubectl get pod -n test ~/K8s/Day4$ kubectl logs -n test readiness-httpget-pod
(2) 存活指针 or 存活探针 HttpGet方式: 即 通过 Http 请求的方式验证应用服务或者Pod容器是否正常运行;1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 apiVersion: v1 kind: Pod metadata: name: liveness-httpget-pod namespace: default spec: containers: - name: liveness-httpget-container image: harbor.weiyigeek.top/test/nginx:v2.2 imagePu11Policy: IfNotPresent ports: - name: http containerPort: 80 livenessProbe: httpGet: port: http path: /index.html httpHeaders: - name: X-Custom-Header value: WeiyiGeek initialDelaySeconds: 1 timeoutSeconds: 10 periodSeconds: 3
Exec方式: 即通过验证容器中服务正常启动后的标志性文件是被存在创建;1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 apiVersion: v1 kind: Pod metadata: name: liveness-exec-pod namespace: test spec: containers: - name: liveness-exec-container image: hub.coreqi.cn/1ibrary/busybox imagePullPolicy: IfNotPresent command: ["/bin/sh","-c","touch /tmp/live;sleep 60 ;rm -rf /tmp/live;sleep 3600 "] livenessProbe: #探活指针 exec: #执行命令 command: [" test","-e","/tmp/live"] initialDelaySeconds: 1 periodSeconds: 3
Tcp方式: 我们以此方式进行演示上面与下面的操作与之类似;1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 cat > ~/K8s/Day4/livenessProbe-tcpSocket.yaml <<'EOF' apiVersion: v1 kind: Pod metadata: name: livenessprobe-tcpsocket namespace: test spec: containers: - name: nginx image: harbor.weiyigeek.top/test/nginx:v2.2 livenessProbe: tcpSocket: port: 81 initialDelaySeconds: 5 timeoutSeconds: 1 periodSeconds: 3 EOF
操作步骤:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 ~/K8s/Day4$ kubectl create -f livenessProbe-tcpSocket.yaml ~/K8s/Day4$ kubectl get pod -n test -o wide ~/K8s/Day4$ kubectl get pod -n test -o wide -w ~/K8s/Day4$ kubectl describe pod -n test livenessprobe-tcpsocket
Init Container 使用示例: 一个用来检查 redis 是否启动成功,另外一个用来检查 mysql 是否启动成功,开始部署的时候,首先会通过 nslookup 检查 redis 是否成功启动,检测到 redis 启动了之后,域名解析也就会成功,然后会检查 mysql 的状态 mysql 也成功启动之后才会开始启动 reservation-server
container。1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 apiVersion: v1 kind: Pod metadata: name: myapp-pod labels: app: myapp spec: containers: - name: reservation-server image: weiyigeek/activityreservation:dev ports: - name: http containerPort: 80 protocol: TCP livenessProbe: httpGet: path: /health port: http initialDelaySeconds: 60 periodSeconds: 10 readinessProbe: httpGet: path: /api/notice port: http initialDelaySeconds: 60 periodSeconds: 10 initContainers: - name: init-redis image: busybox:1.31 command: ['sh', '-c' , 'until nslookup redis-server; do echo waiting for redis; sleep 2; done;' ] - name: init-mysql image: busybox:1.31 command: ['sh', '-c' , 'until nslookup mysql-server; do echo waiting for mysql; sleep 2; done;' ]
Pod Hook 描述: Pod hook(钩子)是由Kubernetes管理的kubelet发起的,它在Pod生命周期(Pod Lifecycle)内提供两种钩子 (Hook) 分别在容器中的进程启动前 (postStart)
或者容器中的进程终止之前 (preStop)
运行,可以同时为Pod中的所有容器都配置 hook, 它们包含在容器的生命周期之中。
Hook 事件分类:
1) PostStart: 在容器创建启动之后PostStart Hook将会被立即执行,值得注意的是容器里的Entrypoint 和 Poststart的执行顺序前后并不确定
2) PreStart: 在容器被终止之前执行采用一种阻塞式的方式,即在PreStop Hook执行完毕之后销毁容器的动作才会执行;
Hook Handler 分类: 描述: 容器通过实现和注册一个Handler来实现对Hook的访问有两种类型的 Hook Handlers
;
exec: 执行 一个 Shell命令
http:向 一个endpoint 发送HTTP请求
Tips : 如果 PostStart
或 PreStop
hook 执行失败容器将会被Kill掉;
简单实例: 在 Pod 生存周期内在容器创建或者在容器结束时, 指定执行的命令或者脚本;
1.将镜像上传到Harbor仓库之中
1 2 $ docker tag nginx:latest harbor.weiyigeek.top/test /nginx:latest $ docker push harbor.weiyigeek.top/test /nginx:latest
2.Pod资源清单的编写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 $ kubectl explain Pod.spec.containers.lifecycle cat > ~/K8s/Day4/lifecycle-demoStartStop.yaml<<'EOF' apiVersion: v1 kind: Pod metadata: name: lifecycle-demo namespace: test labels: app: nginx spec: containers: - name: lifecycle-demo-container image: harbor.weiyigeek.top/test/nginx imagePullPolicy: IfNotPresent lifecycle: postStart: exec: command: ["/bin/sh","-c","echo ${HOSTNAME},${NGINX_VERSION}> /usr/share/nginx/html/info.html"] preStop: exec: command: ["/usr/sbin/nginx","-s","quit"] restartPolicy: OnFailure EOF
3.部署资源清单与部署信息查看
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 weiyigeek@ubuntu:~/K8s/Day4$ kubectl create -f lifecycle-demoStartStop.yaml weiyigeek@ubuntu:~/K8s/Day4$ kubectl get pod -n test -o wide | grep "lifecycle-demo" weiyigeek@ubuntu:~/K8s/Day4$ kubectl logs -n test lifecycle-demo ~/K8s/Day4$ curl http://10.244.1.13/info.html kubectl delete -f lifecycle-demoStartStop.yaml
命令补充说明: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 ~$ kubectl get deployment NAME READY UP-TO-DATE AVAILABLE AGE nginx-deployment 3/3 3 3 2d14h ~$ kubectl delete deployment --all deployment.apps "nginx-deployment" deleted ~$ kubectl delete pod --all pod "nginx-deployment-7f5d9779c6-dr5h8" deleted pod "nginx-deployment-7f5d9779c6-hhl7k" deleted pod "nginx-deployment-7f5d9779c6-sk2f4" deleted ~$ kubectl delete svc nginx-deployment ~$ kubectl exec nginx-deployment-7f5d9779c6-dr5h8 -it -- /bin/sh env kubectl get pod kubecrl describe pod