Kubernetes 提供了一些工具来帮助管理应用部署,包括扩缩容和更新。本教程详细介绍了Kubernetes管理应用部署,例如组织资源配置、kubectl 中的批量操作、金丝雀部署、更新注解、扩缩应用、更新资源等等。
一、组织资源配置
许多应用需要创建多个资源,例如 Deployment 和 Service。 可以通过将多个资源组合在同一个文件中(在 YAML 中以 — 分隔) 来简化对它们的管理。例如:
apiVersion: v1 kind: Service metadata: name: my-nginx-svc labels: app: nginx spec: type: LoadBalancer ports: - port: 80 selector: app: nginx --- apiVersion: apps/v1 kind: Deployment metadata: name: my-nginx labels: app: nginx spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.14.2 ports: - containerPort: 80
可以用创建单个资源相同的方式来创建多个资源:
kubectl apply -f https://k8s.io/examples/application/nginx-app.yaml service/my-nginx-svc created deployment.apps/my-nginx created
资源将按照它们在文件中的顺序创建。 因此,最好先指定服务,这样在控制器(例如 Deployment)创建 Pod 时能够 确保调度器可以将与服务关联的多个 Pod 分散到不同节点。
kubectl apply 也接受多个 -f 参数:
kubectl apply -f https://k8s.io/examples/application/nginx/nginx-svc.yaml \ -f https://k8s.io/examples/application/nginx/nginx-deployment.yaml
建议的做法是,将同一个微服务或同一应用层相关的资源放到同一个文件中, 将同一个应用相关的所有文件按组存放到同一个目录中。 如果应用的各层使用 DNS 相互绑定,可以将堆栈的所有组件一起部署。
还可以使用 URL 作为配置源,便于直接使用已经提交到 GitHub 上的配置文件进行部署:
kubectl apply -f https://k8s.io/examples/application/nginx/nginx-deployment.yaml deployment.apps/my-nginx created
二、kubectl批量操作
资源创建并不是 kubectl 可以批量执行的唯一操作, kubectl 还可以从配置文件中提取资源名,以便执行其他操作, 特别是删除之前创建的资源:
kubectl delete -f https://k8s.io/examples/application/nginx-app.yaml deployment.apps "my-nginx" deleted service "my-nginx-svc" deleted
在仅有两种资源的情况下,可以使用”资源类型/资源名”的语法在命令行中 同时指定这两个资源:
kubectl delete deployments/my-nginx services/my-nginx-svc
对于资源数目较大的情况,会发现使用 -l 或 –selector 指定筛选器(标签查询)能很容易根据标签筛选资源:
kubectl delete deployment,services -l app=nginx deployment.apps "my-nginx" deleted service "my-nginx-svc" deleted
由于 kubectl 用来输出资源名称的语法与其所接受的资源名称语法相同, 可以使用 $() 或 xargs 进行链式操作:
kubectl get $(kubectl create -f docs/concepts/cluster-administration/nginx/ -o name | grep service) kubectl create -f docs/concepts/cluster-administration/nginx/ -o name | grep service | xargs -i kubectl get {}
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE my-nginx-svc LoadBalancer 10.0.0.208 <pending> 80/TCP 0s
上面的命令中,我们首先使用 examples/application/nginx/ 下的配置文件创建资源, 并使用 -o name 的输出格式(以”资源/名称”的形式打印每个资源)打印所创建的资源。 然后,我们通过 grep 来过滤 “service”,最后再打印 kubectl get 的内容。
如果碰巧在某个路径下的多个子路径中组织资源,那么也可以递归地在所有子路径上 执行操作,方法是在 –filename,-f 后面指定 –recursive 或者 -R。
例如,假设有一个目录路径为 project/k8s/development,它保存开发环境所需的 所有清单,并按资源类型组织:
project/k8s/development ├── configmap │ └── my-configmap.yaml ├── deployment │ └── my-deployment.yaml └── pvc └── my-pvc.yaml
默认情况下,对 project/k8s/development 执行的批量操作将停止在目录的第一级, 而不是处理所有子目录。 如果我们试图使用以下命令在此目录中创建资源,则会遇到一个错误:
kubectl apply -f project/k8s/development
error: you must provide one or more resources by argument or filename (.json|.yaml|.yml|stdin)
正确的做法是,在 –filename,-f 后面标明 –recursive 或者 -R 之后:
kubectl apply -f project/k8s/development --recursive
configmap/my-config created deployment.apps/my-deployment created persistentvolumeclaim/my-pvc created
–recursive 可以用于接受 –filename,-f 参数的任何操作,例如: kubectl {create,get,delete,describe,rollout} 等。
有多个 -f 参数出现的时候,–recursive 参数也能正常工作:
kubectl apply -f project/k8s/namespaces -f project/k8s/development --recursive
namespace/development created namespace/staging created configmap/my-config created deployment.apps/my-deployment created persistentvolumeclaim/my-pvc created
三、金丝雀部署
另一个需要多标签的场景是用来区分同一组件的不同版本或者不同配置的多个部署。 常见的做法是部署一个使用金丝雀发布来部署新应用版本 (在 Pod 模板中通过镜像标签指定),保持新旧版本应用同时运行。 这样,新版本在完全发布之前也可以接收实时的生产流量。
例如,可以使用 track 标签来区分不同的版本。主要稳定的发行版将有一个 track 标签,其值为 stable:
name: frontend replicas: 3 ... labels: app: guestbook tier: frontend track: stable ... image: gb-frontend:v3
然后,可以创建 guestbook 前端的新版本,让这些版本的 track 标签带有不同的值 (即 canary),以便两组 Pod 不会重叠:
name: frontend-canary replicas: 1 ... labels: app: guestbook tier: frontend track: canary ... image: gb-frontend:v4
前端服务通过选择标签的公共子集(即忽略 track 标签)来覆盖两组副本, 以便流量可以转发到两个应用:
selector: app: guestbook tier: frontend
可以调整 stable 和 canary 版本的副本数量,以确定每个版本将接收 实时生产流量的比例(在本例中为 3:1)。 一旦有信心,就可以将新版本应用的 track 标签的值从 canary 替换为 stable,并且将老版本应用删除。
四、更新注解
注解是 API 客户端(如工具、库等) 用于检索的任意非标识元数据,可以通过 kubectl annotate 来完成。例如:
kubectl annotate pods my-nginx-v4-9gw19 description='my frontend running nginx' kubectl get pods my-nginx-v4-9gw19 -o yaml
apiVersion: v1 kind: pod metadata: annotations: description: my frontend running nginx ...
五、扩缩应用
当应用上的负载增长或收缩时,使用 kubectl 能够实现应用规模的扩缩。 例如,要将 nginx 副本的数量从 3 减少到 1,请执行以下操作:
kubectl scale deployment/my-nginx --replicas=1
deployment.apps/my-nginx scaled
现在, Deployment 管理的 Pod 只有一个了。
kubectl get pods -l app=nginx
NAME READY STATUS RESTARTS AGE my-nginx-2035384211-j5fhi 1/1 Running 0 30m
想要让系统自动选择需要 nginx 副本的数量,范围从 1 到 3,请执行以下操作:
kubectl autoscale deployment/my-nginx --min=1 --max=3
horizontalpodautoscaler.autoscaling/my-nginx autoscaled
现在, nginx 副本将根据需要自动地增加或者减少。
六、更新资源
有时,有必要对所创建的资源进行小范围、无干扰地更新。
1、kubectl apply
建议在源代码管理中维护一组配置文件 (参见配置即代码), 这样,它们就可以和应用代码一样进行维护和版本管理。 然后,可以用 kubectl apply 将配置变更应用到集群中。
这个命令将会把推送的版本与以前的版本进行比较,并应用所做的更改, 但是不会自动覆盖任何没有指定更改的属性。
kubectl apply -f https://k8s.io/examples/application/nginx/nginx-deployment.yaml
deployment.apps/my-nginx configured
注意:kubectl apply 将为资源增加一个额外的注解,以确定自上次调用以来对配置的更改。 执行时,kubectl apply 会在以前的配置、提供的输入和资源的当前配置之间 找出三方差异,以确定如何修改资源。
目前,新创建的资源是没有这个注解的,所以,第一次调用 kubectl apply 时 将使用提供的输入和资源的当前配置双方之间差异进行比较。 在第一次调用期间,它无法检测资源创建时属性集的删除情况, 因此,kubectl 不会删除它们。
所有后续的 kubectl apply 操作以及其他修改配置的命令,如 kubectl replace 和 kubectl edit,都将更新注解,并允许随后调用的 kubectl apply 使用三方差异进行检查和执行删除。
2、kubectl edit
或者,也可以使用 kubectl edit 更新资源:
kubectl edit deployment/my-nginx
这相当于首先 get 资源,在文本编辑器中编辑它,然后用更新的版本 apply 资源:
kubectl get deployment my-nginx -o yaml > /tmp/nginx.yaml vi /tmp/nginx.yaml # 做一些编辑,然后保存文件 kubectl apply -f /tmp/nginx.yaml deployment.apps/my-nginx configured rm /tmp/nginx.yaml
这使可以更加容易地进行更重大的更改。 请注意,可以使用 EDITOR 或 KUBE_EDITOR 环境变量来指定编辑器。
3、kubectl patch
可以使用 kubectl patch 来更新 API 对象。此命令支持 JSON patch、 JSON merge patch、以及 strategic merge patch。
七、破坏性更新
在某些情况下,可能需要更新某些初始化后无法更新的资源字段,或者可能只想立即进行递归更改, 例如修复 Deployment 创建的不正常的 Pod。若要更改这些字段,请使用 replace –force, 它将删除并重新创建资源。在这种情况下,可以修改原始配置文件:
kubectl replace -f https://k8s.io/examples/application/nginx/nginx-deployment.yaml --force
deployment.apps/my-nginx deleted deployment.apps/my-nginx replaced
八、不中断服务更新应用
在某些时候,最终需要更新已部署的应用,通常都是通过指定新的镜像或镜像标签, 如上面的金丝雀发布的场景中所示。kubectl 支持几种更新操作, 每种更新操作都适用于不同的场景。
我们将指导通过 Deployment 如何创建和更新应用。
假设正运行的是 1.14.2 版本的 nginx:
kubectl create deployment my-nginx --image=nginx:1.14.2
deployment.apps/my-nginx created
运行 3 个副本(这样新旧版本可以同时存在)
kubectl scale deployment my-nginx --current-replicas=1 --replicas=3
deployment.apps/my-nginx scaled
要更新到 1.16.1 版本,只需使用我们前面学到的 kubectl 命令将 .spec.template.spec.containers[0].image 从 nginx:1.14.2 修改为 nginx:1.16.1。
kubectl edit deployment/my-nginx
Deployment 将在后台逐步更新已经部署的 nginx 应用。 它确保在更新过程中,只有一定数量的旧副本被开闭,并且只有一定基于所需 Pod 数量的新副本被创建。