基于 Kubernetes 1.22 版本
一、基础概念
在了解 Deployment 之前,先来简单了解下 Replication Controller(RC)和 Replica Set(RS)。
RC 是 Kubemetes 的核心概念之一,简单来说,它其实是定义了一个期望的场景, 即声明某种 Pod 的副本数量在任意时刻都符合某个预期值。RC 的定义包括 Pod 期待的副本数(replicas)、用于筛选目标 Pod Label Selector、Pod 的副本数量小于预期数量时用于创建新 Pod 的模板(template)。
Replica Set ,官方解释为“下一代的 RC ”,它与 RC 最大的区别是 Replica Set 支持基于集合的 Label selector,其余基本一致。
Deployment 为 Pod 和 ReplicaSet 提供声明性更新,它的出现为了更好地解决 Pod 的编排问题,它在内部使用了 Replica Set 来实现目的,我们都可以把它看作 RC 的升级。
基本上,Replica Set 和 Deployment 这两个重要资源对象已经替换了之前的 RC 的作用,官方也是推荐用这个。
Deployment 的典型使用场景有以下几个:
• 创建 Deployment 对象来生成对应的 Replica Set 井完成 Pod 副本的创建过程。检查 Deployment 的状态来看部署动作是否完成( Pod 副本的数量是否达到预期的值)
• 更新 Deployment 的 PodTemplateSpec 来声明 Pod 的新状态,一个新的 ReplicaSet 被创建,Deployment 将会以受控速率将 Pod 从旧 ReplicaSet 移动到新 ReplicaSet中。
• 如果当前 Deployment 不稳定,则回滚到一个早先的 Deployment 版本。
• 扩容 Deployment 以承受更高负载。
• 暂停 Deployment 以便于一次性修改多个 PodTemplateSpec 的配置项,之后再恢复 Deployment ,进行新的部署发布。
• 查看 Deployment 的状态,以此作为发布是否成功的指标。
• 清理不再需要的旧版本 ReplicaSets。
官方文档:https://kubernetes.io/docs/concepts/workloads/controllers/deployment/
二、基本使用
我们来看一个简单 Deployment 示例,它创建了一个 ReplicaSet 来启动三个 nginx Pod:
[root@master ~]# vim nginx-deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3 # 副本数
selector: # 定义了Deployment如何找到要管理的 Pod,与template的labels对应。
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.18.0
ports:
- containerPort: 80
[root@master ~]# kubectl apply -f nginx-deployment.yaml --record
deployment.apps/nginx-deployment created
注:
--record:记录当前命令到正在创建或更新的资源的注释中
查看:
[root@master ~]# kubectl get deployments # 查看部署
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 34s
注:
NAME:列出命名空间中deployment的名称。
READY:显示有多少应用程序副本可供您的用户使用,它遵循准备/期望的模式。
UP-TO-DATE: 显示已更新以达到所需状态的副本数。
AVAILABLE:显示有多少应用程序副本可供您的用户使用。
AGE:显示应用程序运行的时间。
[root@master ~]# kubectl get pods -o=wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deployment-7848d4b86f-4h5rj 1/1 Running 0 11m 10.244.2.19 node2 <none> <none>
nginx-deployment-7848d4b86f-wkz9c 1/1 Running 0 11m 10.244.1.42 node1 <none> <none>
nginx-deployment-7848d4b86f-xrgjx 1/1 Running 0 11m 10.244.2.20 node2 <none> <none>
[root@master ~]# kubectl rollout status deployment nginx-deployment # 查看部署状态
deployment "nginx-deployment" successfully rolled out
三、更新
Deployment 更新采用滚动更新策略,过程就是 Deployment 通过创建新的 ReplicaSet 并将其扩展到 3 个副本以及将旧的 ReplicaSet 缩小到 0 个副本来更新 Pod。
上述例子中 nginx 版本为1.18.0,现在将它升级到1.20.0,有下面两种方式。
方法1:
# 更新镜像
[root@master ~]# kubectl set image deployment/nginx-deployment nginx=nginx:1.20.0 --record
deployment.apps/nginx-deployment image updated
# 查看更新状态
[root@master ~]# kubectl rollout status deployment/nginx-deployment
Waiting for deployment "nginx-deployment" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish: 1 old replicas are pending termination...
Waiting for deployment "nginx-deployment" rollout to finish: 1 old replicas are pending termination...
deployment "nginx-deployment" successfully rolled out
# 检查版本
[root@master ~]# kubectl exec nginx-deployment-84f4dd795b-95gpn -- nginx -v
nginx version: nginx/1.20.0
# 查看rs
[root@master ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-579fdb4c89 0 0 0 74s
nginx-deployment-84f4dd795b 3 3 3 55s
方法2:
使用 edit 修改 Deploym 的 .spec.template.spec.containers[0].image 将 nginx:1.18.0 改为 nginx:1.20.0
# 更新镜像
[root@master ~]# kubectl edit deployments.apps nginx-deployment
deployment.apps/nginx-deployment edited
# 查看更新状态
[root@master ~]# kubectl rollout status deployment/nginx-deployment
Waiting for deployment "nginx-deployment" rollout to finish: 2 out of 3 new replicas have been updated...
Waiting for deployment "nginx-deployment" rollout to finish: 1 old replicas are pending termination...
Waiting for deployment "nginx-deployment" rollout to finish: 1 old replicas are pending termination...
deployment "nginx-deployment" successfully rolled out
查看 nginx-deployment 的详细信息:
[root@master ~]# kubectl describe deployments.apps nginx-deployment
Name: nginx-deployment
Namespace: default
CreationTimestamp: Wed, 03 Nov 2021 22:41:50 +0800
Labels: app=nginx
Annotations: deployment.kubernetes.io/revision: 2
Selector: app=nginx
Replicas: 3 desired | 3 updated | 3 total | 3 available | 0 unavailable
StrategyType: RollingUpdate
MinReadySeconds: 0
RollingUpdateStrategy: 25% max unavailable, 25% max surge
Pod Template:
Labels: app=nginx
Containers:
nginx:
Image: nginx:1.20.0
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
Conditions:
Type Status Reason
---- ------ ------
Available True MinimumReplicasAvailable
Progressing True NewReplicaSetAvailable
OldReplicaSets: <none>
NewReplicaSet: nginx-deployment-84f4dd795b (3/3 replicas created)
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal ScalingReplicaSet 6m7s deployment-controller Scaled up replica set nginx-deployment-67dfd6c8f9 to 3
Normal ScalingReplicaSet 5m5s deployment-controller Scaled up replica set nginx-deployment-84f4dd795b to 1
Normal ScalingReplicaSet 5m3s deployment-controller Scaled down replica set nginx-deployment-67dfd6c8f9 to 2
Normal ScalingReplicaSet 5m3s deployment-controller Scaled up replica set nginx-deployment-84f4dd795b to 2
Normal ScalingReplicaSet 5m2s deployment-controller Scaled down replica set nginx-deployment-67dfd6c8f9 to 1
Normal ScalingReplicaSet 5m2s deployment-controller Scaled up replica set nginx-deployment-84f4dd795b to 3
Normal ScalingReplicaSet 5m1s deployment-controller Scaled down replica set nginx-deployment-67dfd6c8f9 to 0
在这里我们可以看到,当第一次创建 Deployment 时,它创建了一个 ReplicaSet 并直接将其扩展到 3 个副本。当更新 Deployment 时,它创建了一个新的 ReplicaSet 并将其放大到 1,然后将旧的 ReplicaSet 缩小到 2,这样至少有 2 个 Pod 可用,最多创建 4 个 Pod。然后它使用滚动更新策略继续扩大和缩小新的和旧的 ReplicaSet。最后,将在新 ReplicaSet 中拥有 3 个可用副本,而旧 ReplicaSet 将缩减为 0。
Deployment 确保在更新时只有一定数量的 Pod 关闭。默认情况下,它确保至少 75% 的所需 Pod 数量已启动(最多 25% 不可用)。
Deployment 还确保在所需的 Pod 数量之上只创建一定数量的 Pod。默认情况下,它确保最多 125% 的所需 Pod 数量启动(最大激增 25%)。
例如,我们仔细查看上面的 Deployment,会看到它首先创建了一个新 Pod,然后删除了一些旧 Pod,并创建了新 Pod。在有足够数量的新 Pod 出现之前它不会杀死旧 Pod,并且在有足够数量的旧 Pod 被杀死之前不会创建新 Pod。它确保至少有 2 个 Pod 可用,并且总共有最多 4 个 Pod 可用。
四、回滚
有时候我们可能需要回滚到上一个版本,默认情况下,所有 Deployment 的 rollout 历史都保存在系统中,以便随时回滚,我们可以通过修改修订历史限制来更改它。
需要注意的是:当一个 Deployment 的 rollout 被触发时,一个 Deployment 的修订版本被创建,但是也仅当 Deployment 的 Pod 模板 ( .spec.template) 发生更改时才会创建新修订版本。例如,如果更新模板的标签或容器映像、其他更新或者扩展部署,是不会创建新修订版本。这意味着当我们回滚到早期版本时,只会回滚 Deployment 的 Pod 模板部分。
现在我们将 nginx 从1.20.0 回滚到1.18.0。
1、先检查此 Deployment 的修订版本:
[root@master ~]# kubectl rollout history deployment nginx-deployment
deployment.apps/nginx-deployment
REVISION CHANGE-CAUSE
1 kubectl apply --filename=nginx-deployment.yaml --record=true
2 kubectl set image deployment/nginx-deployment nginx=nginx:1.20.0 --record=true
2、查看版本的详细信息,确定要回滚的版本
[root@master ~]# kubectl rollout history deployment nginx-deployment --revision=1
deployment.apps/nginx-deployment with revision #1
Pod Template:
Labels: app=nginx
pod-template-hash=67dfd6c8f9
Annotations: kubernetes.io/change-cause: kubectl apply --filename=nginx-deployment.yaml --record=true
Containers:
nginx:
Image: nginx:1.18.0
Port: 80/TCP
Host Port: 0/TCP
Environment: <none>
Mounts: <none>
Volumes: <none>
3、回滚到上一个版本
[root@master ~]# kubectl rollout undo deployment nginx-deployment
deployment.apps/nginx-deployment rolled back
# 当然我们可以指定回滚到特定修订
[root@master ~]# kubectl rollout undo deployment nginx-deployment --to-revision=2
4、检查验证
[root@master ~]# kubectl get deployments.apps nginx-deployment
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 10m
[root@master ~]# kubectl describe deployments.apps nginx-deployment | grep -i image
Image: nginx:1.18.0
[root@master ~]# kubectl exec nginx-deployment-67dfd6c8f9-qrkwk -- nginx -v
nginx version: nginx/1.18.0
五、扩容和缩容
在实际生产系统中,我们经常会遇某个服务需要扩容或者缩容场景,我们可以利用 Deployment Scale 机制来完成这些工作。
扩容和缩容操作有手动和自动两种模式:
• 手动模式:通过执行 kubectl scale 命令对一个 Deployment 进行 Pod 副本数量的设置即可。
• 自动模式:根据某个性能指标或者自定义业务指标,并指定 Pod 副本数量的范围,系统将自动在这个范围内根据性能指标自动进行调整。
1、手动
手动扩容和缩容,通过调整 replicas 数量来实现:
[root@master ~]# kubectl scale deployment nginx-deployment --replicas=5
deployment.apps/nginx-deployment scaled
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-67dfd6c8f9-jxtd8 1/1 Running 0 16m
nginx-deployment-67dfd6c8f9-mnnq7 1/1 Running 0 10s
nginx-deployment-67dfd6c8f9-pd7n4 1/1 Running 0 16m
nginx-deployment-67dfd6c8f9-xc4zb 1/1 Running 0 16m
nginx-deployment-67dfd6c8f9-zhp9n 1/1 Running 0 10s
[root@master ~]# kubectl scale deployment nginx-deployment --replicas=2
deployment.apps/nginx-deployment scaled
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-67dfd6c8f9-jxtd8 1/1 Running 0 19m
nginx-deployment-67dfd6c8f9-pd7n4 1/1 Running 0 19m
2、自动
推荐阅读官方文档:https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/
自动调整模式是通过 Horizontal Pod Autoscaler(HPA)控制器根据某个性能指标或者自定义业务指标来自动调整的,HPA 不适用于无法缩放的对象,例如 DaemonSet。
HPA 会定期(默认为 15 秒)根据定义中指定的指标(例如平均 CPU 利用率、平均内存利用率或任何其他自定义指标)查询资源利用率以调整副本数量。
所以前提是我们能获取到 Pod 的资源指标,这些指标我们可以通过 Metrics API 获取,下面我们先装一下 Metrics Server。官方文档:https://github.com/kubernetes-sigs/metrics-server。
[root@master ~]# wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml
[root@master ~]# vim components.yaml
......
spec:
containers:
- args:
- --cert-dir=/tmp
- --secure-port=443
- --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
- --kubelet-use-node-status-port
- --metric-resolution=15s
- --kubelet-insecure-tls # 新增
image: k8s.gcr.io/metrics-server/metrics-server:v0.5.1
......
[root@master ~]# kubectl apply -f components.yaml
serviceaccount/metrics-server created
[root@master ~]# kubectl get pods -A | grep metrics-server
kube-system metrics-server-7b9c4d7fd9-69drn 0/1 Running 0 2m20s
[root@master ~]# kubectl api-versions | grep metrics
metrics.k8s.io/v1beta1
[root@master ~]# kubectl top node
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
master 158m 7% 1184Mi 32%
node1 43m 2% 540Mi 14%
node2 37m 1% 487Mi 13%
[root@master ~]# kubectl top pod
NAME CPU(cores) MEMORY(bytes)
nginx-deployment-67dfd6c8f9-pvc87 0m 1Mi
nginx-deployment-67dfd6c8f9-qxvmt 0m 1Mi
nginx-deployment-67dfd6c8f9-tm2s8 0m 1Mi
还是复用之前的 Deployment 例子,再创建一个服务供客户端访问以便后面测试。注意需要额外定义下 Pod 的 resources.requests 资源请求值,如果不设置会导致 HPA 无法正常工作。
[root@master ~]# vim nginx-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.18.0
ports:
- containerPort: 80
resources:
requests:
cpu: 100m # 表示0.1个cpu
---
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
ports:
- port: 80
selector:
app: nginx
[root@master ~]# kubectl apply -f nginx-deployment.yaml --record
deployment.apps/nginx-deployment created
service/nginx created
[root@master ~]# kubectl get pod,svc
NAME READY STATUS RESTARTS AGE
pod/nginx-deployment-fd7779d-ngfjq 1/1 Running 0 7m38s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/nginx ClusterIP 10.1.196.33 <none> 80/TCP 7m38s
创建一个 HPA 控制器,在 1 到 10 之间调整 Pod 的副本数量,以使得平均 Pod CPU 使用率维持在 50%。
[root@master ~]# kubectl autoscale deployment nginx-deployment --min=1 --max=5 --cpu-percent=50
horizontalpodautoscaler.autoscaling/nginx-deployment autoscaled
[root@master ~]# kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
nginx-deployment Deployment/nginx-deployment 0%/50% 1 5 1 78s
[root@master ~]# kubectl top pod
NAME CPU(cores) MEMORY(bytes)
nginx-deployment-fd7779d-sxqwv 0m 1Mi
压测看看效果:
[root@master ~]# for in in {1..5};do ab -n 50000 -c 500 http://10.1.196.33/;done
[root@master ~]# kubectl get hpa;kubectl get pod;kubectl top pod
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
nginx-deployment Deployment/nginx-deployment 92%/50% 1 5 5 7m8s
NAME READY STATUS RESTARTS AGE
nginx-deployment-fd7779d-4zvjq 1/1 Running 0 67s
nginx-deployment-fd7779d-95d84 1/1 Running 0 3m53s
nginx-deployment-fd7779d-bcksw 1/1 Running 0 82s
nginx-deployment-fd7779d-ngfjq 1/1 Running 0 17m
nginx-deployment-fd7779d-nwzw2 1/1 Running 0 82s
NAME CPU(cores) MEMORY(bytes)
nginx-deployment-fd7779d-4zvjq 104m 2Mi
nginx-deployment-fd7779d-95d84 102m 1Mi
nginx-deployment-fd7779d-bcksw 134m 1Mi
nginx-deployment-fd7779d-ngfjq 59m 1Mi
nginx-deployment-fd7779d-nwzw2 112m 1Mi
# 从上面可以看到HPA己经根据Pod CPU使用率的提高进行了自动扩容,Pod的副本数量变成了5个。
# 结束测试,等待几分钟,可以看到HPA根据Pod CPU使用率的降低对副本数量进行了缩容操作,Pod副本数量变成1个。
[root@master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx-deployment-fd7779d-4zvjq 1/1 Running 0 13m
[root@master ~]# kubectl get hpa;kubectl get pod;kubectl top pod
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
nginx-deployment Deployment/nginx-deployment 0%/50% 1 5 1 19m
NAME READY STATUS RESTARTS AGE
nginx-deployment-fd7779d-4zvjq 1/1 Running 0 13m
NAME CPU(cores) MEMORY(bytes)
nginx-deployment-fd7779d-4zvjq 0m 2Mi
除了使用命令,我们还可以使用 yaml 文件来创建 HPA:
[root@master ~]# kubectl get hpa nginx-deployment -o yaml > hpa-nginx.yaml
[root@master ~]# cat hpa-nginx.yaml # 精简下
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: nginx-deployment
spec:
maxReplicas: 5
minReplicas: 1
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: nginx-deployment
targetCPUUtilizationPercentage: 50
六、暂停和恢复
有时候我们需要进行一次复杂的 Deployment 配置修改,为了避免频繁触发 Deployment 更新操作,可以先暂停,然后进行配置修改,再恢复,一次性触发完整的更新操作,就可以避免不必要的更新操作了。
以之前的nginx为例:
# 查看信息
[root@master ~]# kubectl get deployments.apps
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 1/1 1 1 51m
[root@master ~]# kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-fd7779d 1 1 1 52m
# 暂停 Deployment 的更新操作
[root@master ~]# kubectl rollout pause deployment nginx-deployment
deployment.apps/nginx-deployment paused
# 此时我们修改 Deployment 是不会触发更新的
[root@master ~]# kubectl set image deployment/nginx-deployment nginx=nginx:1.20.0 --record
deployment.apps/nginx-deployment image updated
[root@master ~]# kubectl set resources deployment nginx-deployment -c=nginx --limits=cpu=200m,memory=512Mi
deployment.apps/nginx-deployment resource requirements updated
[root@master ~]# kubectl rollout history deployment nginx-deployment
deployment.apps/nginx-deployment
REVISION CHANGE-CAUSE
1 kubectl apply --filename=nginx-deployment.yaml --record=true
# 最后恢复更新,观察下更新
[root@master ~]# kubectl rollout resume deployment nginx-deployment
deployment.apps/nginx-deployment resumed
[root@master ~]# kubectl describe deployments.apps nginx-deployment | grep -E -A2 'Limits|Image'
Image: nginx:1.20.0
Port: 80/TCP
Host Port: 0/TCP
Limits:
cpu: 200m
memory: 512Mi
七、灰度发布
灰度发布也叫金丝雀发布,这种发布方式,一般是将新版本的服务与当前服务的生产版本一起部署。然后,将10%的流量引流到新版本,以在生产环境中对其进行测试。如果服务那些流量的新版本没问题,那么就可以将更多的流量逐渐引流过去。在此期间不断地调整新旧两个版本的运行的服务器副本数量,随着时间的推移对新版本增量部署,直到 100% 的流量都调度到新版本上,完成灰度发布
如果在灰度发布过程中发现了新版本有问题,我们可以立即将流量切回老版本上,这样,就可以将负面影响控制在最小范围内。
以 nginx 为例简单实现下,我们通过使用 track 标签来区分不同的版本。稳定版本和新版本都有一个 track 标签,其值分别为 stable 和 canary。我们可以随时调整 stable 版本和 canary 版本的副本数量,以确定两个版本接收实时生产流量的比例(在本例中为 3:1)。如果没问题,我们可以将 stable 版本更新到最新的程序版本。
[root@master ~]# vim nginx-canary.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
track: stable
spec:
containers:
- name: nginx
image: nginx:1.18.0
ports:
- containerPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-canary
labels:
app: nginx
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
track: canary
spec:
containers:
- name: nginx
image: nginx:1.20.0
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
labels:
app: nginx
spec:
ports:
- port: 80
selector:
app: nginx
下面我们使用上例来进行一次简单的灰度发布:
[root@master ~]# kubectl apply -f nginx-canary.yaml --record
Flag --record has been deprecated, --record will be removed in the future
deployment.apps/nginx created
deployment.apps/nginx-canary created
service/nginx-svc created
[root@master ~]# kubectl get deploy,pod,svc
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/nginx 3/3 3 3 24s
deployment.apps/nginx-canary 1/1 1 1 24s
NAME READY STATUS RESTARTS AGE
pod/nginx-54475dd767-4vvkx 1/1 Running 0 24s
pod/nginx-54475dd767-cl8mk 1/1 Running 0 24s
pod/nginx-54475dd767-spvsr 1/1 Running 0 24s
pod/nginx-canary-5c888cf895-fmb55 1/1 Running 0 24s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/kubernetes ClusterIP 10.1.0.1 <none> 443/TCP 21d
service/nginx-svc ClusterIP 10.1.44.26 <none> 80/TCP 24s
[root@master ~]# curl -si 10.1.44.26 | grep Server
Server: nginx/1.18.0
[root@master ~]# curl -si 10.1.44.26 | grep Server
Server: nginx/1.20.0
[root@master ~]# curl -si 10.1.44.26 | grep Server
Server: nginx/1.18.0
[root@master ~]# curl -si 10.1.44.26 | grep Server
Server: nginx/1.18.0
参考文章:
https://kubernetes.io/docs/
《Kubernetes 权威指南》