目录
在kubernetes中基本所有资源的一级属性都是一样的,主要包含5部分:
在上面的属性中,spec是接下来研究的重点,继续看下它的常见子属性:
(2)端口设置,创建一个poed-ports.yaml文件:
2.在整个生命周期中,Pod会出现5中状态(相位),分别如下:
(2)以exec 方式为例,演示钩子函数的使用,创建一个pod-exec.yaml 文件,如下:
1. 方式一:Exec——创建pod-live.yaml文件
2.方式二: TCPSocket —— 创建pod-liveness-tcpsocket.yaml
3.方式三:HTTPGet —— pod-liveness-httpget.yaml
一、Pod 介绍
Pod是Kubernetes中的最小调度单元,一个Pod封装一个容器(也可以封装多个容器),Pod里的容器共享存储、网络等。也就是说,可以把整个pod看作虚拟机,然后每个容器相当于运行在虚拟机的进程。同一个pod里的所有容器都被统一安排和调度。
二、Pod 配置
1.yaml配置文件模板:
apiVersion: v1 #必选,版本号,例如v1
kind: Pod #必选,资源类型,例如 Pod
metadata: #必选,元数据
name: string #必选,Pod名称
annotations: #选做,描述信息
nginx: nginx
namespace: string #Pod所属的命名空间,默认为"default"
labels: #自定义标签列表
- name: string
spec: #必选,Pod中容器的详细定义
containers: #必选,Pod中容器列表
- name: string #必选,容器名称
image: string #必选,容器的镜像名称
imagePullPolicy: [ Always|Never|IfNotPresent ] #获取镜像的策略
command: [string] #容器的启动命令列表,如不指定,使用打包时使用的启动命令
args: [string] #容器的启动命令参数列表
workingDir: string #容器的工作目录
volumeMounts: #挂载到容器内部的存储卷配置
- name: string #引用pod定义的共享存储卷的名称,需用volumes[]部分定义的的卷名
mountPath: string #存储卷在容器内mount的绝对路径,应少于512字符
readOnly: boolean #是否为只读模式
ports: #需要暴露的端口库号列表
- name: string #端口的名称
containerPort: 80 #容器需要监听的端口号
hostPort: int #容器所在主机需要监听的端口号,默认与Container相同
protocol: string #端口协议,支持TCP和UDP,默认TCP
env: #容器运行前需设置的环境变量列表
- name: string #环境变量名称
value: string #环境变量的值
resources: #资源限制和请求的设置
limits: #资源限制的设置
cpu: string #Cpu的限制,单位为core数,将用于docker run --cpu-shares参数
memory: string #内存限制,单位可以为Mib/Gib,将用于docker run --memory参数
requests: #资源请求的设置
cpu: string #Cpu请求,容器启动的初始可用数量
memory: string #内存请求,容器启动的初始可用数量
lifecycle: #生命周期钩子
postStart: #容器启动后立即执行此钩子,如果执行失败,会根据重启策略进行重启
preStop: #容器终止前执行此钩子,无论结果如何,容器都会终止
livenessProbe: #对Pod内各容器健康检查的设置,当探测无响应几次后将自动重启该容器
exec: #对Pod容器内检查方式设置为exec方式
command: [string] #exec方式需要制定的命令或脚本
httpGet: #对Pod内个容器健康检查方法设置为HttpGet,需要制定Path、port
path: string
port: number
host: string
scheme: string
HttpHeaders:
- name: string
value: string
tcpSocket: #对Pod内个容器健康检查方式设置为tcpSocket方式
port: number
initialDelaySeconds: 0 #容器启动完成后首次探测的时间,单位为秒
timeoutSeconds: 0 #对容器健康检查探测等待响应的超时时间,单位秒,默认1秒
periodSeconds: 0 #对容器监控检查的定期探测时间设置,单位秒,默认10秒一次
successThreshold: 0
failureThreshold: 0
securityContext:
privileged: false
restartPolicy: [Always | Never | OnFailure] #Pod的重启策略
nodeName: <string> #设置NodeName表示将该Pod调度到指定到名称的node节点上
nodeSelector: obeject #设置NodeSelector表示将该Pod调度到包含这个label的node上
imagePullSecrets: #Pull镜像时使用的secret名称,以key:secretkey格式指定
- name: string
hostNetwork: false #是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络
volumes: #在该pod上定义共享存储卷列表
- name: string #共享存储卷名称 (volumes类型有很多种)
emptyDir: {} #类型为emtyDir的存储卷,与Pod同生命周期的一个临时目录。为空值
hostPath: string #类型为hostPath的存储卷,表示挂载Pod所在宿主机的目录
path: string #Pod所在宿主机的目录,将被用于同期中mount的目录
secret: #类型为secret的存储卷,挂载集群与定义的secret对象到容器内部
scretname: string
items:
- key: string
path: string
configMap: #类型为configMap的存储卷,挂载预定义的configMap对象到容器内部
name: string
items:
- key: string
path: string
在kubernetes中基本所有资源的一级属性都是一样的,主要包含5部分:
- apiVersion 版本:由kubernetes内部定义,版本号必须可以用 kubectl api-versions 查询到
- kind 类型:指定资源的类型,比如 deployment,pod,service
- metadata 元数据,主要是资源标识和说明,常用的有name、namespace、labels等
- spec 描述,这是配置中最重要的一部分,里面是对各种资源配置的详细描述
- status 状态信息,里面的内容不需要定义,由kubernetes自动生成
在上面的属性中,spec是接下来研究的重点,继续看下它的常见子属性:
- containers <[]Object> 容器列表,用于定义容器的详细信息
- nodeName 根据nodeName的值将pod调度到指定的Node节点上
- nodeSelector <map[]> 根据NodeSelector中定义的信息选择将该Pod调度到包含这些label的Node 上
- hostNetwork 是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络
- volumes<[]Object> 存储卷,用于定义Pod上面挂在的存储信息
- restartPolicy 重启策略,表示Pod在遇到故障的时候的处理策略
2.基本配置
(1)创建一个pod-base.yaml文件,内容如下:
[root@k8s-master test]# cat pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-base
namespace: dev
labels:
user: lhs
spec:
containers:
- name: nginx
image: nginx:1.17.1
- name: busybox
image: busybox:1.30
上面定义了一个比较简单Pod的配置,里面有两个容器:
- nginx:用nginx:1.17.1版本的nginx镜像创建
- busybox:用1.30版本的busybox镜像创建,(busybox是一个小巧的linux命令集合)
1. 创建Pod
[root@k8s-master test]# kubectl create -f pod.yaml
pod/pod-base created
2.查看pod状态
# READY 1/2 : 表示当前Pod中有2个容器,其中1个准备就绪,1个未就绪
# RESTARTS : 重启次数,因为有1个容器故障了,Pod一直在重启试图恢复它
[root@k8s-master test]# kubectl get -f pod-base1.yaml
NAME READY STATUS RESTARTS AGE
pod-base 1/2 CrashLoopBackOff 1 (10s ago) 12s
[root@k8s-master test]# kubectl get -f pod-base1.yaml
NAME READY STATUS RESTARTS AGE
pod-base 1/2 NotReady 2 (26s ago) 28s
3. 删除pod-base
[root@k8s-master test]# kubectl delete pod pod-base -n dev
pod "pod-base" deleted
# kubectl delete pod pod-base -n dev --grace-period=0 --force 是强制删除Pod-base
--grace-period=0:设置优雅删除时间为 0,跳过等待。
--force:强制删除,绕过部分状态检查。
4. 在 yaml 配置文件中加入 command命令 ,然后再创建
command: ["/bin/sh","-c","touch /tmp/hello.txt;while true;do /bin/echo $(date +%T)>>/tmp/hello.txt;sleep 3;done;"]
#注释:
"/bin/sh","-c", 使用sh执行命令
touch /tmp/hello.txt; 创建一个/tmp/hello.txt 文件
while true;do /bin/echo $(date +%T) >> /tmp/hello.txt; sleep 3; done; 每隔3秒向文件中写入当前时间
[root@k8s-master test]# kubectl create -f pod.yaml
pod/pod-base created
5.再次查看
[root@k8s-master test]# kubectl get -f pod.yaml
NAME READY STATUS RESTARTS AGE
pod-base 2/2 Running 0 7s
[root@k8s-master test]# kubectl describe -f pod.yaml
注意:
# 在一开始的案例中,一直有一个问题没有解决,就是的busybox容器一直没有成功运行,那么到底是什么原因导致这个容器的故障呢?
原来busybox并不是一个程序,而是类似于一个工具类的集合,kubernetes集群启动管理后,它会自动关闭。
# 解决方法就是让其一直在运行,这就用到了command配置。
在 Kubernetes 的 Pod YAML 中如果未加入 command
命令时,容器会直接执行镜像默认定义的启动命令(即镜像制作时的 CMD
或 ENTRYPOINT
)。若镜像默认命令存在以下问题,会引发对应故障:
- 容器启动后立即退出:
若镜像默认命令执行的任务是一次性操作(如脚本执行完即结束),且没有持续运行的进程,容器会在启动后迅速退出。Kubernetes 检测到容器退出后会尝试重启,形成CrashLoopBackOff
状态,导致 Pod 始终无法进入Ready
状态。- 服务未正常启动:
若镜像默认命令存在错误(如路径错误、依赖缺失),容器启动时会因命令执行失败而崩溃,同样触发反复重启,最终表现为 Pod 状态异常(如NotReady
)。
修改完成之后 创建Pod 并进入到busybox 容器中,查看文件内容:
kubectl exec -it pod名称 -n 命名空间 -c 容器 /bin/sh ——这条命令可以进入到某个容器内部进行相关操作
(2)端口设置,创建一个poed-ports.yaml文件:
端口设置就是containers的ports选项
查看 Pod 规范里容器的端口部分 :
[root@k8s-master test]# kubectl explain pod.spec.containers.ports
KIND: Pod
VERSION: v1
RESOURCE: ports <[]Object>
FIELDS:
name <string> # 端口名称,如果指定,必须保证name在pod中是唯一的
containerPort<integer> # 容器要监听的端口(0<x<65536)
hostPort <integer> # 容器要在主机上公开的端口,如果设置,主机上只能运行容器的一个副本(一般省略)
hostIP <string> # 要将外部端口绑定到的主机IP(一般省略)
protocol <string> # 端口协议。必须是UDP、TCP或SCTP。默认为“TCP”。
pod-ports.yaml 文件:
[root@k8s-master test]# vim pod-ports.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-ports
namespace: dev
labels:
user: lhs
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports: #设置容器暴露的端口列表
- name: nginx-port
containerPort: 80
protocol: TCP
#1、创建Pod
[root@k8s-master test]# kubectl create -f pod-ports.yaml
pod/pod-ports created
#2、查看Pod
[root@k8s-master test]# kubectl get -f pod-ports.yaml
NAME READY STATUS RESTARTS AGE
pod-ports 1/1 Running 0 69s
[root@k8s-master test]# kubectl get -f pod-ports.yaml -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-ports 1/1 Running 0 11m 172.16.85.211 k8s-node01 <none> <none>
三、Pod 生命周期
1.定义
我们一般将pod对象从创建至终的这段时间范围称为pod的生命周期,它主要包含下面的过程:
- pod创建过程
- 运行初始化容器(init container)过程
- 运行主容器(main container)
容器启动后钩子(post start)、容器终止前钩子(pre stop)
容器的存活性探测(liveness probe)、就绪性探测(readiness probe)
- pod终止过程
2.在整个生命周期中,Pod会出现5中状态(相位),分别如下:
1、挂起(Pending): API Server 创建了 pod 资源对象已存入 etcd 中,但它尚未被调度完成,或者仍处于从仓库下载镜像的过程中。
2、运行中(Running): Pod 已经被调度至某节点,并且所有容器都已经被 kubelet 创建完成
3、成功(Succeeded): Pod 中的所有容器都已经成功终止并且不会被重启。
4、失败(Failed): Pod 中的所有容器都已终止了,并且至少有一个容器是因为失败终止。即容器以非 0 状态退出或者被系统禁止。
5、未知(Unknown):Api Server 无法正常获取到 Pod 对象的状态信息,通常是由于无法与所在工作节点的kubelet 通信所致。
# 6、ImgPullErr : (不常用) 镜像拉取失败
# 7、ContainerCreating : (不常用) 容器创建中
kubernetes在集群启动之后,集群中的各个组件也都是以Pod方式运行的。可以通过下面命令查看:
3.创建和终止
(1)Pod的创建过程
1. 用户通过kubectl或其他api客户端提交需要创建的Pod信息给apiServer
2. apiServer开始生成Pod对象的信息,并将信息存入etcd,然后返回确认信息至客户端
3. apiServer开始反映etcd中的Pod对象的变化,其它组件使用watch机制来跟踪检查apiServer上的变动
4. scheduler发现有新的Pod对象要创建,开始为Pod分配主机并将结果信息更新至apiServer
5. node节点上的kubelet发现有pod调度过来,尝试调用docker启动容器,并将结果回送至apiServer
6. apiServer将接收到的pod状态信息存入etcd中
(2)Pod的终止过程
1. 用户向apiServer发送删除pod对象的命令
2. apiServcer中的pod对象信息会随着时间的推移而更新,在宽限期内(默认30s),pod被视为dead
3. 将pod标记为terminating状态(正在删除状态)
4. kubelet在监控到pod对象转为terminating状态的同时启动pod关闭过程
5. 端点控制器监控到pod对象的关闭行为时将其从所有匹配到此端点的service资源的端点列表中移除
6. 如果当前pod对象定义了preStop钩子处理器,则在其标记为terminating后即会以同步的方式启动执行
7. pod对象中的容器进程收到停止信号
8. 宽限期结束后,若pod中还存在仍在运行的进程,那么pod对象会收到立即终止的信号
9. kubelet请求apiServer将此pod资源的宽限期设置为0从而完成删除操作,此时pod对于用户已不可见
4.初始化容器
初始化容器是在pod的主容器启动之前要运行的容器,主要是做一些主容器的前置工作,它具有两大特征:
1. 初始化容器必须运行完成直至结束,若某初始化容器运行失败,那么kubernetes需要重启它直到成功完成
2. 初始化容器必须按照定义的顺序执行,当且仅当前一个成功之后,后面的一个才能运行
接下来做一个案列,模拟下面需求:
假设要以主容器来运行nginx,但是要求在运行nginx之前先要能够连接上mysql和redis所在服务器
为了简化测试,事先规定好mysql(1.1.1.1)和redis(2.2.2.2)服务器的地址
创建pod-init.yaml文件:
apiVersion: v1
kind: Pod
metadata:
name: pod-base
namespace: dev
labels:
user: lhs
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- containerPort: 80
initContainers:
- name: test-mysql
image: busybox:1.30
command: ["/bin/sh","-c","until ping 1.1.1.1 -c 1; do echo waitint for mysql start ...; sleep 3;done;"]
- name: test-redis
image: busybox:1.30
command: ["/bin/sh","-c","until ping 2.2.2.2 -c 1; do echo waitint for mysql start ...; sleep 3;done;"]
然后将mysql和redis 的ip配置到需要调度的node节点上:
#1、查看Pod的状态,发现pod卡在启动第一个初始化容器过程中,后面的容器不会运行
[root@k8s-master test]# kubectl get -f pod-init.yaml -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-init 0/1 Init:1/2 0 12m 172.16.85.212 k8s-node01 <none> <none>
#2、将MySQL和redis ip配置到上面查看的调度的 k8s-node01 节点上面
[root@k8s-node01 ~]# ifconfig ens160:1 1.1.1.1 netmask 255.255.255.0 up
[root@k8s-node01 ~]# ifconfig ens160:2 2.2.2.2 netmask 255.255.255.0 up
[root@k8s-node01 ~]#
#3、然后再次查看Pod的状态,状态变成了Running
[root@k8s-master test]# kubectl get -f pod-init.yaml -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-init 1/1 Running 0 16m 172.16.85.212 k8s-node01 <none> <none>
5.钩子函数
钩子函数
能够感知自身生命周期中的事件,并在相应的时刻到来时运行用户指定的程序代码。
kubernetes在主容器的启动之后和停止之前提供了两个钩子函数:
1、post start: # 容器创建之后执行,如果失败了会重启容器
2、pre stop : # 容器终止之前执行,执行完成之后容器将成功终止,在其完成之前会阻塞删除容器的操作
(1)钩子处理器支持下面三种定义动作:
- Exec 命令:在容器内执行一次命令:
……
lifecycle:
postStart:
exec:
command:
- cat
- /tmp/healthy
……
- TCPSocket:在当前容器尝试访问指定的socket
……
lifecycle:
postStart:
tcpSocket:
port: 8080
……
- HTTPGet:在当前容器中向某url发起http请求
……
lifecycle:
postStart:
httpGet:
path: / #URI地址
port: 80 #端口号
host: 192.168.15.100 #主机地址
scheme: HTTP #支持的协议,http或者https
……
(2)以exec 方式为例,演示钩子函数的使用,创建一个pod-exec.yaml 文件,如下:
apiVersion: v1
kind: Pod
metadata:
name: pod-hook-exec
namespace: dev
labels:
user: lhs
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- name: nginx-port
containerPort: 80
lifecycle:
postStart:
exec: #在容器启动时执行一个命令,修改掉nginx的默认主页内容
command: ["/bin/sh","-c","echo postStart.... > /usr/share/nginx/html/index.html"]
preStop:
exec: #在容器停止之前停止nginx服务
command: ["/usr/sbin/nginx","-s","quit"]
#创建
[root@k8s-master test]# kubectl create -f pod-exec.yaml
pod/pod-hook-exec created
#查看
[root@k8s-master test]# kubectl get -f pod-exec.yaml -o wide
NAME READY STATUS RESTARTS AGE IP NODE ED NODE READINESS GATES
pod-hook-exec 1/1 Running 0 15s 172.16.58.201 k8s-node02 <none>
(3)验证:
6、容器探测
`容器探测`用于检测容器中的应用实例是否正常工作,是保障业务可用性的一种传统机制。如果经过探测,实例的状态不符合预期,那么kubernetes就会把该问题实例" 摘除 ",不承担业务流量。kubernetes提供了两种探针来实现容器探测,分别是:
1、存活性检查 :容器是否正常启动,探测失败,立即删除容器
2、就绪性检查 : 容器是否能够正常提供服务,探测失败,立即移除负载均衡
- liveness probes: 存活性探针,用于检测应用实例当前是否处于正常运行状态,如果不是,k8s会重启容器
- readiness probes:就绪性探针,用于检测应用实例当前是否可以接收请求,如果不能,k8s不会转发流量
livenessProbe 决定是否重启容器,readinessPr obe 决定是否将请求转发给容器
(1)上面两种探针目前均支持三种探测方式:
- Exec命令:在容器内执行一次命令,如果命令执行的退出码为0,则认为程序正常,否则不正常
…… livenessProbe: exec: command: - cat - /tmp/healthy ……
- TCPSocket:将会尝试访问一个用户容器的端口,如果能够建立这条连接,则认为程序正常,否则不正常
…… livenessProbe: tcpSocket: port: 8080 ……
- HTTPGet:调用容器内Web应用的URL,如果返回的状态码在200和399之间,则认为程序正常,否则不正常
…… livenessProbe: httpGet: path: / #URI地址 port: 80 #端口号 host: 127.0.0.1 #主机地址 scheme: HTTP #支持的协议,http或者https ……
(2)以liveness probes 为例演示:
1. 方式一:Exec——创建pod-live.yaml文件
apiVersion: v1
kind: Pod
metadata:
name: pod-live
namespace: dev
labels:
user: lhs
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- containerPort: 80
livenessProbe:
exec:
command: ["/bin/cat","/tmp/test.txt"]
2.方式二: TCPSocket —— 创建pod-liveness-tcpsocket.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-liveness-tcpsocket
namespace: dev
labels:
user: lhs
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- name: nginx-port
containerPort: 80
livenessProbe:
tcpSocket:
port: 80
测试:
3.方式三:HTTPGet —— pod-liveness-httpget.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-liveness-httpget
namespace: dev
labels:
user: lhs
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- name: nginx-port
containerPort: 80
livenessProbe:
httpGet:
scheme: HTTP
port: 80
path: /haha
测试:
为什么会在健康检查这里出错呢?分析了一下存活探针配置,可能在 livenessProbe 的 HTTP 路径不对,我的/haha目录并不存在。然后就需要创建目录,再重新部署Pod,Kubernetes 会根据新配置进行健康检查。
再次查看Pod详情:
当然,如果需要访问的话,需要将路径修改成:/【path: /】(应该说这才是正确的路径)
7.重启策略
- Always :容器失效时,自动重启该容器,这也是默认值。
- OnFailure : 容器终止运行且退出码不为0时 ,由 kubelet 自动重启改容器
- Never : 不论容器运行状态是什么,kebelet 都不会重启该容器
apiVersion: v1
kind: Pod
metadata:
name: pod-restartpolicy
namespace: dev
labels:
user: lhs
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- containerPort: 80
livenessProbe:
httpGet:
scheme: HTTP
port: 80
path: /haha
restartPolicy: Never
测试:在查看Pod详情时,发现nginx容器启动失败,然后再去查看Pod的重启次数时,发现一直是0 ,并没有重启。