3 Kubernetes-资源清单
一、K8S 中的资源
Kubernetes 中所有内容,都抽象为资源,资源实例化后,叫做对象
实例化:将 pod 资源,部署成想要的结果(实例化过程仅需一次)
资源分类:
注意:K8S中的 namespace 与容器中的 namespace 区别
K8S中:逻辑上的分隔
docker中:真正的分隔
名称空间级别:(类似学校中,班级的分类)(namespace)
工作负载型资源: Pod、ReplicaSet、Deployment ...
服务发现及负载均衡型资源: Service、Ingress...
配置与存储型资源:Volume、CSI ...
特殊类型的存储卷:ConfigMap、Secre ...
集群级资源:(类似学校本身)
Namespace、Node、ClusterRole、ClusterRoleBinding
元数据型资源:(依附于其他之上,比如:自动扩容缩、pod模板、资源限制)
HPA、PodTemplate、LimitRange
二、资源清单
资源通过 yaml 文件,定义怎么创建对象
1)K8S 创建流程
查看 K8S 初始化的日志
相关解释:
$ kubeadm config images pull #根据配置文件,下载所有镜像到本地
# kubelet环境变量文件 /var/lib/kubelet/kubeadm-flags.env
$ cat /var/lib/kubelet/kubeadm-flags.env
KUBELET_KUBEADM_ARGS="--cgroup-driver=systemd --network-plugin=cni --pod-infra-container-image=k8s.gcr.io/pause:3.1"
#kubelet_kubeadm 启动参数:(KUBELET_KUBEADM_ARGS)
指定cgroup驱动为systemd,对应 /etc/docker/daemon.json 中指定的cgroup驱动
指定网络插件使用 cni 接口
指定pod初始化容器为:pause:3.1版
# kubelet 配置文件 /var/lib/kubelet/config.yaml(资源清单的格式)
重要选项:指定静态pod路径
staticPodPath: /etc/kubernetes/manifests
kubeadm 初始化 K8S 集群原理图:
查看逻辑上分割的 kube-system 的名称空间中所有pod:
(当前 K8S 所有组件、插件、附件所在位置)
[root@k8s-master01 ~]# kubectl get pod -n kube-system
NAME READY STATUS RESTARTS AGE
calico-node-cr9jt 2/2 Running 2 24h
calico-node-gl48k 2/2 Running 2 24h
calico-node-kqrr6 2/2 Running 2 24h
coredns-5c98db65d4-fb8z2 1/1 Running 1 24h
coredns-5c98db65d4-gqtpz 1/1 Running 1 24h
etcd-k8s-master01 1/1 Running 1 24h
kube-apiserver-k8s-master01 1/1 Running 1 24h
kube-controller-manager-k8s-master01 1/1 Running 1 24h
kube-proxy-29bmx 1/1 Running 1 24h
kube-proxy-flwtk 1/1 Running 1 24h
kube-proxy-hrkx2 1/1 Running 1 24h
kube-scheduler-k8s-master01 1/1 Running 1 24h
/etc/kubernetes/pki #存放证书的目录
有两套不同的证书:
因为有两个C/S架构:
服务:
S apiserver
C CM、sch、kubeproxy.....
存储:
S ETCD
C apiserver
/etc/kubernetes/
admin.conf #管理员权限配置文件,管理员拥有此文件才能管理集群
所以初始化进群以后,会执行命令:
$ cp /etc/kubernetes/admin.conf ~/.kube/config
controller-manager.conf #其他组件权限相关的配置文件
scheduler.conf
kubelet.conf
pki #证书相关的路径
manifests #静态pod路径
详细解释:
2)资源清单
1、资源清单格式
apiversion: 组/版本 #指定位置,实现实例化
拓展:(实现不同位置的实例化)
有一个项目:教学管理系统
寝室管理:
apis/core/v1
apis/core/v1
班级管理:
apis/apps/v1
...
学生管理:
...
课程管理:
...
$ kubectl explain pod #查看pod控制器的 组/版本 ,以及帮助信息
$ kubectl api-versions #查看 K8S 中所有的 组/版本
#若只显示版本,则表示: core/v1
kind: #资源类别
metadata: #资源元数据
name
namespace
lables
annotations # 主要目的是方便用户阅读查找
spec: # 期望的状态(disired state)
status: # 当前资源实例化对象后的结果状态(由K8S本身维护,用户不能自定义)
2、资源清单的常用命令
获取 apiversion 版本信息
[root@k8s-master01 ~]# kubectl api-versions
admissionregistration.k8s.io/v1beta1
apiextensions.k8s.io/v1beta1
apiregistration.k8s.io/v1
apiregistration.k8s.io/v1beta1
apps/v1
......(以下省略)
获取资源的 apiVersion 版本信息
[root@k8s-master01 ~]# kubectl explain pod
KIND: Pod
VERSION: v1
.....(以下省略)
[root@k8s-master01 ~]# kubectl explain Ingress
KIND: Ingress
VERSION: extensions/v1beta1
获取字段设置帮助文档
[root@k8s-master01 ~]# 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>
........
........
字段配置格式
apiVersion <string> #表示字符串类型
metadata <Object> #表示需要嵌套多层字段
labels <map[string]string> #表示由k:v组成的映射
finalizers <[]string> #表示字串列表
ownerReferences <[]Object> #表示对象列表
hostPID <boolean> #布尔类型
priority <integer> #整型
name <string> -required- #如果类型后面接 -required-,表示为必填字段
3、通过定义清单文件创建 Pod
apiVersion: v1 #定义组/版本
kind: Pod #定义资源类别
metadata: #定义资源实例化后的对象,具备的元信息
name: pod-demo
namespace: default
labels:
app: myapp
spec: #期望
containers:
- name: myapp-1
image: wangyanglinux/myapp:v1
- name: busybox-1
image: busybox:1.38.0
command:
- "/bin/sh"
- "-c"
- "sleep 3600"
实验:创建pod-demo对象
Ⅰ 根据yaml文件,创建pod
[root@k8s-master01 ~]# mkdir 1
[root@k8s-master01 ~]# cd 1/
[root@k8s-master01 1]# vim 1.pod.yaml
[root@k8s-master01 1]# cat 1.pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-demo
namespace: default
labels:
app: myapp
spec:
containers:
- name: myapp-1
image: wangyanglinux/myapp:v1
- name: busybox-1
image: busybox:1.38.0
command:
- "/bin/sh"
- "-c"
- "sleep 3600"
[root@k8s-master01 1]# kubectl create -f 1.pod.yaml #根据yaml文件创建pod
Ⅱ 发现创建的pod有问题
[root@k8s-master01 1]# kubectl get pod
NAME READY STATUS RESTARTS AGE
pod-demo 1/2 ImagePullBackOff 0 5m36s
Ⅲ 排错:查看pod资源的pod-damo资源对象的详细信息
Ⅳ 修改 yaml文件,重新创建pod
进入 hub.docker.com 查找 busybos 确定版本,并修改 yaml文件,重新创建pod
[root@k8s-master01 1]# kubectl delete pod pod-demo #删除pod-demo对象
[root@k8s-master01 1]# kubectl delete pod pod-demo
pod "pod-demo" deleted
[root@k8s-master01 1]# vim 1.pod.yaml
[root@k8s-master01 1]# cat 1.pod.yaml |grep image
image: wangyanglinux/myapp:v1
image: busybox:1.36.0
[root@k8s-master01 1]# kubectl get pod
No resources found.
[root@k8s-master01 1]# kubectl create -f 1.pod.yaml
pod/pod-demo created
[root@k8s-master01 1]# kubectl get pod -w #查看pod的变化信息,这时候运行成功
NAME READY STATUS RESTARTS AGE
pod-demo 0/2 ContainerCreating 0 7s
pod-demo 2/2 Running 0 44s
Ⅴ 测试pod创建的容器
验证:kubectl创建的pod中,对应的容器为docker所创建
方法一:
#在master节点中,查看pod-demo所在位置,node02
[root@k8s-master01 1]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-demo 2/2 Running 0 22m 172.100.2.28 k8s-node02 <none> <none>
[root@k8s-master01 1]# curl 172.100.2.28
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
#在node02节点中,查看myapp容器,并进入
[root@k8s-node02 ~]# docker ps |grep myapp
2a629bf05305 d4a5e0eaa84f "nginx -g 'daemon of…" 25 minutes ago Up 25 minutes k8s_myapp-1_pod-demo_default_1bdfc2f8-615e-44f2-9ae9-914b3d78b09b_0
[root@k8s-node02 ~]# docker exec -it k8s_myapp-1_pod-demo_default_1bdfc2f8-615e-44f2-9ae9-914b3d78b09b_0 /bin/sh
/ # echo "yangqin" >> /usr/share/nginx/html/index.html
/ #
#回到master节点中,再次访问容器ip
[root@k8s-master01 1]# curl 172.100.2.28
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
yangqin
方法二:
#master节点通过kubectl,直接登录pod-demo的myapp-1容器
[root@k8s-master01 ~]# kubectl get pod -o wide #查看pod-demo对象运行所在的节点
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-demo 2/2 Running 0 18m 172.100.1.33 k8s-node01 <none> <none>
[root@k8s-master01 ~]# kubectl exec -it pod-demo -c myapp-1 -- /bin/sh #kubectl命令进入myapp-1容器
/ # echo "yangqin........" >> /usr/share/nginx/html/index.html
/ # cat /usr/share/nginx/html/index.html
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
yangqin........
#进入nnode01节点验证
[root@k8s-node01 ~]# docker ps |grep myapp
ac4c253d4244 d4a5e0eaa84f "nginx -g 'daemon of…" 16 minute257-4ce9-8ff8-cae9475b4844_0
[root@k8s-node01 ~]# docker exec -it k8s_myapp-1_pod-demo_default_8b1f43
/ # cat /usr/share/nginx/html/index.html
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
yangqin........
3)kubectl 常用命令
# 查看资源清单选项解释说明
$ kubectl explain pod.spec.containers
# 查看资源对象
$ kubectl get pod
-o wide # 查看更多的信息,包括 Pod ip、pod 运行的节点
yaml # 将当前的资源对象输出为 yaml 文件
json # 将当前的资源对象输出为 json 文件
-w # 监听变换,将变化信息输出至前台
--show-labels # 查看标签
-l # 通过标签过滤当前的输出 -l app=nginx
-n default # 指定名字空间,默认即 default
--all-namespaces == -A # 查看所有名字空间中的对象
# 删除资源对象
$ kubectl delete 资源类别 对象名称
$ kubectl delete pod pod-demo
$ kubectl delete -f xxx.yaml
--all 删除当前所有的资源对象
kubectl delete pod --all
kubectl delete deployment --all
# 实例化资源对象
$ kubectl create -f xxx.yaml/xxx.json
原理:
yaml文件 --> kubectl (yaml文件 --> json文件) --> apiServer
windows安装kubectl教程:
https://cloudmessage.top/archives/k8s-zai-windowszhong-shi-yong-kubectllian-jie-ji-qun
# 查看资源对象的详细信息(包括事件)
$ kubectl describe 资源类别 对象名称
注意:
此条命令常用于排错
pod的事件并不是持久化存储的
# 让 pod 内部的容器执行命令
$ kubectl exec -it podName -c cName -- command
kubectl exec -it pod-demo -c myapp-1 -- /bin/sh
注意:如果 pod 内部只封装了一个容器,那么 -c 可以省略(pod中只有 pause 和 c1 容器)
# 查看容器日志
$ kubectl logs podName -c cName
kubectl logs pod-demo -c myapp-1
-p -c # 查看已经停止的容器日志
-f # 持续输出容器日志信息
--tail=20 # 查看容器最近20条日志
--since=1h # 查看容器最近一小时产生的日志
实验:创建pod-2
1、根据 2.pod.yaml 文件,创建pod-2对象
[root@k8s-master01 ~]# vim 1/2.pod.yaml
[root@k8s-master01 ~]# cat 1/2.pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-2
namespace: default
labels:
app: myapp
spec:
containers:
- name: myapp-1
image: wangyanglinux/myapp:v1
- name: myapp-2
image: wangyanglinux/myapp:v2
[root@k8s-master01 ~]# kubectl create -f 1/2.pod.yaml
pod/pod-2 created
[root@k8s-master01 ~]# kubectl get pod -w
NAME READY STATUS RESTARTS AGE
pod-2 2/2 Running 0 4s
pod-2 1/2 Error 0 4s
pod-2 2/2 Running 1 5s
pod-2 1/2 Error 1 7s
pod-2 1/2 CrashLoopBackOff 1 22s
pod-2 2/2 Running 2 22s
pod-2 1/2 Error 2 25s
2、发现创建的pod出现问题
排错1:
查看资源对象详细信息
并未找到问题原因,仅提示了:重启容器,重启失败
排错2:
[root@k8s-master01 ~]# kubectl logs pod-2 -c myapp-1
[root@k8s-master01 ~]# kubectl logs pod-2 -c myapp-2
查看 pod-2 的 myapp-1 容器,没有日志
查看 pod-2 的 myapp-2 容器,产生日志,找到原因由于与 80端口已被占用,所以 myapp-2 无法启动
排错3:
若以上排错仍未找到问题,可能出现问题的原因:
1)镜像的问题
2)K8S本身有问题
注意:两个资源对象放到一个yaml文件中
用 --- 将两个需要创建的资源对象分开
资源清单的选项顺序无所谓
apiVersion: v1
kind: Pod
metadata:
name: pod-demo
namespace: default
labels:
app: myapp
spec:
containers:
- name: myapp-1
image: wangyanglinux/myapp:v1
- name: busybox-1
image: busybox:1.36.0
command:
- "/bin/sh"
- "-c"
- "sleep 3600"
---
apiVersion: v1
kind: Pod
metadata:
name: pod-3
namespace: default
labels:
app: myapp
spec:
containers:
- name: myapp-1
image: wangyanglinux/myapp:v1
- name: myapp-2
image: wangyanglinux/myapp:v2
command:
- "/bin/sh"
- "-c"
- "sed -i '2 s/80/8080/' /etc/nginx/conf.d/default.conf && echo 'yangqin' >> /usr/share/nginx/html/index.html && nginx && sleep 3 && tail -f /dev/null"
三、常用字段解释
详细请点击 👉 常用字段解释.md
四、pod生命周期
pause生命周期为:整个pod存在的生命周期
1)启动过程:
1、pause初始化
2、initC初始化(个数 >= 0)
可以执行下载文件、编译等,再交给 pause 挂载存储
必须有成功操作,才能进行下一步,即返回码为0,否则整个 pod 会从pause开始重建
多个 initC 初始化时,采用线性初始化启动
3、启动 mainC
启动过程为流式启动容器
注意: kubectl describe pod pod-demo #查看pod-demo的事件信息,信息采用的式异步保存的
异步:两者之间避免实时交互,耗费资源(ETCD在两者之间作缓冲)
kubelet完成钩子机制
容器初始化
启动后钩子:获取代码
执行启动命令:
没办法保证执行启动命令位于启动钩子完成以后才执行(即:在执行启动命令时,有可能 “启动后钩子” 还未完成)
关闭前钩子
关闭信号
注意:限制性容器初始化,再执行启动后钩子,再执行启动命令,但是,启动命令,不一定在,启动后钩子执行完成以后,才开始执行
探针机制:
就绪探测:容器启动以后,探测一次
存活探测:容器启动以后,一直探测,可定义探测的间隔
探测机制详解:
探测的方法:
EXEC:
返回码为0 ---> 成功
返回码非0 ---> 失败
返回码未知 ---> 未知(设置此项原因:为了确保鲁棒性,即稳定性)
TCPSOCKET:
TCP连接此端口成功 ---> 成功
TCP连接此端口失败 ---> 失败
TCP连接此端口未知 ---> 未知
HTTPGET:
200=< 返回码 < 400 ---> 成功
返回码 < 200 或者 返回码 >= 300 ---> 失败
返回码未知 ---> 未知
工作类型:
就绪探测(readinessProbe):若容器不添加就绪探测,默认为就绪状态
若容器添加就绪探测,则默认为未就绪状态,除非就绪探测成功
成功 ---> 将当前容器未就绪状态改为就绪状态
失败 ---> 等待下一次探测
未知 ---> 静默,不改变状态,等待下一次探测
存活探测(livenessProbe):若不添加存活探测,只要容器能运行,此pod就一直运行,哪怕内部服务不饿能给用户提供访问
成功 ---> 静默,不改变状态,等待下一次探测
失败 ---> 根据pod的重启策略,重建容器
未知 ---> 静默,不改变状态,等待下一次探测
2)实验
1、验证 initC 为线性启动、mainC 为流式启动
前提相关介绍:
Ⅰ 此特性还可以实现:mysql与tomcat的先后启动: 在initC中,连接数据库,判断数据是否可用,不可用退出循环 详细实验请点击👉 mysql与tomcat的先后启动 (建议先完成下面的实验1,再完成这个实验)
Ⅱ service 资源实例化为对象时,对象名会写入 coredns ,从而实现 K8S 中的域名解析
service实现负载均衡原理:
匹配条件:
Ⅲ K8S中的缩写:点击查看所有缩写
此处用到缩写:service ~ svc
$ kubectl create svc clusterip myservice --tcp=80:80
#clusterip 创建的类型
#myservice 创建的对象名
#--tcp=80:80 创建一个负载均衡的集群
实验步骤
1)创建yaml文件,创建pod
[root@k8s-master01 ~]# ls
1
[root@k8s-master01 ~]# mkdir 2
[root@k8s-master01 ~]# cd 2/
[root@k8s-master01 2]# vim 1.pod.yaml
[root@k8s-master01 2]# cat 1.pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: myapp-container
image: busybox:1.35.0
command: ['sh', '-c', 'echo The app is running! && sleep 3600']
initContainers:
- name: init-myservice
image: busybox:1.35.0
command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;']
- name: init-mydb
image: busybox:1.35.0
command: ['sh', '-c', 'until nslookup mydb;do echo waiting for mydb; sleep 2; done;']
[root@k8s-master01 2]# kubectl create -f 1.pod.yaml
2)查看pod状态,出现问题
3)检查问题并排错
发现集群的myapp-pod信息没有报错信息,myapp-pod中的init-service容器创建成功,也启动成功
查看 init-myservice容器日志,发现容器中无法识别myservice域名解析
所以,根据yaml文件中内容,在myapp-pod中有一个init容器 init-service ,在这个容器启动时写了一个死循环:若不能解析myservice域名,则会循环
导致 init-service容器一直无法成功完成操作,以至于下一个 init容器 init-mydb 无法创建启动,mainC容器也无法创建启动
下面解决:myservice域名正常解析
4)将service资源实例化为 myservice 对象
5)查看pod状态,任然出现问题
[root@k8s-master01 2]# kubectl get pod -w
NAME READY STATUS RESTARTS AGE
myapp-pod 0/1 Init:1/2 0 17m
同样的,init-mydb容器无法识别 mydb 的域名解析,进入死循环,需要将service资源实例化为 mydb 对象,从而实现域名解析
6)将service资源实例化为mydb对象
7)检查pod状态,myapp-pod正常启动
[root@k8s-master01 2]# kubectl get pod -w
NAME READY STATUS RESTARTS AGE
myapp-pod 0/1 Init:1/2 0 28m
myapp-pod 0/1 PodInitializing 0 28m
myapp-pod 1/1 Running 0 28m
进入pod所在节点,查看myapp-pod相关容器
能够发现pod生命周期:
pause容器一直存在、init容器按照线性启动,并且每个init容器完成以后再回进行下一个init容器,所有init容器完成以后,才会创建程序容器
2、验证 initC 中的容器,返回码为0,才能往后
若返回码不为0,则init容器会重建
实验步骤
1)上传压缩包
[root@k8s-master01 2]# tar -xf initC.tar.gz
[root@k8s-master01 2]# ls
1.pod.yaml initC initC.tar.gz
[root@k8s-master01 2]# ls initC
1.pod.yaml 2.pod.yaml Dockerfile go.mod main.go randexit
#文件解释:
两个yaml文件创建pod
Dockerfile中,封装为镜像 wangyanglinux/tools:randexitv1
镜像中用最小的alpine系统
将randexit程序设置为启动执行,并定义默认睡眠时间为5
go.mod,信息
main.go源码中的逻辑:
先定义环境变量睡眠时间和返回码,默认睡眠时间为4,默认返回码为2
执行程序后,判断休眠时间是否大于等于0
若判断成功
则判断返回码
若返回码为0,则睡眠定义的时间并返回码为0
若返回码为1,则睡眠定义的时间并返回码为1
若其他返回码,则生成一个随机数
若随机数大于等于50,则睡眠定义时间并返回码为1
若随机数小于50,则睡眠定义 时间并返回码为0
-----------------总结---------------------
执行程序后,若未指定睡眠时间,默认睡眠4秒
若未指定返回码,根据默认返回码为2,再根据判断,生成随机数,再根据判断睡眠定义时间并返回码为1或0
验证程序:
[root@k8s-master01 2]# cd initC
[root@k8s-master01 initC]# ls
1.pod.yaml 2.pod.yaml Dockerfile go.mod main.go randexit
[root@k8s-master01 initC]# ./randexit
休眠 4 秒,产生的随机数为 17,小于等于 50 ,返回码为 0!
[root@k8s-master01 initC]# echo $?
0
[root@k8s-master01 initC]# ./randexit
休眠 4 秒,产生的随机数为 81,大于等于 50 ,返回码为 1!
[root@k8s-master01 initC]# echo $?
1
2)根据 1.pod.yaml 文件创建pod
此yaml文件根据pod资源创建pod,pod名为:myapp-pod,期望创建一个init容器、程序容器(封装了nginx)
此yaml文件中未定义init容器的返回码
创建的pod中,其中的init容器启动时则执行randexit程序,程序中随机返回返回码为0|1
若返回的返回码为1,则重建init容器,再来一次
若返回的返回码为0,则init容器完成执行,进入下一个程序容器的创建运行
创建pod,名为:myapp-pod
[root@k8s-master01 initC]# cat 1.pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: myapp
image: wangyanglinux/myapp:v1
initContainers:
- name: randexit
image: wangyanglinux/tools:randexitv1
[root@k8s-master01 initC]# kubectl get pod
No resources found.
[root@k8s-master01 initC]# kubectl create -f 1.pod.yaml
pod/myapp-pod created
快速执行命令,查看变化信息
3)根据2.pod.yaml 文件创建pod
此yaml文件根据pod资源创建pod,pod名为:myapp-pod,期望创建一个init容器、程序容器(封装了nginx)
此yaml文件中定义了返回码为1
创建的pod中,其中的init容器启动时执行randexit程序,程序执行完后返回返回码为1
则重建init容器
重建后init容器再次执行randexit程序,程序返回返回码为1
再次重建init容器(进入死循环)
创建pod,名为myapp-pod
[root@k8s-master01 initC]# cat 2.pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: myapp
image: wangyanglinux/myapp:v1
initContainers:
- name: randexit
image: wangyanglinux/tools:randexitv1
args: ["--exitcode=1"]
[root@k8s-master01 initC]# kubectl get pod
No resources found.
[root@k8s-master01 initC]# kubectl create -f 2.pod.yaml
pod/myapp-pod created
快速执行命令,查看变化信息,发现initC一直重建
[root@k8s-master01 initC]# kubectl get pod -w
myapp-pod 0/1 Pending 0 0s
myapp-pod 0/1 Pending 0 0s
myapp-pod 0/1 Init:0/1 0 0s
myapp-pod 0/1 Init:0/1 0 1s
myapp-pod 0/1 Init:0/1 0 2s
myapp-pod 0/1 Init:Error 0 7s
myapp-pod 0/1 Init:0/1 1 8s
myapp-pod 0/1 Init:Error 1 13s
myapp-pod 0/1 Init:CrashLoopBackOff 1 29s
myapp-pod 0/1 Init:0/1 2 29s
myapp-pod 0/1 Init:Error 2 34s
myapp-pod 0/1 Init:CrashLoopBackOff 2 47s
myapp-pod 0/1 Init:0/1 3 62s
myapp-pod 0/1 Init:Error 3 67s
myapp-pod 0/1 Init:CrashLoopBackOff 3 81s
3、验证重启策略
pod.spec.restartPolicy #重启策略,默认为always
always:pod中,若其中容器损坏,则会一直创建容器修复
onFailure:pod中,若容器以失败退出(返回码不为0),则会重建容器
若容器以正常退出(返回码为0),则不会重建容器
Never:pod中,无论容器怎样损坏,都不会重建修复
验证Never选项
创建一个3.pod.yaml 文件,其中定义容器重启策略为: Never
基于3.pod.yaml 文件启动pod
[root@k8s-master01 initC]# cp -a 2.pod.yaml 3.pod.yaml
[root@k8s-master01 initC]# vim 3.pod.yaml
[root@k8s-master01 initC]# cat 3.pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
restartPolicy: Never
containers:
- name: myapp
image: wangyanglinux/myapp:v1
initContainers:
- name: randexit
image: wangyanglinux/tools:randexitv1
args: ["--exitcode=1"]
[root@k8s-master01 initC]# kubectl delete pod --all
pod "myapp-pod" deleted
[root@k8s-master01 initC]# kubectl create -f 3.pod.yaml
Never 重启策略验证
pod中的容器没有重启
[root@k8s-master01 initC]# kubectl get pod
NAME READY STATUS RESTARTS AGE
myapp-pod 0/1 Init:Error 0 3m55s
[root@k8s-node02 ~]# docker ps -a|grep myapp
03859617db84 0d0bbbbe5f6c "/root/randexit --ex…" 5 minutes ago Exited (1) 5 minutes ago k8s_randexit_myapp-pod_default_c4af8d7c-7a8e-4b3e-8ee3-cb01b8c68efe_0
3a04eebbd047 k8s.gcr.io/pause:3.1 "/pause" 5 minutes ago Exited (0) 5 minutes ago k8s_POD_myapp-pod_default_c4af8d7c-7a8e-4b3e-8ee3-cb01b8c68efe_
4、检测探针-就绪探测
在扩容时,意义很大:
在以前负载均衡集群中,若要添加一个pod,需要进行就绪探测,再加入进群中
若不进行就绪探测,默认就绪状态,则再创建完pod后会自动加入集群,用户有可能并不会访问成功
(httpget就绪探测,相当于在加入集群之前,进行了一次http访问,通过以后才会处于就绪状态)
千万不要随便执行的命令:
1)在未定义就绪探测时,默认就绪状态,实现负载均衡
Ⅰ 依据两个yaml'文件,创建两个pod
[root@k8s-master01 2]# ls
1.pod.yaml initC initC.tar.gz
[root@k8s-master01 2]# mkdir 2
[root@k8s-master01 2]# cd 2/
[root@k8s-master01 2]# vim 1.pod.yaml
[root@k8s-master01 2]# cat 1.pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-1
labels:
app: myapp
spec:
containers:
- name: myapp
image: wangyanglinux/myapp:v1
[root@k8s-master01 2]# vim 2.pod.yaml
[root@k8s-master01 2]# cat 2.pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-2
labels:
app: myapp
version: v1
spec:
containers:
- name: myapp
image: wangyanglinux/myapp:v1
[root@k8s-master01 2]# kubectl create -f 1.pod.yaml
[root@k8s-master01 2]# kubectl create -f 2.pod.yaml
Ⅱ 创建svc资源的对象myapp,实现均衡负载
[root@k8s-master01 2]# kubectl create service clusterip myapp --tcp=80:80
[root@k8s-master01 2]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2d8h
myapp ClusterIP 10.96.50.132 <none> 80/TCP 5s
[root@k8s-master01 2]# curl 10.96.50.132
Hello MyApp | Version: v1 | <a href="hostname.html">Pod Name</a>
[root@k8s-master01 2]# curl 10.96.50.132/hostname.html
pod-1
[root@k8s-master01 2]# curl 10.96.50.132/hostname.html
pod-2
[root@k8s-master01 2]# curl 10.96.50.132/hostname.html
pod-1
[root@k8s-master01 2]# curl 10.96.50.132/hostname.html
pod-2
[root@k8s-master01 2]# kubectl get pod --show-labels
NAME READY STATUS RESTARTS AGE LABELS
pod-1 1/1 Running 0 2m25s app=myapp
pod-2 1/1 Running 0 2m21s app=myapp,version=v1
2)定义就绪探测,实现负载均衡
Ⅰ 根据yaml文件,创建pod
[root@k8s-master01 2]# vim 3.pod.yaml
[root@k8s-master01 2]# cat 3.pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: readiness-httpget-pod
namespace: default
labels:
app: myapp
env: test
spec:
containers:
- name: readiness-httpget-container
image: wangyanglinux/myapp:v1
readinessProbe:
httpGet:
port: 80
path: /index1.html
initialDelaySeconds: 1
periodSeconds: 3
[root@k8s-master01 2]# kubectl create -f 3.pod.yaml
Ⅱ 查看pod信息,出现问题
describe 查看信息,发现就绪探测未成功,http返回网页404
[root@k8s-master01 2]# kubectl get pod
NAME READY STATUS RESTARTS AGE
pod-1 1/1 Running 0 17m
pod-2 1/1 Running 0 17m
readiness-httpget-pod 0/1 Running 0 51s
Ⅲ 修改yaml 文件,重新创建pod
[root@k8s-master01 2]# vim 3.pod.yaml
[root@k8s-master01 2]# cat 3.pod.yaml |grep index.html
path: /index.html
[root@k8s-master01 2]# kubectl create -f 3.pod.yaml
pod/readiness-httpget-pod created
Ⅳ 再次查看pod信息,创建成功
httpget就绪探测成功
[root@k8s-master01 2]# kubectl get pod
NAME READY STATUS RESTARTS AGE
pod-1 1/1 Running 0 23m
pod-2 1/1 Running 0 23m
readiness-httpget-pod 1/1 Running 0 10s
Ⅴ 测试负载均衡
[root@k8s-master01 2]# kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 2d8h
myapp ClusterIP 10.96.50.132 <none> 80/TCP 26m
[root@k8s-master01 2]# curl 10.96.50.132/hostname.html
readiness-httpget-pod
[root@k8s-master01 2]# curl 10.96.50.132/hostname.html
pod-1
[root@k8s-master01 2]# curl 10.96.50.132/hostname.html
pod-2
[root@k8s-master01 2]# curl 10.96.50.132/hostname.html
readiness-httpget-pod
[root@k8s-master01 2]# curl 10.96.50.132/hostname.html
pod-1
[root@k8s-master01 2]# curl 10.96.50.132/hostname.html
pod-2
5、检测探针-存活探测
总结:一般使用httpget进行存活探测
1)exec存活tance
Ⅰ 根据 4.pod.yaml 文件,创建pod
4.pod.yaml 中,将pod资源创建pod,名为:liveness-exec-pod,在default空间中
在pod中创建容器,名为:liveness-exec-container,使用镜像为:busybox:1.35.0
定义这个容器启动时,默认创建一个文件,休眠60秒后将文件删除,在休眠3600秒
对这个容器采用了exec存活探测:
exec容器,判断 /tmp/live 文件是否存在(1秒延迟、3秒探测重试)
若探测到文件不存在,则会根据pod重启策略,重建容器
[root@k8s-master01 2]# vim 4.pod.yaml
[root@k8s-master01 2]# cat 4.pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: liveness-exec-pod
namespace: default
spec:
containers:
- name: liveness-exec-container
image: busybox:1.35.0
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
[root@k8s-master01 2]# kubectl create -f 4.pod.yaml
Ⅱ 查看pod信息
发现:liveness-exec-pod 会 每隔一段时间都重建一次 容器 liveness-exec-container
原理:因为容器在创建后,一分钟之内有 /temp/live 文件存在,而此处存活探测的机制就是判断是否存在 /temp/live 文件
一分钟以后,文件删除,存活探测失败,容器重建
[root@k8s-master01 2]# kubectl get pod -w
NAME READY STATUS RESTARTS AGE
liveness-exec-pod 1/1 Running 0 22s
pod-1 1/1 Running 0 47m
pod-2 1/1 Running 0 47m
readiness-httpget-pod 1/1 Running 0 23m
liveness-exec-pod 1/1 Running 1 97s
liveness-exec-pod 1/1 Running 2 3m17s
liveness-exec-pod 1/1 Running 3 4m55s
2)httpget存活探测
Ⅰ 根据 5.pod.yaml 文件,创建 pod
5.pod.yaml 中,将pod资源创建为pod,名为:liveness-httpget-pod,在default 空间中
在pod中创建容器,名为:liveness-httpget-container,使用镜像为:wangyanglinux/myapp:v1
声明了80为重要端口(信息级别),使得后面httpget能进行探测
定义httpget探测,端口为80,访问路径为:网页主目录下的 index.html 文件。(延迟1秒、3秒探测重试、探测超时时间3秒)
根据网页是否能访问,作为探测成功的条件
若网页无法访问,重建容器
若网页能否访问,或者返回结果未知,静默等待下一次探测
[root@k8s-master01 2]# vim 5.pod.yaml
[root@k8s-master01 2]# cat 5.pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: liveness-httpget-pod
namespace: default
spec:
containers:
- name: liveness-httpget-container
image: wangyanglinux/myapp:v1
ports:
- name: http
containerPort: 80
livenessProbe:
httpGet:
port: 80
path: /index.html
initialDelaySeconds: 1
periodSeconds: 3
timeoutSeconds: 3
[root@k8s-master01 2]# kubectl create -f 5.pod.yaml
pod/liveness-httpget-pod created
Ⅱ 查看pod信息,正常运行
因为容器的网页一直能访问,存活探测成功,静默,等待下一次探测
[root@k8s-master01 2]# kubectl get pod |grep liveness-httpget-container
[root@k8s-master01 2]# kubectl get pod |grep liveness-httpget-pod
liveness-httpget-pod 1/1 Running 0 84s
Ⅲ 模拟网页文件损坏
让 httpget 存活探测,探测到存活失败,从而重建容器
#进入容器,修改网页主文件,发现一段时间后,自动退出
[root@k8s-master01 2]# kubectl exec -it liveness-httpget-pod -c liveness-httpget-container /bin/sh
/ # ls /usr/share/nginx/html/
50x.html index.html
/ # mv /usr/share/nginx/html/index.html /usr/share/nginx/html/index1.html
/ # command terminated with exit code 137
#再次查看pod信息,发现容器出现重建
[root@k8s-master01 2]# kubectl get pod |grep liveness-httpget-pod
liveness-httpget-pod 1/1 Running 1 8m18s
3)tcp存活探测
Ⅰ 根据 6.pod.yaml 文件,创建pod
6.pod.yaml 中,将pod资源创建为pod,名为:probe-tcp,未指定名字空间(默认也在 default 空间中)
在pod中创建容器,名为 nginx ,使用镜像为:wangyanglinux/myapp:v1
定义tcp存活探测,探测是否有80端口。(延迟5秒,探测超时时间1秒)
根据是否存在80端口,作为探测成功的条件(一般不用此探测)
若tcp连接80端口失败,则重建容器
若tcp连接80端口成功,或者未知,静默等待下一次探测
[root@k8s-master01 2]# vim 6.pod.yaml
[root@k8s-master01 2]# cat 6.pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: probe-tcp
spec:
containers:
- name: nginx
image: wangyanglinux/myapp:v1
livenessProbe:
initialDelaySeconds: 5
timeoutSeconds: 1
tcpSocket:
port: 80
[root@k8s-master01 2]# kubectl create -f 6.pod.yaml
pod/probe-tcp created
Ⅱ 查看pod信息,正常运行
6、钩子机制
Pod hook(钩子)是由 K8S 管理的 kubectl 发起的,当容器中的进程启动前,或容器中进程终止前运行。这是包含在容器的生命周期中。可以同时为Pod中所有容器都配置钩子
Hook 的类型包括两种:
exec:执行一段命令
HTTP:发送http请求
实验:启动后钩子+关闭前钩子
Ⅰ 根据 /root/3/1.pod.yaml 文件创建 pod
1.pod.yaml 文件中,将pod资源创建为pod,名为:lifecycle-demo,未指定名字空间(使用默认 default 空间)
在pod中创建容器,名为:lifecycle-demo-container,使用镜像:
wangyanglinux/myapp:v1
定义启动后钩子,exec动作:向 /usr/share/message 中写入数据
定义关闭前钩子,exec动作:想 /usr/share/message 中写入数据
[root@k8s-master01 ~]# mkdir 3
[root@k8s-master01 ~]# cd 3
[root@k8s-master01 3]# vim 1.pod.yaml
[root@k8s-master01 3]# cat 1.pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: lifecycle-demo
spec:
containers:
- name: lifecycle-demo-container
image: wangyanglinux/myapp:v1
lifecycle:
postStart:
exec:
command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /usr/share/message"]
preStop:
exec:
command: ["/bin/sh", "-c", "echo Hello from the preStop handler > /usr/share/message"]
[root@k8s-master01 3]# kubectl get pod
No resources found.
[root@k8s-master01 3]# kubectl create -f 1.pod.yaml
Ⅱ 测试钩子机制
进入容器,查看启动后钩子创建的文件存在
[root@k8s-master01 3]# kubectl exec -it lifecycle-demo -c lifecycle-demo-container -- /bin/sh
/ # cat /usr/share/message
Hello from the postStart handler
在容器中写一个死循环,方便删除pod时,能查看到关闭前钩子创建的文件
#在pod的容器中执行
/ # while true ;do cat /usr/share/message ;done
#另开一个终端删除pod
[root@k8s-master01 3]# kubectl delete -f 1.pod.yaml
观察到关闭前钩子创建的文件
7、将 pod 生命周期中定义的内容结合
Ⅰ 根据 all.yaml 文件,创建pod
#all.yaml文件详解
all.yaml 文件中,将pod资源创建为pod,名为:myapp-pod,定义标签为:app=myapp(未指定名字空间,默认在default空间中)
创建两个initC:
一个为名为:init-myservice,使用镜像为:busybox:1.35.0,启动容器时执行命令为:不能识别myservice域名解析,就陷入死循环,直到能解析才退出死循环
另一个名为:init-mydb,使用镜像为:busybox:1.35.0,启动容器时执行命令为:不能识别mydb域名解析,就陷入死循环,直到能解析才退出死循环
创建两个mainC:
一个名为:busybox-c,使用镜像为:busybox:1.35.0
启动容器时执行命令为:创建一个 /tmp/live文件,睡眠10分钟后,将其删除,再睡眠3600秒
定义一个存活探测:exec动作,进入容器后,判断是否有 /tmp/live文件存在,若不存在则重建容器(延迟1秒,探测重试3秒)
定于启动后钩子:向 /var/message 中写入,启动后钩子执行完成的信息
定义关闭前钩子:想 /var/message 中写入,关闭前钩子执行完成的信息
另一个名为:myapp-c,使用镜像为:wangyanglinux/myapp:v1
定义一个就绪探测:httpget动作,若能访问80端口下的,index1.html文件成功则转换为就绪状态,否则处于未就绪状态(探测延迟1秒,探测重试3秒)
定义一个存活探测:httpget动作,若能访问80端口下的,index.html文件成功,则一直处于存活状态,否则重建容器(探测延迟1秒,探测重试3秒,探测超时3秒)
[root@k8s-master01 ~]# cd /root/3/
[root@k8s-master01 3]# vim all.yaml
[root@k8s-master01 3]# cat all.yaml
apiVersion: v1
kind: Pod
metadata:
name: myapp-pod
labels:
app: myapp
spec:
containers:
- name: busybox-c
image: busybox:1.35.0
command: ["/bin/sh","-c","touch /tmp/live ; sleep 600; rm -rf /tmp/live; sleep 3600"]
livenessProbe:
exec:
command: ["test","-e","/tmp/live"]
initialDelaySeconds: 1
periodSeconds: 3
lifecycle:
postStart:
exec:
command: ["/bin/sh", "-c", "echo Hello from the postStart handler > /var/message"]
preStop:
exec:
command: ["/bin/sh", "-c", "echo Hello from the preStop handler > /var/message"]
- name: myapp-c
image: wangyanglinux/myapp:v1
readinessProbe:
httpGet:
port: 80
path: /index1.html
initialDelaySeconds: 1
periodSeconds: 3
livenessProbe:
httpGet:
port: 80
path: /index.html
initialDelaySeconds: 1
periodSeconds: 3
timeoutSeconds: 3
initContainers:
- name: init-myservice
image: busybox:1.35.0
command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;']
- name: init-mydb
image: busybox:1.35.0
command: ['sh', '-c', 'until nslookup mydb; do echo waiting for mydb; sleep 2; done;']
[root@k8s-master01 3]# kubectl create -f all.yaml
Ⅱ 查看pod状态,发现问题并解决
发现需要解决域名解析问题,才能让initC容器完成退出,并返回码为0
[root@k8s-master01 3]# kubectl get pod
NAME READY STATUS RESTARTS AGE
myapp-pod 0/2 Init:0/2 0 115s
#解决域名解析问题,添加svc
[root@k8s-master01 3]# kubectl create service clusterip myservice --tcp=80:80
service/myservice created
[root@k8s-master01 3]# kubectl create service clusterip mydb --tcp=80:80
service/mydb created
[root@k8s-master01 3]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 5d
mydb ClusterIP 10.107.123.80 <none> 80/TCP 6s
myservice ClusterIP 10.103.225.22 <none> 80/TCP 24s
发现需要解决其中一个容器的,就绪探测问题
进入容器写入网页文件 index1.html
解决:
[root@k8s-master01 3]# kubectl exec -it myapp-pod -c myapp-c -- /bin/sh
/ # cd /usr/share/nginx/html/
/usr/share/nginx/html # ls
50x.html index.html
/usr/share/nginx/html # echo "hello YQ.." > index1.html
再次检查pod状态:
以上已经验证完的特性:initC特性、就绪探测机制
接下来验证存活探测机制、钩子机制
Ⅲ 测试
#根据yaml文件,定义了myapp-c的存活探测httpget动作
#进入容器删除网页主文件,存活探测失败,重建容器
[root@k8s-master01 ~]# kubectl exec -it myapp-pod -c myapp-c -- /bin/sh
/ # cd /usr/share/nginx/html/
/usr/share/nginx/html # ls
50x.html index.html index1.html
/usr/share/nginx/html # rm -rf index.html
/usr/share/nginx/html # command terminated with exit code 137
#定义了busybox-c的钩子机制
[root@k8s-master01 3]# kubectl exec -it myapp-pod -c busybox-c -- /bin/sh
/ # cat /var/message
Hello from the postStart handler
#若容器退出时,也有内容写入 /var/message (可用死循环进行查看,另起一个终端删除pod,验证)















