Kubernetes之九---kubernetes资源清单定义入门
认识kubernetes资源
1.1 常用资源/对象
- workload工作负载型资源:pod,ReplicaSet,Deployment,StatefulSet,daemonset,job...
- 服务器发现及均衡:Service,Lngress...
- 配置与存储:volume,CSI
- configmap,secret
- downwardAPI
- 集群级资源
- namespace,node,role,clusterrole,rolebinding,clusterrolebinding
- 元数据型资源
- HPA,podtemplate,limitrange
1.2 创建资源的方法
- apiserver 仅接受JSON格式的资源定义;
- yaml格式提供配置清单,apiserver 可自动将其转为JSON格式,而后再提交;
1.3 大部分(主流)资源的配置清单:有5个一级字段组成
- apiserver:group/version
- 查询当前支持哪些apiserver:$ kubectl api-versions
- kind:资源类别
- metadata:元数据
- name:名称
- namespace:名称空间
- labels:标签
- annotation:资源注解
- selfLink:每个资源的引用PATH,/api/GROUP/VERSION/namespaces/NAMESPACE/TYPE/NAME
- spec:期望的状态(disired state),期望资源应该用于什么特性
- status:当前状态(current state),本字段由kubernetes集群维护,用户不能自己定义
Pod 对象的生命周期
Pod 对象自从其创建开始至其终止退出的时间范围称为其生命周期。 在这段时间中, Pod 会处于多种不同的状态, 并执行一些操作;其中,创建主容器( main container)为必 需的操作,其他可选的操作还包括运行初始化容器 ( init container)、容器启动后钩子( post start hook)、容器的存活性探测( liveness probe)、 就绪性探测( readiness probe)以及容器终 止前钩子(pre stop hook)等,这些操作是否执行则取决于 Pod 的定义,如图所示。
无论是类似前面几节中的由用户手动创建,还是通过 Deployment 等控制器创建, Pod 对象总是应该处于其生命进程中以下几个相位(phase)之一。
- Pending : API Serv巳r 创建了 Pod 资源对象并已存入巳etcd 中,但它尚未被调度完成, 或者仍处于从仓库下载镜像的过程中。
- Running: Pod 已经被调度至某节点,并且所有容器都已经被 kubelet 创建完成o D Succeeded: Pod 中的所有容器都已经成功终止并且不会被重启 。
- Failed :所有容器都已经终止,但至少有一个容器终止失败, 即容器返回了非 0 值的 退出状态或已经被系统终止。
- Unknown : API Server 无法正常获取到 Pod 对象的状态信息,通常是由于其无法与 所在工作节点的 kubelet 通信所致。
Pod 的相位是在其生命周期中的宏观概述,而非对容器或 Pod 对象的综合汇总,而且相 位的数量和含义被严格界定,它仅包含上面列举的相位值。
1.4 使用kubectl explain查询每个资源如何配置
(1)例如查询如何定义pod资源
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
[root@master ~] # kubectl explain pod KIND: Pod VERSION: v1 DESCRIPTION: Pod is a collection of containers that can run on a host. This resource is created by clients and scheduled onto hosts. FIELDS: apiVersion <string> ... ... kind <string> ... ... metadata <Object> ... ... spec <Object> ... ... status <Object> ... ... |
(2)能一级一级进入查询;如查询定义pod 的metadata字段
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
|
[root@master ~] # kubectl explain pod.spec KIND: Pod VERSION: v1 RESOURCE: spec <Object> DESCRIPTION: ... ... FIELDS: ... .. affinity <Object> ... ... [root@master ~] # kubectl explain pod.spec.containers KIND: Pod VERSION: v1 RESOURCE: containers <[]Object> DESCRIPTION: ... ... FIELDS: args <[]string> ... ... command <[]string> ... ... |
自己定义资源时,不清楚如何定义,可以进行快速的查询
1.5 示例
(1)查询集群中的pod(上篇创建的pod)
1
2
3
4
5
6
|
[root@master ~] # kubectl get pods NAME READY STATUS RESTARTS AGE client 1 /1 Running 0 4h myapp-848b5b879b-9slqg 1 /1 Running 0 46m myapp-848b5b879b-wtrjr 1 /1 Running 0 46m myapp-848b5b879b-z2sqc 1 /1 Running 0 46m |
(2)-o yaml输出为yaml格式,查看pod创建的操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
[root@master ~] # kubectl get pod myapp-848b5b879b-9slqg -o yaml apiVersion: v1 #api版本 kind: Pod #资源类别 metadata: #元数据 annotations: cni.projectcalico.org /podIP : 10.244.1.60 /32 labels: pod-template- hash : "4046164356" run: myapp name: myapp-848b5b879b-9slqg namespace: default ... ... selfLink: /api/v1/namespaces/default/pods/myapp-848b5b879b-9slqg spec: #规格、规范;期望资源应该用于什么特性;期望目标状态 ... ... status: #当前状态 ... ... |
1.6 演示:基于yaml格式文件,创建pod
1
2
|
[root@master ~] # mkdir manifests [root@master ~] # cd manifests/ |
(1)编写pod-demo.yaml文件
创建2个容器,一个运行nginx;一个在busybox中执行sleep命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
[root@master manifests] # vim pod-demo.yaml apiVersion: v1 kind: Pod metadata: name: pod-demo namespace: default #labels: {app:myapp, tier:frontend} #映射可以写为{}形式; labels: #也可以在下边分级写 app: myapp tier: frontend spec: containers: - name: myapp image: ikubernetes /myapp :v1 - name: busybox image: busybox:latest #command: ["/bin/sh","-c","sleep 3600"] #列表可以写为[]形式; command : #也可以在下边分级写,要加- - "/bin/sh" - "-c" - "sleep 3600" |
(2)基于pod-demo.yaml 文件创建create pod
1
2
|
[root@master manifests] # kubectl create -f pod-demo.yaml pod /pod-demo created |
(3)验证
① 查询创建pod的信息
1
2
3
4
5
6
7
8
9
10
|
[root@master manifests] # kubectl create -f pod-demo.yaml pod /pod-demo created [root@master manifests] # kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE pod-demo 2 /2 Running 0 1m 10.244.1.61 node1 ---查看详细信息 [root@master manifests] # kubectl describe pods pod-demo Name: pod-demo Namespace: default ... ... |
② 访问pod中的服务
1
2
3
4
5
|
[root@master manifests] # curl 10.244.1.61 Hello MyApp | Version: v1 | <a href= "hostname.html" >Pod Name< /a > ---查询pod产生的日志 [root@master manifests] # kubectl logs pod-demo myapp 192.168.130.104 - - [23 /Jan/2019 :05:35:35 +0000] "GET / HTTP/1.1" 200 65 "-" "curl/7.29.0" "-" |
③ 基于yaml文件删除pod
1
2
3
4
|
[root@master manifests] # kubectl delete -f pod-demo.yaml pod "pod-demo" deleted [root@master manifests] # kubectl get pods No resources found. |
2、Pod资源
2.1 Pod资源常用选项
- metadata.label:标签
- key=value
- key:字母、数字、_、-、.
- value:可以为空,只能字母或数字开头及结尾,中间可使用字母、数字、_、-、.
- key=value
- metadata.annotations:资源注解
- spec.containers <[]object>
- - name:容器名称
- image:镜像
- imagePullPolicy:下载镜像规则,若镜像时latest标签,默认是Always;否则默认IfNotPresen
- Always总是镜像,Never不下载镜像,IfNotPresent本地有则不下载
- ports:从容器中公开的端口列表
- containerPort:Pod中服务的端口号
- hostIP:暴露绑定在主机哪个IP上
- hostPort:暴露在主机的端口号
- name:暴露这个端口的名称
- args:参数
- command:执行命令
- spec.nodeSelector:节点标签选择器
2.2 演示
(1)修改pod-demo.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
|
[root@master manifests] # vim pod-demo.yaml apiVersion: v1 kind: Pod metadata: name: pod-demo namespace: default #labels: {app:myapp, tier:frontend} #映射可以写为{}形式; labels: #也可以在下边分级写 app: myapp tier: frontend annotations: along.com /created-by : "cluster admin" spec: containers: - name: myapp image: ikubernetes /myapp :v1 ports: - name: http containerPort: 80 - name: https containerPort: 443 - name: busybox image: busybox:latest imagePullPolicy: IfNotPresent #command: ["/bin/sh","-c","sleep 3600"] #列表可以写为[]形式; command : #也可以在下边分级写,要加- - "/bin/sh" - "-c" - "sleep 3600" nodeSelector: disktype: ssd |
(2)将node1节点打上disktype=ssd的标签
1
2
3
4
|
[root@master manifests] # kubectl label node node1 disktype=ssd [root@master manifests] # kubectl get nodes node1 --show-labels NAME STATUS ROLES AGE VERSION LABELS node1 Ready <none> 140d v1.11.2 beta.kubernetes.io /arch =amd64,beta.kubernetes.io /os =linux,disktype=ssd,kubernetes.io /hostname =node1 |
(3)基于yaml文件创建pod
1
2
|
[root@master manifests] # kubectl create -f pod-demo.yaml pod /pod-demo created |
(4)验证
1
2
3
4
5
6
7
8
|
--- pod只会创建到node1节点上,因为node1的disktype=ssd标签 [root@master manifests] # kubectl get pod -o wide NAME READY STATUS RESTARTS AGE IP NODE pod-demo 2 /2 Running 0 11s 10.244.1.68 node1 --- -l 指定标签,实现标签过滤 [root@master manifests] # kubectl get pods --show-labels -l app NAME READY STATUS RESTARTS AGE LABELS pod-demo 2 /2 Running 0 30s app=myapp,tier=frontend |
3、Pod健康检测
3.1 pod健康检测介绍
- pod健康检测分为存活性探测、 就绪型探测;这在生产环境几乎是必须配置的;
- 如果没有就绪型探测;pod一启动就会被分配用户流量;若pod中的服务像tomcat等,需要时间启动;就会导致有一定时间,用户访问不到服务;
- 如果没有存活性探测:pod中服务一旦失败,没有检测,不会将容器重启关闭;也会导致用户访问服务失败。
目前, Kubernetes 的容器支持存活性探测的方法包含以下三种: ExecAction、 TCPSocketAction 和 HTTPGetAction。
3.2 pod健康检测选项
(1)在spec字段下、containers字段配置,可使用explain查看详细用法
$ kubectl explain pod.spec.containers.
- livenessProbe 存活性探测
- exec:指定检测的命令
- failureThreshold:连续失败次数被认为失败,默认为3,最小值为1
- httpGet:指定要执行的http请求
- initialDelaySeconds:在容器启动多少秒后再检测
- periodSeconds:每隔多少秒探测一次;默认为10秒。最低限度值是1
- successThreshold:连续成功次数认为服务正常
- tcpSocket:定涉及TCP端口的操作
- timeoutSeconds:探测超时的秒数,默认为1秒
- readinessProbe 就绪型探测(和livenessProbe 存活性探测选项一样)
3.3 容器重启策略
容器程序发生崩溃或容器申请超出限制的资源等原因都可能会导致 Pod 对象的终止, 此时是否应该重建该 Pod 对象则取决于其重启策略(restartPolicy)属性的定义。
- Always: 但凡 Pod 对象终止就将其重启,此为默认设定。
- OnFailure :仅在 Pod 对象出现错误时方才将其重启 。
需要注意的是, restartPolicy 适用于 Pod 对象中的所有容器,而且它仅用于控制在同一 节点上重新启动 Pod 对象的相关容器。 首次需要重启的容器,将在其需要时立即进行重启, 随后再次需要重启的操作将由 k:ubelet 延迟一段时间后进行,且反复的重启操作的延迟时长 依次为 10 秒、 20 秒、 40 秒、 80 秒、 160 秒和 300 秒, 300 秒是最大延迟时长。 事实上, 一 旦绑定到一个节点, Pod 对象将永远不会被重新绑定到另一个节点,它要么被重启,要么终 止, 直到节点发生故障或被删除。
$ kubectl explain pod.spec.restartPolicy.
- Always:总是重启(默认)
- OnFailure:只有容器状态为错误时,才重启
- Never:绝不重启
3.4 演示:exec方式实现存活性探测
exec 类型的探针通过在目标容器中执行由用户自定义的命令来判定容器的健康状态, 若命令状态返回值为 0 则表示“成功”通过检测,其值均为“失败”状态。 “spec.containers. !iv巳nessProbe.exec”字段用于定义此类检测,它只有一个可用属性“"command ",用于指定 要执行的命令。
(1)编写yaml文件
当探测到/tmp/healthy文件不存在时,认为服务故障;
容器在30秒后执行删除/tmp/healthy文件
[root@master manifests]# vim liveness-exec.yaml apiVersion: v1 kind: Pod metadata: name: liveness-exec-pod namespace: default spec: containers: - name: liveness-exec-container image: busybox:latest imagePullPolicy: IfNotPresent command: ["/bin/sh","-c","touch /tmp/healthy; sleep 30; rm -f /tmp/healthy; sleep 3600"] livenessProbe: exec: command: ["test","-e","/tmp/healthy"]
(2)创建运行pod
1
2
3
4
5
|
[root@master manifests] # kubectl create -f liveness-exec.yaml pod /liveness-exec-pod created [root@master manifests] # kubectl get pods NAME READY STATUS RESTARTS AGE liveness- exec -pod 1 /1 Running 0 6s |
(3)等30s,容器就会检测失败,重启pod;使用describe可以查看详细信息
1
2
3
4
5
6
7
8
9
10
11
12
13
|
[root@master manifests] # kubectl describe pods liveness-exec-pod ... ... State: Running Started: Wed, 23 Jan 2019 16:58:09 +0800 Last State: Terminated #上次状态为终止 Reason: Error Exit Code: 137 Started: Wed, 23 Jan 2019 16:57:01 +0800 Finished: Wed, 23 Jan 2019 16:58:09 +0800 Ready: True Restart Count: 1 #重启次数1次 Liveness: exec [ test -e /tmp/healthy ] delay=1s timeout=1s period=3s #success=1 #failure=3 ... ... |
3.5 演示:httpget方式实现存活性探测
基于 HTTP 的探测 ( HTTPGetAction) 向 目标容器发起一个 HTTP 请求,根据其响应码进行结果判定,响应码形如 2xx 或 3xx 时表示检测通过。 “ spec.containers.livenessProbe. httpGet” 字段用于定义此类检测,它的可用配置字段包括如下几个。
- host <string>:请求的主机地址, 默认为 Pod IP;也可以在 httpHeaders 中使用“Host:” 来定义。
- port <string>: 请求的端口 ,必选宇段。
- bttpHeaders <[]Object> : 自定义的请求报文首部。
- path <string> : 请求的 HTTP 资源路径,即 URL path。
- scheme: 建立连接使用的协议,仅可为 HTTP 或 HTTPS , 默认为 HTTP。
下面是一个定义在资源清单文件 liveness占ttp.yarr让中的示例,它通过 lifecycle 中的 postSta此 book 创建了一个专用于 httpGet 测试的页面文件 bealthz:
(1)编写yaml文件,创建并运行pod
当探测不到容器内80端口,和提供80端口的/index.html文件时,认为服务故障;
[root@master manifests]# cat liveness-httpget.yaml apiVersion: v1 kind: Pod metadata: name: liveness-httpget-pod namespace: default spec: containers: - name: liveness-exec-container image: ikubernetes/myapp:v1 ports: - name: http containerPort: 80 livenessProbe: httpGet: # 注意Get要大写 port: http path: /index.html # 访问此默认页 initialDelaySeconds: 1 # 在容器启动后1秒开始检测 periodSeconds: 3 # 每隔3秒时间探测一次 failureThreshold: 2 # 成功状态下连续检测两次失败将会发生重启 restartPolicy: Always
(2)手动连入容器,删除index.html文件
1
2
|
[root@master manifests] # kubectl exec -it liveness-httpget-pod -- /bin/sh / # rm -f /usr/share/nginx/html/index.html |
(3)容器会检测失败,重启pod;使用describe可以查看详细信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
[root@master manifests] # kubectl describe pods liveness-httpget-pod ... ... Port: 80 /TCP Host Port: 0 /TCP State: Running Started: Wed, 23 Jan 2019 17:10:03 +0800 Last State: Terminated #上次状态为终止 Reason: Completed Exit Code: 0 Started: Wed, 23 Jan 2019 17:08:22 +0800 Finished: Wed, 23 Jan 2019 17:10:03 +0800 Ready: True Restart Count: 1 #重启次数1次 Liveness: http-get http: // :http /index .html delay=1s timeout=1s period=3s #success=1 #failure=3 ... ... |
3.6 演示:exec方式实现就绪性探测
- Pod 对象启动后,容器应用通常需要一段时间才能完成其初始化过程,例如加载配置或 数据,甚至有些程序需要运行某类的预热过程,若在此阶段完成之前即接人客户端的请求, 势必会因为等待太久而影响用户体验。 因此,应该避免于 Pod 对象启动后立即让其处理客 户端请求,而是等待容器初始化工作执行完成并转为“就绪”状态,尤其是存在其他提供相 同服务的 Pod 对象的场景更是如此。
- 与存活性探测机制类似,就绪性探测是用来判断容器就绪与否的周期性(默认周期为 10 秒钟)操作, 它用于探测容器是否已经初始化完成并可服务于客户端请求,探测操作返 回“success”状态时,即为传递容器已经“就绪”的信号。
- 与存活性探测机制相同,就绪性探测也支持 Ex町、 HTTP GET 和 TCP Socket 三种探测 方式,且各自的定义机制也都相同。 但与存活性探测触发的操作不同的是,探测失败时,就绪性探测不会杀死或重启容器以保证其健康性,而是通知其尚未就绪,并触发依赖于其就 绪状态的操作(例如,从 Service 对象中移除此 Pod 对象)以确保不会有客户端请求接入此 Pod 对象。 不过,即便是在运行过程中, Pod 就绪性探测依然有其价值所在,例如 Pod A 依 赖到的 Pod B 因网络故障等原因而不可用时, Pod A 上的服务应该转为未就绪状态,以免无 法向客户端提供完整的响应。
- 将容器定义中的 livenessProbe 字段名替换为 readinessProbe 即可定义出就绪性探测的配 置, 一个简单的示例如下面的配置清单( readiness-exec. yam!)所示,它会在 Pod 对象创建完成 3秒钟后使用 test -e/tmp/healthy 命令来探测容器的就绪性,命令执行成功即为就绪,探 测周期为 3秒钟:
(1)编写yaml文件,创建启动容器
当探测到/tmp/healthy文件不存在时,就认为服务就绪不成功;pod启动失败;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
[root@master manifests] # vim readiness-exec.yaml apiVersion: v1 kind: Pod metadata: name: readiness- exec -pod namespace: default spec: containers: - name: readiness- exec -container image: busybox:latest imagePullPolicy: IfNotPresent command: ["/bin/sh","-c","touch /tmp/healthy; sleep 30; rm -f /tmp/healthy; sleep 3600"] command : [ "sleep 3600" ] readinessProbe: exec : command : [ "test" , "-e" , "/tmp/healthy" ] periodSeconds: 3 # 探测周期we为3秒钟 restartPolicy: Always [root@master manifests] # kubectl create -f readiness-exec.yaml pod /readiness-exec-pod created |
(2)查看,pod启动就绪失败
1
2
3
|
[root@master ~] # kubectl get pods NAME READY STATUS RESTARTS AGE readiness- exec -pod 0 /1 RunContainerError 1 12s |
4、Pod启动前/后钩子
4.1 介绍
- pod在启动前后都可以设置钩子hook;在spec.containers.lifecycle字段下设置;
- postStart:创建容器后立即调用PostStart操作;如果失败,根据重启策略终止;
- preStop:在容器终止之前立即调用PreStop操作,该容器在处理程序完成后终止
生命周期钩子函数( lifecycle hook)是编程语言(如 Angular)中常用的生命周期管理的 组件,它实现了程序运行周期中的关键时刻的可见性,并赋予用户为此采取某种行动的能 力。 类似地, 容器生命周期钩子使它能够感知其自身生命周期管理中的事件,并在相应的时 刻到来时运行由用户指定的处理程序代码。 Kubernetes 为容器提供了两种生命周期钩子。
- postStart :于容器创建完成之后立即运行的钩子处理器( handler),不过 Kubernetes 无法确保它一定会于容器中的 ENTRYPOINT 之前运行。
- preStop :于容器终止操作之前立即运行的钩子处理器,它以同步的方式调用,因此 在其完成之前会阻塞删除容器的操作的调用。
钩子处理器的实现方式有“Exec ”和“HTTP ”两种,前一种在钩子事件触发时直接在 当前容器中运行由用户定义的命令,后一种则是在当前容器中向某 URL 发起 HTTP 请求。
postStart 和 preStop 处理器定义在容器的 spec.lifecycle 嵌套字段中,其使用方法如下面 的资源清单所示,读者可自行创建相关的 Pod 资源对象,井验证其执行结果:
4.2 语法
$ kubectl explain pod.spec.containers.lifecycle
- postStart
- exec:指定了要采取的命令;
- httpGet:指定要执行的http请求;
- tcpSocket:指定涉及TCP端口的操作
- preStop (和postStart命令一样)
4.3 演示:使用exec设置pod启动前钩子
(1)编写yaml文件,创建启动容器
启动容器前,先创建准备一个httpd服务的主页面文件/tmp/index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
[root@master manifests] # vim poststart-pod.yaml apiVersion: v1 kind: Pod metadata: name: poststart-pod namespace: default spec: containers: - name: poststart-container image: busybox:latest imagePullPolicy: IfNotPresent lifecycle: postStart: exec : command : [ '/bin/sh' , '-c' , 'echo hello > /tmp/index.html' ] command : [ '/bin/sh' , '-c' , '/bin/httpd -f -h /tmp' ] [root@master manifests] # kubectl create -f poststart-pod.yaml pod /poststart-pod created |
(2)验证,访问服务
[root@master ~]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE poststart-pod 1/1 Running 0 26s 10.244.2.69 node2 [root@master ~]# curl 10.244.2.69 hello