你已经部署了你的应用并且通过 Service 将其暴露出来。现在要做什么?Kubernetes 提供了一系列的工具帮助你管理应用的部署,包括扩缩和更新。
一些应用需要创建多个资源,例如 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
资源会按照在清单中出现的顺序创建。因此,最好先指定 Service,这样可以确保调度器能在控制器(如 Deployment)创建 Pod 时对Service 相关的 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 链接也可以被指定为配置源,这对于直接基于源码控制系统的清单进行部署来说非常方便:
kubectl apply -f https://k8s.io/examples/application/nginx/nginx-deployment.yaml
deployment.apps/my-nginx created
如果你需要定义更多清单,例如添加一个 ConfigMap,你也可以这样做。
这一节列出了在 Kubernetes 中管理工作负载最常用的一些工具。如果想要查看完整的清单,参阅 CNCF文章 Application definition and image build。
Helm 是一种管理预配置 Kubernetes 资源包的工具。这些资源包被称为 Helm Chart。
Kustomize 遍历 Kubernetes 清单以添加、删除或更新配置选项。它既可以作为独立的二级制文件使用,也可以作为 kubectl的原生功能使用。
资源创建并不是 kubectl 可以批量执行的唯一操作。它还能提取配置文件中的资源名称来执行其他操作,尤其是删除已经创建的相同资源:
kubectl delete -f https://k8s.io/examples/application/nginx-app.yaml
deployment.apps "my-nginx" deleted
service "my-nginx-svc" deleted
如果有两个资源,你可以使用 resource/name 语法在命令行中指定这两个资源:
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
使用上面的命令,首先会创建 docs/concepts/cluster-administration/nginx/ 目录下的资源,然后使用 -o name 输出格式打印创建的资源(以 resource/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、kubectl get、kubectl delete、kubectl describe,甚至是 kubectl 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
如果你对了解更多 kubectl 有兴趣,请阅读命令行工具(kubectl)。
有时候,你需要更新你所部署的应用,通常是指定新的镜像或镜像标签。kubectl 支持多种更新操作,每一种都适用于不同的场景。
你可以运行应用的多个副本,并使用 上线(Rollout) 操作将流量逐渐转移到新的健康 Pod 上。最终,所有正在运行的 Pod 都将拥有新的应用。
本节将指导你如何使用 Deployment 创建和更新应用。
假设你运行了 Nginx 1.14.2 版本。
kubectl create deployment my-nginx --image=nginx:1.14.2
deployment.apps/my-nginx created
确保只有一个副本:
kubectl scale --replicas 1 deployments/my-nginx --subresource='scale' --type='merge' -p '{"spec":{"replicas": 1}}'
deployment.apps/my-nginx scaled
允许 Kubernetes 在上线过程中添加更多的临时副本,方法是设置最大涨幅为 100%。
kubectl patch --type='merge' -p '{"spec":{"strategy":{"rollingUpdate":{"maxSurge": "100%" }}}}'
deployment.apps/my-nginx patched
要更新到版本 1.61.1,使用 kubectl edit 将 .spec.template.spec.containers[0].image
值从 nginx:1.14.2 修改为 nginx:1.16.1。
kubectl edit deployment/my-nginx
# 修改清单文件以使用新的容器镜像,然后保存你所作的更改
就是这样!Deployment 会逐步声明式地更新已部署的 Nginx 应用。它确保只有一定数量的旧副本会在更新时处于宕机状态,并且超过所需的 Pod 数量的新副本个数在创建期间可控。要了解更多关于如何实现的详细信息,参照 Deployment。
你可以使用 DaemonSet、Deployment 或 StatefulSet 来完成上线。
你可以使用 kubectl rollout
管理现有应用的逐步更新。
例如:
kubectl apply -f my-deployment.yaml
# 等待上线完成
kubectl rollout status deployment/my-deployment --timeout 10m # 超时时长为 10 分钟
或者
kubectl apply -f backing-stateful-component.yaml
# 不用等待上线完成,只需要检查状态
kubectl rollout status statefulsets/backing-stateful-component --watch=false
你也可以暂停、恢复或取消上线。参阅 kubectl rollout
以深入了解。
另一种需要使用多个标签的情况是区分部署的是同一组件的不同版本或不同配置。通常的做法是将新应用版本的金丝雀(在 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
你可以调整稳定版本和金丝雀版本的副本数量,以确定每个版本接收实时生产流量的比例(本例中为 3:1)。一旦有把握,你可以更新所有 track 标签为 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 annotate。
当应用的负载增长或收缩时,使用 kubectl 扩缩你的应用。例如,将 Nginx 的副本数量从 3 减少到 1,这样做:
kubectl scale deployment/my-nginx --replicas=1
deployment.apps/my-nginx scaled
现在,你的 Deployment 只管理一个 Pod。
kubectl get pods -l app=my-nginx
NAME READY STATUS RESTARTS AGE
my-nginx-2035384211-j5fhi 1/1 Running 0 30m
为了让系统按需从 1 到 3 自动选择 Nginx 副本数量,这样做:
# 需要存在容器和 Pod 指标数据源
kubectl autoscale deployment/my-nginx --min=1 --max=3
horizontalpodautoscaler.autoscaling/my-nginx autoscaled
现在你的 Nginx 副本数量将会按需自动扩缩。
更多信息请参阅文档 kubectl scale,kubectl autoscale 和Pod 水平自动扩缩。
有时需要对创建的资源进行小范围、非破坏性的更新。
建议参照(configuration as code),在源码控制系统中维护配置文件集合,这样它们就能与所配置资源的代码一起得到维护和版本控制。然后,你可以使用 kubectl apply
将配置集更新推送到集群中。
这个命令会将你推送的配置的版本和之前的版本进行比较,并应用你所作的更改,而不会覆盖任何你没有指定的属性。
kubectl apply -f https://k8s.io/examples/application/nginx/nginx-deployment.yaml
deployment.apps/my-nginx configured
要进一步了解底层原理,参阅服务器端应用。
或者,你也可以使用 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 环境变量来指定编辑器。
更多信息参阅 kubectl edit。
你可以使用 kubectl patch
来就地更新 API 对象。该子命令支持 JSON 补丁、JSON 合并补丁和策略合并补丁。
参阅使用 kubectl patch 更新 API 对象获取更多细节。
某些场景下,你可能需要更新那些一旦被初始化就无法被更新的资源字段,或者希望立刻进行递归修改,例如修复被 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
进一步学习如何调试运行中的 Pod。