管理资源
你已经部署了应用并通过服务暴露它。然后呢?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
资源将按照它们在文件中的顺序创建。因此,最好先指定服务,这样在控制器(例如Deployment)创建Pod时能够确保调度器可以将与服务关联的多个Pod分散到不同节点。
kubectlcreate也接受多个-f参数:
kubectl apply -f https://k8s.io/examples/application/nginx/nginx-svc.yaml -f https://k8s.io/examples/application/nginx/nginx-deployment.yaml
还可以指定目录路径,而不用添加多个单独的文件:
kubectl apply -f https://k8s.io/examples/application/nginx/
kubectl将读取任何后缀为.yaml、.yml或者.json的文件。
建议的做法是,将同一个微服务或同一应用层相关的资源放到同一个文件中,将同一个应用相关的所有文件按组存放到同一个目录中。如果应用的各层使用DNS相互绑定,那么你可以将堆栈的所有组件一起部署。
还可以使用URL作为配置源,便于直接使用已经提交到Github上的配置文件进行部署:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/website/main/content/zh/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 80/TCP 0s
上面的命令中,我们首先使用examples/application/nginx/下的配置文件创建资源,并使用-oname的输出格式(以”资源/名称”的形式打印每个资源)打印所创建的资源。然后,我们通过grep来过滤“service”,最后再打印kubectlget的内容。
如果你碰巧在某个路径下的多个子路径中组织资源,那么也可以递归地在所有子路径上执行操作,方法是在--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
有效地使用标签
到目前为止我们使用的示例中的资源最多使用了一个标签。在许多情况下,应使用多个标签来区分集合。
例如,不同的应用可能会为app标签设置不同的值。但是,类似guestbook示例这样的多层应用,还需要区分每一层。前端可以带以下标签:
labels:
app: guestbook
tier: frontend
Redis的主节点和从节点会有不同的tier标签,甚至还有一个额外的role标签:
labels:
app: guestbook
tier: backend
role: master
以及
labels:
app: guestbook
tier: backend
role: slave
标签允许我们按照标签指定的任何维度对我们的资源进行切片和切块:
kubectl apply -f examples/guestbook/all-in-one/guestbook-all-in-one.yaml
kubectl get pods -Lapp -Ltier -Lrole
NAME READY STATUS RESTARTS AGE APP TIER ROLE
guestbook-fe-4nlpb 1/1 Running 0 1m guestbook frontend
guestbook-fe-ght6d 1/1 Running 0 1m guestbook frontend
guestbook-fe-jpy62 1/1 Running 0 1m guestbook frontend
guestbook-redis-master-5pg3b 1/1 Running 0 1m guestbook backend master
guestbook-redis-slave-2q2yf 1/1 Running 0 1m guestbook backend slave
guestbook-redis-slave-qgazl 1/1 Running 0 1m guestbook backend slave
my-nginx-divi2 1/1 Running 0 29m nginx
my-nginx-o0ef1 1/1 Running 0 29m nginx
kubectl get pods -lapp=guestbook,role=slave
NAME READY STATUS RESTARTS AGE
guestbook-redis-slave-2q2yf 1/1 Running 0 3m
guestbook-redis-slave-qgazl 1/1 Running 0 3m
金丝雀部署(CanaryDeployments)
另一个需要多标签的场景是用来区分同一组件的不同版本或者不同配置的多个部署。常见的做法是部署一个使用金丝雀发布来部署新应用版本(在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,并且将老版本应用删除。
想要了解更具体的示例,请查看Ghost部署教程。
更新标签
有时,现有的pod和其它资源需要在创建新资源之前重新标记。这可以用kubectllabel完成。例如,如果想要将所有nginxpod标记为前端层,运行:
kubectl label pods -l app=nginx tier=fe
pod/my-nginx-2035384211-j5fhi labeled
pod/my-nginx-2035384211-u2c7e labeled
pod/my-nginx-2035384211-u3t6x labeled
首先用标签“app=nginx”过滤所有的Pod,然后用“tier=fe”标记它们。想要查看你刚才标记的Pod,请运行:
kubectl get pods -l app=nginx -L tier
NAME READY STATUS RESTARTS AGE TIER
my-nginx-2035384211-j5fhi 1/1 Running 0 23m fe
my-nginx-2035384211-u2c7e 1/1 Running 0 23m fe
my-nginx-2035384211-u3t6x 1/1 Running 0 23m fe
这将输出所有“app=nginx”的Pod,并有一个额外的描述Pod的tier的标签列(用参数-L或者--label-columns标明)。
更新注解
有时,你可能希望将注解附加到资源中。注解是API客户端(如工具、库等)用于检索的任意非标识元数据。这可以通过kubectlannotate来完成。例如:
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.extensions/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
就地更新资源
有时,有必要对你所创建的资源进行小范围、无干扰地更新。
kubectlapply
建议在源代码管理中维护一组配置文件(参见配置即代码),这样,它们就可以和应用代码一样进行维护和版本管理。然后,你可以用kubectlapply将配置变更应用到集群中。
这个命令将会把推送的版本与以前的版本进行比较,并应用你所做的更改,但是不会自动覆盖任何你没有指定更改的属性。
kubectl apply -f https://k8s.io/examples/application/nginx/nginx-deployment.yaml
deployment.apps/my-nginx configured
注意,kubectlapply将为资源增加一个额外的注解,以确定自上次调用以来对配置的更改。执行时,kubectlapply会在以前的配置、提供的输入和资源的当前配置之间找出三方差异,以确定如何修改资源。
目前,新创建的资源是没有这个注解的,所以,第一次调用kubectlapply时将使用提供的输入和资源的当前配置双方之间差异进行比较。在第一次调用期间,它无法检测资源创建时属性集的删除情况。因此,kubectl不会删除它们。
所有后续的kubectlapply操作以及其他修改配置的命令,如kubectlreplace和kubectledit,都将更新注解,并允许随后调用的kubectlapply使用三方差异进行检查和执行删除。
Note:想要使用apply,请始终使用kubectlapply或kubectlcreate--save-config创建资源。
kubectledit
或者,你也可以使用kubectledit更新资源:
kubectl edit deployment/my-nginx
这相当于首先get资源,在文本编辑器中编辑它,然后用更新的版本apply资源:
kubectl get deployment my-nginx -o yaml > /tmp/nginx.yaml
vi /tmp/nginx.yaml
# do some edit, and then save the file
kubectl apply -f /tmp/nginx.yaml
deployment.apps/my-nginx configured
rm /tmp/nginx.yaml
这使你可以更加容易地进行更重大的更改。请注意,可以使用EDITOR或KUBE_EDITOR环境变量来指定编辑器。