作者:周虚(应金挺)
SREWorks 的开源吸引了大量用户来尝试部署和应用咱们的产品,其中不乏一些首次接触 Kubernetes 的敌人。随着 SREWorks 云原生运维平台应用的继续深刻,局部用户对于其中的原理和概念还存在一些困惑。因而,咱们特推出《Kubernetes 资源编排系列》,从底层的 Pod YAML 开始,逐渐递进地解说相干内容,心愿可能解答大家对于 Kubernetes 的一些疑难,让用户对于云原生相干技术有更深刻的理解。
1.Pod 整体构造
Pod YAML 的整体构造,能够初步分为 Resource(资源)、Object(元数据)、Spec(标准)、Status(状态)。本文将会围绕这四局部一一开展。
- Resource:定义资源类型与版本,作为从 Rest API 中获取资源必带的属性。
- Object:资源的元数据属性,明确资源的根本标识。
- Spec / Status:
- Spec:定义资源的冀望状态,包含用户提供的配置、零碎扩大的默认值,以及周边零碎初始化或者更改值(scheduler、hpa 等)。
- Status:定义资源的以后状态,从而基于 Spec 定义的申明式配置,使 pod 一直朝冀望状态凑近。
2.Resource(资源)-Rest API
k8s 资源依照 Scope 能够分为 Namespace 资源、Cluster 资源,Namespace 在 k8s 能够认为是软租户的成果,实现资源层面的隔离,Pod 资源就是属于 Namespace 资源,而 Namespace 不光体现在 YAML 参数中,也体现在 k8s Rest API 中。
Rest API 的整体构造,以 Pod 举例
apiVersion: v1
kind: Pod
metadata:
name: test-pod
namespace: default
基于上述 YAML,能够明确出 namespace 为 default,name 为 test-pod 的 Pod 资源对象,也就是明确出 Pod 为 Namespace 资源,该 Pod 资源对象对应的 apiVersion 为 v1,后续 k8s 自内联相干的 Group 为 /api,自然而然,咱们就将该对象的数据分离出来了:
- group:api
- apiVersion:v1
- kind:Pod
- name:test-pod
- namespace:default
基于上述的数据展现,apiserver 自然而然会相应的注册出下列 rest api,
- /api/{apiVersion}/{kind}:该 kind 下的所有资源列表
- /api/{apiVersion}/namespace/{namespace}/{kind}/:该 kind 下以后 namespace 的所有资源列表
- /api/{apiVersion}/namespace/{namespace}/{kind}/{name}:该 kind 下以后 namespace 且名为 name 的资源
- /api/{apiVersion}/namespace/{namespace}/{kind}/{name}/{subresource}:该 kind 下以后 namespace 且名为 name 的资源下子资源操作
后续基于扩大,咱们就须要明确出 method,这样一个真正残缺的 Rest API 就诞生了。
3.Object(元数据)
在 rest api 中明确了 Resource 的 kind、apiVersion,也确定了 Object 的 namespace、name,作为但凡 k8s 资源对象都会援用的公共构造,天然也存在很多公共机制供应用。
metadata:
annotations:
alibabacloud.com/owner: testdemo
k8s.aliyun.com/pod-eni: "true"
creationTimestamp: "2022-06-02T07:21:36Z"
deleteTimestamp: "2022-06-02T07:22:51Z"
labels:
app: taihao-app-cn-shanghai-pre-cloud-resource
pod-template-hash: 5bbb759f78
name: testdemo-5bbb759f78-27v88
namespace: default
ownerReferences:
- apiVersion: apps/v1
blockOwnerDeletion: true
controller: true
kind: ReplicaSet
name: testdemo-5bbb759f78
uid: 9c3f268a-c0d1-4038-bb2b-b92928f45e3d
resourceVersion: "60166035"
uid: e4236960-8be2-41bf-ac44-e7460378afbb
察看上述 YAML,咱们将其整顿一下,有这样一些字段:
- namespace:惯例来说,Namespace 资源才会应用该资源对象
- name:代表资源实例名称
- uid:是资源的惟一标识,能够区别已删除与从新创立的同名资源实例
- resourceVersion:是 k8s 的外部版本,具备工夫属性,基于此就能明确该资源对是什么时候产生扭转的,也是保障 k8s list-watch 外围机制
- creationTimestamp: 资源实例创立工夫
- deleteTimestamp: 资源实例删除工夫,后续会在 pod 的生命周期内讲到对该字段利用
- ownerReferences: 资源隶属对象,从下面 yaml 可知,该 Pod 资源从属于名为 testdemo-5bb759f78,ownerReferences 外部是没有 namespace 参数,也就是 ownerReferences 不容许跨 namespace,将资源由下到上可能建设起来
- labels:标签,k8s 内的服务发现以及相应的软关联,都是围绕 label 运作的,比方 testdemo-5bb759f78 replicaset 的 labelselector(标签筛选器)可能筛选到以后 Pod 的 label,保障两者关联由上到下的建设
- annotations: 正文,通常来说会是作为额定字段供给给周边零碎应用,比方以后 k8s.aliyun.com/pod-eni=”true” 是提供网络系统应用
label & labelSelector
Deployment 会依据本人的 labelseletor:app=taihao-app-cluster 以及计算出 podtemplate 的 hash lable:pod-template-hash: 5b8b879786 , 筛选出出合乎的 replicaset,replicaset 再依据本人的 labelselector 去筛选出合乎的 pods,相应的服务发现 service,也是通过 labelselector 去筛选出合乎的 Pod
Owner & GC(垃圾回收)
基于 Pod 的 metadata.ownerReferences 找寻到对应的 replicaset,replicaset 基于本身的 metadata.ownerReferences 找寻到 deploy;当 deployment 被删除后,基于原有 owner 构建的树状,回收原有的 rs 与 pod。
Deploy & Replicaset
基于 label&labelselector,明确了从上到下的筛选演绎;基于 owner&GC,明确了关联资源的回收流程。
apiVersion: apps/v1
kind: ReplicaSet
metadata:
generation: 1
labels:
app: testdemo
pod-template-hash: bcd889947
name: testdemo-bcd889947
namespace: taihao
ownerReferences:
- apiVersion: apps/v1
blockOwnerDeletion: true
controller: true
kind: Deployment
name: testdemo
uid: 1dddc849-c254-4cf5-aec8-9e1c2b5e65af
spec:
replicas: 1
selector:
matchLabels:
app: testdemo
pod-template-hash: bcd889947
template:
metadata:
creationTimestamp: null
labels:
app: testdemo
pod-template-hash: bcd889947
spec:
containers:
- args:
- -c
- sleep 1000000
command:
- sh
image: centos:7
imagePullPolicy: IfNotPresent
name: testdemo
status:
fullyLabeledReplicas: 1
observedGeneration: 1
replicas: 1
replicaset.spec.replicas: 实例数,rs 管制下的 Pod 个数
replicaset.spec.selector:基于 label 筛选出对应的 Pod
replicaset.spec.template:replicaset 创立的 Pod 会基于 podtemplate
replicaset.status:replicaset 以后治理 Pod 的状态
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: testdemo
name: testdemo
spec:
replicas: 1
revisionHistoryLimit: 10
selector:
matchLabels:
app: testdemo
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 25%
type: RollingUpdate
template:
metadata:
creationTimestamp: null
labels:
app: testdemo
spec:
containers:
- args:
- -c
- sleep 1000000
command:
- sh
image: centos:7
imagePullPolicy: IfNotPresent
name: testdemo
status:
availableReplicas: 1
observedGeneration: 2
readyReplicas: 1
replicas: 2
unavailableReplicas: 1
updatedReplicas: 1
deploy.spec.replicas: deploy 冀望的 pod 实例格局
deploy.spec.revisionHistoryLimit:deploy 治理 replicaset 的保留三个月
deploy.spec.selector:deploy 筛选合乎标签
deploy.spec.strategy:deploy 的降级策略
deploy.template:deploy 基于此模版要创立的 pod 格局
4.Spec(标准)
Spec 作为 Pod 的冀望状态,肯定水平上也笼罩了 Pod 残缺生命周期的逻辑,Pod 的生命周期分为以下阶段
- Pending:代表 Pod 处于未调度阶段
- Creating:节点上的 kubelet 曾经发现了 Pod,处于创立阶段
- Running:至多一个容器运行结束,kubelet 这会发动衰弱监测
- Terminating:Pod 处于删除状态,kubelet 开始回收容器
- Terminated: Pod 销毁实现
Pod 生命周期: Pending
Pod 资源创立结束后,处于还未调度阶段,这个时候 scheduler(调度器)基于 pod yaml 自身的配置与节点资源状态状况,来进行调度。
scheduler 会去剖析 podyaml,将其中的策略提取进去,与节点组中的节点配置进行匹配,若匹配胜利后,会选出最佳节点,从新批改 pod yaml,将 spec.nodeName 更新掉,实现整个调度环节、
资源策略
资源策略表明 Pod 运行须要的资源状况,以 demo 为例,Pod 须要 2 核 4G 的资源,那么调度过来的节点也须要有 2 核 4G 的资源残余,Pod 能力运行在该节点上
节点标签筛选策略
节点标签筛选策略,筛选节点是否存在 topology.kubernetes.io/region: cn-hangzhou
亲和策略
亲和策略,有节点亲和与 Pod 亲和(Pod 所在节点优先调度),惯例来说能够优先满足亲和的节点上,以后例子就是节点亲和,满足标签 disk-type=aaa 或者 disk-type=bbb
污点策略
污点策略,当节点上配置了污点,若 Pod 没有容忍该污点的策略,则 Pod 不容许调度到该节点上
Pod 生命周期: Creating
当 Pod 调度结束后,开始创立阶段,kubelet 会基于 pod.spec 冀望状态来创立出 Pod
kubelet 在创立 Pod 阶段,总共大抵经验以下过程
、
- Group 配置:次要是为了容器配置 cgroup,外面波及了对容器资源限度,比方不容许超过 cpu、memory 配置, 这里波及到 Pod 的 qos 级别断定
- 初始化环境配置:次要是对相干 Pod 数据存储目录进行配置,波及到 volume,则会去援用 CSI 协定,也会去获取镜像 secret,为了后续拉取镜像进行筹备工作
- 创立 pause 容器:创立 pause 容器,该容器次要是为了后续配置容器网络,配置容器网络会去调用 CNI
- 创立 Pod 容器:基于 imagesecret 拉取业务镜像,在创立 Pod 容器阶段,也会将相应的 Pod YAML 配置传输进去,在启动 Pod 容器结束后,会基于 poststart 进行相干的回调
上述阶段,会抉择局部要害概念进行具体阐明
image
spec:
containers:
- image: testdemo:v1
imagePullPolicy: Always
name: test-config
imagePullSecrets:
- name: image-regsecret
imagePullSecrets: 拉取镜像的密钥,保障可能拉取 image:testdemo:v1,尤其在镜像库是公有库的阶段
imagePullPolicy:镜像拉取策略
- Always:总是拉取镜像
- IfNotPresent:本地若有则应用本地镜像,不进行拉取
- Never:只应用本地镜像,不拉取
containers
留神这个 containers 用的是复数,能够填多个容器镜像: 比方能够放 nginx 和 业务容器。这样做的益处是能够尽量减少业务容器中与业务无关的代码或过程。
container 波及很多配置,其中有波及到 volume、env、dnsconfig、host 等根底配置
spec:
containers:
- env:
- name: TZ
value: Asia/Shanghai
image: testdemo:v1
name: taihao-app-cn-shanghai-pre-share
volumeMounts:
- mountPath: /home/admin
name: test-config
readOnly: true
dnsConfig:
nameservers:
- 100.100.1.1
- 100.100.2.1
options:
- name: ndots
value: "3"
- name: timeout
value: "3"
- name: attempts
value: "3"
searches:
- default.svc.cluster.local
- svc.cluster.local
- cluster.local
hostAliases:
- hostnames:
- kubernetes
- kubernetes.default
- kubernetes.default.svc
- kubernetes.default.svc.cluster.local
ip: 1.1.1.1
volumes:
- configMap:
defaultMode: 420
name: test-config
name: test-config
env:配置 Pod 的环境变量
dnsConfig:配置 Pod 的域名解析
hostALiases:配置 /etc/hosts 文件内容
volume/volumeMount: 配置文件挂载到容器内,也能够配置文件存储系统挂载到容器内
postStart
containers:
- image: testdemo:v1
imagePullPolicy: Always
lifecycle:
postStart:
exec:
command:
- /bin/sh
- -c
- sleep 5
以后 poststart demo 是发动 command 命令,也能够发动 http 申请,次要作用能够作为资源部署以及环境筹备。
Pod 生命周期: Running
在 Pod running 阶段的时候,Pod 就迎来对其衰弱的查看,以后 kubelet 提供三种形式断定
- readiness:查看 Pod 是否为衰弱
- liveness:件看 Pod 是否失常,若查看失败,则重启容器
- readinessGate:提供给第三方组件衰弱验证,第三方组件验证不过,则 Pod 不为衰弱
spec:
readinessGates:
- conditionType: TestPodReady
containers:
- image: testdemo:v1
imagePullPolicy: Always
livenessProbe:
failureThreshold: 3
initialDelaySeconds: 45
periodSeconds: 5
successThreshold: 1
tcpSocket:
port: 8080
timeoutSeconds: 1
readinessProbe:
failureThreshold: 3
httpGet:
path: /actuator/health
port: 8989
scheme: HTTP
initialDelaySeconds: 25
periodSeconds: 3
successThreshold: 1
timeoutSeconds: 1
readiness 与 liveness 查看参数都是统一的
- httpGet / tcpSocket:都是查看形式,一种是 http 申请验证,一种是 tcpSocket,其中也有 exec 执行命令,以及 grpc 模式验证
- initialDelaySeconds:提早多久开始查看,起因在于容器启动的时候,通常须要过段时间进行验证
- periodSeconds:测验工夫周期
- failureThreshold:间断几次失败,则代表这轮测验失败
- successThreshold:间断几次胜利,则代表这轮测验胜利
- timeoutSeconds:代表测验超时工夫,若测验在该配置工夫内没有返回,则认为测验失败
readiness、liveness 尽管参数不一样,但对测验的后果行为不统一。
- readiness 默认状态下为 false,也就是 Pod 为不衰弱,直到查看通过,才将 Pod 变为衰弱
- liveness 默认状态下为 true,不会在刚开始就将 Pod 重启,只有等查看不通过后,才会进行容器重启操作
readinessGate 是 Pod 衰弱的扩大,kubelet 会基于此,默认在 pod.status.conditions 上配置对应的 condition,比方以后例子 readinessGate 为 conditionType: TestPodReady,则相应就会有 conditions
status:
conditions:
- lastProbeTime: null
lastTransitionTime: "2022-07-05T09:16:07Z"
status: "false"
type: TestPodReady
当该 condition.status 为 false 时,则 Pod 就会始终是不衰弱,哪怕 readiness 查看通过,直到第三方零碎去操作更新 Pod 该 condition.status 为 true,才能够将 Pod 变为衰弱,这样就能够接入更多的 Pod 衰弱指标。
Pod 生命周期: Terminating
client 在发动申请删除 Pod 的时候,实际上是配置
pod.metadata.deletionTimestamp,kubelet 感知到后,开始进行 Pod 回收流程
整个 Pod 的回收周期,惯例来说 preStop—>SIGTERM—>SIGKILL
lifecycle:
preStop:
exec:
command:
- /bin/sh
- -c
- sleep 5
当 kubelet 进行 preStop 后,开始发动 SIGTERM 给容器内过程,若超过总默认耗时 30S(metadata.DeletionGracePeriodSeconds), 则强制发动 SIGKILL 给容器,也就是 prestop+SIGTERM 总耗时不容许超过 30s。
5.Status(状态)
status:
conditions:
- lastProbeTime: null
lastTransitionTime: "2022-07-05T09:16:07Z"
status: "True"
type: TestPodReady
- lastProbeTime: null
lastTransitionTime: "2022-07-05T09:16:07Z"
status: "True"
type: Initialized
- lastProbeTime: null
lastTransitionTime: "2022-07-05T09:16:14Z"
status: "True"
type: Ready
- lastProbeTime: null
lastTransitionTime: "2022-07-05T09:16:14Z"
status: "True"
type: ContainersReady
- lastProbeTime: null
lastTransitionTime: "2022-07-05T09:16:07Z"
status: "False"
type: ContainerDiskPressure
- lastProbeTime: null
lastTransitionTime: "2022-07-05T09:16:07Z"
status: "True"
type: PodScheduled
containerStatuses:
- containerID: containerd://xxxxx
image: docker.io/library/testdemo:v1
imageID: docker.io/library/centos@sha256:xxxx
lastState: {}
name: zxtest
ready: true
restartCount: 0
started: true
state:
running:
startedAt: "2022-07-05T09:16:13Z"
hostIP: 21.1.96.23
phase: Running
podIP: 10.11.17.172
podIPs:
- ip: 10.11.17.172
qosClass: Guaranteed
startTime: "2022-07-05T09:16:07Z"
基于上述 YAML 样例,将 Pod status 状态拆建进去剖析一下:
- conditions: conditions 是作为一种更详尽的状态报告,其自身也是一种扩大机制,其余的扩大字段也能够放入其中,比方能够表明网络情况,其中 readinessGate 就是这种扩大机制的体现,但决定 Pod 是否 ready,永远只看 type: Ready 是否为 true
- containerStatuses: Pod 内各容器的状态
- hostIP: Pod 所在节点 ip 地址
-
phase: Pod 的生命周期状态
- Pending:代表 Pod 有一个容器或者多个容器还未运行,其中包含 Pod 调度到节点之前以及拉取镜像
- Running:代表 Pod 已绑定到节点上,至多有一个容器运行或在重启
- Successed:代表 Pod 所有容器已终止
- Failed:代表 Pod 内至多有一个容器终止失败
- Unknown:代表无奈获取 Pod 状态
- podIP / podIPs:Pod 的 IP 地址,如果有 ipv4、ipv6,则能够在 podIPs 上配置
-
qosClass:代表 kubernetes 服务等级
- Guaranteed:resource.requests 与 resource.limits 统一
- Burstable:resource.requests 与 resource.limits 不统一
- BestEffort:没有配置 resource.requests 与 resource.limits
- startTime:启动工夫
通过以上 Pod 四个局部拆解,咱们根本搞清了一个 Pod 在 k8s 下“从哪里来 ”的这个问题。本系列的后续的文章会对“ 到哪里去”这个问题持续开展:Kubernetes 的魅力在于不仅仅是拉起一个工作负载,而是可能召之即来挥之即去地编排海量工作负载。
后续文章均会公布在咱们的公众号“阿里智能运维 ”上,请大家继续关注~也欢送大家在公众号后盾留言想理解的内容和感兴趣的相干话题,与SREWorks 团队进行交换。