0x00 资源清单
Q:什么是资源?
A:k8s中所有的内容都抽象为资源,在资源实例化后称为对象.
Q:什么是k8s对象?
A:k8s对象指的是k8s系统的持久化实体,所有这些对象合起来代表了你集群的实际情况。创建一个k8s对象就是告诉k8s,集群中的工作负载是什么(集群的目标状态),因为一个k8s对象代表着用户的一个意图,一旦创建了一个k8s对象,k8s将持续工作以尽量实现此用户的意图
Q:k8s集群中相关的信息存储在什么位置?
A:常规的应用里我们把应用程序的数据存储在数据库中,k8s将其数据以k8s对象的形式通过api-server存储在etcd中。k8s对象的数据描述的信息包含:1,集群中运行了哪些容器化应用程序(以及在哪个节点上运行);2,集群中对应程序可用的资源;3,应用程序相关的策略定义,例如重启策略,升级策略,容错策略;4,其他k8s管理应用程序时所需要的信息
Q:如何进行k8s对象的CURD呢?
A:自带的kubectl命令或者一些管理k8s的图形化工具,例如kuboard或者kubedash
Q:k8s对资源的分类
A:1,名称空间级别资源:仅在此名称空间下生效,k8s的系统组件默认是放在kube-system名称空间下的,而kubectl get pod等价于kubectl get pod -n default,因此查看不到k8s的系统组件。
a,工作负载型资源(workload):pod,ReplicaSet(调度器控制器通过标签保证Pod的副本数量以及创建Pod),Deployment,StatefulSet(有状态服务的控制器),DaemonSet(可以在每个节点都运行一个Pod的组件),Job,CronJob(ReplicationController)
b,服务发现以及负载均衡型资源(Service Discovery LoadBalance):Service, Ingress
c,配置与存储型资源:Volumn(存储卷),CSI(容器存储接口,可以扩展各种各样的第三方存储卷)
d,特殊类型的存储卷:ConfigMap(当配置中心来使用的资源类型可以达到热更新),Secret(保存敏感数据),DownwardAPI(把外部环境中的信息输出给容器)
2,集群级资源:不管在任何名称空间下,在其他的名称空间下都能看到,在定义的时候无需指定名称空间:
a,Namespace, Node, Role, ClusterRole, RoleBinding, ClusterRoleBingding
3,元数据类型资源:提供一个指标,不像是名称空间类型又不是集群级别,本质上是在两者之间,并且有自己的特点,所以作为单独的分类,例如HPA就是一个很明显的元数据类型,通过指标进行操作,例如:
a,HPA,PodTemlate,LimitRange
Q:什么是资源清单?
A:可以理解为剧本,里面规定了每一步如何操作,k8s只需要安装要求去做即可,在k8s中一般使用yaml/json文件来创建符合我们预期期望的Pod,该yaml文件我们称为资源清单
Q:如何编辑资源清单?
A:在编写资源清单的时候必须对k8s定义Pod以及控制器常用字段有一定的了解,如果忘记对象的资源清单字段可以通过explain命令查看相对应的控制清单编写字段
Q:资源清单编写帮助
A:kubectl explain pod/ kubectl explain pod.apiVersion(查看指定属性说明)
Q:查看k8s中有对象可用哪些资源的API版本
A:kubectl api-server
0x01 资源文件描述
1,对象字段
描述:每个k8s控制器对象都包含了两个重要的字段,即spec和status字段,k8s通过对应的控制器,不断的使实际状态趋向于期望的目标状态:
spec必须提供,描述了对该对象所期望的目标状态
status由k8s系统来修改,描述了该对象在k8s系统中的实际状态
例如:一个k8s Deployment对象可以代表一个应用程序在集群中的运行状态。当创建Deployment对象时,可以通过Deployment的spec字段指定需要运行应用程序副本数(replicas假设为3),K8s从Deployment的spec读取这些信息,并创建吃定容器化应用程序的3个副本,再将实际状态更新到Deployment的status字段,k8s系统将不断的比较实际状态status和目标状态spec之间的差异,并根据差异作出对应的调整,如果任何一个副本运行失败了,k8s将启动一个新的副本,以替代失败的副本
1> apiVersion(必须)
描述:用来创建对象时所使用的k8s API版本,可以通过kubectl api-version查询可用的API版本
2> kind(必须)
描述:被创建对象的类型常用的有Deployment,Service
3> metadata(必须)
描述:用于唯一确定对象的元数据,包括name和namespace,如果namespace为空,则默认值为default
metadata:
name: nginx-deployment # 创建的资源对象名称
namespace: nginx-app # 设置指定的名称空间,默认为default
4> annottation(注解)
描述:从Annotation是注解,类似前面的Label也使用key/value进行表示
metadata:
annotation:
key1: value1
key2: value2
5> spec(必须)
描述:表示该对象的期望状态,但是需要注意不同类型的k8s资源,不同的kind的spec的格式不同.
资源清单常用的字段描述
1,必须存在的属性
version String k8sAPI版本
kind String 资源类型
metadata Object 元数据对象
metadata.name String 元数据对象的名字
metadata.namespace String 元数据对象的命名空间
Spec Object 对象定义
spec.containers[] List 容器列表
spec.containers[].name String 容器名称
Spec.containers[].image String 镜像名称
2,主要属性
spec.container[].name String 容器名称
spec.container[].image String 用到的镜像名称
spec.container[].imagePullPolicy String 镜像拉取策略,Always:每次都重新拉取,Never:用本地镜像,lfNotPresent:本地有则用本地,本地无则拉取
spec.container[].command[] List 容器启动命令,可以是多个,不指定则使用镜像打包时使用的启动命令
spec.container[].args[] List 容器启动命令参数,可以是多个
spec.container[].workingDir String 容器工作目录
spec.container[].volumnMounts[] List 存储卷配置
spec.container[].volumnMounts[].name String 可以被容器挂载的存储卷名称
spec.container[].volumnMounts[].mountPath String 可以被容器挂载的存储卷的路径
spec.container[].volumnMounts[].readOnly String 设置存储卷的读写模式
spec.container[].ports[] List 容器端口列表
spec.container[].ports[].name String 端口名称
spec.container[].ports[].containerPort String 容器监听的端口
spec.container[].ports[].hostPort String 指定容器所在主机需要监听的端口号,默认跟containerPort相同,设置了hostPort同一台主机无法启动该容器的相同副本,因为主机的端口号不能相通,这样会冲突
spec.container[].ports[].protocol String 端口协议,TCP/UDP
spec.container[].env[] List 容器环境列表
spec.container[].env[].name String 环境变量名称
spec.container[].env[].value String 环境变量值
spec.container[].resources Object 资源限制
spec.container[].resources.limits Object 资源运行上限
spec.container[].resources.limits.cpu。 String CPU限制 单位 core
spec.container[].resources.limits.memory String 内存限制 单位 MlB, GiB
spec.container[].resources.request Object 容器启动和调度时的限制
spec.container[].resources.request.cpu String CPU,容器启动时初始化可用数量
spec.container[].resources.request.memory String 内存,容器启动时初始化可用数量
3,额外参数
spec.restartPolicy String Pod的重启策略;Always:Pod一旦终止运行,则无论容器是如何终止的kubelet都将重启它;OnFailure:只有Pod以非0退出码终止时,kubelet才会重启该容器,如容器时正常退出,退出码为0,则kubelet不会重启它;Never:Pod终止后,kubelet将退出码报告给Master,不会重启该Pod
spec.nodeSelector Object Node的Label过滤标签,以key:value格式指定,选择node节点去运行
spec.imagePullSecrets Object 定义pull镜像时使用secret名称,以name:secretKey格式指定
spec.hostNetwork Boolean 定义是否使用主机网络模式,默认false,设置true表示使用宿主机网络,不用docker网桥,同时设置了true将无法在同一台宿主机上启动第二个副本
4,Pod的demo
apiVersion: v1
Kind: Pod
metadata:
name: pod-name
namespace: default
labels:
app: myapp
spec:
containers:
- name: myapp-1
image: harbor.weiyigeek.top/library/myapp:v1
- name: busybox-1
image: busybox:latest
command:
- "/bin/sh"
- "-c"
- "sleep 3600"
5,创建Pod时发生错误可以通过kubectl describe pod myapp-pod-name和kubectl logs myapp-pod-name查看pod相关信息
0x02 NameSpace 名称空间
描述:由于创建多个集群会导致集群资源使用碎片化以及更多的维护成本,可以通过k8s的Namespace对不同工作组的需求隔离
Q:namespace有何作用?
A:它可以通过不同的资源对象调度到不同的namespace中,从逻辑上形成不同项目,小组或用户组,便于不同的分组之间能够共享使用整个集群的资源,同时还能分别管理
Q:namespace命名规则?
A:[a-z0-9]最长63位,默认k8s会创建一个默认的名称空间Default,如果未指定namespace时,则用户创建的资源对象,如Pod,RC,RS,Deployment,Service都将被分配到default的namespace中
namespace创建,查看,删除
创建
1,kubectl create namespace dev-ops
2,yaml脚本方式
apiVsersion: v1
kind: namespace
metadata:
name: dev-ops
kubectl create -f namespace-create.yaml
查看
1,kubectl get ns # 列表
2,kubectl describe ns dev-ops # 详情
删除
1,kubectl delete namespace dev-ops
2,kubectl delete -f namespace-create.yaml
namespace配额
描述:默认情况下创建的namespace并不会对资源进行配额,如果要对某一个namespace配额则需要配合ResourceQuota使用
示例:ResourceQuota配额管理
# 1,创建名称空间
kubectl create namespace dev-ops
# 2,resource-quota-demo.yaml 资源清单
apiVersion: v1
kind: ResourceQuota
metadata:
name: resource-quota-demo
spec:
hard:
requests.cpu: "1"
requests.memory: 1Gi
limits.cpu: "2"
limits.memory: 2Gi
# 3,创建ResourceQuota并为其指定名称空间
kubectl create -f resoucrce-quota-demo.yaml -n dev-ops
# 4,获取名称空间配额信息
kubectl get resourcequota -n dev-ops
kubectl describe rescourcequota -n dev-ops
# 5,如果在该名称空间中创建Pod并设置了resource,则通过-o yaml可以查看该空间的使用的情况
kubectl get resourcequota -n dev-ops -o yaml
0x03 Pod 基础&进阶
描述:Pod是k8s里面的最小单元,部署在节点上包含一组容器和卷,同一个Pod中容器共享同一个网络命名空间,即可以通过localhost进行相互通信;简单的说Pod是一组可以在主机上运行的容器,该资源由客户端创建并调度到主机上
Q:如果Pod生命周期是短暂的,那么如何才能持久化容器数据,即使在Pod被销毁或者重启到其他机器上?
A:k8s支持Volumn,Persistent Volumns的概念,所以可以使用持久化的卷类型
Q:如何创建大批量的实例副本?
A:采用Replication Controller/ Replica Set / Deployment / StateSetful 使用Pod模版创建多份拷贝
Q:如果Pod生命周期是短暂的,那么重建Pod后意味着IP地址可能会发生变化,那么如何才能从前端容器正确可靠的指向后端容器?
A:使用Service服务发现对象
0x03 1, 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调度到其他健康的节点上
常用于创建Pod的控制器列表:
一版来说Pod并不会自动消失,除非是特意将他们进行销毁,如人为操作或者控制器操作,该规则唯一例外的是成功或者失败的Phase超过一段时间的Pod将被过期并被自动销毁;
如下控制器:
1,Replication Controller
2,Deployment
3,StatefulSet
4,DaemonSet
5,Job
Q:通常Controller会通过Pod Template来创建相应的Pod,而又为什么建议使用控制器创建Pod而非直接创建呢?
A:因为单独的Pod在机器故障的情况下没办法自动复原,而控制器则可以按照期望副本数进行构建复原
Q:什么是Pod模版?
A:Pod模版包含了其他对象(RC,Jobs,DeamonSet)中的Pod定义,Controller控制器使用Pod模版以及selector选择器来创建实际需要的Pod
Q:Pod资源配额以及限额
A:每个Pod都可以对其能使用的服务器上的计算机资源比如CPU和Memory进行限额,值得注意的是CPU的资源单位为CPU(Core)的数量是一个绝对值而非相对值,同时Memory也是一个绝对值;k8s中通常以CPU的千分之一的CPU配额作为最小的单元,通常用m表示,而Memory配额单位是内存字节数,通常用Mi表示;例如:通常一个容器的配额被定义为100-300m即占用0.1-0.3个CPU,由于CPU配额是个绝对值所以说无论是1C或者是48C的机器上,100M的代表额都是一样的
resources:
limits:
cpu: 500m
memory: 200Mi
requests:
cpu: 500m
memory: 6Gi
Pod Template & Pod Resource 案例:
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: 100m
memory: 100Mi
limits:
cpu: 800m
memory: 800Mi
ports:
- containerPort: 8000
操作此文件:
kubectl apply -f deployment.yaml
使用RUN也可以直接创建Pod
kubectl run nginx --image nginx:latest --port=80 --replicas=2
2,Static Pod(静态Pod)
Q:什么是静态Pod?
A:在k8s中由kubelet创建并运行的Pod,该种类型的Pod可以在某个节点上长期运行,即静态Pod,简单说,Pod是由kubelet创建和管理的只在特定node上存在的Pod,并且只在kubelet所在的Node上运行
Q:静态Pod的特点?
A: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
而且由于Pod不能被api-server直接管理,所以他的更新删除操作不能由kubectl来执行,只能直接修改或者删除文本文件
Q:静态Pod创建的两种方式?
A:1,Http,kubelet周期性从采用--manifest-url参数指定的地址下载文件,并且将它翻译成JSON/Yaml格式的Pod定义;2,配置文件,kubelet启动时采用--pod-manifest-path=/etc/kubernetes/manifests指定yaml文件存放目录,会定期扫描这个目录,并且根据这个目录下的yaml或者json文件进行创建和更新操作。
例如,将下面的文件放到该文件夹,重启kubelet或者等待几秒即可闯将静态Pod
static-nginx-web.yaml
apiVersion: v1
kind: Pod
metadata:
name: static-nginx-web
labels:
app: nginx
spec:
containers:
- name: web
image: nginx:latest
imagePullPolicy: IfNotPresent
ports:
- name: nginx-port
containerPort: 80
protocol: TCP
Q:操作流程
A:1,将文件拷贝到/etc/kubernetes/manifests目录后查看kubelet状态,systemctl status kubelet
2,查看静态Pod: kubelet get pod -o wide | grep "static"
3,移除文件,从而移除静态Pod
0x03 2, Pod生命周期
Q:主要通过以下层面了解Pod的生命周期
A:在Pod被创建后经历的过程及其状态;Pod中的容器探测纠察
上图的简单说明
1,Pause容器:它是Pod容器里共享网络栈以及存储卷必备的
2,Init C:先于应用容器启动的init容器
2.1:init容器与普通容器的区别:init容器总是运行到成功完成为止,每个init容器都必须在下一个init容器启动之前成功完成
2.2:如果Pod的Init容器失败,k8s会不断重启该Pod,直到init容器成功,如果Pod对应的restartPolicy设置为Nerver,则它将不会启动
3,Main C:在pod中可以运行的若干容器都有自己的生命周期,当Pod中主容器结束退出时Pod将结束
4,Start/Stop:容器启动或停止时执行的脚本
5,Readliness:在主容器启动后进行应用进程探测,完成后容器的状态将改变为Running
6,Liveness:在主容器的生命周期都有它的身影,其作用是在主容器的进程与其检测结果不一致的情况下将执行重启或者删除容器
2.1 Pod Phase
描述:Pod的status字段是保存在一个PodStatus对象中,该PodStatus中有一个phase字段,Pod的phase是Pod在其生命周期中的简单宏观概述
状态值:
1,挂起Pending:Pod已被k8s系统接受,但有一个或者多个容器镜像尚未创建。等待时间包括调度Pod的时间和通过网络下载镜像的时间
2,运行中Running:该Pod已经绑定到一个节点上,Pod中所有的容器已经被创建。至少有一个容器正在运行,或者正处于启动或者重启状态
3,成功Success:Pod中所有容器都被成功种植,并且不会在重启
4,失败Failed:Pod中所有容器都终止,并且至少有一个容器是因为失败终止,也就是说容器以非0状态退出或者被系统终止
5,未知Unknown:因为某些原因无法取得Pod的状态,通常是因为与Pod所在主机通信失败
检查Pod运行状态:
kubectl get pod redis-cluster-operator -o yaml | grep "phase"
kubectl describe pod redis-cluster-operator | grep "Status"
2.2 重启策略
描述:当Pod中某一个Container处于退出状态Exited时,kubelet会根据Pod Spec中的restartPolicy字段的取值(Always,OnFailure,Nerver)进行相应的操作
kubectl explain statefulset.spec.template.spec | grep "restartPolicy"
策略说明:
Always:默认重启策略,只要有一个容器处于Exited时,即会重启
OnFailure:当容器异常退出或者退出状态不为0时,即会重启
Nerver:无论如何都不重启
策略补充说明:
1,当一个Pod设置重启策略,则适用于Pod中的所有容器,触发规则时通过节点上的kubelet重新启动容器,restartPolicy仅指失败的容器(由kubelet以五分钟为上限的指数退避延迟重新启动),并在成功执行十分钟后重置
2,不同控制器对不同Pod重启策略的处理机制是不一样的,例如:A,使用Job控制器创建Pod运行预期会终止,如批量计算;此时Job仅适用于重启策略为OnFailure或Nerver的Pod;B,使用RC,RS,Deployment,StatefulSet控制器创建的Pod预期是不会终止的,如web服务器。注意RC仅适用于具有RestartPolicy为Always的Pod;C,使用DeamonSet控制器创建的Pod将会在每台工作节点上运行,提供特定于机器的系统服务
Pod状态示例:
1,Pod中只有一个容器并且正在运行,容器成功退出
如果RestartPolicy为
Always: 重启容器; # Pod Phase 为 Running
OnFailure: # Pod Phase 为 Succeeded
Never: # Pod Phase 为 Succeeded
2,Pod中只有一个容器并且正在运行,容器退出失败
如果RestartPolicy为
Always: 重启容器; # Pod Phase 为 Running
OnFailure: # Pod Phase 为 Running
Never: # Pod Phase 为 Failure
3,Pod中有两个容器并且正在运行,如果容器1退出失败
如果RestartPolicy为
Always: 重启容器; # Pod Phase 为 Running
OnFailure: # Pod Phase 为 Running
Never: # Pod Phase 为 Running
4,如果容器1没有处于运行状态并且容器2退出
如果RestartPolicy为
Always: 重启容器; # Pod Phase 为 Running
OnFailure: # Pod Phase 为 Running
Never: # Pod Phase 为 Failure
5,Pod中只有一个容器并处于运行状态,容器运行时内存超出限制
如果RestartPolicy为
Always: 重启容器; # Pod Phase 为 Running
OnFailure: # Pod Phase 为 Running
Never: # Pod Phase 为 Failure
6,Pod正在运行,磁盘故障
杀掉所有容器,记录适当事件
Pod Phase变为Failed
如果使用控制器来运行Pod,将在其他节点重建
7,Pod正在运行,其节点被分段
节点控制器等待直到超时
节点控制器将Pod phase设置为Failed
如果是用控制器来运行,Pod将在别处重建
2.3 Pod Init 容器
Q:什么是Init Container?
A:一个Pod中可以有一个或者多个Init Container即初始化容器操作,其启动顺序手yaml文件中描述顺序的影响进行启动,这表示每个容器必须在下一个容器启动之前成功退出,否则将会阻止后续的Init Container和app Container服务启动,例如:Init Container 1 -> init Container 2 -> init COntainer n -> app Container
Q:Init容器的作用?
A:因为init容器具有与应用程序容器分离的单独镜像,所以利用其特征主要作为服务依赖处理,例如某个服务A需要依赖DB或者Redis,那么可以利用服务A Pod的init container判断db或者redis是否正常提供服务,如果启动服务失败或者工作异常,则设置的init容器也将启动失败,并且Pod的app容器也不会运行。
A:优势:1,init container可以包含并运行实用工具,但是出于安全考虑,是不建议在应用程序容器镜像中包含这些实用工具的;2,可以包含使用工具和定制化代码来安装,但是不能出现在应用程序镜像中,例如创建镜像没必要FROM另一个镜像,只需要在安装过程中使用类似sed,awk,python,dig等工具;3,应用程序镜像可以分离出创建和部署的角色,而没有必要联合它们构建一个单独的镜像;4,init容器使用linux namespace,所以相对应应用程序容器来说具有不同的文件系统视图,因此它们能够具有访问secret的权限而应用容器则不能(init container可以访问app container无法访问的内容);5,它们必须在应用程序容器启动之前完成,而应用程序容器事并行运行的,所以init容器能够提供一种简单的阻塞或者延迟应用容器的方法,直到满足一组先决条件
补充说明:
1,在Pod启动过程中init容器会按顺序在网络和数据卷初始化之后启动,即在Pause容器启动后,Pause只负责网络和数据卷的初始化
2,如果由于运行时或失败退出,将导致容器启动失败,它会根据Pod的restartPolicy指定的策略进行充实,然而,如果Pod的restartPolicy设置为Always,init容器失败时会使用RestartPolicy策略
3,从上面的Pod创建过程与各对象生命周期流程图中可知init容器必须要在Pod状态变成Ready之前完成,以及在资源的request和limits与app container有些许差别,除了以上两种,init与app容器大致相同
4,在所有init容器没有成功之前,Pod将不会改变为Ready状态,Init容器的端口将不会在Service中进行聚集,正在初始化中的Pod处于Pending状态,但应该会将Initializing状态设置为true
5,如果Pod重启,所有的init容器必须重新执行,因此init容器应该配置为幂等的状态
6,init容器具有应用容器的所有字段,除了readiness Probe,因为init容器无法定义除了就绪之外的其他状态
7,在Pod中的每个app和init容器名称必须唯一
8,对init容器的spec的修改被限制在容器的image字段,修改其他字段都不会生效,更改init容器的image字段等价于重启该Pod
Init容器的简单示例
initC.yaml Pod资源清单
apiVersion: v1
kind: Namespce
metadata:
name: test
labels:
name: test
---
kind: Pod
apiVersion: v1
metadata:
name: myapp-pod
namespace: test
labels:
app: myapp
version: v1
author: zhangsan
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
image: busybox
command: ['sh','-c',"curl --connect-timeout 3 --max-time 5 --retry-delay 5 --retry-max-time 60 http://serverB:port/Path"]
dependService.yaml Service清单
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: zhangsan
ports:
- protocol: TCP
port: 80
targetPort: 9377
执行部署
# 0 部署Pod资源
kubectl create -f initC.yaml
# 1 检查部署
kubectl get pod -n test
# 2 部署init
kubectl create -f dependService.yaml
# 3 检查init部署
kubectl describe pod -n test myapp-pod
# 4 init完毕后,容器状态为Running
kubectl get pod -n test
Tips: 如Pod容器重启了所有的init Container将会重新运行,由于k8s禁止init Container使用readiness探针,则可以使用Pod定义activeDeadineSeconds和Container的livenessProbe防止init容器重启失败
2.4 Pod容器探针
Q:什么是容器探针Probe
A:探针是由各个节点Node的kubelet对容器执行的定期诊断,而执行诊断时kubelet需要调用由容器实现的handler处理程序,注意它不是在MainC内,这是为了便于减少主容器的运行压力
Q:为什么需要探针
A:对于线上业务来说保证服务的正常稳定是重中之重,而对于故障的及时处理避免影响业务,以及快速恢复一直是开发运维的难点,而采用k8s提供的两种探针方式(readiness Probe,Liveness Probe)进行健康检查服务,如检测到故障服务将会被及时下线以及通过重启服务的方式使服务自动恢复
Q:readiness Probe/Liveness Probe探测方式
A:readiness Probe,就绪探针,指示判断容器是否准备好服务请求,如果就绪探测失败(服务未加载或者工作加载异常),端点控制器将从与Pod所匹配的Service的端点中删除该Pod的IP地址;简单的说当服务没有Ready时,将其从服务的Load Balancer中移除,并不会再接受或者响应任何请求;如果容器不提供就绪探针,则默认状态为Success,初始延迟之前的就绪状态默认为Failure
liveness Probe,存活探针,指示判断容器是否正在运行,如果存活探测失败(服务Crash或者死锁等),则kubelet会杀死容器,而容器将接受其重启策略spec.restartPolicy: Always的影响进行重启容器或者分发到其他机器上运行;如果不提供存活探针,则默认状态为Success
Q:探针如何实现服务可用性与自动恢复
A:1,如服务的Readiness Probe健康检查失败,则故障服务实例从Service Endpoint中剔除,外部请求将不会转发到该故障服务实例中;2,如对该故障服务实例设置了Liveness Probe,那么它将会失效,并且该Container会被kill掉,然后根据restartPolicy策略将会在当前节点重启容器或者其他可用节点重建容器
Q:Probe探测反馈结果
A:成功 Success,失败 Failure,未知 Unknown
Q:Probe监控检查方式
A:Probe handler处理程序类型:ExecAction,在容器Container内执行指定的Shell指令,如果命令退出时返回码为0则认为诊断成功;TCPSocketAction,对指定端口上的容器Container的IP地址,端口进行TCP检查,如果端口打开则诊断被认为是成功的;HTTPGetAction,对指定的端口和路径上的容器Container的IP地址,端口,Path路径执行HttpGet请求,如果相应的状态码大于等于200且小于400,则被认为是成功的
Q:Probe使用建议
A:建议对全部服务实例同时设置服务Readiness Probe和Liveness Probe进行健康检查;在对端口TCPSocketAction检测的同时一般建议使用ExecAction或者HTTPGetAction去进行健康检查;无论采用哪种类型探针建议Readiness探针的时间短于Liveness探针时间,当然也可以设置一致,其目的是为了将故障服务下线并等待恢复
示例
1> Readiness Probe
kubectl explain pod.spec.containers.readinessProbe | egrep "FIELDS|"
# HttpGet检测方案
1,file: readinessProbe-httpget.yaml
apiVersion: v1
kind: Pod
metadata:
name: readiness-httpget-pod
namespace: test
spec:
containers:
- name: readiness-httpget-container
image: redis
imagePullPolicy: IfNotPresent
readinessProbe:
httpGet:
port: 80
path: /index1.html
initialDelaySeconds: 1 # 初始化检测延时,1秒后
timeOutSeconds: 1 # 请求等待超时时间,1秒后
periodSeconds: 3 # 重试检测时间,3秒后
2,部署清单
kubectl create -f readinessProbe-httpget.yaml
3,查看
kubectl get pod -n test | grep "readiness-httpget-pod"
kubectl describe -n test pod readiness-httpget-pod
4,进入容器创建index1.html
kubectl exec -n test readiness-httpget-pod -it sh
5,添加文件后容器状态的改变
kubectl get pod -n test
kubectl logs -n test readiness-httpget-pod
2> Liveness Probe
1,HttpGet方式
apiVersion: v1
kind: Pod
metadata:
name: liveness-httpget-pod
namespace: default
spec:
containers:
- name: liveness-httpget-container
image: redis
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
livenessProbe:
httpGet:
port: http
path: /index.html
httpHeaders:
- name: X-Custom-Header
value: zhangsan
initialDelaySeconds: 1 # 延迟1秒后开始检测
timeoutSeconds: 10 # 每次访问的最大超时时间
periodSeconds: 3 # 每3秒重复一次
2,Exec方式
apiVersion: v1
kind: Pod
metadata:
name: liveness-exec-pod
namespace: test
spec:
containers:
- name: liveness-exec-container
image: hub.coreqi.cn/library/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
3,Tcp方式
apiVersion: v1
kind: Pod
metadata:
name: livenessprobe-tcpsocket
namespace: test
spec:
containers:
- name: nginx
image: nginx
livenessProbe:
tcpSocket:
port: 81
initialDelaySeconds: 5
timeoutSeconds: 1
periodSeconds: 3
操作部署:
1,部署资源清单
kubectl create -f livenessProbe-tcpSocket.yaml
2,查看
kubectl get pod -n test -o wide
kubectl get pod -n test -o wide -w # 生命周期内探测为满足条件退出,重启
3,查看事件和信息
kubectl describe pod -n test livenessprobe-tcpsocket
Init Container使用探针示例
#首先检测redis和mysql,通过nslookup检查redis是否成功启动,然后检测mysql,mysql成功后启动reservation-server
file: init-container.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: reservation-server
image: test-image
ports:
- name: http
containerPort: 80
protocol: TCP
livenessProbe:
httpGet:
path: /health
port: http
initalDelaySeconds: 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;']
2.5 Pod Hook
描述:Pod Hook是由Kubernetes管理的,kubelet发起的,他在Pod的生命周期内提供两种钩子,分别在容器中的进程启动前(postStart)或者进程终止前(preStop)运行,可以同时为Pod中的所有容器都配置hook,它们包含在容器的生命周期之中
Hook事件分类:1,postStart,在容器创建启动之后PostStart将会被立即执行,值得注意的是容器里的Entrypoint和PostStart的执行顺序前后并不确定;2,preStart在容器被终止之前执行,采用阻塞的方式,在preStop执行完毕之后销毁容器的动作才会执行
HookHandler分类:容器通过实现和注册一个Handler来实现对Hook的访问有两种类型的Hook Handlers:exec,执行一个Shell命令;http,向一个endpoint发送http请求
Hook例子
Pod资源清单
file: lifecycle-demoStartStop.yaml
apiVersion: v1
kind: Pod
metadata:
name: lifecycle-demo
namespace: test
labels:
app: nginx
spec:
containers:
- name: lifecycle-demo-container
image: test
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
部署:
# 1,执行部署
kubectl create -f lifecycle-demoStartStop.yaml
# 2,查看部署
kubectl get pod -n test -o wide | grep "lifecycle-demo"
# 3,检查日志
kubectl logs -n test lifecycle-demo
# 4,访问检测
curl http://x.x.x.x/info.html
# 5,停止然后删除Pod
kubectl delete -f lifecycle-demoStartStop.yaml