自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

K8s 增強(qiáng)版工作負(fù)載 OpenKruise 之運(yùn)維增強(qiáng)功能

云計(jì)算 云原生 運(yùn)維
SidecarSet 支持通過 Admission Webhook 來自動(dòng)為集群中創(chuàng)建的符合條件的 Pod 注入 Sidecar 容器,除了在 Pod 創(chuàng)建時(shí)候注入外,SidecarSet 還提供了為 Pod 原地升級(jí)其中已經(jīng)注入的 Sidecar 容器鏡像的能力。

前面我們和大家已經(jīng)學(xué)習(xí)了 OpenKruise 的基本概念以及常用的幾個(gè)增強(qiáng)控制器,接下來我們來繼續(xù)了解其他高級(jí)功能。

SidecarSet

SidecarSet 支持通過 admission webhook 來自動(dòng)為集群中創(chuàng)建的符合條件的 Pod 注入 sidecar 容器,除了在 Pod 創(chuàng)建時(shí)候注入外,SidecarSet 還提供了為 Pod 原地升級(jí)其中已經(jīng)注入的 sidecar 容器鏡像的能力。SidecarSet 將 sidecar 容器的定義和生命周期與業(yè)務(wù)容器解耦,它主要用于管理無(wú)狀態(tài)的 sidecar 容器,比如監(jiān)控、日志等 agent。

比如我們定義一個(gè)如下所示的 SidecarSet 資源對(duì)象:

# sidecarset-demo.yaml
apiVersion: apps.kruise.io/v1alpha1
kind: SidecarSet
metadata:
name: scs-demo
spec:
selector:
matchLabels: # 非常重要的屬性,會(huì)去匹配具有 app=nginx Pod
app: nginx
updateStrategy:
type: RollingUpdate
maxUnavailable: 1
containers:
- name: sidecar1
image: busybox
command: ["sleep", "999d"]
volumeMounts:
- name: log-volume
mountPath: /var/log
volumes: # 該屬性會(huì)被合并到 pod.spec.volumes
- name: log-volume
emptyDir: {}

直接創(chuàng)建這個(gè)資源對(duì)象即可:

? kubectl get sidecarset
NAME MATCHED UPDATED READY AGE
scs-demo 0 0 0 6s

需要注意上面我們?cè)诙x SidecarSet 對(duì)象的時(shí)候里面有一個(gè)非常重要的屬性就是 label selector,會(huì)去匹配具有 app=nginx? 的 Pod,然后向其中注入下面定義的 sidecar1? 這個(gè)容器,比如定義如下所示的一個(gè) Pod,該 Pod 中包含 app=nginx 的標(biāo)簽,這樣可以和上面的 SidecarSet 對(duì)象匹配:

apiVersion: v1
kind: Pod
metadata:
labels:
app: nginx # 匹配 SidecarSet 里面指定的標(biāo)簽
name: test-pod
spec:
containers:
- name: app
image: nginx:1.7.9

直接創(chuàng)建上面的資源對(duì)象:

? kubectl get pod test-pod
NAME READY STATUS RESTARTS AGE
test-pod 2/2 Running 0 22s

可以看到該 Pod 中有 2 個(gè)容器,被自動(dòng)注入了上面定義的 sidecar1 容器:

? kubectl get pod test-pod -o yaml
apiVersion: v1
kind: Pod
metadata:
labels:
app: nginx
name: test-pod
namespace: default
spec:
containers:
- command:
- sleep
- 999d
env:
- name: IS_INJECTED
value: "true"
image: busybox
imagePullPolicy: Always
name: sidecar1
resources: {}
volumeMounts:
- mountPath: /var/log
name: log-volume
- image: nginx:1.7.9
imagePullPolicy: IfNotPresent
name: app
# ......
volumes:
- emptyDir: {}
name: log-volume
# ......

現(xiàn)在我們?nèi)ジ?SidecarSet 中的 sidecar 容器鏡像替換成 busybox:1.35.0:

? kubectl patch sidecarset scs-demo --type='json' -p='[{"op": "replace", "path": "/spec/containers/0/image", "value": "busybox:1.35.0"}]'
sidecarset.apps.kruise.io/scs-demo patched

更新后再去查看 Pod 中的 sidecar 容器:

? kubectl get pod test-pod
NAME READY STATUS RESTARTS AGE
test-pod 2/2 Running 1 (67s ago) 28m
? kubectl describe pod test-pod
......
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
# ......
Normal Created 10m kubelet Created container app
Normal Started 10m kubelet Started container app
Normal Killing 114s kubelet Container sidecar1 definition changed, will be restarted
Normal Pulling 84s kubelet Pulling image "busybox:1.35.0"
Normal Created 77s (x2 over 11m) kubelet Created container sidecar1
Normal Started 77s (x2 over 11m) kubelet Started container sidecar1
Normal Pulled 77s kubelet Successfully pulled image "busybox:1.35.0" in 6.901558972s (6.901575894s including waiting)
? kubectl get pod test-pod -o yaml |grep busybox
kruise.io/sidecarset-inplace-update-state: '{"scs-demo":{"revision":"f78z4854d9855xd6478fzx9c84645z2548v24z26455db46bdfzw44v49v98f2cw","updateTimestamp":"2023-04-04T08:05:18Z","lastContainerStatuses":{"sidecar1":{"imageID":"docker.io/library/busybox@sha256:b5d6fe0712636ceb7430189de28819e195e8966372edfc2d9409d79402a0dc16"}}}}'
image: busybox:1.35.0
image: docker.io/library/busybox:1.35.0
imageID: docker.io/library/busybox@sha256:223ae047b1065bd069aac01ae3ac8088b3ca4a527827e283b85112f29385fb1b

可以看到 Pod 中的 sidecar 容器鏡像被原地升級(jí)成 busybox:1.35.0 了, 對(duì)主容器沒有產(chǎn)生任何影響。

基本特性

需要注意的是 sidecar 的注入只會(huì)發(fā)生在 Pod 創(chuàng)建階段,并且只有 Pod spec 會(huì)被更新,不會(huì)影響 Pod 所屬的工作負(fù)載 template 模板。 spec.containers 除了默認(rèn)的 k8s container 字段,還擴(kuò)展了如下一些字段,來方便注入:

apiVersion: apps.kruise.io/v1alpha1
kind: SidecarSet
metadata:
name: sidecarset
spec:
selector:
matchLabels:
app: sample
containers:
# 默認(rèn)的 K8s 容器字段
- name: nginx
image: nginx:alpine
volumeMounts:
- mountPath: /nginx/conf
name: nginxconf
# 擴(kuò)展的 sidecar 容器字段
podInjectPolicy: BeforeAppContainer
shareVolumePolicy: # 數(shù)據(jù)卷共享
type: disabled | enabled
transferEnv: # 環(huán)境變量共享
- sourceContainerName: main # 會(huì)把main容器中的PROXY_IP環(huán)境變量注入到當(dāng)前定義的sidecar容器中
envName: PROXY_IP
volumes:
- Name: nginxconf
hostPath: /data/nginx/conf

  • podInjectPolicy? 定義了容器 注入到 pod.spec.containers 中的位置。
  • BeforeAppContainer:表示注入到 pod 原 containers 的前面(默認(rèn))。
  • AfterAppContainer: 表示注入到 pod 原 containers 的后面。
  • 數(shù)據(jù)卷共享。
  • 共享指定卷:通過 spec.volumes 來定義 sidecar 自身需要的 volume。
  • 共享所有卷:通過 spec.containers[i].shareVolumePolicy.type = enabled | disabled 來控制是否掛載 pod 應(yīng)用容器的卷,常用于日志收集等 sidecar,配置為 enabled 后會(huì)把應(yīng)用容器中所有掛載點(diǎn)注入 sidecar 同一路經(jīng)下(sidecar 中本身就有聲明的數(shù)據(jù)卷和掛載點(diǎn)除外)。
  • 環(huán)境變量共享:可以通過 spec.containers[i].transferEnv 來從別的容器獲取環(huán)境變量,會(huì)把名為 sourceContainerName 容器中名為 envName 的環(huán)境變量拷貝到本容器。

SidecarSet 不僅支持 sidecar 容器的原地升級(jí),而且提供了非常豐富的升級(jí)、灰度策略。同樣在 SidecarSet 對(duì)象中 updateStrategy? 屬性下面也可以配置 partition? 來定義保留舊版本 Pod 的數(shù)量或百分比,默認(rèn)為 0;同樣還可以配置的有 maxUnavailable 屬性,表示在發(fā)布過程中的最大不可用數(shù)量。

  • 當(dāng) {matched pod}=100,partitinotallow=40,maxUnavailable=10,控制器會(huì)發(fā)布 100-40=60 個(gè) Pod 到新版本,但是同一時(shí)間只會(huì)發(fā)布 10 個(gè) Pod,每發(fā)布好一個(gè) Pod 才會(huì)再找一個(gè)發(fā)布,直到 60 個(gè)發(fā)布完成。
  • 當(dāng) {matched pod}=100,partitinotallow=80,maxUnavailable=30,控制器會(huì)發(fā)布 20 個(gè) Pod 到新版本,因?yàn)闈M足 maxUnavailable 數(shù)量,所以這 20 個(gè) Pod 會(huì)同時(shí)發(fā)布。

同樣也可以設(shè)置 paused: true 來暫停發(fā)布,此時(shí)對(duì)于新創(chuàng)建的、擴(kuò)容的 pod 依舊會(huì)實(shí)現(xiàn)注入能力,已經(jīng)更新的 pod 會(huì)保持更新后的版本不動(dòng),還沒有更新的 pod 會(huì)暫停更新。

apiVersion: apps.kruise.io/v1alpha1
kind: SidecarSet
metadata:
name: sidecarset
spec:
# ...
updateStrategy:
type: RollingUpdate
maxUnavailable: 20%
partition: 10
paused: true

金絲雀發(fā)布

對(duì)于有金絲雀發(fā)布需求的業(yè)務(wù),可以通過 selector? 來實(shí)現(xiàn),對(duì)于需要率先金絲雀灰度的 pod 打上固定的 [canary.release] = true? 的標(biāo)簽,再通過 selector.matchLabels 來選中該 pod 即可。

比如現(xiàn)在我們有一個(gè) 3 副本的 Pod,也具有 app=nginx 的標(biāo)簽,如下所示:

apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: default
spec:
replicas: 3
revisionHistoryLimit: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: ngx
image: nginx:1.7.9
ports:
- containerPort: 80

創(chuàng)建后現(xiàn)在就具有 4 個(gè) app=nginx? 標(biāo)簽的 Pod 了,由于都匹配上面創(chuàng)建的 SidecarSet 對(duì)象,所以都會(huì)被注入一個(gè) sidecar1? 的容器,鏡像為 busybox:

? kubectl get pods -l app=nginx
NAME READY STATUS RESTARTS AGE
nginx-6457955f7-7hnjw 2/2 Running 0 51s
nginx-6457955f7-prkgz 2/2 Running 0 51s
nginx-6457955f7-tbtxk 2/2 Running 0 51s
test-pod 2/2 Running 0 4m2s

現(xiàn)在如果我們想為 test-pod? 這個(gè)應(yīng)用來執(zhí)行灰度策略,將 sidecar 容器鏡像更新成 busybox:1.35.0?,則可以在 updateStrategy? 下面添加 selector.matchLabels? 屬性 canary.release: "true":

piVersion: apps.kruise.io/v1alpha1
kind: SidecarSet
metadata:
name: test-sidecarset
spec:
updateStrategy:
type: RollingUpdate
selector:
matchLabels:
canary.release: "true"
containers:
- name: sidecar1
image: busybox:1.35.0
# ......

然后同樣需要給 test-pod 添加上 canary.release=true 這個(gè)標(biāo)簽:

apiVersion: v1
kind: Pod
metadata:
labels:
app: nginx
canary.release: "true"
name: test-pod
spec:
containers:
- name: app
image: nginx:1.7.9

更新后可以發(fā)現(xiàn) test-pod 的 sidecar 鏡像更新了,其他 Pod 沒有變化,這樣就實(shí)現(xiàn)了 sidecar 的灰度功能:

? kubectl describe pod test-pod
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Killing 7m53s kubelet Container sidecar1 definition changed, will be restarted
Normal Created 7m23s (x2 over 8m17s) kubelet Created container sidecar1
Normal Started 7m23s (x2 over 8m17s) kubelet Started container sidecar1
Normal Pulling 7m23s kubelet Pulling image "busybox"
Normal Pulled 7m23s kubelet Successfully pulled image "busybox" in 603.928658ms

熱升級(jí)

SidecarSet 原地升級(jí)會(huì)先停止舊版本的容器,然后創(chuàng)建新版本的容器,這種方式適合不影響 Pod 服務(wù)可用性的 sidecar 容器,比如說日志收集的 Agent。

但是對(duì)于很多代理或運(yùn)行時(shí)的 sidecar 容器,例如 Istio Envoy,這種升級(jí)方法就有問題了,Envoy 作為 Pod 中的一個(gè)代理容器,代理了所有的流量,如果直接重啟,Pod 服務(wù)的可用性會(huì)受到影響,如果需要單獨(dú)升級(jí) envoy sidecar,就需要復(fù)雜的優(yōu)雅終止和協(xié)調(diào)機(jī)制,所以我們?yōu)檫@種 sidecar 容器的升級(jí)提供了一種新的解決方案。

# hotupgrade-sidecarset.yaml
apiVersion: apps.kruise.io/v1alpha1
kind: SidecarSet
metadata:
name: hotupgrade-sidecarset
spec:
selector:
matchLabels:
app: hotupgrade
containers:
- name: sidecar
image: openkruise/hotupgrade-sample:sidecarv1
imagePullPolicy: Always
lifecycle:
postStart:
exec:
command:
- /bin/sh
- /migrate.sh
upgradeStrategy:
upgradeType: HotUpgrade
hotUpgradeEmptyImage: openkruise/hotupgrade-sample:empty

  • upgradeType?: HotUpgrade 代表該 sidecar 容器的類型是熱升級(jí)方案。
  • hotUpgradeEmptyImage?: 當(dāng)熱升級(jí) sidecar 容器時(shí),業(yè)務(wù)必須要提供一個(gè) empty 容器用于熱升級(jí)過程中的容器切換,empty 容器同 sidecar 容器具有相同的配置(除了鏡像地址),例如:command?、lifecycle?、probe 等,但是它不做任何工作。
  • lifecycle.postStart: 在 postStart 這個(gè) hook 中完成熱升級(jí)過程中的狀態(tài)遷移,該腳本需要由業(yè)務(wù)根據(jù)自身的特點(diǎn)自行實(shí)現(xiàn),例如:nginx 熱升級(jí)需要完成 Listen FD 共享以及流量排水(reload)操作。

整體來說熱升級(jí)特性總共包含以下兩個(gè)過程:

  • Pod 創(chuàng)建時(shí),注入熱升級(jí)容器。
  • 原地升級(jí)時(shí),完成熱升級(jí)流程。

注入熱升級(jí)容器

Pod 創(chuàng)建時(shí),SidecarSet Webhook 將會(huì)注入兩個(gè)容器:

  • {sidecarContainer.name}-1?: 如下圖所示 envoy-1?,這個(gè)容器代表正在實(shí)際工作的 sidecar 容器,例如:envoy:1.16.0。
  • {sidecarContainer.name}-2?: 如下圖所示 envoy-2?,這個(gè)容器是業(yè)務(wù)配置的 hotUpgradeEmptyImage? 容器,例如:empty:1.0,用于后面的熱升級(jí)機(jī)制。

圖片

注入熱升級(jí)容器

熱升級(jí)流程

熱升級(jí)流程主要分為三個(gè)步驟:

  • Upgrade: 將 empty 容器升級(jí)為當(dāng)前最新的 sidecar 容器,例如:envoy-2.Image = envoy:1.17.0
  • Migration?: lifecycle.postStart 完成熱升級(jí)流程中的狀態(tài)遷移,當(dāng)遷移完成后退出
  • Reset: 狀態(tài)遷移完成后,熱升級(jí)流程將設(shè)置 envoy-1 容器為 empty 鏡像,例如:envoy-1.Image = empty:1.0

上述三個(gè)步驟完成了熱升級(jí)中的全部流程,當(dāng)對(duì) Pod 執(zhí)行多次熱升級(jí)時(shí),將重復(fù)性的執(zhí)行上述三個(gè)步驟。

圖片

熱升級(jí)流程

這里我們以 OpenKruise 的官方示例來進(jìn)行說明,首先創(chuàng)建上面的 hotupgrade-sidecarset 這個(gè) SidecarSet。然后創(chuàng)建一個(gè)如下所示的 CloneSet 對(duì)象:

# hotupgrade-cloneset.yaml
apiVersion: apps.kruise.io/v1alpha1
kind: CloneSet
metadata:
name: busybox
labels:
app: hotupgrade
spec:
replicas: 1
selector:
matchLabels:
app: hotupgrade
template:
metadata:
labels:
app: hotupgrade
spec:
containers:
- name: busybox
image: openkruise/hotupgrade-sample:busybox

創(chuàng)建完成后,CloneSet 管理的 Pod 已經(jīng)注入 sidecar-1? 和 sidecar-2 兩個(gè)容器:

? kubectl get sidecarset hotupgrade-sidecarset
NAME MATCHED UPDATED READY AGE
hotupgrade-sidecarset 1 1 0 58s
? kubectl get pods -l app=hotupgrade
NAME READY STATUS RESTARTS AGE
busybox-nd5bp 3/3 Running 0 31s
? kubectl describe pod busybox-nd5bp
Name: busybox-nd5bp
Namespace: default
Node: node2/10.206.16.10
# ......
Controlled By: CloneSet/busybox
Containers:
sidecar-1:
Container ID: containerd://511aa4b60d36483177e92805653c1b618495e47d8d5de331008259f78b3be89e
Image: openkruise/hotupgrade-sample:sidecarv1
Image ID: docker.io/openkruise/hotupgrade-sample@sha256:3d677ca19712b67d2c264374736d71089d21e100eff341f6b4bb0f5288ec6f34
Environment:
IS_INJECTED: true
SIDECARSET_VERSION: (v1:metadata.annotations['version.sidecarset.kruise.io/sidecar-1'])
SIDECARSET_VERSION_ALT: (v1:metadata.annotations['versionalt.sidecarset.kruise.io/sidecar-1'])
# ......
sidecar-2:
Container ID: containerd://6b0678695ccb977695248e41108606b409ad0c7e3e4fe1ba9b48e839e3c235ef
Image: openkruise/hotupgrade-sample:empty
Image ID: docker.io/openkruise/hotupgrade-sample@sha256:606be602967c9f91c47e4149af4336c053e26225b717a1b5453ac8fa9a401cc5
Environment:
IS_INJECTED: true
SIDECARSET_VERSION: (v1:metadata.annotations['version.sidecarset.kruise.io/sidecar-2'])
SIDECARSET_VERSION_ALT: (v1:metadata.annotations['versionalt.sidecarset.kruise.io/sidecar-2'])
# ......
busybox:
Container ID: containerd://da7eebb0161bab37f7de75635e68c5284a973a21f6d3f095bb5e8212ac8ce908
Image: openkruise/hotupgrade-sample:busybox
Image ID: docker.io/openkruise/hotupgrade-sample@sha256:08f9ede05850686e1200240e5e376fc76245dd2eb56299060120b8c3dba46dc9
# ......
# ......
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 50s default-scheduler Successfully assigned default/busybox-nd5bp to node2
Normal Pulling 49s kubelet Pulling image "openkruise/hotupgrade-sample:sidecarv1"
Normal Pulled 41s kubelet Successfully pulled image "openkruise/hotupgrade-sample:sidecarv1" in 7.929984849s (7.929998445s including waiting)
Normal Created 41s kubelet Created container sidecar-1
Normal Started 41s kubelet Started container sidecar-1
Normal Pulling 36s kubelet Pulling image "openkruise/hotupgrade-sample:empty"
Normal Pulled 29s kubelet Successfully pulled image "openkruise/hotupgrade-sample:empty" in 7.434180553s (7.434189239s including waiting)
Normal Created 29s kubelet Created container sidecar-2
Normal Started 29s kubelet Started container sidecar-2
Normal Pulling 29s kubelet Pulling image "openkruise/hotupgrade-sample:busybox"
Normal Pulled 22s kubelet Successfully pulled image "openkruise/hotupgrade-sample:busybox" in 6.583450981s (6.583456512s including waiting)
Normal Created 22s kubelet Created container busybox
Normal Started 22s kubelet Started container busybox
......

busybox 主容器每 100 毫秒會(huì)請(qǐng)求一次 sidecar(versinotallow=v1)服務(wù):

? kubectl logs -f busybox-nd5bp -c busybox
I0404 09:12:26.513128 1 main.go:39] request sidecar server success, and response(body=This is version(v1) sidecar)
I0404 09:12:26.623496 1 main.go:39] request sidecar server success, and response(body=This is version(v1) sidecar)
I0404 09:12:26.733958 1 main.go:39] request sidecar server success, and response(body=This is version(v1) sidecar)
......

現(xiàn)在我們?nèi)ド?jí) sidecar 容器,將鏡像修改為 openkruise/hotupgrade-sample:sidecarv2:

? kubectl patch sidecarset hotupgrade-sidecarset --type='json' -p='[{"op": "replace", "path": "/spec/containers/0/image", "value": "openkruise/hotupgrade-sample:sidecarv2"}]'

更新后再去觀察 pod 的狀態(tài),可以看到 sidecar-2 鏡像正常更新了:

? kubectl get pods -l app=hotupgrade
NAME READY STATUS RESTARTS AGE
busybox-nd5bp 3/3 Running 2 (45s ago) 23m
? kubectl describe pods busybox-nd5bp
......
Events:
......
Normal Pulling 33s kubelet Pulling image "openkruise/hotupgrade-sample:sidecarv2"
Normal Killing 33s kubelet Container sidecar-2 definition changed, will be restarted
Normal Started 25s (x2 over 22m) kubelet Started container sidecar-2
Normal Created 25s (x2 over 22m) kubelet Created container sidecar-2
Normal Pulled 25s kubelet Successfully pulled image "openkruise/hotupgrade-sample:sidecarv2" in 8.169453753s (8.16946743s including waiting)
Normal Killing 14s kubelet Container sidecar-1 definition changed, will be restarted
Normal ResetContainerSucceed 14s sidecarset-controller reset sidecar container image empty successfully
Normal Pulling 14s kubelet Pulling image "openkruise/hotupgrade-sample:empty"
Normal Created 12s (x2 over 22m) kubelet Created container sidecar-1
Normal Started 12s (x2 over 22m) kubelet Started container sidecar-1
Normal Pulled 12s kubelet Successfully pulled image "openkruise/hotupgrade-sample:empty" in 1.766097364s (1.766109087s including waiting)

并且在更新過程中觀察 busybox 容器仍然會(huì)不斷請(qǐng)求 sidecar 服務(wù),但是并沒有失敗的請(qǐng)求出現(xiàn):

? kubectl logs -f busybox-nd5bp -c busybox
I0306 11:08:47.587727 1 main.go:39] request sidecar server success, and response(body=This is version(v1) sidecar)
I0404 09:14:28.588973 1 main.go:39] request sidecar server success, and response(body=This is version(v2) sidecar)
# ......

整個(gè)熱升級(jí)示例代碼可以參考倉(cāng)庫(kù)的實(shí)現(xiàn):https://github.com/openkruise/samples/tree/master/hotupgrade。

Container Restart

ContainerRecreateRequest? 控制器可以幫助用戶重啟/重建存量 Pod 中一個(gè)或多個(gè)容器。和 Kruise 提供的原地升級(jí)類似,當(dāng)一個(gè)容器重建的時(shí)候,Pod 中的其他容器還保持正常運(yùn)行,重建完成后,Pod 中除了該容器的 restartCount 增加以外不會(huì)有什么其他變化。

不過需要注意之前臨時(shí)寫到舊容器 rootfs? 中的文件會(huì)丟失,但是 volume mount 掛載卷中的數(shù)據(jù)都還存在。這個(gè)功能依賴于 kruise-daemon 組件來停止 Pod 容器。

為要重建容器的 Pod 提交一個(gè) ContainerRecreateRequest 自定義資源(縮寫 CRR):

# crr-demo.yaml
apiVersion: apps.kruise.io/v1alpha1
kind: ContainerRecreateRequest
metadata:
name: crr-dmo
spec:
podName: pod-name
containers: # 要重建的容器名字列表,至少要有 1 個(gè)
- name: app
- name: sidecar
strategy:
failurePolicy: Fail # 'Fail' 或 'Ignore',表示一旦有某個(gè)容器停止或重建失敗, CRR 立即結(jié)束
orderedRecreate: false # 'true' 表示要等前一個(gè)容器重建完成了,再開始重建下一個(gè)
terminationGracePeriodSeconds: 30 # 等待容器優(yōu)雅退出的時(shí)間,不填默認(rèn)用 Pod 中定義的
unreadyGracePeriodSeconds: 3 # 在重建之前先把 Pod 設(shè)為 not ready,并等待這段時(shí)間后再開始執(zhí)行重建
minStartedSeconds: 10 # 重建后新容器至少保持運(yùn)行這段時(shí)間,才認(rèn)為該容器重建成功
activeDeadlineSeconds: 300 # 如果 CRR 執(zhí)行超過這個(gè)時(shí)間,則直接標(biāo)記為結(jié)束(未結(jié)束的容器標(biāo)記為失?。?br> ttlSecondsAfterFinished: 1800 # CRR 結(jié)束后,過了這段時(shí)間自動(dòng)被刪除掉

一般來說,列表中的容器會(huì)一個(gè)個(gè)被停止,但可能同時(shí)在被重建和啟動(dòng),除非 orderedRecreate? 被設(shè)置為 true。unreadyGracePeriodSeconds? 功能依賴于 KruisePodReadinessGate? 這個(gè) feature-gate,后者會(huì)在每個(gè) Pod 創(chuàng)建的時(shí)候注入一個(gè) readinessGate?,否則,默認(rèn)只會(huì)給 Kruise 工作負(fù)載創(chuàng)建的 Pod 注入 readinessGate,也就是說只有這些 Pod 才能在 CRR 重建時(shí)使用 unreadyGracePeriodSeconds。

當(dāng)用戶創(chuàng)建了一個(gè) CRR,Kruise webhook 會(huì)把當(dāng)時(shí)容器的 containerID/restartCount 記錄到 spec.containers[x].statusContext? 之中。 在 kruise-daemon 執(zhí)行的過程中,如果它發(fā)現(xiàn)實(shí)際容器當(dāng)前的 containerID? 與 statusContext? 不一致或 restartCount 已經(jīng)變大,則認(rèn)為容器已經(jīng)被重建成功了(比如可能發(fā)生了一次原地升級(jí))。

圖片

容器重啟請(qǐng)求

一般情況下,kruise-daemon 會(huì)執(zhí)行 preStop hook 后把容器停掉,然后 kubelet 感知到容器退出,則會(huì)新建一個(gè)容器并啟動(dòng)。最后 kruise-daemon 看到新容器已經(jīng)啟動(dòng)成功超過 minStartedSeconds 時(shí)間后,會(huì)上報(bào)這個(gè)容器的 phase 狀態(tài)為 Succeeded。

如果容器重建和原地升級(jí)操作同時(shí)觸發(fā)了:

  • 如果 kubelet 根據(jù)原地升級(jí)要求已經(jīng)停止或重建了容器,kruise-daemon 會(huì)判斷容器重建已經(jīng)完成。
  • 如果 kruise-daemon 先停了容器,Kubelet 會(huì)繼續(xù)執(zhí)行原地升級(jí),即創(chuàng)建一個(gè)新版本容器并啟動(dòng)。
  • 如果針對(duì)一個(gè) Pod 提交了多個(gè) ContainerRecreateRequest 資源,會(huì)按時(shí)間先后一個(gè)個(gè)執(zhí)行。

ImagePullJob

NodeImage? 和 ImagePullJob 是從 Kruise v0.8.0 版本開始提供的 CRD。Kruise 會(huì)自動(dòng)為每個(gè)節(jié)點(diǎn)創(chuàng)建一個(gè) NodeImage,它包含了哪些鏡像需要在這個(gè) Node 上做預(yù)熱,比如我們這里 3 個(gè)節(jié)點(diǎn),則會(huì)自動(dòng)創(chuàng)建 3 個(gè) NodeImage 對(duì)象:

? kubectl get nodeimage
NAME DESIRED PULLING SUCCEED FAILED AGE
master1 0 0 0 0 5d
node1 0 0 0 0 5d
node2 0 0 0 0 5d

比如我們查看 node1 節(jié)點(diǎn)上的 NodeImage 對(duì)象:

? kubectl get nodeimage node1 -o yaml
apiVersion: apps.kruise.io/v1alpha1
kind: NodeImage
metadata:
name: node1
# ......
spec: {}
status:
desired: 0
failed: 0
pulling: 0
succeeded: 0

比如我們希望在這個(gè)節(jié)點(diǎn)上拉去一個(gè) ubuntu:latest 鏡像,則可以按照如下所示的去修改 spec:

......
spec:
images:
ubuntu: # 鏡像 name
tags:
- tag: latest # 鏡像 tag
pullPolicy:
ttlSecondsAfterFinished: 300 # [required] 拉取完成(成功或失?。┏^ 300s 后,將這個(gè)任務(wù)從 NodeImage 中清除
timeoutSeconds: 600 # [optional] 每一次拉取的超時(shí)時(shí)間, 默認(rèn)為 600
backoffLimit: 3 # [optional] 拉取的重試次數(shù),默認(rèn)為 3
activeDeadlineSeconds: 1200 # [optional] 整個(gè)任務(wù)的超時(shí)時(shí)間,無(wú)默認(rèn)值

更新后我們可以從 status 中看到拉取進(jìn)度以及結(jié)果,并且你會(huì)發(fā)現(xiàn)拉取完成 600s 后任務(wù)會(huì)被清除。

? kubectl describe nodeimage node1
Name: node1
Namespace:
# ......
Spec:
Images:
Ubuntu:
Tags:
Created At: 2023-04-04T09:29:18Z
Pull Policy:
Active Deadline Seconds: 1200
Backoff Limit: 3
Timeout Seconds: 600
Ttl Seconds After Finished: 300
Tag: latest
Status:
Desired: 1
Failed: 0
Image Statuses:
Ubuntu:
Tags:
Completion Time: 2023-04-04T09:29:28Z
Phase: Succeeded
Progress: 100
Start Time: 2023-04-04T09:29:18Z
Tag: latest
Pulling: 0
Succeeded: 1
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal PullImageSucceed 11s kruise-daemon-imagepuller Image ubuntu:latest, ecalpsedTime 10.066193581s

我們可以在 node1 節(jié)點(diǎn)上查看到這個(gè)鏡像已經(jīng)被拉取下來了:

ubuntu@node1:~$ sudo ctr -n k8s.io i ls  |grep ubuntu
docker.io/library/ubuntu:latest application/vnd.oci.image.index.v1+json sha256:67211c14fa74f070d27cc59d69a7fa9aeff8e28ea118ef3babc295a0428a6d21 28.2 MiB linux/amd64,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x io.cri-containerd.image=managed
docker.io/library/ubuntu@sha256:67211c14fa74f070d27cc59d69a7fa9aeff8e28ea118ef3babc295a0428a6d21 application/vnd.oci.image.index.v1+json sha256:67211c14fa74f070d27cc59d69a7fa9aeff8e28ea118ef3babc295a0428a6d21 28.2 MiB linux/amd64,linux/arm/v7,linux/arm64/v8,linux/ppc64le,linux/s390x io.cri-containerd.image=managed
ubuntu@node1:~$

此外用戶可以創(chuàng)建 ImagePullJob 對(duì)象,來指定一個(gè)鏡像要在哪些節(jié)點(diǎn)上做預(yù)熱。

圖片

比如創(chuàng)建如下所示的 ImagePullJob 資源對(duì)象:

apiVersion: apps.kruise.io/v1alpha1
kind: ImagePullJob
metadata:
name: job-with-always
spec:
image: nginx:1.9.1 # [required] 完整的鏡像名 name:tag
parallelism: 10 # [optional] 最大并發(fā)拉取的節(jié)點(diǎn)梳理, 默認(rèn)為 1
selector: # [optional] 指定節(jié)點(diǎn)的 名字列表 或 標(biāo)簽選擇器 (只能設(shè)置其中一種)
names:
- node1
- node2
matchLabels:
node-type: xxx
# podSelector: # [optional] pod label 選擇器來在這些 pod 所在節(jié)點(diǎn)上拉取鏡像, 與 selector 不能同時(shí)設(shè)置.
# pod-label: xxx
completionPolicy:
type: Always # [optional] 默認(rèn)為 Always
activeDeadlineSeconds: 1200 # [optional] 無(wú)默認(rèn)值, 只對(duì) Alway 類型生效
ttlSecondsAfterFinished: 300 # [optional] 無(wú)默認(rèn)值, 只對(duì) Alway 類型生效
pullPolicy: # [optional] 默認(rèn) backoffLimit=3, timeoutSecnotallow=600
backoffLimit: 3
timeoutSeconds: 300
pullSecrets:
- secret-name1
- secret-name2

我們可以在 selector? 字段中指定節(jié)點(diǎn)的名字列表或標(biāo)簽選擇器 (只能設(shè)置其中一種),如果沒有設(shè)置 selector 則會(huì)選擇所有節(jié)點(diǎn)做預(yù)熱?;蛘呖梢耘渲?nbsp;podSelector 來在這些 pod 所在節(jié)點(diǎn)上拉取鏡像,podSelector 與 selector 不能同時(shí)設(shè)置。

同時(shí),ImagePullJob 有兩種 completionPolicy 類型:

  • Always:表示這個(gè) job 是一次性預(yù)熱,不管成功、失敗都會(huì)結(jié)束。
  • activeDeadlineSeconds:整個(gè) job 的 deadline 結(jié)束時(shí)間。
  • ttlSecondsAfterFinished:結(jié)束后超過這個(gè)時(shí)間,自動(dòng)清理刪除 job。
  • Never:表示這個(gè) job 是長(zhǎng)期運(yùn)行、不會(huì)結(jié)束,并且會(huì)每天都會(huì)在匹配的節(jié)點(diǎn)上重新預(yù)熱一次指定的鏡像。

同樣如果你要預(yù)熱的鏡像來自私有倉(cāng)庫(kù),則可以通過 pullSecrets 來指定倉(cāng)庫(kù)的 Secret 信息。

如果這個(gè)鏡像來自一個(gè)私有倉(cāng)庫(kù),則可以通過 pullSecrets 來指定倉(cāng)庫(kù)的 Secret 信息。

# ...
spec:
pullSecrets:
- secret-name1
- secret-name2

因?yàn)?nbsp;ImagePullJob? 是一種 namespaced-scope 資源,所以這些 Secret 必須存在 ImagePullJob 所在的 namespace 中。然后你只需要在 pullSecrets 字段中寫上這些 secret 的名字即可。

容器啟動(dòng)順序

Container Launch Priority 提供了控制一個(gè) Pod 中容器啟動(dòng)順序的方法。通常來說 Pod 容器的啟動(dòng)和退出順序是由 Kubelet 管理的,Kubernetes 曾經(jīng)有一個(gè) KEP 計(jì)劃在 container 中增加一個(gè) type 字段來標(biāo)識(shí)不同類型容器的啟停優(yōu)先級(jí),但是由于sig-node 考慮到對(duì)現(xiàn)有代碼架構(gòu)的改動(dòng)太大,所以將該提案拒絕了。

這個(gè)功能作用在 Pod 對(duì)象上,不管它的 owner 是什么類型的,因此可以適用于 Deployment、CloneSet 以及其他的工作負(fù)載。

比如我們可以設(shè)置按照容器順序啟動(dòng),只需要在 Pod 中定義一個(gè) apps.kruise.io/container-launch-priority 的注解即可:

apiVersion: v1
kind: Pod
annotations:
apps.kruise.io/container-launch-priority: Ordered
spec:
containers:
- name: sidecar
# ...
- name: main
# ...

Kruise 會(huì)保證前面的容器(sidecar)會(huì)在后面容器(main)之前啟動(dòng)。

此外我們還可以按自定義順序啟動(dòng),但是需要在 Pod 容器中添加 KRUISE_CONTAINER_PRIORITY 這個(gè)環(huán)境變量:

apiVersion: v1
kind: Pod
spec:
containers:
- name: main
# ...
- name: sidecar
env:
- name: KRUISE_CONTAINER_PRIORITY
value: "1"
# ...

該環(huán)境變量值的范圍在 [-2147483647, 2147483647],不寫默認(rèn)是 0,權(quán)重高的容器,會(huì)保證在權(quán)重低的容器之前啟動(dòng),但是需要注意相同權(quán)重的容器不保證啟動(dòng)順序。

資源分發(fā)

在對(duì) Secret、ConfigMap 等命名空間級(jí)別資源進(jìn)行跨 namespace 分發(fā)及同步的場(chǎng)景中,原生 Kubernetes 目前只支持用戶手動(dòng)分發(fā)與同步,十分地不方便。比如:

  • 當(dāng)用戶需要使用 SidecarSet 的 imagePullSecrets 能力時(shí),要先重復(fù)地在相關(guān) namespaces 中創(chuàng)建對(duì)應(yīng)的 Secret,并且需要確保這些 Secret 配置的正確性和一致性。
  • 當(dāng)用戶想要采用 ConfigMap 來配置一些通用的環(huán)境變量時(shí),往往需要在多個(gè) namespaces 做 ConfigMap 的下發(fā),并且后續(xù)的修改往往也要求多 namespaces 之間保持同步。
  • 在多個(gè)命名空間中的 Ingress 對(duì)象需要使用同一個(gè) Secret 對(duì)象

面對(duì)這些需要跨命名空間進(jìn)行資源分發(fā)和多次同步的場(chǎng)景,OpenKruise 設(shè)計(jì)了一個(gè)新的 CRD - ResourceDistribution,可以更便捷的自動(dòng)化分發(fā)和同步這些資源。

ResourceDistribution? 目前支持 Secret? 和 ConfigMap 兩類資源的分發(fā)和同步。

ResourceDistribution? 是全局的 CRD,其主要由 resource? 和 targets? 兩個(gè)字段構(gòu)成,其中 resource? 字段用于描述用戶所要分發(fā)的資源,targets 字段用于描述用戶所要分發(fā)的目標(biāo)命名空間。

apiVersion: apps.kruise.io/v1alpha1
kind: ResourceDistribution
metadata:
name: sample
spec:
resource: ... ...
targets: ... ...

其中 resource 字段必須是一個(gè)完整、正確的資源描述,如下所示:

apiVersion: apps.kruise.io/v1alpha1
kind: ResourceDistribution
metadata:
name: sample
spec:
resource:
apiVersion: v1
kind: ConfigMap
metadata:
name: game-demo
data:
game.properties: |
enemy.types=aliens,monsters
player.maximum-lives=5
player_initial_lives: "3"
ui_properties_file_name: user-interface.properties
user-interface.properties: |
color.good=purple
color.bad=yellow
allow.textmode=true
targets: ... ...

用戶可以先在本地某個(gè)命名空間中創(chuàng)建相應(yīng)資源并進(jìn)行測(cè)試,確認(rèn)資源配置正確后再拷貝過來。

targets? 字段目前支持四種規(guī)則來描述用戶所要分發(fā)的目標(biāo)命名空間,包括 allNamespaces?、includedNamespaces?、namespaceLabelSelector? 以及 excludedNamespaces:

  • allNamespaces: bool 值,如果為 true,則分發(fā)至所有命名空間。
  • includedNamespaces: 通過 Name 來匹配目標(biāo)命名空間。
  • namespaceLabelSelector:通過 LabelSelector 來匹配目標(biāo)命名空間。
  • excludedNamespaces: 通過 Name 來排除某些不想分發(fā)的命名空間。

allNamespaces?、includedNamespaces?、namespaceLabelSelector? 之間是**或(OR)**的關(guān)系,而 excludedNamespaces? 一旦被配置,則會(huì)顯式地排除掉這些命名空間。另外,targets? 還將自動(dòng)忽略 kube-system? 和 kube-public 兩個(gè)命名空間。

一個(gè)配置正確的 targets 字段如下所示:

apiVersion: apps.kruise.io/v1alpha1
kind: ResourceDistribution
metadata:
name: sample
spec:
resource: ... ...
targets:
includedNamespaces:
list:
- name: ns-1
- name: ns-4
namespaceLabelSelector:
matchLabels:
group: test
excludedNamespaces:
list:
- name: ns-3

該配置表示該 ResourceDistribution? 的目標(biāo)命名空間一定會(huì)包含 ns-1? 和 ns-4?,并且 Labels 滿足 namespaceLabelSelector? 的命名空間也會(huì)被包含進(jìn)目標(biāo)命名空間,但是,即使 ns-3? 即使?jié)M足 namespaceLabelSelector? 也不會(huì)被包含,因?yàn)樗呀?jīng)在 excludedNamespaces 中被顯式地排除了。

如果同步的資源需要更新則可以去更新 resource? 字段,更新后會(huì)自動(dòng)地對(duì)所有目標(biāo)命名空間中的資源進(jìn)行同步更新。每一次更新資源時(shí),ResourceDistribution? 都會(huì)計(jì)算新版本資源的哈希值,并記錄到資源的 Annotations 之中,當(dāng) ResourceDistribution 發(fā)現(xiàn)新版本的資源與目前資源的哈希值不同時(shí),才會(huì)對(duì)資源進(jìn)行更新。

apiVersion: v1
kind: ConfigMap
metadata:
name: demo
annotations:
kruise.io/resourcedistribution.resource.from: sample
kruise.io/resourcedistribution.resource.distributed.timestamp: 2021-09-06 08:44:52.7861421 +0000 UTC m=+12896.810364601
kruise.io/resourcedistribution.resource.hashcode: 0821a13321b2c76b5bd63341a0d97fb46bfdbb2f914e2ad6b613d10632fa4b63
... ...

當(dāng)然非常不建議用戶繞過 ResourceDistribution 直接對(duì)資源進(jìn)行修改,除非用戶知道自己在做什么。

  • 因?yàn)橹苯有薷馁Y源后,資源的哈希值不會(huì)被自動(dòng)計(jì)算,因此,下次 resource 字段被修改后,ResourceDistribution 可能將用戶對(duì)這些資源的直接修改覆蓋掉。
  • ResourceDistribution? 通過 kruise.io/resourcedistribution.resource.from? 來判斷資源是否由該 ResourceDistribution? 分發(fā),如果該 Annotation 被修改或刪除,則被修改的資源會(huì)被 ResourceDistribution? 當(dāng)成沖突資源,并且無(wú)法通過 ResourceDistribution 進(jìn)行同步更新。

除了這些增強(qiáng)控制器之外 OpenKruise 還有很多高級(jí)的特性,可以前往官網(wǎng) https://openkruise.io 了解更多信息。

責(zé)任編輯:姜華 來源: k8s技術(shù)圈
相關(guān)推薦

2023-04-04 07:25:46

KubernetesOpenKruise

2023-09-03 19:43:46

htmxJavaScript網(wǎng)絡(luò)

2013-05-15 09:14:01

2011-01-05 11:12:34

C++

2011-09-15 14:00:52

IOS應(yīng)用SpoolInstapaper

2021-01-27 10:01:46

MySQL數(shù)據(jù)庫(kù)SQLX

2022-09-21 10:50:43

pickledillPython

2011-05-26 17:55:08

2009-01-05 10:30:23

賽門鐵克Veritas數(shù)據(jù)中心

2020-06-30 08:08:25

k8s監(jiān)控

2023-05-10 08:17:22

合并事件推送

2009-12-29 14:18:43

ADO.NET2.0

2022-04-22 13:32:01

K8s容器引擎架構(gòu)

2015-09-23 11:27:20

Office 2016ISO鏡像微軟

2013-08-20 17:46:43

通達(dá)OA

2015-06-01 16:09:02

聯(lián)想

2012-08-28 13:37:30

2010-08-25 10:42:20

GroovyGroovy++

2025-03-26 00:00:00

k8m工具Kubernete
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)