OpenKruise运维增强控制器
OpenKruise运维增强控制器
目录
[TOC]
实验环境
实验环境:1、win10,vmwrokstation虚机;2、k8s集群:3台centos7.61810虚机,1个master节点,2个node节点k8sversion:v1.22.2containerd:apiVersion:apps.kruise.io/v1alpha1kind:SidecarSetmetadata:name:test-sidecarsetspec:selector:matchLabels:#去匹配pod的标签app:nginxupdateStrategy:type:RollingUpdatemaxUnavailable:1containers:- name:sidecar1image:busyboxcommand:["sleep","999d"]volumeMounts:- name:log-volumemountPath:/var/logvolumes:# this field will be merged into pod.spec.volumes- name:log-volumeemptyDir:{}
- 直接创建这个资源对象即可:
$kubectlapply-f01-sidecarset.yamlsidecarset.apps.kruise.io/test-sidecarsetcreated[root@master1 ~]#kubectl get sidecarsetNAMEMATCHEDUPDATEDREADYAGEtest-sidecarset00030s
需要注意上面我们在定义 SidecarSet 对象的时候里面有一个非常重要的属性就是 label selector,会去匹配具有 app=nginx
的 Pod,然后向其中注入下面定义的 sidecar1
这个容器。
- 比如定义如下所示的一个 Pod,该 Pod 中包含
app=nginx
的标签,这样可以和上面的 SidecarSet 对象匹配:
#02-test-pod.yamlapiVersion:v1kind:Podmetadata:labels:app:nginx# 匹配sidercarset中的label selector标签name:test-podspec:containers:- name:appimage:nginx:1.7.9
- 直接创建上面的资源对象:
$kubectlapply-f02-test-pod.yamlpod/test-podcreated[root@master1 ~]#kubectl get po test-pod NAMEREADYSTATUSRESTARTSAGEtest-pod2/2Running07s
可以看到该 Pod 中有2个容器,被自动注入了上面定义的 sidecar1
容器:
[root@master1 ~]#kubectl describe po test-podEvents:TypeReasonAgeFromMessage-------------------------NormalScheduled45sdefault-schedulerSuccessfullyassigneddefault/test-podtonode2NormalPulling45skubeletPullingimage"busybox"NormalPulled44skubeletSuccessfullypulledimage"busybox"in495.870587msNormalCreated44skubeletCreatedcontainersidecar1NormalStarted44skubeletStartedcontainersidecar1NormalPulled44skubeletContainerimage"nginx:1.7.9"alreadypresentonmachineNormalCreated44skubeletCreatedcontainerappNormalStarted44skubeletStartedcontainerapp[root@master1 ~]#kubectl get po test-pod -oyaml……spec:containers:-command:-sleep-999denv:-name:IS_INJECTEDvalue:"true"image:busyboximagePullPolicy:Alwaysname:sidecar1resources:{}terminationMessagePath:/dev/termination-logterminationMessagePolicy:FilevolumeMounts:-mountPath:/var/logname:log-volume-mountPath:/var/run/secrets/kubernetes.io/serviceaccountname:kube-api-access-k4cqjreadOnly:true-image:nginx:1.7.9imagePullPolicy:IfNotPresentname:appresources:{}terminationMessagePath:/dev/termination-logterminationMessagePolicy:FilevolumeMounts:-mountPath:/var/run/secrets/kubernetes.io/serviceaccountname:kube-api-access-k4cqjreadOnly:true……
- 现在我们去更新 SidecarSet 中的 sidecar 容器镜像替换成
busybox:1.35.0
:
[root@master1 ~]# kubectl patch sidecarset test-sidecarset --type='json'-p='[{"op":"replace","path":"/spec/containers/0/image","value":"busybox:1.35.0"}]'sidecarset.apps.kruise.io/test-sidecarsetpatched
更新后再去查看 Pod 中的 sidecar 容器:
[root@master1 ~]#kubectl get poNAMEREADYSTATUSRESTARTSAGEtest-pod2/2Running1(25s ago) 8m35s[root@master1 ~]#kubectl describe po test-pod......Events:TypeReasonAgeFromMessage-------------------------NormalScheduled8m28sdefault-schedulerSuccessfullyassigneddefault/test-podtonode2NormalPulling8m28skubeletPullingimage"busybox"NormalPulled8m27skubeletSuccessfullypulledimage"busybox"in495.870587msNormalPulled8m27skubeletContainerimage"nginx:1.7.9"alreadypresentonmachineNormalCreated8m27skubeletCreatedcontainerappNormalStarted8m27skubeletStartedcontainerappNormalKilling49skubeletContainersidecar1definitionchanged,willberestartedNormalPulling19skubeletPullingimage"busybox:1.35.0"NormalStarted1s(x2 over8m27s) kubelet Started container sidecar1NormalCreated1s(x2 over8m27s) kubelet Created container sidecar1NormalPulled1skubeletSuccessfullypulledimage"busybox:1.35.0"in17.221245188s[root@master1 ~]#kubectl get po test-pod -oyaml|grepbusyboxkruise.io/sidecarset-inplace-update-state:'{"test-sidecarset":{"revision":"f78z4854d9855xd6478fzx9c84645z2548v24z26455db46bdfzw44v49v98f2cw","updateTimestamp":"2022-03-12T01:55:56Z","lastContainerStatuses":{"sidecar1":{"imageID":"docker.io/library/busybox@sha256:5acba83a746c7608ed544dc1533b87c737a0b0fb730301639a0179f9344b1678"}}}}'image:busybox:1.35.0image:docker.io/library/busybox:1.35.0imageID:docker.io/library/busybox@sha256:130df6999605f982ec67e5bee29d3a52614a075e949490f0a41702ee1dd98f3f
可以看到 Pod 中的 sidecar 容器镜像被原地升级成 busybox:1.35.0
了, 对主容器没有产生任何影响。
实验结束。😘
1.同意特性
需要注意的是 sidecar 的注入只会发生在 Pod 创建阶段,并且只有 Pod spec 会被更新,不会影响 Pod 所属的 workload template 模板。 spec.containers
除了默认的 k8s container 字段,还扩展了如下一些字段,来方便注入:
apiVersion:apps.kruise.io/v1alpha1kind:SidecarSetmetadata:name:sidecarsetspec:selector:matchLabels:app:samplecontainers:# 默认的K8s容器字段- name:nginximage:nginx:alpinevolumeMounts:- mountPath:/nginx/confname:nginx.conf# 扩展的sidecar容器字段podInjectPolicy:BeforeAppContainershareVolumePolicy:type:disabled |enabledtransferEnv:- sourceContainerName:mainenvName:PROXY_IPvolumes:- Name:nginx.confhostPath:/data/nginx/conf
podInjectPolicy:定义了容器 注入到
pod.spec.containers
中的位置BeforeAppContainer
:表示注入到 pod 原 containers 的前面((默认) )AfterAppContainer
: 表示注入到 pod 原 containers 的后面
数据卷共享
- 共享指定卷:通过
spec.volumes
来定义 sidecar 自身需要的 volume - 共享所有卷:通过
spec.containers[i].shareVolumePolicy.type =enabled |disabled
来控制是否挂载 pod 应用容器的卷,常用于日志收集等 sidecar,配置为enabled
后会把应用容器中所有挂载点注入 sidecar 同一路经下(sidecar 中本身就有声明的数据卷和挂载点除外)
- 共享指定卷:通过
环境变量共享:可以通过
spec.containers[i].transferEnv
来从别的容器获取环境变量,会把名为sourceContainerName
容器中名为envName
的环境变量拷贝到本容器
🍀 SidecarSet 不仅支持 sidecar 容器的原地升级,而且提供了非常丰富的升级、灰度策略。同样在 SidecarSet 对象中 updateStrategy
属性下面也可以配置 partition
来定义保留旧版本 Pod 的数量或百分比,默认为 0;同样还可以配置的有 maxUnavailable
属性,表示在发布过程中的最大不可用数量。
- 当
{matched pod}=100,partition=50,maxUnavailable=10
,控制器会发布 50 个 Pod 到新版本,但是同一时间只会发布 10 个 Pod,每发布好一个 Pod 才会再找一个发布,直到 50 个发布完成。 - 当
{matched pod}=100,partition=80,maxUnavailable=30
,控制器会发布 20 个 Pod 到新版本,因为满足 maxUnavailable 数量,所以这 20 个 Pod 会同时发布。
🍀 同样也可以设置 paused:true
来暂停发布,此时对于新创建的、扩容的 pod 依旧会实现注入能力,已经更新的 pod 会保持更新后的版本不动,还没有更新的 pod 会暂停更新。
apiVersion:apps.kruise.io/v1alpha1kind:SidecarSetmetadata:name:sidecarsetspec:# ...updateStrategy:type:RollingUpdatemaxUnavailable:20%partition:10paused:true
2.金丝雀发布
对于有金丝雀发布需求的业务,可以通过 selector
来实现,对于需要率先金丝雀灰度的 pod 打上固定的 [canary.release] =true
的标签,再通过 selector.matchLabels
来选中该 pod 即可。
💘 实验:金丝雀发布
- 比如现在我们有一个3副本的 Pod,也具有
app=nginx
的标签,如下所示
#03-deployment.yamlapiVersion:apps/v1kind:Deploymentmetadata:name:nginxnamespace:defaultspec:replicas:3revisionHistoryLimit:3selector:matchLabels:app:nginxtemplate:metadata:labels:app:nginxspec:containers:- name:ngximage:nginx:1.7.9ports:- containerPort:80
- 创建后现在就具有4个
app=nginx
标签的 Pod 了,由于都匹配上面创建的 SidecarSet 对象,所以都会被注入一个sidecar1
的容器,镜像为busybox
:
$kubectlapply-f03-deployment.yamldeployment.apps/nginxcreated[root@master1 ~]#kubectl get pods -l app=nginxNAMEREADYSTATUSRESTARTSAGEnginx-6457955f7-bt5fk2/2Running036snginx-6457955f7-jphvr2/2Running036snginx-6457955f7-zjvh92/2Running036stest-pod2/2Running1(127m ago) 135m
- 现在如果我们想为
test-pod
这个应用来执行灰度策略,将 sidecar 容器镜像更新成busybox:1.35.0
,则可以在updateStrategy
下面添加selector.matchLabels
属性canary.release:"true"
:
注意:我这里就直接在01-sidecarset.yaml
上面直接修改了。另外,我之前原本test-pod里的busybox镜像就已经是busybox:1.35.0了,本次yaml里写成busybox即可。
# 01-sidecarset.yamlapiVersion:apps.kruise.io/v1alpha1kind:SidecarSetmetadata:name:test-sidecarsetspec:selector:matchLabels:app:nginxupdateStrategy:type:RollingUpdatemaxUnavailable:1selector:matchLabels:# 修改1:canary.release:"true"containers:- name:sidecar1image:busybox# 修改2:command:["sleep","999d"]volumeMounts:- name:log-volumemountPath:/var/logvolumes:# this field will be merged into pod.spec.volumes- name:log-volumeemptyDir:{}
- 然后同样需要给 test-pod 添加上
canary.release=true
这个标签:
#直接在02-test-pod文件里添加即可apiVersion:v1kind:Podmetadata:labels:app:nginxcanary.release:"true"name:test-podspec:containers:- name:appimage:nginx:1.7.9
- 更新后可以发现 test-pod 的 sidecar 镜像更新了,其他 Pod 没有变化,这样就实现了 sidecar 的灰度功能:
$kubectlapply-f02-test-pod.yamlpod/test-podconfigured$kubectlapply-f01-sidecarset.yamlsidecarset.apps.kruise.io/test-sidecarsetconfigured[root@master1 ~]#kubectl get po -l app=nginxNAMEREADYSTATUSRESTARTSAGEnginx-6457955f7-bt5fk2/2Running07m34snginx-6457955f7-jphvr2/2Running07m34snginx-6457955f7-zjvh92/2Running07m34stest-pod2/2Running2(10s ago) 142m [root@master1 ~]#kubectl describe po test-podEvents:TypeReasonAgeFromMessage-------------------------NormalKilling74s(x2 over135m) kubelet Container sidecar1 definition changed,will be restartedNormalPulling44s(x2 over142m) kubelet Pulling image "busybox"NormalCreated43s(x3 over142m) kubelet Created container sidecar1NormalStarted43s(x3 over142m) kubelet Started container sidecar1NormalPulled43skubeletSuccessfullypulledimage"busybox"in505.082017ms#符合预期[root@master1 ~]#kubectl get po test-pod -oyaml|grepbusyboxkruise.io/sidecarset-inplace-update-state:'{"test-sidecarset":{"revision":"f78z4854d9855xd6478fzx9c84645z2548v24z26455db46bdfzw44v49v98f2cw","updateTimestamp":"2022-03-12T01:55:56Z","lastContainerStatuses":{"sidecar1":{"imageID":"docker.io/library/busybox@sha256:130df6999605f982ec67e5bee29d3a52614a075e949490f0a41702ee1dd98f3f"}}}}'image:busyboximage:docker.io/library/busybox:latestimageID:docker.io/library/busybox@sha256:5acba83a746c7608ed544dc1533b87c737a0b0fb730301639a0179f9344b1678
实验结束。😘
3.热升级
💘 实验:热升级
SidecarSet 原地升级会先停止旧版本的容器,然后创建新版本的容器,这种方式适合不影响 Pod 服务可用性的 sidecar 容器,比如说日志收集的 Agent。
但是对于很多代理或运行时的 sidecar 容器,例如 Istio Envoy,这种升级方法就有问题了,Envoy 作为 Pod 中的一个代理容器,代理了所有的流量,如果直接重启,Pod 服务的可用性会受到影响,如果需要单独升级 envoy sidecar,就需要复杂的优雅终止和协调机制,所以我们为这种 sidecar 容器的升级提供了一种新的解决方案。
- 编写04-sidecarset-hot.yaml
#04-sidecarset-hot.yamlapiVersion:apps.kruise.io/v1alpha1kind:SidecarSetmetadata:name:hotupgrade-sidecarsetspec:selector:matchLabels:app:hotupgradecontainers:- name:sidecarimage:openkruise/hotupgrade-sample:sidecarv1imagePullPolicy:Alwayslifecycle:postStart:exec:command:- /bin/sh- /migrate.sh#在主容器启动之前,做一些网络方面的迁移upgradeStrategy:upgradeType:HotUpgradehotUpgradeEmptyImage:openkruise/hotupgrade-sample:empty
upgradeType
:HotUpgrade
代表该 sidecar 容器的类型是热升级方案hotUpgradeEmptyImage
:当热升级 sidecar 容器时,业务必须要提供一个 empty 容器用于热升级过程中的容器切换,empty 容器同 sidecar 容器具有相同的配置(除了镜像地址),例如:command、lifecycle、probe 等,但是它不做任何工作。lifecycle.postStart
:在 postStart 这个 hook 中完成热升级过程中的状态迁移,该脚本需要由业务根据自身的特点自行实现,例如:nginx 热升级需要完成 Listen FD 共享以及 reload 操作。
整体来说热升级特性总共包含以下两个过程:
- Pod 创建时,注入热升级容器
- 原地升级时,完成热升级流程
注入热升级容器
Pod 创建时,SidecarSet Webhook 将会注入两个容器:
{sidecarContainer.name}-1
:如下图所示 envoy-1,这个容器代表正在实际工作的 sidecar 容器,例如:envoy:1.16.0{sidecarContainer.name}-2
:如下图所示 envoy-2,这个容器是业务配置的 hotUpgradeEmptyImage 容器,例如:empty:1.0,用于后面的热升级机制
热升级流程
热升级流程主要分为三个步骤:
Upgrade
:将 empty 容器升级为当前最新的 sidecar 容器,例如:envoy-2.Image =envoy:1.17.0Migration
:lifecycle.postStart
完成热升级流程中的状态迁移,当迁移完成后退出Reset
:状态迁移完成后,热升级流程将设置 envoy-1 容器为 empty 镜像,例如:envoy-1.Image =empty:1.0
上述三个步骤完成了热升级中的全部流程,当对 Pod 执行多次热升级时,将重复性的执行上述三个步骤。
empty这个空容器的目的就是占位。
- 部署上面04-sidecarset-hot.yaml资源
$kubectlapply-f04-sidecarset-hot.yamlsidecarset.apps.kruise.io/hotupgrade-sidecarsetcreated[root@master1 ~]#kubectl get sidecarsetNAMEMATCHEDUPDATEDREADYAGEhotupgrade-sidecarset00020s
- 这里我们以 OpenKruise 的官方示例来进行说明,首先创建上面的
hotupgrade-sidecarset
这个 SidecarSet。然后创建一个如下所示的 CloneSet 对象:
#05-hotupgrade-CloneSet.yamlapiVersion:apps.kruise.io/v1alpha1kind:CloneSetmetadata:labels:app:hotupgradename:busyboxspec:replicas:1selector:matchLabels:app:hotupgradetemplate:#下面是pod模板metadata:labels:app:hotupgrade#这个标签要和上面的sidercarset匹配spec:containers:- name:busyboximage:openkruise/hotupgrade-sample:busybox
- 创建完成后,CloneSet 管理的 Pod 已经注入
sidecar-1
和sidecar-2
两个容器:
#部署$kubectlapply-f05-hotupgrade-CloneSet.yamlcloneset.apps.kruise.io/busyboxcreated[root@master1 ~]#kubectl get po -l app=hotupgradeNAMEREADYSTATUSRESTARTSAGEbusybox-695lv3/3Running071s[root@master1 ~]#kubectl describe po busybox-695lvEvents:TypeReasonAgeFromMessage-------------------------NormalScheduled119sdefault-schedulerSuccessfullyassigneddefault/busybox-695lvtonode2NormalPulling119skubeletPullingimage"openkruise/hotupgrade-sample:sidecarv1"NormalPulled116skubeletSuccessfullypulledimage"openkruise/hotupgrade-sample:sidecarv1"in2.430148491sNormalCreated116skubeletCreatedcontainersidecar-1NormalStarted116skubeletStartedcontainersidecar-1NormalPulling111skubeletPullingimage"openkruise/hotupgrade-sample:empty"NormalPulled93skubeletSuccessfullypulledimage"openkruise/hotupgrade-sample:empty"in17.732956857sNormalCreated93skubeletCreatedcontainersidecar-2NormalStarted93skubeletStartedcontainersidecar-2NormalPulling93skubeletPullingimage"openkruise/hotupgrade-sample:busybox"NormalPulled90skubeletSuccessfullypulledimage"openkruise/hotupgrade-sample:busybox"in2.81313947sNormalCreated90skubeletCreatedcontainerbusybox[root@master1 ~]#kubectl get po busybox-695lv -oyaml……spec:containers:-env:-name:IS_INJECTEDvalue:"true"-name:SIDECARSET_VERSIONvalueFrom:fieldRef:apiVersion:v1fieldPath:metadata.annotations['version.sidecarset.kruise.io/sidecar-1']-name:SIDECARSET_VERSION_ALTvalueFrom:fieldRef:apiVersion:v1fieldPath:metadata.annotations['versionalt.sidecarset.kruise.io/sidecar-1']image:openkruise/hotupgrade-sample:sidecarv1imagePullPolicy:Alwayslifecycle:postStart:exec:command:-/bin/sh-/migrate.shname:sidecar-1resources:{}terminationMessagePath:/dev/termination-logterminationMessagePolicy:FilevolumeMounts:-mountPath:/var/run/secrets/kubernetes.io/serviceaccountname:kube-api-access-n9lpfreadOnly:true-env:-name:IS_INJECTEDvalue:"true"-name:SIDECARSET_VERSIONvalueFrom:fieldRef:apiVersion:v1fieldPath:metadata.annotations['version.sidecarset.kruise.io/sidecar-2']-name:SIDECARSET_VERSION_ALTvalueFrom:fieldRef:apiVersion:v1fieldPath:metadata.annotations['versionalt.sidecarset.kruise.io/sidecar-2']image:openkruise/hotupgrade-sample:emptyimagePullPolicy:Alwayslifecycle:postStart:exec:command:-/bin/sh-/migrate.shname:sidecar-2resources:{}terminationMessagePath:/dev/termination-logterminationMessagePolicy:FilevolumeMounts:-mountPath:/var/run/secrets/kubernetes.io/serviceaccountname:kube-api-access-n9lpfreadOnly:true-image:openkruise/hotupgrade-sample:busyboximagePullPolicy:Alwaysname:busyboxresources:{}terminationMessagePath:/dev/termination-logterminationMessagePolicy:FilevolumeMounts:-mountPath:/var/run/secrets/kubernetes.io/serviceaccountname:kube-api-access-n9lpfreadOnly:true……
- busybox 主容器每100毫秒会请求一次sidecar(version=v1)服务:
[root@master1 ~]#kubectl logs -f busybox-695lv -c busyboxI031211:51:49.1008321main.go:39]requestsidecarserversuccess,andresponse(body=Thisisversion(v1) sidecar)I031211:51:49.2128471main.go:39]requestsidecarserversuccess,andresponse(body=Thisisversion(v1) sidecar)......
- 现在我们去升级 sidecar 容器,将镜像修改为
openkruise/hotupgrade-sample:sidecarv2
:
[root@master1 ~]#kubectl patch sidecarset hotupgrade-sidecarset --type='json'-p='[{"op":"replace","path":"/spec/containers/0/image","value":"openkruise/hotupgrade-sample:sidecarv2"}]'sidecarset.apps.kruise.io/hotupgrade-sidecarsetpatched
- 更新后再去观察 pod 的状态,可以看到 sidecar-2 镜像正常更新了:
[root@master1 ~]#kubectl get po -l app=hotupgradeNAMEREADYSTATUSRESTARTSAGEbusybox-695lv3/3Running2(103s ago) 8m38s[root@master1 ~]#kubectl describe po busybox-695lvEvents:TypeReasonAgeFromMessage-------------------------NormalScheduled9m10sdefault-schedulerSuccessfullyassigneddefault/busybox-695lvtonode2NormalPulling9m10skubeletPullingimage"openkruise/hotupgrade-sample:sidecarv1"NormalPulled9m7skubeletSuccessfullypulledimage"openkruise/hotupgrade-sample:sidecarv1"in2.430148491sNormalPulling9m2skubeletPullingimage"openkruise/hotupgrade-sample:empty"NormalPulling8m44skubeletPullingimage"openkruise/hotupgrade-sample:busybox"NormalPulled8m44skubeletSuccessfullypulledimage"openkruise/hotupgrade-sample:empty"in17.732956857sNormalStarted8m41skubeletStartedcontainerbusyboxNormalCreated8m41skubeletCreatedcontainerbusyboxNormalPulled8m41skubeletSuccessfullypulledimage"openkruise/hotupgrade-sample:busybox"in2.81313947sNormalKilling2m49skubeletContainersidecar-2definitionchanged,willberestartedNormalPulling2m48skubeletPullingimage"openkruise/hotupgrade-sample:sidecarv2"NormalPulled2m27skubeletSuccessfullypulledimage"openkruise/hotupgrade-sample:sidecarv2"in21.791000213sNormalCreated2m27s(x2 over8m44s) kubelet Created container sidecar-2NormalStarted2m26s(x2 over8m44s) kubelet Started container sidecar-2NormalKilling2m16skubeletContainersidecar-1definitionchanged,willberestartedNormalResetContainerSucceed2m16ssidecarset-controllerresetsidecarcontainerimageemptysuccessfullyNormalPulling2m15skubeletPullingimage"openkruise/hotupgrade-sample:empty"NormalStarted2m(x2 over9m7s) kubelet Started container sidecar-1NormalCreated2m(x2 over9m7s) kubelet Created container sidecar-1NormalPulled2mkubeletSuccessfullypulledimage"openkruise/hotupgrade-sample:empty"in15.229447021s[root@master1 ~]#kubectl get po busybox-695lv -oyaml……spec:containers:-env:-name:IS_INJECTEDvalue:"true"-name:SIDECARSET_VERSIONvalueFrom:fieldRef:apiVersion:v1fieldPath:metadata.annotations['version.sidecarset.kruise.io/sidecar-1']-name:SIDECARSET_VERSION_ALTvalueFrom:fieldRef:apiVersion:v1fieldPath:metadata.annotations['versionalt.sidecarset.kruise.io/sidecar-1']image:openkruise/hotupgrade-sample:emptyimagePullPolicy:Alwayslifecycle:postStart:exec:command:-/bin/sh-/migrate.shname:sidecar-1resources:{}terminationMessagePath:/dev/termination-logterminationMessagePolicy:FilevolumeMounts:-mountPath:/var/run/secrets/kubernetes.io/serviceaccountname:kube-api-access-n9lpfreadOnly:true-env:-name:IS_INJECTEDvalue:"true"-name:SIDECARSET_VERSIONvalueFrom:fieldRef:apiVersion:v1fieldPath:metadata.annotations['version.sidecarset.kruise.io/sidecar-2']-name:SIDECARSET_VERSION_ALTvalueFrom:fieldRef:apiVersion:v1fieldPath:metadata.annotations['versionalt.sidecarset.kruise.io/sidecar-2']image:openkruise/hotupgrade-sample:sidecarv2imagePullPolicy:Alwayslifecycle:postStart:exec:command:-/bin/sh-/migrate.shname:sidecar-2resources:{}terminationMessagePath:/dev/termination-logterminationMessagePolicy:FilevolumeMounts:-mountPath:/var/run/secrets/kubernetes.io/serviceaccountname:kube-api-access-n9lpfreadOnly:true-image:openkruise/hotupgrade-sample:busyboximagePullPolicy:Alwaysname:busyboxresources:{}terminationMessagePath:/dev/termination-logterminationMessagePolicy:FilevolumeMounts:-mountPath:/var/run/secrets/kubernetes.io/serviceaccountname:kube-api-access-n9lpfreadOnly:true……
并且在更新过程中观察 busybox 容器仍然会不断请求 sidecar 服务,但是并没有失败的请求出现:
[root@master1 ~]#kubectl logs -f busybox-695lv -c busybox
一般来说,列表中的容器会一个个被停止,但可能同时在被重建和启动,除非 orderedRecreate
被设置为 true。 unreadyGracePeriodSeconds
功能依赖于 KruisePodReadinessGate
这个 feature-gate,后者会在每个 Pod 创建的时候注入一个 readinessGate
,否则,默认只会给 Kruise workload 创建的 Pod 注入 readinessGate,也就是说只有这些 Pod 才能在 CRR 重建时使用 unreadyGracePeriodSeconds
。
3、ImagePullJob
NodeImage
和 ImagePullJob
是从 Kruise v0.8.0 版本开始提供的 CRD。Kruise 会自动为每个 Node 创建一个 NodeImage,它包含了哪些镜像需要在这个 Node 上做预热,比如我们这里3个节点,则会自动创建3个 NodeImage 对象:
➜kubectlgetnodeimageNAMEDESIREDPULLINGSUCCEEDFAILEDAGEmaster1000010dnode1000010dnode2000010d
- 比如我们查看 node1 节点上的 NodeImage 对象:
➜kruisekubectlgetnodeimagenode1-oyamlapiVersion:apps.kruise.io/v1alpha1kind:NodeImagemetadata:labels:beta.kubernetes.io/arch:amd64beta.kubernetes.io/os:linuxkubernetes.io/arch:amd64kubernetes.io/hostname:node1kubernetes.io/os:linuxname:node1spec:{}status:desired:0failed:0pulling:0succeeded:0
- 比如我们希望在这个节点上拉去一个
ubuntu:latest
镜像,则可以按照如下所示的去修改 spec:
......spec:images:ubuntu:# 镜像 nametags:- tag:latest# 镜像 tagpullPolicy:ttlSecondsAfterFinished:300# [required] 拉取完成(成功或失败)超过 300s 后,将这个任务从 NodeImage 中清除timeoutSeconds:600# [optional] 每一次拉取的超时时间,默认为 600backoffLimit:3# [optional] 拉取的重试次数,默认为 3activeDeadlineSeconds:1200# [optional] 整个任务的超时时间,无默认值
更新后我们可以从 status 中看到拉取进度以及结果,并且你会发现拉取完成 600s 后任务会被清除。
🍀 此外用户可以创建 ImagePullJob
对象,来指定一个镜像要在哪些节点上做预热。
- 比如创建如下所示的
ImagePullJob
资源对象:
apiVersion:apps.kruise.io/v1alpha1kind:ImagePullJobmetadata:name:job-with-alwaysspec:image:nginx:1.9.1# [required] 完整的镜像名 name:tagparallelism:10# [optional] 最大并发拉取的节点数量,默认为 1selector:# [optional] 指定节点的 名字列表 或 标签选择器 (只能设置其中一种)names:- node-1- node-2matchLabels:node-type:xxx# podSelector:# [optional] pod label 选择器来在这些 pod 所在节点上拉取镜像,与 selector 不能同时设置.# pod-label:xxxcompletionPolicy:type:Always# [optional] 默认为 AlwaysactiveDeadlineSeconds:1200# [optional] 无默认值,只对 Alway 类型生效ttlSecondsAfterFinished:300# [optional] 无默认值,只对 Alway 类型生效pullPolicy:# [optional] 默认 backoffLimit=3,timeoutSeconds=600backoffLimit:3timeoutSeconds:300pullSecrets:#secret是命名空间级别的,当然ImagePullJob也是命名空间级别的。- secret-name1- secret-name2
我们可以在 selector
字段中指定节点的名字列表或标签选择器 (只能设置其中一种),如果没有设置 selector 则会选择所有节点做预热。或者可以配置 podSelector
来在这些 pod 所在节点上拉取镜像,podSelector 与 selector 不能同时设置。
同时,ImagePullJob 有两种 completionPolicy
类型:
Always
:表示这个 job 是一次性预热,不管成功、失败都会结束activeDeadlineSeconds
:整个 job 的 deadline 结束时间ttlSecondsAfterFinished
:结束后超过这个时间,自动清理删除 jobNever
:表示这个 job 是长期运行、不会结束,并且会每天都会在匹配的节点上重新预热一次指定的镜像
同样如果你要预热的镜像来自私有仓库,则可以通过 pullSecrets
来指定仓库的 Secret 信息。
4、容器启动顺序
Container Launch Priority
提供了控制一个 Pod 中容器启动顺序的方法。通常来说 Pod 容器的启动和退出顺序是由 Kubelet 管理的,Kubernetes 曾经有一个 KEP计划在 container 中增加一个 type 字段来标识不同类型容器的启停优先级,但是由于sig-node 考虑到对现有代码架构的改动太大,所以将该提案拒绝了。
这个功能作用在 Pod 对象上,不管它的 owner 是什么类型的,因此可以适用于 Deployment、CloneSet 以及其他的 workload 种类。
🍀 比如我们可以设置按照容器顺序启动,只需要在 Pod 中定义一个 apps.kruise.io/container-launch-priority
的注解即可:
apiVersion:v1kind:Podannotations:apps.kruise.io/container-launch-priority:Orderedspec:containers:- name:sidecar# ...- name:main# ...
Kruise 会保证前面的容器(sidecar)会在后面容器(main)之前启动。
🍀 此外我们还可以按自定义顺序启动,但是需要在 Pod 容器中添加 KRUISE_CONTAINER_PRIORITY
这个环境变量:
apiVersion:v1kind:Podspec:containers:- name:main# ...- name:sidecarenv:- name:KRUISE_CONTAINER_PRIORITYvalue:"1"# ...
该环境变量值的范围在 [-2147483647,2147483647]
,不写默认是 0,权重高的容器,会保证在权重低的容器之前启动,但是需要注意相同权重的容器不保证启动顺序。
🍀 除了这些常用的增强控制器之外 OpenKruise 还有很多高级的特性,可以前往官网 https: 版权:此文章版权归 One 所有,如有转载,请注明出处! 链接:可点击右上角分享此页面复制文章链接