容器与pod资源对象
为什么Kubernetes要引入pod概念不直接操作Docker容器
首先要明确一个概念,Kubernetes不仅仅是支持Docker当这个容器运行时,我的另一篇文章是什么?Kubernetes的CRI-我们知道容器运行时界面介绍的内容Kubernetes通过CRI支持去除抽象层Docker其他容器运行时,如rkt甚至支持客户自定义容器运行。
- 第一个原因:借助CRI使抽象层Kubernetes它不依赖于底层特定容器运行时的技术,而是直接操作pod,pod内部管理多个与业务密切相关的用户业务容器,方便Kubernetes做扩展。
- 第二个原因原因Kubernetes没有pod这个概念是直接管理容器,所以一组容器作为一个单元,假设其中一个容器死亡,该单元的状态应该如何定义?它应该被理解为整体死亡还是个人死亡?
这个问题之所以不容易回答,是因为它包含了这组业务容器的逻辑单元,没有统一的方法来代表整个容器组的状态。Kubernetes引入pod的概念,并且每个pod里都有一个Kubernetes系统自带的pause容器的原因,通过引入pause这与业务无关,功能相似Linux操作系统保护过程Kubernetes以系统标准容器为准pause容器的状态代表整个容器组的状态。
- 第三个原因:pod所有业务容器共享pause容器的IP地址,以及pause容器mount的Volume,通过这种设计,业务容器可以直接通信,文件可以直接共享。
Pod资源清单
下面是Pod资源清单:
apiVersion: v1 #必选,版本号,比如v1 kind: Pod #必选,资源类型,如 Pod metadata: #必选,元数据 name: string #必选,Pod名称 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: int #容器需要监听的端口号 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
#小提示:
# 在这里,可通过一个命令来查看每种资源的可配置项
# kubectl explain 资源类型 查看某种资源可以配置的一级属性
# kubectl explain 资源类型.属性 查看属性的子属性
[root@k8s-master01 ~]# kubectl explain pod
KIND: Pod
VERSION: v1
FIELDS:
apiVersion <string>
kind <string>
metadata <Object>
spec <Object>
status <Object>
[root@k8s-master01 ~]# kubectl explain pod.metadata
KIND: Pod
VERSION: v1
RESOURCE: metadata <Object>
FIELDS:
annotations <map[string]string>
clusterName <string>
creationTimestamp <string>
deletionGracePeriodSeconds <integer>
deletionTimestamp <string>
finalizers <[]string>
generateName <string>
generation <integer>
labels <map[string]string>
managedFields <[]Object>
name <string>
namespace <string>
ownerReferences <[]Object>
resourceVersion <string>
selfLink <string>
uid <string>
在kubernetes中基本所有资源的一级属性都是一样的,主要包含5部分:
apiVersion <string>
版本,由kubernetes内部定义,版本号必须可以用 kubectl api-versions 查询到kind <string>
类型,由kubernetes内部定义,版本号必须可以用 kubectl api-resources 查询到metadata <Object>
元数据,主要是资源标识和说明,常用的有name、namespace、labels等spec <Object>
描述,这是配置中最重要的一部分,里面是对各种资源配置的详细描述status <Object>
状态信息,里面的内容不需要定义,由kubernetes自动生成
在上面的属性中,spec是接下来研究的重点,继续看下它的常见子属性:
containers <[]Object>
容器列表,用于定义容器的详细信息nodeName <String>
根据nodeName的值将pod调度到指定的Node节点上nodeSelector <map[]>
根据NodeSelector中定义的信息选择将该Pod调度到包含这些label的Node 上hostNetwork <boolean>
是否使用主机网络模式,默认为false,如果设置为true,表示使用宿主机网络volumes <[]Object>
存储卷,用于定义Pod上面挂在的存储信息restartPolicy <string>
重启策略,表示Pod在遇到故障的时候的处理策略
管理pod中的容器
镜像及其获取策略
kubernetes支持用户自定义镜像文件的获取策略,例如在网络资源较为紧张时可以禁止从仓库中获取镜像文件等。容器的imagePullPolicy字段用于为其指定镜像获取策略,它的值可以包括以下几种
- Always:镜像标签为latest或镜像不存在时总是从指定的仓库中获取镜像
- IfNotPresent:仅当本地镜像缺失时方才从目标仓库下载镜像
- Never:禁止从仓库下载镜像,即仅使用本地镜像
默认值说明:
如果镜像tag为具体版本号, 默认策略是:IfNotPresent
如果镜像tag为:latest(最终版本) ,默认策略是always
[root@k8s-master1 ~]# cat pod1.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-example
spec:
containers:
- name: nginx
image: nginx:latest
imagePullPolicy: Always
[root@k8s-master1 ~]# kubectl apply -f pod1.yaml
pod/pod-example configured
暴露端口
Docker的网络模型中,使用默认网络的容器化应用需要通过NAT将其暴露到外部网络中才能被其他节点之上的容器客户端所访问。然而kubernetes系统的网络模型中,各pod的ip地址处于同一网络平面上,无论是否为容器指定了要暴露的端口,都不会影响集群中其他节点之上的pod客户端对其进行访问,这就意味着,任何监听在非lo接口的端口都可以通过pod网络直接被请求
- 指定暴露端口为tcp的80,并将之命名为http
[root@k8s-master1 ~]# cat pod1.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-example
spec:
containers:
- name: nginx
image: nginx:latest
imagePullPolicy: Always
ports:
- name: http
containerPort: 80
protocol: TCP
[root@k8s-master1 ~]# kubectl delete pods pod-example
pod "pod-example" deleted
[root@k8s-master1 ~]# kubectl apply -f pod1.yaml
pod/pod-example created
[root@k8s-master1 ~]# curl 10.244.3.9 -I
HTTP/1.1 200 OK
Server: nginx/1.21.1
Date: Mon, 16 Aug 2021 16:18:22 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 06 Jul 2021 14:59:17 GMT
Connection: keep-alive
ETag: "60e46fc5-264"
Accept-Ranges: bytes
自定义运行的容器化应用
由docker镜像启动容器时运行的应用程序在相应的Dokcerfile中由ENTRYPOINT指令进行定义,传递给程序的参数则通过CMD指令指定,ENTRYPOINT指令不存在时,CMD可用于同时指定程序及其参数。
容器的command字段能够指定不同于镜像默认运行的应用程序,并且可以同时使用args字段进行参数传递,他们将覆盖镜像中的默认定义。
[root@k8s-master1 ~]# cat pod1.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-example
spec:
containers:
- name: nginx
image: nginx:latest
imagePullPolicy: Always
ports:
- name: http
containerPort: 80
protocol: TCP
command: ["/bin/sh"]
args: ["-c","while true;do sleep 30;done"]
[root@k8s-master1 ~]# kubectl delete pods pod-example
pod "pod-example" deleted
[root@k8s-master1 ~]# kubectl apply -f pod1.yaml
pod/pod-example created
[root@k8s-master1 ~]# kubectl get pods pod-example -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-example 1/1 Running 0 33s 10.244.3.10 k8s-node2 <none> <none>
创建pod-command.yaml文件,内容如下:
apiVersion: v1
kind: Pod
metadata:
name: pod-command
namespace: dev
spec:
containers:
- name: nginx
image: nginx:1.17.1
- name: busybox
image: busybox:1.30
command: ["/bin/sh","-c","touch /tmp/hello.txt;while true;do /bin/echo $(date +%T) >> /tmp/hello.txt; sleep 3; done;"]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-q2TICaPq-1651206830823)(04.kubernetes pod资源/image-20210617224457945.png)]
command,用于在pod中的容器初始化完毕之后运行一个命令。
稍微解释下上面命令的意思:
“/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秒向文件中写入当前时间
# 创建Pod
[root@k8s-master01 pod]# kubectl create -f pod-command.yaml
pod/pod-command created
# 查看Pod状态
# 此时发现两个pod都正常运行了
[root@k8s-master01 pod]# kubectl get pods pod-command -n dev
NAME READY STATUS RESTARTS AGE
pod-command 2/2 Runing 0 2s
# 进入pod中的busybox容器,查看文件内容
# 补充一个命令: kubectl exec pod名称 -n 命名空间 -it -c 容器名称 /bin/sh 在容器内部执行命令
# 使用这个命令就可以进入某个容器的内部,然后进行相关操作了
# 比如,可以查看txt文件的内容
[root@k8s-master01 pod]# kubectl exec pod-command -n dev -it -c busybox /bin/sh
/ # tail -f /tmp/hello.txt
14:44:19
14:44:22
14:44:25
特别说明:
通过上面发现command已经可以完成启动命令和传递参数的功能,为什么这里还要提供一个args选项,用于传递参数呢?这其实跟docker有点关系,kubernetes中的command、args两项其实是实现覆盖Dockerfile中ENTRYPOINT的功能。
1 如果command和args均没有写,那么用Dockerfile的配置。
2 如果command写了,但args没有写,那么Dockerfile默认的配置会被忽略,执行输入的command
3 如果command没写,但args写了,那么Dockerfile中配置的ENTRYPOINT的命令会被执行,使用当前args的参数
4 如果command和args都写了,那么Dockerfile的配置被忽略,执行command并追加上args参数
pod资源限制
在kubernetes上,可由容器或Pod请求或消费的计算资源指的是cpu和内存。cpu属于可压缩型资源,即资源额度可按需收缩,而内存则是不可压缩型资源,对其执行收缩操作可能会导致某种程度的问题。
资源隔离属于容器级别,cpu和内存资源的配置需要在Pod中的容器上进行,每种资源均可由requests属性定义其请求的确保可用值,即容器运行可能用不到这些额度的资源,但用到时必须确保由如此多的资源可用,而limits属性则用于限制资源的可用的最大值。
Pod和Container的资源请求和限制: • spec.containers[].resources.limits.cpu • spec.containers[].resources.limits.memory • spec.containers[].resources.requests.cpu • spec.containers[].resources.requests.memory
- 定义资源请求和限制
[root@k8s-master1 ~]# cat pod-stress-ng.yaml
apiVersion: v1
kind: Pod
metadata:
name: frontend
spec:
containers:
- name: db
image: mysql
env:
- name: MYSQL_ROOT_PASSWORD
value: "password"
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
- name: wp
image: wordpress
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
[root@k8s-master1 ~]# kubectl apply -f pod-stress-ng.yaml
pod/frontend created
- 查看pod描述
[root@k8s-master1 ~]# kubectl describe pod frontend
Name: frontend
Namespace: default
Priority: 0
Node: k8s-node1/192.168.80.101
Start Time: Wed, 18 Aug 2021 01:18:11 +0800
Labels: <none>
Annotations: <none>
Status: Pending
IP:
IPs: <none>
Containers:
db:
Container ID:
Image: mysql
Image ID:
Port: <none>
Host Port: <none>
State: Waiting
Reason: ContainerCreating
Ready: False
Restart Count: 0
Limits:
cpu: 500m
memory: 128Mi
Requests:
cpu: 250m
memory: 64Mi
Environment:
MYSQL_ROOT_PASSWORD: password
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-9dwb4 (ro)
wp:
Container ID:
Image: wordpress
Image ID:
Port: <none>
Host Port: <none>
State: Waiting
Reason: ContainerCreating
Ready: False
Restart Count: 0
Limits:
cpu: 500m
memory: 128Mi
Requests:
cpu: 250m
memory: 64Mi
Environment: <none>
Mounts:
/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-9dwb4 (ro)
注:limits是对资源的总限制、requests是最低分配的资源。requests一般要比limits要小一些。
注:250m/单核CPU的白分之25 /0.25
注:资源限制 cpu可以直接设置为数字 “1”为1核“2”为2核。
环境变量
通过环境变量配置容器化应用时,需要在容器配置段中嵌套使用env字段
创建pod-env.yaml文件,内容如下:
apiVersion: v1
kind: Pod
metadata:
name: pod-env
namespace: dev
spec:
containers:
- name: busybox
image: busybox:1.30
command: ["/bin/sh","-c","while true;do /bin/echo $(date +%T);sleep 60; done;"]
env: # 设置环境变量列表
- name: "username"
value: "admin"
- name: "password"
value: "123456"
env,环境变量,用于在pod中的容器设置环境变量。
# 创建Pod
[root@k8s-master01 ~]# kubectl create -f pod-env.yaml
pod/pod-env created
# 进入容器,输出环境变量
[root@k8s-master01 ~]# kubectl exec pod-env -n dev -c busybox -it /bin/sh
/ # echo $username
admin
/ # echo $password
123456
这种方式,推荐将这些配置单独存储在配置文件中,这种方式将在后面介绍。
apiVersion: v1
kind: Pod
metadata:
name: pod-example
spec:
containers:
- name: nginx
image: nginx:latest
imagePullPolicy: Always
ports:
- name: http
containerPort: 80
protocol: TCP
command: ["/bin/sh"]
args: ["-c","while true;do sleep 30;done"]
env:
- name: REDIS_HOST
value: 地址:6379
- name: LOG_LEVEL
value: info
共享节点的网络名称空间
同一个pod对象的各容器均运行于一个独立的、隔离的Network名称空间中,共享同一个网络协议栈及相关的网络设备。也有一些特殊的pod对象需要运行于所在节点的名称空间中,执行系统级的管理任务,例如查看和操作节点的网络资源甚至是网络设备等。
apiVersion: v1
kind: Pod
metadata:
name: pod-example
spec:
containers:
......
hostNetwork: True
pod的安全上下文
参考博客:https://blog.csdn.net/qq_34556414/article/details/118529692
标签与标签选择器
管理资源标签
标签是kubernetes极具特色的功能之一,它能够附加于kubernetes的任何资源对象之上。简单来说,标签就是键值类型的数据,他们可用于资源创建时直接指定,也可随时按需添加于活动对象中。
创建资源时,可以直接在其metadata中嵌套使用labels字段以定义要附加的标签项。
[root@k8s-master1 ~]# cat pod1.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-example
labels:
env: qa
tier: frontend
spec:
containers:
- name: nginx
image: nginx:latest
imagePullPolicy: Always
ports:
- name: http
containerPort: 80
protocol: TCP
command: ["/bin/sh"]
args: ["-c","while true;do sleep 30;done"]
[root@k8s-master1 ~]# kubectl apply -f pod1.yaml
pod/pod-example configured
[root@k8s-master1 ~]# kubectl get pods pod-example --show-labels
NAME READY STATUS RESTARTS AGE LABELS
pod-example 1/1 Running 1 (21h ago) 21h env=qa,tier=frontend
- 指定显示特定标签
[root@k8s-master1 ~]# kubectl get pods pod-example -L env,tier
NAME READY STATUS RESTARTS AGE ENV TIER
pod-example 1/1 Running 1 (21h ago) 22h qa frontend
- 管理活动对象的标签
[root@k8s-master1 ~]# kubectl label pods/pod-example env2=production
pod/pod-example labeled
[root@k8s-master1 ~]# kubectl get pods pod-example -L env,tier,env2
NAME READY STATUS RESTARTS AGE ENV TIER ENV2
pod-example 1/1 Running 1 (21h ago) 22h qa frontend production
- 覆盖已经存在的标签
[root@k8s-master1 ~]# kubectl label pods/pod-example env=qa
error: 'env' already has a value (qa), and --overwrite is false
[root@k8s-master1 ~]# kubectl label pods/pod-example env=qq --overwrite
pod/pod-example labeled
[root@k8s-master1 ~]# kubectl get pods pod-example -L env,tier,env2
NAME READY STATUS RESTARTS AGE ENV TIER ENV2
pod-example 1/1 Running 1 (21h ago) 22h qq frontend production
标签选择器
标签选择器用于表达标签的查询条件或选择标准,kubernetes api支持两个选择器,基于等值关系以及基于集合关系的标签选择器
- 选择出env不等于qq的pod
[root@k8s-master1 ~]# kubectl get pods -l "env!=qq" --show-labels
NAME READY STATUS RESTARTS AGE LABELS
nginx-6799fc88d8-46gmb 1/1 Running 4 (22h ago) 9d app=nginx,pod-template-hash=6799fc88d8
nginx-6799fc88d8-kn2dq 1/1 Running 4 (22h ago) 9d app=nginx,pod-template-hash=6799fc88d8
nginx-6799fc88d8-qthk8 1/1 Running 4 (22h ago) 9d app=nginx,pod-template-hash=6799fc88d8
- 多个标签选择器
[root@k8s-master1 ~]# kubectl get pods -l "env=qq,tier=frontend" --show-labels
NAME READY STATUS RESTARTS AGE LABELS
pod-example 1/1 Running 1 (22h ago) 22h env2=production,env=qq,tier=frontend
- 显示值为production或dev中的一个的所有pod
[root@k8s-master1 ~]# kubectl get pods -l "env in (qq,qa)" --show-labels
NAME READY STATUS RESTARTS AGE LABELS
pod-example 1/1 Running 1 (22h ago) 22h env2=production,env=qq,tier=frontend
- 显示所有存在env标签的pod
[root@k8s-master1 ~]# kubectl get pods -l "env " --show-labels
NAME READY STATUS RESTARTS AGE LABELS
pod-example 1/1 Running 1 (22h ago) 22h env2=production,env=qq,tier=frontend
- 显示所有不存在env标签,但有app的标签的pod
[root@k8s-master1 ~]# kubectl get pods -l '!env,app' --show-labels
NAME READY STATUS RESTARTS AGE LABELS
nginx-6799fc88d8-46gmb 1/1 Running 4 (22h ago) 9d app=nginx,pod-template-hash=6799fc88d8
nginx-6799fc88d8-kn2dq 1/1 Running 4 (22h ago) 9d app=nginx,pod-template-hash=6799fc88d8
nginx-6799fc88d8-qthk8 1/1 Running 4 (22h ago) 9d app=nginx,pod-template-hash=6799fc88d8
pod节点选择器
pod节点选择器是标签及标签选择器的一种应用,它能够让pod对象基于集群中工作节点的标签来挑选倾向运行的目标节点。
- 给node对象添加标签
[root@k8s-master1 ~]# kubectl get nodes --show-labels
NAME STATUS ROLES AGE VERSION LABELS
k8s-master1 Ready control-plane,master 9d v1.22.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-master1,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node-role.kubernetes.io/master=,node.kubernetes.io/exclude-from-external-load-balancers=
k8s-node1 Ready <none> 9d v1.22.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-node1,kubernetes.io/os=linux
k8s-node2 Ready <none> 9d v1.22.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-node2,kubernetes.io/os=linux
[root@k8s-master1 ~]# kubectl label nodes k8s-node1 disktype=ssd
node/k8s-node1 labeled
[root@k8s-master1 ~]# kubectl get nodes --show-labels
NAME STATUS ROLES AGE VERSION LABELS
k8s-master1 Ready control-plane,master 9d v1.22.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-master1,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node-role.kubernetes.io/master=,node.kubernetes.io/exclude-from-external-load-balancers=
k8s-node1 Ready <none> 9d v1.22.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,disktype=ssd,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-node1,kubernetes.io/os=linux
k8s-node2 Ready <none> 9d v1.22.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-node2,kubernetes.io/os=linux
- 指定pod资源调度至这些具有ssd设备的节点上,只需要为其使用spec.nodeSelector标签选择器即可
[root@k8s-master1 ~]# cat pod1.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-example
labels:
env: qa
tier: frontend
spec:
containers:
- name: nginx
image: nginx:latest
imagePullPolicy: Always
ports:
- name: http
containerPort: 80
protocol: TCP
command: ["/bin/sh"]
args: ["-c","while true;do sleep 30;done"]
nodeSelector:
disktype: ssd
[root@k8s-master1 ~]# kubectl delete pod pod-example
pod "pod-example" deleted
[root@k8s-master1 ~]# kubectl apply -f pod1.yaml
pod/pod-example created
[root@k8s-master1 ~]# kubectl get pods pod-example -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-example 1/1 Running 0 33s 10.244.1.12 k8s-node1 <none> <none>
pod对象的生命周期
我们一般将pod对象从创建至终的这段时间范围称为pod的生命周期,它主要包含下面的过程:
- pod创建过程
- 运行初始化容器(init container)过程
- 运行主容器(main container)
- 容器启动后钩子(post start)、容器终止前钩子(pre stop)
- 容器的存活性探测(liveness probe)、就绪性探测(readiness probe)
- pod终止过程
pod的相位
在整个生命周期中,Pod会出现5种(),分别如下:
- 挂起(Pending):apiserver已经创建了pod资源对象,但它尚的过程中
- 运行中(Running):pod已经被调度至某节点,并且所有容器都已经被kubelet创建完成
- 成功(Succeeded):pod中的所有容器都已经成功终止并且不会被重启
- 失败(Failed):所有容器都已经终止,但至少有一个容器终止失败,即容器返回了非0值的退出状态
- 未知(Unknown):apiserver无法正常获取到pod对象的状态信息,通常由网络通信失败所导致
pod的创建过程
- 用户通过kubectl或其他api客户端提交pod spec给api server
- api server尝试着将pod对象的相关信息存入etcd中,待写入操作执行完成,api server即会返回确认信息至客户端
- api server开始反应etcd中的状态变化
- 所有的kubernetes组件均使用watch机制来跟踪检查api server上的相关的变动
- kube-scheduler(调度器)通过其watcher觉察到api server创建了新的pod对象但尚未绑定至任何工作节点
- kube-scheduler为pod对象挑选一个工作节点并将结果信息更新至api server
- 调度结果信息由api server更新至etcd存储系统中,而却api server也开始反映此pod对象的调度结果
- pod被调度到的目标工作节点上的kubelet尝试在当前节点上调用docker启动容器,并将容器的结果状态回送至api server
- api server将pod状态信息存入etcd中
- 在etcd确认写入操作成功完成之后,api server将确认信息发送至相关的kubelet事件将通过它被接收
pod的终止过程
- 用户发送删除pod对象的命令
- api服务器中的pod对象会随着事件的推移而更新,在宽限期内(默认为30秒),pod被视为“dead”
- 将pod标记为terminating状态
- (与第三步同时运行)kubelet在监控到pod对象转为“Terminating”状态的同时启动Pod关闭过程
- (与第三步同时运行)端点控制器监控到pod对象的关闭行为时将其从所有匹配到此端点的service资源的端点列表中移除
- 如果当前Pod对象定义了preStop钩子处理器,则在其标记为“terminating”后即会以同步的方式启动执行;如若宽限期结束后,preStop仍未执行结束,则第2步会被重新执行并额外获取一个时长为2秒的小宽限期。
- Pod对象中的容器进程收到TERM信号。
- 宽限期结束后,若存在任何一个仍在运行的进程,那么Pod对象即会收到SIGKILL信号
- Kubelet请求API Server将此Pod资源的宽限期设置为0从而完成删除操作,它变得对用户不再可见。
钩子函数
钩子函数能够感知自身生命周期中的事件,并在相应的时刻到来时运行用户指定的程序代码。
kubernetes在主容器的启动之后和停止之前提供了两个钩子函数:
- post start:容器创建之后执行,如果失败了会重启容器
- pre stop :容器终止之前执行,执行完成之后容器将成功终止,在其完成之前会阻塞删除容器的操作
钩子处理器支持使用下面三种方式定义动作:
-
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.5.3 #主机地址 scheme: HTTP #支持的协议,http或者https ……
接下来,以exec方式为例,演示下钩子函数的使用,创建pod-hook-exec.yaml文件,内容如下:
apiVersion: v1
kind: Pod
metadata:
name: pod-hook-exec
namespace: dev
spec:
containers:
- name: main-container
image: nginx:1.17.1