使用 kubectl patch 就地更新 API 对象
此任务演示如何使用 kubectl patch
就地更新 API 对象。本任务中的练习演示了策略合并补丁和 JSON 合并补丁。
准备工作
你需要拥有一个 Kubernetes 集群,并且 kubectl 命令行工具已配置为与你的集群通信。建议在至少有两个节点不充当控制平面主机的集群上运行本教程。如果你还没有集群,可以使用 minikube 创建一个,或者使用这些 Kubernetes 操场之一
要检查版本,请输入 kubectl version
。
使用策略合并补丁更新 Deployment
这是一个具有两个副本的 Deployment 的配置文件。每个副本是一个 Pod,其中有一个容器
apiVersion: apps/v1
kind: Deployment
metadata:
name: patch-demo
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: patch-demo-ctr
image: nginx
tolerations:
- effect: NoSchedule
key: dedicated
value: test-team
创建 Deployment
kubectl apply -f https://k8s.io/examples/application/deployment-patch.yaml
查看与你的 Deployment 关联的 Pod
kubectl get pods
输出显示 Deployment 有两个 Pod。1/1
表示每个 Pod 有一个容器
NAME READY STATUS RESTARTS AGE
patch-demo-28633765-670qr 1/1 Running 0 23s
patch-demo-28633765-j5qs3 1/1 Running 0 23s
记下正在运行的 Pod 的名称。稍后,你将看到这些 Pod 被终止并被新的 Pod 替换。
此时,每个 Pod 都有一个运行 nginx 镜像的容器。现在假设你希望每个 Pod 有两个容器:一个运行 nginx,一个运行 redis。
创建一个名为 patch-file.yaml
的文件,其内容如下
spec:
template:
spec:
containers:
- name: patch-demo-ctr-2
image: redis
修补你的 Deployment
kubectl patch deployment patch-demo --patch-file patch-file.yaml
查看已修补的 Deployment
kubectl get deployment patch-demo --output yaml
输出显示 Deployment 中的 PodSpec 有两个容器
containers:
- image: redis
imagePullPolicy: Always
name: patch-demo-ctr-2
...
- image: nginx
imagePullPolicy: Always
name: patch-demo-ctr
...
查看与你的已修补 Deployment 关联的 Pod
kubectl get pods
输出显示正在运行的 Pod 的名称与之前运行的 Pod 的名称不同。Deployment 终止了旧 Pod 并创建了两个新的 Pod,它们符合更新后的 Deployment 规范。2/2
表示每个 Pod 有两个容器
NAME READY STATUS RESTARTS AGE
patch-demo-1081991389-2wrn5 2/2 Running 0 1m
patch-demo-1081991389-jmg7b 2/2 Running 0 1m
仔细查看其中一个 patch-demo Pod
kubectl get pod <your-pod-name> --output yaml
输出显示 Pod 有两个容器:一个运行 nginx,一个运行 redis
containers:
- image: redis
...
- image: nginx
...
关于策略合并补丁的注意事项
你在前面的练习中执行的补丁称为*策略合并补丁*。请注意,补丁没有替换 containers
列表。相反,它向列表中添加了一个新的容器。换句话说,补丁中的列表与现有列表合并。当你在列表上使用策略合并补丁时,并非总是如此。在某些情况下,列表被替换,而不是合并。
使用策略合并补丁时,列表是替换还是合并取决于其补丁策略。补丁策略由 Kubernetes 源代码中字段标签中的 patchStrategy
键的值指定。例如,PodSpec
结构体的 Containers
字段具有 merge
的 patchStrategy
type PodSpec struct {
...
Containers []Container `json:"containers" patchStrategy:"merge" patchMergeKey:"name" ...`
...
}
你还可以在 OpenApi 规范 中看到补丁策略
"io.k8s.api.core.v1.PodSpec": {
...,
"containers": {
"description": "List of containers belonging to the pod. ...."
},
"x-kubernetes-patch-merge-key": "name",
"x-kubernetes-patch-strategy": "merge"
}
你还可以在 Kubernetes API 文档 中看到补丁策略。
创建一个名为 patch-file-tolerations.yaml
的文件,其内容如下
spec:
template:
spec:
tolerations:
- effect: NoSchedule
key: disktype
value: ssd
修补你的 Deployment
kubectl patch deployment patch-demo --patch-file patch-file-tolerations.yaml
查看已修补的 Deployment
kubectl get deployment patch-demo --output yaml
输出显示 Deployment 中的 PodSpec 只有一个容忍度(Toleration)
tolerations:
- effect: NoSchedule
key: disktype
value: ssd
请注意,PodSpec 中的 tolerations
列表被替换,而不是合并。这是因为 PodSpec 的 Tolerations 字段在其字段标签中没有 patchStrategy
键。因此,策略合并补丁使用默认补丁策略,即 replace
。
type PodSpec struct {
...
Tolerations []Toleration `json:"tolerations,omitempty" protobuf:"bytes,22,opt,name=tolerations"`
...
}
使用 JSON 合并补丁更新 Deployment
策略合并补丁不同于 JSON 合并补丁。使用 JSON 合并补丁,如果你想更新列表,你必须指定整个新列表。新列表会完全替换现有列表。
kubectl patch
命令有一个 type
参数,你可以将其设置为以下值之一
参数值 | 合并类型 |
---|---|
json | JSON 补丁,RFC 6902 |
merge | JSON 合并补丁,RFC 7386 |
strategic | 策略合并补丁 |
有关 JSON 补丁和 JSON 合并补丁的比较,请参见 JSON Patch and JSON Merge Patch。
type
参数的默认值为 strategic
。因此在前面的练习中,你执行的是策略合并补丁。
接下来,在你的同一个 Deployment 上执行 JSON 合并补丁。创建一个名为 patch-file-2.yaml
的文件,其内容如下
spec:
template:
spec:
containers:
- name: patch-demo-ctr-3
image: gcr.io/google-samples/hello-app:2.0
在你的补丁命令中,将 type
设置为 merge
kubectl patch deployment patch-demo --type merge --patch-file patch-file-2.yaml
查看已修补的 Deployment
kubectl get deployment patch-demo --output yaml
你在补丁中指定的 containers
列表只有一个容器。输出显示你的一容器列表替换了现有的 containers
列表。
spec:
containers:
- image: gcr.io/google-samples/hello-app:2.0
...
name: patch-demo-ctr-3
列出正在运行的 Pod
kubectl get pods
在输出中,你可以看到现有 Pod 已终止,并创建了新的 Pod。1/1
表示每个新 Pod 只运行一个容器。
NAME READY STATUS RESTARTS AGE
patch-demo-1307768864-69308 1/1 Running 0 1m
patch-demo-1307768864-c86dc 1/1 Running 0 1m
使用带 retainKeys 策略的策略合并补丁更新 Deployment
这是一个使用 RollingUpdate
策略的 Deployment 配置文件
apiVersion: apps/v1
kind: Deployment
metadata:
name: retainkeys-demo
spec:
selector:
matchLabels:
app: nginx
strategy:
rollingUpdate:
maxSurge: 30%
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: retainkeys-demo-ctr
image: nginx
创建 Deployment
kubectl apply -f https://k8s.io/examples/application/deployment-retainkeys.yaml
此时,部署已创建并正在使用 RollingUpdate
策略。
创建一个名为 patch-file-no-retainkeys.yaml
的文件,其内容如下
spec:
strategy:
type: Recreate
修补你的 Deployment
kubectl patch deployment retainkeys-demo --type strategic --patch-file patch-file-no-retainkeys.yaml
在输出中,你可以看到当为 spec.strategy.rollingUpdate
定义了值时,不能将 type
设置为 Recreate
The Deployment "retainkeys-demo" is invalid: spec.strategy.rollingUpdate: Forbidden: may not be specified when strategy `type` is 'Recreate'
更新 type
值时,删除 spec.strategy.rollingUpdate
值的方法是使用策略合并的 retainKeys
策略。
创建另一个名为 patch-file-retainkeys.yaml
的文件,其内容如下
spec:
strategy:
$retainKeys:
- type
type: Recreate
通过此补丁,我们表明我们只想保留 strategy
对象的 type
键。因此,rollingUpdate
将在补丁操作期间被移除。
再次使用此新补丁修补你的 Deployment
kubectl patch deployment retainkeys-demo --type strategic --patch-file patch-file-retainkeys.yaml
检查 Deployment 的内容
kubectl get deployment retainkeys-demo --output yaml
输出显示 Deployment 中的策略对象不再包含 rollingUpdate
键
spec:
strategy:
type: Recreate
template:
关于使用 retainKeys 策略的策略合并补丁的注意事项
你在前面的练习中执行的补丁称为*带 retainKeys 策略的策略合并补丁*。此方法引入了一个新的指令 $retainKeys
,它具有以下策略
- 它包含一个字符串列表。
- 所有需要保留的字段都必须存在于
$retainKeys
列表中。 - 存在的字段将与活动对象合并。
- 修补时,所有缺失的字段都将被清除。
$retainKeys
列表中的所有字段必须是补丁中存在的字段的超集或相同。
retainKeys
策略不适用于所有对象。它只在 Kubernetes 源代码中字段标签中的 patchStrategy
键的值包含 retainKeys
时才起作用。例如,DeploymentSpec
结构体的 Strategy
字段具有 retainKeys
的 patchStrategy
type DeploymentSpec struct {
...
// +patchStrategy=retainKeys
Strategy DeploymentStrategy `json:"strategy,omitempty" patchStrategy:"retainKeys" ...`
...
}
你还可以在 OpenApi 规范 中看到 retainKeys
策略
"io.k8s.api.apps.v1.DeploymentSpec": {
...,
"strategy": {
"$ref": "#/definitions/io.k8s.api.apps.v1.DeploymentStrategy",
"description": "The deployment strategy to use to replace existing pods with new ones.",
"x-kubernetes-patch-strategy": "retainKeys"
},
....
}
你还可以在 Kubernetes API 文档 中看到 retainKeys
策略。
kubectl patch 命令的其他形式
kubectl patch
命令接受 YAML 或 JSON。它既可以接受文件作为补丁,也可以直接在命令行上接受补丁。
创建一个名为 patch-file.json
的文件,其内容如下
{
"spec": {
"template": {
"spec": {
"containers": [
{
"name": "patch-demo-ctr-2",
"image": "redis"
}
]
}
}
}
}
以下命令是等效的
kubectl patch deployment patch-demo --patch-file patch-file.yaml
kubectl patch deployment patch-demo --patch 'spec:\n template:\n spec:\n containers:\n - name: patch-demo-ctr-2\n image: redis'
kubectl patch deployment patch-demo --patch-file patch-file.json
kubectl patch deployment patch-demo --patch '{"spec": {"template": {"spec": {"containers": [{"name": "patch-demo-ctr-2","image": "redis"}]}}}}'
使用带有 --subresource
的 kubectl patch
更新对象的副本计数
--subresource=[subresource-name]
标志与 kubectl 命令(如 get、patch、edit、apply 和 replace)一起使用,用于获取和更新你指定的资源的 status
、scale
和 resize
子资源。你可以为任何 Kubernetes API 资源(内置和 CR)指定子资源,这些资源具有 status
、scale
或 resize
子资源。
例如,Deployment 具有 status
子资源和 scale
子资源,因此你可以使用 kubectl
仅获取或修改 Deployment 的 status
子资源。
这是一个具有两个副本的 Deployment 的清单
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 2 # tells deployment to run 2 pods matching the template
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
创建 Deployment
kubectl apply -f https://k8s.io/examples/application/deployment.yaml
查看与你的 Deployment 关联的 Pod
kubectl get pods -l app=nginx
在输出中,你可以看到 Deployment 有两个 Pod。例如
NAME READY STATUS RESTARTS AGE
nginx-deployment-7fb96c846b-22567 1/1 Running 0 47s
nginx-deployment-7fb96c846b-mlgns 1/1 Running 0 47s
现在,使用 --subresource=[subresource-name]
标志修补该 Deployment
kubectl patch deployment nginx-deployment --subresource='scale' --type='merge' -p '{"spec":{"replicas":3}}'
输出为:
scale.autoscaling/nginx-deployment patched
查看与你的已修补 Deployment 关联的 Pod
kubectl get pods -l app=nginx
在输出中,你可以看到创建了一个新的 Pod,因此现在你有 3 个正在运行的 Pod。
NAME READY STATUS RESTARTS AGE
nginx-deployment-7fb96c846b-22567 1/1 Running 0 107s
nginx-deployment-7fb96c846b-lxfr2 1/1 Running 0 14s
nginx-deployment-7fb96c846b-mlgns 1/1 Running 0 107s
查看已修补的 Deployment
kubectl get deployment nginx-deployment -o yaml
...
spec:
replicas: 3
...
status:
...
availableReplicas: 3
readyReplicas: 3
replicas: 3
注意
如果你运行kubectl patch
并为不支持特定子资源的资源指定 --subresource
标志,API 服务器将返回 404 Not Found 错误。总结
在本练习中,你使用 kubectl patch
更改了 Deployment 对象的实时配置。你没有更改最初用于创建 Deployment 对象的配置文件。用于更新 API 对象的其他命令包括 kubectl annotate、kubectl edit、kubectl replace、kubectl scale 和 kubectl apply。