结构
一个pod中可以有多个容器,容器分为根容器和用户容器,每个pod都有一个根容器,可以有多个用户容器
pause根容器主要有两个作用
- 可以以它为依据,评估整个pod的健康状态。
- 可以在根容器上设置ip地址,其它容器都是这个ip,以实现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 [pod,svc,configmap...]
查看配置项下级(配置项为object才可使用)
#例如
kubectl explain pod.metadata
一级属性
- apiVersion 版本,由k8s内部定义,版本号必须可以用kubectl api-versions可以查询到的
- kind 类型,由k8s内部定义,类型必须可以用kubectl api-resources查询到
- metadata 元数据,主要包括资源的标识和说明,name,namespace,labels等
- spec 描述,这是配置中最重要的一部分,里面是对各种资源的详细描述
status 状态信息,里面的内容不需要定义,由k8s自己生成
二级属性
containers
容器列表,定义容器详细信息。 - nodeName 根据nodeName的值pod调度到指定的node节点上。
- nodeSelector
- hostNetwork 是否使用宿主机网络,默认false。
- volumes
- restartPolicy 重启策略,pod遇到故障时的启动策略
Pod配置
基本配置
脚本pod-base.yml如下apiVersion: v1 kind: Pod metadata: name: pod-base namespace: dev labels: user: heima spec: containers: - name: nginx image: nginx:1.21.1 - name: busybox image: busybox:1.30
上面在一个pod中配置了两个容器,分别是nginx:1.21.1和busybox:1.30
创建pod
查看pod状态 ```bash kubectl get po -n devkubectl apply -f pod-base.yaml
NAME READY STATUS RESTARTS AGE pod-base 1/2 Running 4 95s
可以看到pod-base有两个容器,但是值启动了一个。可以通过describe查看信息,可以看到运行起来一个pod
,但是它暂时是有问题的。
<a name="mrq9a"></a>
## 镜像拉取
创建pod-imagepullpolicy.yaml文件,内容如下:
```yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-imagepullpolicy
namespace: dev
spec:
containers:
- name: nginx
image: nginx:1.21.1
imagePullPolicy: Never # 用于设置镜像拉取策略
- name: busybox
image: busybox:1.30
运行脚本后查看pod情况
imagePullPolicy是用于设置镜像拉取策略,k8s支持三种镜像拉取策略。
- Always :总是从远程拉取镜像
- IfNotPresent: 先在本地找,本地没有去远程拉取
- Never: 只在本地找b
默认值说明
- 如果镜像版本是laster,默认策略为Always
如果镜像版本是具体版本号,默认策略为IfNotPresent
启动命令
在前面启动的脚本中,busybox一直没有运行,是应为busybox并不是一个程序,而是类似一个工具类的集合。k8s启动后,它执行完会自动关闭。解决办法就是让它一直运行,这就用到command配置。
创建pod-command.yaml文件,内容如下。apiVersion: v1 kind: Pod metadata: name: pod-command namespace: dev spec: containers: - name: nginx image: nginx:1.21.5 - 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;"]
“/bin/sh”,”-c”, 使用sh执行命令
进入容器命令kubectl exec -it pod-command -c busybox -n dev /bin/sh #如果pod中只有一个容器,就不需要-c [container]
k8s 中的command args对标DockerFile中的ENTRYPOINT,他们互补互斥,k8s优先级更高。
环境变量
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"
就是外面定义的变量是一个key/value值,定义了之后可以在容器内使用。
这种方式不推荐,建议存储在配置文件中。端口设置
看一下端口子选项
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”。
资源配置
程序在运行过程中是需要占用一定资源的,比如cpu和内存,如果不对其做控制,可能会导致它吃掉大量资源而得不到限制,k8s针对这种情况可以对pod的cpu和内存占用做限制。主要使用两个参数。
limits:用于限制运行时容器的最大占用资源。占用超过limit,会被强制重启。
- requests:用于设置容器最小启动资源,当不满足时pod会呈现pedding状态
测试脚本
apiVersion: v1
kind: Pod
metadata:
name: pod-resources
namespace: dev
spec:
containers:
- name: nginx
image: nginx:1.17.1
resources: # 资源配额
limits: # 限制资源(上限)
cpu: "2" # CPU限制,单位是core数
memory: "10Gi" # 内存限制
requests: # 请求资源(下限)
cpu: "1" # CPU限制,单位是core数
memory: "10Mi" # 内存限制
- cpu:core数,可以是整数或小数
-
Pod生命周期
一个对象从创建到结束的整个过程被称为pod的生命周期。
运行初始化容器过程(init container)
- 运行主容器(main container)
- 容器启动后狗子(post start),容器终止前钩子(pre stop)
- 容器的存活性探测(liveness probe)、就绪性探测(readiness probe)
- 终止过程
整个运行过程中,pod的五种状态
- 挂起(pengding)apiserver已经创建了pod资源对象,但它尚未被调度或者处于资源下载过程中。
- 运行中(Running)pod已经被调度到某个节点,并且内部所有容器已经被创建完成。
- 成功(Successed)pod中的所有容器已经被创建成功并且不会被重启。
- 失败(Faild)所有容器已终止。但至少有一个容器失败。
- 未知(Unknow)
创建和终止
pod的创建过程
- 用户通过kubectl或者api客户端提交需要创建的pod信息给apiserver。
- apiServer开始生成对象pod信息,并将信息存入etcd。
- apiServer开始反应etcd中的pod对象的变化,其他组件使用watch机制来跟踪检查apiServer上的边动。
- scheduler发现有新的pod要创建,开始为pod分配主机并将结果信息更新至apiServer。
- node节点上的kubelet发现有pod调度过来,尝试调用docker启动容器,并将结果返回给apiServer。
- apiServer将接收到的pod状态信息存入etcd。
pod终止过程
- 用户向apiServer发送删除pod对象的命令
- apiServer中的pod对象信息会随时间推移而更新,宽限期内(默认30s),pod会被视为dead。
- 将pod标记为terminating状态。
- kubectl在监控到pod对象转为terminating,状态的同时启动pod关闭过程。
- 端点控制器监控到pod对象的关闭行为时将其从所有匹配到此端点的service资源的端点列表中移除。
- 如果当前pod对象定义了preStop钩子,则在其标记为terminating后即会以同步的方式启动执行。
- pod对象中的容器进程收到停止信号。
- 宽限期结束后,pod中还存在仍在运行的进程,那么pod会立即收到结束终止的信号。
kubelet请求apiServer将此pod资源的宽限期设置为0从而完成删除操作,此时pod对于用户已不可见。
初始化容器
初始化容器是在pod的主容器启动之前运行的容器,主要是做一些主容器的前置工作,它具备两个特征:
初始化容器必须运行完成直至结束,若某初始化容器运行失败,k8s会重启它直到成功完成。
- 初始化容器必须按照定义的顺序执行,只有当前一个成功后,后面的才会运行。
初始化容器有很多应用场景
- 提供主镜像中不具备的工具程序或自定义代码。
- 初始化容器要先于应用容器串行启动并允许完成,因此可以延后应用容器的启动直至依赖条件满足。
脚本示例:
apiVersion: v1
kind: Pod
metadata:
name: pod-initcontainer
namespace: dev
spec:
containers:
- name: main-container
image: nginx:1.17.1
ports:
- name: nginx-port
containerPort: 80
initContainers:
- name: test-mysql
image: busybox:1.30
command: ['sh', '-c', 'until ping 192.168.90.14 -c 1 ; do echo waiting for mysql...; sleep 2; done;']
- name: test-redis
image: busybox:1.30
command: ['sh', '-c', 'until ping 192.168.90.15 -c 1 ; do echo waiting for reids...; sleep 2; done;']
钩子函数
kubernetes在主容器启动之后和终止之前提供两个钩子函数
- post start:容器创建之后执行,如果失败了会重启容器。
- pre start:容器终止之前,执行完成后容器将成功终止,在其完成之前会阻塞删除容器操作。
钩子处理器支持三种方式的定义动作。
Exec命令:在容器内执行一次命令
…… lifecycle: postStart: exec: command: - cat - /tmp/healthy ……
TCPSocket:在当前容器尝试访问socket
…… lifecycle: postStart: tcpSocket: port: 8080 ……
HTTPGet:在当前容器中向某url发起请求
…… lifecycle: postStart: httpGet: path: / #URI地址 port: 80 #端口号 host: 192.168.5.3 #主机地址 scheme: HTTP #支持的协议,http或者https ……
exec方式演示脚本
apiVersion: v1 kind: Pod metadata: name: pod-hook-exec namespace: dev spec: containers: - name: main-container 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"]
容器探测
用于检查容器是否工作,保障可用性,kubernetes提供两种探针来实现容器探测,分别是:
- livenes probes:存活性探针,用于检测当前实例是否是正常运行状态,如果不是,会重启。
- readiness probes:就绪性探针,用于检测实例当前是否可以接受请求,不能则会转发流量。
三种探测方式
Exec命令:在容器内执行一次命令,如果执行退出码为0,则认为程序正常,否则为不正常。
…… livenessProbe: exec: command: - cat - /tmp/healthy ……
TCPSocket:访问容器内端口,如果能够建立连接,则程序正常,否则不正常。
…… livenessProbe: tcpSocket: port: 8080 ……
HTTPGet:调用容器内web应用的URL,返回状态码在200~400则正常,否则不正常
…… livenessProbe: httpGet: path: / #URI地址 port: 80 #端口号 host: 127.0.0.1 #主机地址 scheme: HTTP #支持的协议,http或者https ……
演示脚本:Exec
apiVersion: v1 kind: Pod metadata: name: pod-liveness-exec namespace: dev spec: containers: - name: nginx image: nginx:1.17.1 ports: - name: nginx-port containerPort: 80 livenessProbe: exec: command: ["/bin/cat","/tmp/hello.txt"] # 执行一个查看文件的命令
CPSocket
apiVersion: v1 kind: Pod metadata: name: pod-liveness-tcpsocket namespace: dev spec: containers: - name: nginx image: nginx:1.17.1 ports: - name: nginx-port containerPort: 80 livenessProbe: tcpSocket: port: 8080 # 尝试访问8080端口
HTTPGet
apiVersion: v1 kind: Pod metadata: name: pod-liveness-httpget namespace: dev spec: containers: - name: nginx image: nginx:1.17.1 ports: - name: nginx-port containerPort: 80 livenessProbe: httpGet: # 其实就是访问http://127.0.0.1:80/hello scheme: HTTP #支持的协议,http或者https port: 80 #端口号 path: /hello #URI地址
重启策略
容器探测出现问题或者容器本身出现问题,kubernetes会对容器进行重启,这是由pod的重启策略决定的。
- Always:容器失效时,自动重启。
- OnFailure:容器终止且退出码不为0是重启。
- Never:不重启
第一次失败会立即重启,之后会梯形延迟重启时长10s,20s,40s,80s,160s,300s,300是最大值。
演示脚本
apiVersion: v1
kind: Pod
metadata:
name: pod-restartpolicy
namespace: dev
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- name: nginx-port
containerPort: 80
livenessProbe:
httpGet:
scheme: HTTP
port: 80
path: /hello
restartPolicy: Never # 设置重启策略为Never
Pod调度
在默认情况下,一个pod在哪个节点上运行,是由scheduler组件根据相应算法计算出来的。
kubernetes对pod调度规则,四种调度方式。
- 自动调度:运行在哪个节点上完全由schedule决定。
- 定向调度:NodeName、NodeSelector
- 亲和性调度:NodeAffinity、PodAffinity、PodAntiAffinity
-
定向调度
指在Pod上声明NodeName或者NodeSelector,以此调度到希望的节点上。这是强制调度,如果节点不存在则会进入Pending状态。
NodeName
强制约束pod调度到指定name的node上。
脚本示例apiVersion: v1 kind: Pod metadata: name: pod-nodename namespace: dev spec: containers: - name: nginx image: nginx:1.21.1 nodeName: node1 # 指定调度到node1节点上
NodeSelector
强制约束,根据Node的Label调度到符合条件的Node节点上。
脚本示例apiVersion: v1 kind: Pod metadata: name: pod-nodeselector namespace: dev spec: containers: - name: nginx image: nginx:1.21.1 nodeSelector: nodeenv: pro # 指定调度到具有nodeenv=pro标签的节点上
亲和性调度
优先调度到符合条件的节点上。
Affinity分为三类 NodeAffinity:以node节点为目标,决定可以调度到那些节点上。
- PodAffinity:以Pod节点为目标,决定可以调度到那些已存在指定Pod的拓扑域中。
- PodNoAffinity:以Pod节点为目标,决定不调度到那些已存在指定Pod的拓扑域中。
注意:关于亲和度使用场景示例
- 亲和性:如果两个节点调用频繁,可以让两个pod相互靠的更近,这样可以减少因网络问题带来的性能损耗。
反亲和性:当应用采用多副本部署时,有必要让各个示例打到不同的node上。提升可用性。
NodeAffinity配置项
pod.spec.affinity.nodeAffinity requiredDuringSchedulingIgnoredDuringExecution Node节点必须满足指定的所有规则才可以,相当于硬限制 nodeSelectorTerms 节点选择列表 matchFields 按节点字段列出的节点选择器要求列表 matchExpressions 按节点标签列出的节点选择器要求列表(推荐) key 键 values 值 operat or 关系符 支持Exists, DoesNotExist, In, NotIn, Gt, Lt, Equls preferredDuringSchedulingIgnoredDuringExecution 优先调度到满足指定的规则的Node,相当于软限制 (倾向) preference 一个节点选择器项,与相应的权重相关联 matchFields 按节点字段列出的节点选择器要求列表 matchExpressions 按节点标签列出的节点选择器要求列表(推荐) key 键 values 值 operator 关系符 支持In, NotIn, Exists, DoesNotExist, Gt, Lt, Equls weight 倾向权重,在范围1-100。
关系符使用说明 ```yaml 关系符的使用说明:
matchExpressions:
- key: nodeenv # 匹配存在标签的key为nodeenv的节点 operator: Exists
- key: nodeenv # 匹配标签的key为nodeenv,且value是”xxx”或”yyy”的节点 operator: In values: [“xxx”,”yyy”]
- key: nodeenv # 匹配标签的key为nodeenv,且value大于”xxx”的节点
operator: Gt
values: “xxx”
演示脚本requiredDuringSchedulingIgnoredDuringExecution,强约束
yaml apiVersion: v1 kind: Pod metadata: name: pod-nodeaffinity-required namespace: dev spec: containers: - name: nginx
image: nginx:1.21.1
affinity: #亲和性设置
nodeAffinity: #设置node亲和性
requiredDuringSchedulingIgnoredDuringExecution: # 硬限制
nodeSelectorTerms: - matchExpressions: # 匹配env的值在["xxx","yyy"]中的标签 - key: nodeenv operator: In values: ["xxx","yyy"]
演示脚本requiredDuringSchedulingIgnoredDuringExecution,软约束
yaml apiVersion: v1 kind: Pod metadata: name: pod-nodeaffinity-preferred namespace: dev spec: containers: - name: nginx
image: nginx:1.17.1
affinity: #亲和性设置
nodeAffinity: #设置node亲和性
preferredDuringSchedulingIgnoredDuringExecution: # 软限制
- weight: 1
preference:
matchExpressions: # 匹配env的值在[“xxx”,”yyy”]中的标签(当前环境没有)
- key: nodeenv
operator: In
values: [“xxx”,”yyy”]
1.如果同时定义了NodeSelector和NodeAffinity,那么必须同时满足两个条件。 2.如果NodeAffinity指定了多个NodeSelectorTerms,那么只需要一个匹配成功即可。 3.如果一个NodeSelectorTerms中有多个matchExpressions,那么只需要一个匹配成功即可。 4.如果一个pod在运行期间,node标签被修改不在满足亲和度,系统会忽略该次变化。注意事项:
<a name="xxyta"></a> #### PodAffinity 配置项 ```yaml pod.spec.affinity.podAffinity requiredDuringSchedulingIgnoredDuringExecution 硬限制 namespaces 指定参照pod的namespace topologyKey 指定调度作用域 labelSelector 标签选择器 matchExpressions 按节点标签列出的节点选择器要求列表(推荐) key 键 values 值 operator 关系符 支持In, NotIn, Exists, DoesNotExist. matchLabels 指多个matchExpressions映射的内容 preferredDuringSchedulingIgnoredDuringExecution 软限制 podAffinityTerm 选项 namespaces topologyKey labelSelector matchExpressions key 键 values 值 operator matchLabels weight 倾向权重,在范围1-100
脚本示例requiredDuringSchedulingIgnoredDuringExecution ```yaml apiVersion: v1 kind: Pod metadata: name: pod-podaffinity-required namespace: dev spec: containers:topologyKey用于指定调度时作用域,例如: 如果指定为kubernetes.io/hostname,那就是以Node节点为区分范围 如果指定为beta.kubernetes.io/os,则以Node节点的操作系统类型来区分
- key: nodeenv
operator: In
values: [“xxx”,”yyy”]
- weight: 1
preference:
matchExpressions: # 匹配env的值在[“xxx”,”yyy”]中的标签(当前环境没有)
- name: nginx
image: nginx:1.17.1
affinity: #亲和性设置
podAffinity: #设置pod亲和性
requiredDuringSchedulingIgnoredDuringExecution: # 硬限制
- labelSelector: matchExpressions: # 匹配env的值在[“xxx”,”yyy”]中的标签
- name: nginx image: nginx:1.17.1 affinity: #亲和性设置 podAntiAffinity: #设置pod亲和性 requiredDuringSchedulingIgnoredDuringExecution: # 硬限制
PerferNoSchedule:kubernetes将尽量避免调度pod在该节点上,除非实在没办法。
- NoSchedule:kubernetes不会将Pod调度到该节点上,已存在的节点可以继续保留。
- NoExecute:kubernetes不会将Pod调度到该节点,并该节点上的pod会去驱离。
命令详解:
#新增污点
kubectl taint nodes [nodename] key=value:effect
#删除污点
kubectl taint nodes [nodename] key:effect-
#去除所有污点
kubectl taint nodes [nodename] key-
容忍(Toleration)
污点节点拒绝pod调度到自己,容忍表示忽略拒绝。
脚本演示:
apiVersion: v1
kind: Pod
metadata:
name: pod-toleration
namespace: dev
spec:
containers:
- name: nginx
image: nginx:1.17.1
tolerations: # 添加容忍
- key: "tag" # 要容忍的污点的key
operator: "Equal" # 操作符
value: "heima" # 容忍的污点的value
effect: "NoExecute" # 添加容忍的规则,这里必须和标记的污点规则相同