Concepts

Detailed explanations of Kubernetes system concepts and abstractions.

Edit This Page

管理资源

您已经部署了应用并通过服务暴露它。现在要做的是?Kubernetes 提供了一些工具来帮助管理您的应用部署,包括缩放和更新。我们将更深入讨论的特性包括 配置文件label

您可以 在我们的 doc 仓库中 找到该示例的所有文件。

组织资源配置

许多应用需要创建多个资源,例如一个 Deployment 和一个 Service。可以通过将多个资源组合在同一个文件中(在 YAML 中以 --- 分隔)来简化对它们的管理。例如:

nginx-app.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.7.9
        ports:
        - containerPort: 80

可以用创建单个资源的方式来创建多个资源:

$ kubectl create -f docs/user-guide/nginx-app.yaml
service "my-nginx-svc" created
deployment "my-nginx" created

资源将按照它们在文件中出现的顺序创建。因此,最好先指定服务,因为这将确保调度能够像控制器(例如 Deployment)那样创建与服务相关联的 pod。

kubectl create 也接受多个 -f 参数:

$ kubectl create -f docs/user-guide/nginx/nginx-svc.yaml -f docs/user-guide/nginx/nginx-deployment.yaml

还可以指定目录,而不是指定或单独添加一个文件:

$ kubectl create -f docs/user-guide/nginx/

kubectl 将读取后缀为 .yaml.yml 或者 .json 的所有文件。

建议将那些与同一个微服务或应用层相关的资源放到同一个文件中,并将与应用相关的所有文件分组到同一个目录中。如果应用的各个层使用 DNS 相互绑定,那么您可以简单地将堆栈的所有组件一起部署。

还可以将 URL 指定为配置源,便于直接部署迁入 github 的配置文件:

$ kubectl create -f https://raw.githubusercontent.com/kubernetes/kubernetes/master/docs/user-guide/nginx-deployment.yaml
deployment "nginx-deployment" created

kubectl 中的批量操作

资源创建并不是 kubectl 可以批量执行的唯一操作。它还可以从配置文件中提取资源名,以便执行其他操作,特别是删除您创建的相同资源:

$ kubectl delete -f docs/user-guide/nginx/
deployment "my-nginx" deleted
service "my-nginx-svc" deleted

在只有两个资源的情况下,还可以使用 资源/名称 的语法在命令行中指定这两个资源:

$ kubectl delete deployments/my-nginx services/my-nginx-svc

对于更多的资源,您会发现,使用 -l--selector 指定的选择器(label 查询),很容易通过 label 筛选资源:

$ kubectl delete deployment,services -l app=nginx
deployment "my-nginx" deleted
service "my-nginx-svc" deleted

因为 kubectl 输出的资源名称和它接收的资源名称语法相同,所以很容易使用 $()xargs 形成链操作:

$ kubectl get $(kubectl create -f docs/user-guide/nginx/ -o name | grep service)
NAME           CLUSTER-IP   EXTERNAL-IP   PORT(S)      AGE
my-nginx-svc   10.0.0.208   <pending>     80/TCP       0s

上面的命令中,我们首先使用 docs/user-guide/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 create -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 create -f project/k8s/development --recursive
configmap "my-config" created
deployment "my-deployment" created
persistentvolumeclaim "my-pvc" created

--recursive 与接受 --filename,-f 标志的任何操作都能一起工作,例如:kubectl {create,get,delete,describe,rollout} 等。

有多个 -f 参数出现的时候,--recursive 标志也能正常工作:

$ kubectl create -f project/k8s/namespaces -f project/k8s/development --recursive
namespace "development" created
namespace "staging" created
configmap "my-config" created
deployment "my-deployment" created
persistentvolumeclaim "my-pvc" created

如果您有兴趣学习更多关于 kubectl 的内容,请阅读 kubectl 概述

有效地使用 label

到目前为止,我们的例子中任何资源使用的 label 最多也就一个。很多时候,应该使用多个 label 来区分集合。

例如,不同的应用将为 app label 设置不同的值,但是,类似 guestbook 示例 这样的多层应用,还需要区分每一层。前端可以带以下 label:

     labels:
        app: guestbook
        tier: frontend

Redis 的 master 和 slave 会有不同的 tier 值的 label,甚至还有一个额外的 role label:

     labels:
        app: guestbook
        tier: backend
        role: master

以及

     labels:
        app: guestbook
        tier: backend
        role: slave

label 允许我们沿着 label 指定的任何维度对我们的资源进行切片和剪裁:

$ kubectl create -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   <none>
guestbook-fe-ght6d             1/1       Running   0          1m        guestbook   frontend   <none>
guestbook-fe-jpy62             1/1       Running   0          1m        guestbook   frontend   <none>
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       <none>     <none>
my-nginx-o0ef1                 1/1       Running   0          29m       nginx       <none>     <none>
$ 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

金丝雀部署

区分同一组件不同版本或者配置的部署,是需要多 label 的另外一个场景。常见的做法,是部署一个新应用发布版本(在 pod 模板中通过镜像的 tag 指定)的 金丝雀,保持与以前的版本同时运行,这样,新版本在完全推出之前可以接收实时生产流量。

例如,您可以使用 track label 来区分不同的版本。

主要的、稳定的发行版将有一个值为 stabletrack label:

     name: frontend
     replicas: 3
     ...
     labels:
        app: guestbook
        tier: frontend
        track: stable
     ...
     image: gb-frontend:v3

然后,您可以创建 guestbook 前端的新版本,让这些版本的 track label 带有不同的值(即 canary),以便两组 pod 不会重叠:

     name: frontend-canary
     replicas: 1
     ...
     labels:
        app: guestbook
        tier: frontend
        track: canary
     ...
     image: gb-frontend:v4

前端服务通过选择 label 的公共子集(即省略 track label),就能跨越两组副本,这样,流量将重定向到两个应用:

  selector:
     app: guestbook
     tier: frontend

您可以调整 stable 和 canary 版本的副本数量,以确定每个版本将接收实时生产流量的比例(在本例中为 3:1)。一旦有信心了,您就可以将值为 stabletrack 更新到新的应用发行版本,并删除 canary

想要了解更具体的示例,请查看 部署 Ghost 指南

更新 label

有时,现有的 pod 和其它资源需要在创建新资源之前重新标记。这可以用 kubectl label 完成。例如,如果想要将所有 nginx pod 标记为前端层,只需运行:

$ 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 指定)。

想要了解更多信息,请查看 labelskubectl label 文档。

更新 annotation

有时,您可能希望将 annotation 附加到资源中。annotation 是 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
...

想要了解更多信息,请查看 annotationskubectl annotate 文档。

伸缩您的应用

当应用上的负载增长或收缩时,使用 kubectl 能够轻松实现规模的伸缩。例如,要将 nginx 副本的数量从 3 减少到 1,请执行以下操作:

$ kubectl scale deployment/my-nginx --replicas=1
deployment "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
deployment "my-nginx" autoscaled

现在,您的 nginx 副本将根据需要自动地增加或者减少。

想要了解更多信息,请查看 kubectl scalekubectl autoscalepod 横向自动伸缩 文档。

直接更新资源

有时,有必要对您所创建的资源进行小范围的、无干扰的更新。

kubectl apply

建议在源代码管理中维护一组配置文件(请参阅 像代码一样对待配置 ),这样,它们就可以与它们配置的资源的代码一起维护和版本化。然后,您可以用 kubectl apply 将您的配置更改推送到集群。

这个命令将会把推送的版本与以前的版本进行比较,并应用您所做的更改,但是不会覆盖任何你没有指定的自动更改的属性。

$ kubectl apply -f docs/user-guide/nginx/nginx-deployment.yaml
deployment "my-nginx" configured

注意,kubectl apply 将为资源增加一个额外的 annotation,以确定自上次调用以来对配置的更改。当调用它时,kubectl apply 会在以前的配置、提供的输入和资源的当前配置之间找出三方差异,以确定如何修改资源。

目前,资源是在没有这个 annotation 的情况下创建的,所以,第一次调用 kubectl apply 将回到提供的输入和资源的当前配置之间的双向差异。在第一次调用期间,它无法检测资源创建时属性集的删除。因此,不会删除它们。

所有后续调用 kubectl apply 以及其它修改配置的命令,如 kubectl replacekubectl edit,都将更新 annotation,并允许随后调用 kubectl apply 去使用三向差异检测和执行删除。

注: 想要使用 apply,请始终使用 kubectl applykubectl create --save-config 创建资源。

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 "my-nginx" configured
$ rm /tmp/nginx.yaml

这使您可以更加容易地进行更重大的更改。请注意,可以使用 EDITORKUBE_EDITOR 环境变量来指定编辑器。

想要了解更多信息,请查看 kubectl edit 文档。

kubectl patch

您可以使用 kubectl patch 来更新 API 对象。此命令支持 JSON patch,JSON merge patch,以及 strategic merge patch。请查看 使用 kubectl patch 更新 API 对象kubectl patch

破坏性的更新

在某些情况下,您可能需要更新某些初始化后无法更新的资源字段,或者您可能只想立即进行递归更改,例如修复 Deployment 创建的不正常的 pod。若要更改这些字段,请使用 replace --force,它将删除并重新创建资源。在这种情况下,您可以简单地修改原始配置文件:

$ kubectl replace -f docs/user-guide/nginx/nginx-deployment.yaml --force
deployment "my-nginx" deleted
deployment "my-nginx" replaced

在不中断服务的情况下更新应用

在某些时候,您最终需要更新已部署的应用,通常都是通过指定新的镜像或镜像 tag,如上面的金丝雀部署场景中所示。kubectl 支持几个更新操作,每个更新操作都适用于不同的场景。

我们将指导您通过 Deployment 如何创建和更新应用。如果部署的应用由副本控制器(Replication Controllers)管理,那么您应该选择阅读 怎么样使用 kubectl rolling-update

假设您正运行的是 1.7.9 版本的 nginx:

$ kubectl run my-nginx --image=nginx:1.7.9 --replicas=3
deployment "my-nginx" created

要更新到 1.9.1 版本,只需使用我们前面学到的 kubectl 命令将 .spec.template.spec.containers[0].imagenginx:1.7.9 修改为 nginx:1.9.1

$ kubectl edit deployment/my-nginx

是这样子的。Deployment 将在后台逐步更新已经部署的 nginx 应用。它确保在更新过程中,只有一定数量的旧副本被开闭,并且只有一定超过所需 pod 数量的新副本被创建。想要学习更多关于它的细节,请参考 Deployment 页

接下来呢?

Analytics

Create an Issue Edit this Page