首页 > 技术文章 > [K8s]Kubernetes 基础(上)

jpSpaceX 2022-01-04 18:58 原文

备注:此文档所有操作对应 Kubernetes 版本为 v1.20

1 - Master 节点 和 Node 节点概念

Master节点

Master 节点是 Kubernetes 集群的控制节点,在生产环境中不建议部署集群核心组件外的任何Pod,公司业务的Pod更是不建议部署到Master节点上,以免升级或者维护时对业务造成影响。

Master 节点的组件包括:

APIServer:APIServer是整个集群的控制中枢,提供集群中各个模块之间的数据交换,并将集群状态和信息存储到分布式键-值(key-value)存储系统Etcd集群中。同时它也是集群管理、资源配额、提供完备的集群安全机制的入口,为集群各类资源对象提供增、删、改、查以及watch的 REST API 接口。APIServer 作为 Kubernetes 的关键组件,使用 Kubernetes API 和 JSON over HTTP 提供 Kubernetes 的内部和外部接口。

Scheduler:Scheduler 是集群Pod的调度中心,主要是通过调度算法将 Pod 分配到最佳的节点(Node),它通过 APIServer 监听所有 Pod 的状态,一旦发现新的未被调度到任何 Node 节点的 Pod(PodSpec.NodeName 为空),就会根据一系列策略选择最佳节点进行调度,对每一个 Pod 创建一个绑定(binding),然后被调度的节点上的 Kubelet 负责启动该 Pod。Scheduler 是集群可插拔式组件,它跟踪每个节点上的资源利用率以确保工作负载不会超过可用资源。因此 Scheduler 必须知道资源需求、资源可用性以及其他约束和策略,例如服务质量、亲和力/反关联性要求、数据位置等。Scheduler 将资源供应与工作负载需求相匹配以维持系统的稳定和可靠,因此 Scheduler 在调度的过程中需要考虑公平、资源高效利用、效率等方面的问题。

Controller Manager:Controller Manager 是集群状态管理器(它的英文直译名为控制器管理器),以保证 Pod 或其他资源达到期望值。当集群中某个 Pod 的副本数或其他资源因故障和错误导致无法正常运行,没有达到设定的值时,Controller Manager 会尝试自动修复并使其达到期望状态。Controller Manager 包含 NodeController、ReplicationController、EndpointController、NamespaceController、ServiceAccountController、ResourceQuotaController、ServiceController 和 TokenController,该控制器管理器可与API服务器进行通信以在需要时创建、更新或删除它所管理的资源,如 Pod、服务断点等。

Etcd:Etcd 由 CoreOS 开发,用于可靠地存储集群的配置数据,是一种持久性、轻量型、分布式的键-值(key-value)数据存储组件。Etcd 作为 Kubernetes 集群的持久化存储系统,集群的灾难恢复、状态信息存储都与其密不可分,所以在 Kubernetes 高可用集群中,Etcd 的高可用是至关重要的一部分,在生产环境中建议部署为大于3的奇数个数的 Etcd,以保证数据的安全性和可恢复性。Etcd 可与 Master 组件部署在同一个节点上,大规模集群环境下建议部署在集群外,并且使用高性能服务器来提高 Etcd 的性能和降低 Etcd 同步数据的延迟。

Node节点

Node 节点也被称为 Worker 或 Minion,是主要负责部署容器(工作负载)的单机(或虚拟机),集群中的每个节点都必须具备容器的运行环境(runtime),比如 Docker 及其他组件等。Kubelet 作为守护进程运行在 Node 节点上,负责监听该节点上所有的 Pod,同时负责上报该节点上所有 Pod的运行状态,确保节点上的所有容器都能正常运行。当 Node节点宕机(NotReady状态)时,该节点上运行的 Pod 会被自动地转移到其他节点上。

Node 节点包括:

Kubelet:负责与 Master 通信协作,管理该节点上的 Pod。

Kube-Proxy:负责各 Pod 之间的通信和负载均衡。

Docker Engine:Docker 引擎,负载对容器的管理。

2 - Pod概念

什么是Pod?

Pod 可简单地理解为是一组、一个或多个容器,具有共享存储/网络及如何运行容器的规范。Pad 包含一个或多个相对紧密耦合的应用程序容器,处于同一个 Pod 中的容器共享同样的存储空间(Volume,卷或存储卷)、IP地址和Port端口,容器之间使用 localhost:port 相互访问。根据 Docker 的构造,Pod 可被建模为一组具有共享命令空间、卷、IP地址和Port端口的 Docker 容器。 Pod 包含的容器最好是一个容器只运行一个进程。每个 Pod 包含一个pause 容器,pause 容器是 Pod 的父容器,它主要负责僵尸进程的回收管理。Kubernetes 为每个 Pod 都分配一个唯一的IP地址,这样就可以保证应用程序使用同一端口,避免了发生冲突的问题。

Pod字段解析

apiVersion: v1 # 必选,API的版本号
kind: Pod # 必选,类型Pod
metadata: # 必选,元数据
name: nginx # 必选,符合RFC 1035规范的Pod名称
namespace: web-testing # 可选,不指定默认为default,Pod所在的命名空间
labels: # 可选,标签选择器,一般用于Selector
- app: nginx
annotations: # 可选,注释列表
- app: nginx
spec: # 必选,用于定义容器的详细信息
containers: # 必选,容器列表
- name: nginx # 必选,符合RFC 1035规范的容器名称
image: nginx: v1 # 必选,容器所用的镜像的地址
imagePullPolicy: Always # 可选,镜像拉取策略
command:
- nginx # 可选,容器启动执行的命令
- -g
- "daemon off;"
workingDir: /usr/share/nginx/html # 可选,容器的工作目录
volumeMounts: # 可选,存储卷配置
- name: webroot # 存储卷名称
mountPath: /usr/share/nginx/html # 挂载目录
readOnly: true # 只读
ports: # 可选,容器需要暴露的端口号列表
- name: http # 端口名称
containerPort: 80 # 端口号
protocol: TCP # 端口协议,默认TCP
env: # 可选,环境变量配置
- name: TZ # 变量名
value: Asia/Shanghai
- name: LANG
value: en_US.utf8
resources: # 可选,资源限制和资源请求限制
limits: # 最大限制设置
cpu: 1000m
memory: 1024MiB
requests: # 启动所需的资源
cpu: 100m
memory: 512MiB
readinessProbe: # 可选,容器状态检查
httpGet: # 检测方式
path: / # 检查路径
port: 80 # 监控端口
timeoutSeconds: 2 # 超时时间
initialDelaySeconds: 60 # 初始化时间
livenessProbe: # 可选,监控状态检查
exec: # 检测方式
command:
- cat
- /health
httpGet: # 检测方式
path: /_health
port: 8080
httpHeaders:
- name: end-user
value: jason
tcpSocket: # 检测方式
port: 80
initialDelaySeconds: 60 # 初始化时间
timeoutSeconds: 2 # 超时时间
periodSeconds: 5 # 检测间隔
successThreshold: 2 # 检查成功为2次表示就绪
failureThreshold: 1 # 检测失败1次表示未就绪
securityContext: # 可选,限制容器不可信的行为
provoleged: false
restartPolicy: Always # 可选,默认为Always
nodeSelector: # 可选,指定Node节点
region: subnet7
imagePullSecrets: # 可选,拉取镜像使用的secret
- name: default-dockercfg-86258
hostNetwork: false # 可选,是否为主机模式,如是,会占用主机端口
volumes: # 共享存储卷列表
- name: webroot # 名称,与上述对应
emptyDir: {} # 共享卷类型,空
hostPath: # 共享卷类型,本机目录
path: /etc/hosts
secret: # 共享卷类型,secret模式,一般用于密码
secretName: default-token-tf2jp # 名称
defaultMode: 420 # 权限
configMap: # 一般用于配置文件
name: nginx-conf
defaultMode: 420

3 - Deployment

虽然 ReplicaSet 可以确保在任何给定时间运行的 Pod 副本达到指定的数量,但是 Deployment(部署)是一个更高级的概念,它管理 ReplicaSet 并为 Pod 和 ReplicaSet 提供声明性更新以及许多其他有用的功能,所以建议在实际使用中,使用 Deployment 代替 ReplicaSet 。

如果在 Deployment 对象中描述了所需的状态,Deployment 控制器就会以可控制的速率将实际状态更改为期望状态。也可以在 Deployment 中创建新的 ReplicaSet,或者删除现有的 Deployment 并使用新的 Deployment 部署所用的资源。

3.1 创建 Deployment

创建一个 Deployment 文件,并命名为 dc-nginx.yaml,用于部署三个 Nginx Pod:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  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

示例解析:

  • nginx-deployment:Deployment的名称。
  • replicas:创建Pod的副本数。
  • selector:定义Deployment如何找到要管理的Pod,与template的label(标签)对应。

template 字段包含以下字段:

  • app:nginx使用label(标签)标记Pod
  • spec:表示Pod运行一个名字为nginx的容器。
  • image:运行此Pod使用的镜像
  • Port:容器用于发送和接收流量的端口

使用 kubectl create 创建此 Deployment:

[root@k8s-master01 2.2.8.1]# kubectl create -f dc-nginx.yaml

deployment.apps/nginx-deployment created

使用 kubectl get 或者 kubectl describe 查看此 Deployment:

[root@k8s-master01 2.2.8.1]# kubectl get deploy

NAME               DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3         3         3            1           60s

其中:

  • NAME:集群中Deployment的名称。
  • DESIRED:应用程序副本数。
  • CURRENT:当前正在运行的副本数。
  • UP-TO-DATE:显示已达到期望状态的被更新的副本数。
  • AVAILABLE:显示用户可以使用的应用程序副本数,当前为1,因为部分Pod仍在创建过程中。
  • AGE:显示应用程序运行的时间。

查看此时 Deployment rollout 的状态:

[root@k8s-master01 2.2.8.1]# kubectl rollout status deployment/nginx-deployment

deployment "nginx-deployment" successfully rolled out

再次查看此 Deployment:

[root@k8s-master01 2.2.8.1]# kubectl get deploy

NAME               DESIRED   CURRENT   UP-TO-DATE   AVAILABLE   AGE
nginx-deployment   3         3         3            3           11m

查看此 Deployment 创建的 ReplicaSet:

[root@k8s-master01 2.2.8.1]# kubectl get rs

NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-5c689d88bb   3         3         3       12m

查看此 Deployment 创建的 Pod:

[root@k8s-master01 2.2.8.1]# kubectl get pods --show-labels

NAME                                READY   STATUS    RESTARTS   AGE   LABELS
nginx-deployment-5c689d88bb-6b95k   1/1     Running   0          13m   app=nginx,pod-template-hash=5c689d88bb
nginx-deployment-5c689d88bb-9z5z2   1/1     Running   0          13m   app=nginx,pod-template-hash=5c689d88bb
nginx-deployment-5c689d88bb-jc8hr   1/1     Running   0          13m   app=nginx,pod-template-hash=5c689d88bb

3.2 更新 Deployment

一般对应用程序升级或者版本迭代时,会通过 Deployment 对 Pod 进行滚动更新。

假如更新 Nginx Pod 的 image 使用 nginx:1.9.1:

[root@k8s-master01 2.2.8.1]# kubectl set image deployment nginx-deployment nginx=nginx:1.9.1 --record

deployment.extensions/nginx-deployment image updated

当然也可以直接编辑 Deployment,效果相同:

[root@k8s-master01 2.2.8.1]# kubectl edit deployment.v1.apps/nginx-deployment

deployment.apps/nginx-deployment edited

使用 kubectl rollout status 查看更新状态:

[root@k8s-master01 2.2.8.1]# kubectl rollout status deployment.v1.apps/nginx-deployment

Waiting for deployment "nginx-deployment" rollout to finish: 1 out of 3 new replicas have been updated...
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: 2 out of 3 new replicas have been updated...
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

查看 ReplicaSet:

[root@k8s-master01 2.2.8.1]# kubectl get rs

NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-5c689d88bb   0         0         0       34m
nginx-deployment-6987cdb55b   3         3         3       5m14s

通过 describe 查看 Deployment 的详细信息:

[root@k8s-master01 2.2.8.1]# kubectl describe deploy nginx-deployment

Name:                   nginx-deployment
Namespace:              default
CreationTimestamp:      Thu, 24 Jan 2019 15:15:15 +0800
Labels:                 app=nginx
Annotations:            deployment.kubernetes.io/revision: 2
                        kubernetes.io/change-cause: kubectl set image deployment nginx-deployment nginx=nginx:1.9.1 --record=true
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.9.1
    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-6987cdb55b (3/3 replicas created)
Events:
  Type    Reason             Age    From                   Message
  ----    ------             ----   ----                   -------
  Normal  ScalingReplicaSet  36m    deployment-controller  Scaled up replica set nginx-deployment-5c689d88bb to 3
  Normal  ScalingReplicaSet  7m16s  deployment-controller  Scaled up replica set nginx-deployment-6987cdb55b to 1
  Normal  ScalingReplicaSet  5m18s  deployment-controller  Scaled down replica set nginx-deployment-5c689d88bb to 2
  Normal  ScalingReplicaSet  5m18s  deployment-controller  Scaled up replica set nginx-deployment-6987cdb55b to 2
  Normal  ScalingReplicaSet  4m35s  deployment-controller  Scaled down replica set nginx-deployment-5c689d88bb to 1
  Normal  ScalingReplicaSet  4m34s  deployment-controller  Scaled up replica set nginx-deployment-6987cdb55b to 3
  Normal  ScalingReplicaSet  3m30s  deployment-controller  Scaled down replica set nginx-deployment-5c689d88bb to 0

在describe中可以看出,第一次创建时,它创建了一个名为 nginx-deployment-5c689d88bb 的 ReplicaSet,并直接将其扩展为3个副本。更新部署时,它创建了一个新的 ReplicaSet,命名为 nginx-deployment-6987cdb55b,并将其副本数扩展为1,然后将旧的 ReplicaSet 缩小为2,这样至少可以有2个 Pod 可用,最多创建了4个 Pod。以此类推,使用相同的滚动更新策略向上和向下扩展新旧 ReplicaSet,最终新的 ReplicaSet 可以拥有3个副本,并将旧的 ReplicaSet 缩小为0。

3.3 回滚 Deployment

当新版本不稳定时,可以对其进行回滚操作,默认情况下,所有 Deployment 的 rollout 历史都保留在系统中,可以随时回滚。

假设我们又进行了几次更新:

[root@k8s-master01 2.2.8.1]# kubectl set image deployment nginx-deployment nginx=dotbalo/canary:v1 --record

[root@k8s-master01 2.2.8.1]# kubectl set image deployment nginx-deployment nginx=dotbalo/canary:v2 --record

使用 kubectl rollout history 查看部署历史:

[root@k8s-master01 2.2.8.1]# kubectl rollout history deployment/nginx-deployment

deployment.extensions/nginx-deployment
REVISION  CHANGE-CAUSE
1         <none>
2         kubectl set image deployment nginx-deployment nginx=nginx:1.9.1 --record=true
3         kubectl set image deployment nginx-deployment nginx=dotbalo/canary:v1 --record=true
4         kubectl set image deployment nginx-deployment nginx=dotbalo/canary:v2 --record=true

查看 Deployment 某次更新的详细信息,使用 --revision 指定版本号:

[root@k8s-master01 2.2.8.1]# kubectl rollout history deployment.v1.apps/nginx-deployment --revision=3

deployment.apps/nginx-deployment with revision #3
Pod Template:
  Labels:   app=nginx
    pod-template-hash=645959bf6b
  Annotations:  kubernetes.io/change-cause: kubectl set image deployment nginx-deployment nginx=dotbalo/canary:v1 --record=true
  Containers:
   nginx:
    Image:  dotbalo/canary:v1
    Port:   80/TCP
    Host Port:  0/TCP
    Environment:    <none>
    Mounts: <none>
  Volumes:  <none>

使用 kubectl rollout undo 回滚到上一个版本:

[root@k8s-master01 2.2.8.1]# kubectl rollout undo deployment.v1.apps/nginx-deployment

deployment.apps/nginx-deployment

再次查看更新历史,发现 REVISION 5 回到了 canary:v1:

[root@k8s-master01 2.2.8.1]# kubectl rollout history deployment/nginx-deployment

deployment.extensions/nginx-deployment
REVISION  CHANGE-CAUSE
1         <none>
2         kubectl set image deployment nginx-deployment nginx=nginx:1.9.1 --record=true
4         kubectl set image deployment nginx-deployment nginx=dotbalo/canary:v2 --record=true
5         kubectl set image deployment nginx-deployment nginx=dotbalo/canary:v1 --record=true

使用 --to-revision 参数回到指定版本:

[root@k8s-master01 2.2.8.1]# kubectl rollout undo deployment/nginx-deployment --to-revision=2

deployment.extensions/nginx-deployment

3.4 扩展 Deployment

当公司访问量变大,三个 Pod 已无法支撑业务时,可以对其进行扩展。

使用 kubectl scale 动态调整 Pod 的副本数,比如增加 Pod 为5个:

[root@k8s-master01 2.2.8.1]# kubectl scale deployment.v1.apps/nginx-deployment --replicas=5

deployment.apps/nginx-deployment scaled

查看 Pod,此时 Pod 已经变成了5个:

[root@k8s-master01 2.2.8.1]# kubectl get po

NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-5f89547d9c-5r56b   1/1     Running   0          90s
nginx-deployment-5f89547d9c-htmn7   1/1     Running   0          25s
nginx-deployment-5f89547d9c-nwxs2   1/1     Running   0          99s
nginx-deployment-5f89547d9c-rpwlg   1/1     Running   0          25s
nginx-deployment-5f89547d9c-vlr5p   1/1     Running   0          95s

3.5 暂停和恢复 Deployment 更新

Deployment 支持暂停更新,用于对 Deployment 进行多次修改操作。

使用 kubectl rollout pause 暂停 Deployment 更新:

[root@k8s-master01 2.2.8.1]# kubectl rollout pause deployment/nginx-deployment

deployment.extensions/nginx-deployment paused

然后对 Deployment 进行相关更新操作,比如更新镜像,然后对其资源进行限制:

[root@k8s-master01 2.2.8.1]# kubectl set image deployment.v1.apps/nginx-deployment nginx=nginx:1.9.1

deployment.apps/nginx-deployment image updated

[root@k8s-master01 2.2.8.1]# kubectl set resources deployment.v1.apps/nginx-deployment -c=nginx --limits=cpu=200m,memory=512Mi

deployment.apps/nginx-deployment resource requirements updated

通过 rollout history 可以看到没有新的更新:

[root@k8s-master01 2.2.8.1]# kubectl rollout history deployment.v1.apps/nginx-deployment

deployment.apps/nginx-deployment
REVISION  CHANGE-CAUSE
1         <none>
5         kubectl set image deployment nginx-deployment nginx=dotbalo/canary:v1 --record=true
7         kubectl set image deployment nginx-deployment nginx=dotbalo/canary:v2 --record=true
8         kubectl set image deployment nginx-deployment nginx=dotbalo/canary:v2 --record=true

使用 kubectl rollout resume 恢复 Deployment 更新:

[root@k8s-master01 2.2.8.1]# kubectl rollout resume deployment.v1.apps/nginx-deployment

deployment.apps/nginx-deployment resumed

可以查看到恢复更新的 Deployment 创建了一个新的 RS(复制集):

[root@k8s-master01 2.2.8.1]# kubectl get rs

NAME                          DESIRED   CURRENT   READY   AGE
nginx-deployment-57895845b8   5         5         4       11s

可以查看 Deployment 的 image(镜像)已经变为 nginx:1.9.1:

[root@k8s-master01 2.2.8.1]# kubectl describe deploy nginx-deployment

Name:                   nginx-deployment
Namespace:              default
CreationTimestamp:      Thu, 24 Jan 2019 15:15:15 +0800
Labels:                 app=nginx
Annotations:            deployment.kubernetes.io/revision: 9
                        kubernetes.io/change-cause: kubectl set image deployment nginx-deployment nginx=dotbalo/canary:v2 --record=true
Selector:               app=nginx
Replicas:               5 desired | 5 updated | 5 total | 5 available | 0 unavailable
StrategyType:           RollingUpdate
MinReadySeconds:        0
RollingUpdateStrategy:  25% max unavailable, 25% max surge
Pod Template:
  Labels:  app=nginx
  Containers:
   nginx:
    Image:      nginx:1.9.1
    Port:       80/TCP
    Host Port:  0/TCP

3.6 更新 Deployment 的注意事项

清理策略:

在默认情况下,revision 保留10个旧的 ReplicaSet,其余的将在后台进行垃圾回收,可以在 .spec.revisionHistoryLimit 设置保留 ReplicaSet 的个数。当设置为0时,不保留历史记录。

更新策略:

  • .spec.strategy.type==Recreate,表示重建,先删掉旧的 Pod 再创建新的 Pod。

  • .spec.strategy.type==RollingUpdate,表示滚动更新,可以指定 maxUnavailable 和 maxSurge 来控制滚动更新过程。

  • .spec.strategy.rollingUpdate.maxUnavailable,指定在回滚更新时最大不可用的 Pod 数量,可选字段,默认为25%,可以设置为数字或百分比,如果 maxSurge 为0,则该值不能为0。

  • .spec.strategy.rollingUpdate.maxSurge 可以超过期望值的最大 Pod 数,可选字段,默认为25%,可以设置成数字或百分比,如果 maxUnavailable 为0,则该值不能为0。

4 - StatefulSet

StatefulSet(有状态集)常用于部署有状态的且需要有序启动的应用程序。

4.1 StatefulSet 的基本概念

StatefulSet 主要用于管理有状态应用程序的工作负载API对象。比如在生产环境中,可以部署 ElasticSearch 集群、MongoDB 集群或者需要持久化的 RabbitMQ集群、Redis集群、Kafka集群和ZooKeeper集群等。

而 StatefulSet 创建的 Pod 一般使用 Headless Service(无头服务)进行通信,和普通的Service的区别在于 Headless Service 没有ClusterIP,它使用的是 Endpoint 进行互相通信,Headless 一般的格式为:

statefulSetName-{0..N-1}.serviceName.namespace.svc.cluster.local.

说明:

  • serviceName为 Headless Service 的名字。
  • 0..N-1为Pod所在的序号,从0开始到N-1。
  • statefulSetName 为 StatefulSet 的名字。
  • namespace 为服务所在的命名空间。
  • .cluster.local为 Cluster Domain(集群域)。

比如,一个 Redis 主从架构,Slave 连接 Master 主机配置就可以使用不会更改的 Master 的 Headless Service,例如 Redis 从节点(Slave)配置文件如下:

port 6379
slaveofredis-sentinel-master-ss-0.redis-sentinel-master-ss.public-service.svc.cluster.local 6379
tcp-backlog 511
timeout 0
tcp-keepalive 0
……

其中,redis-sentinel-master-ss-0.redis-sentinel-master-ss.public-service.svc.cluster.local 是 Redis Master 的 Headless Service。

4.2 StatefulSet 组件

定义一个简单的 StatefulSet 的示例如下:

apiVersion: v1
kind: Service
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  ports:
  - port: 80
    name: web
  clusterIP: None
  selector:
    app: nginx
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: web
spec:
  serviceName: "nginx"
  replicas: 2
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80
          name: web

其中:

  • kind: Service 定义了一个名字为 Nginx 的 Headless Service,创建的 Service 格式为 nginx-0.nginx.default.svc.cluster.local,其他的类似,因为没有指定 Namespace(命名空间),所以默认部署在 default 命名空间下。
  • kind: StatefulSet 定义了一个名字为 web 的 StatefulSet,replicas 表示部署 Pod 的副本数,本实例为2。

4.3 创建 StatefulSet

创建 StatefulSet:

[root@k8s-master01 2.2.7]# kubectl create -f sts-web.yaml

service/nginx created
statefulset.apps/web created

[root@k8s-master01 2.2.7]# kubectl get sts

NAME   DESIRED   CURRENT   AGE
web    2         2         12s

[root@k8s-master01 2.2.7]# kubectl get svc

NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1    <none>        443/TCP   7d2h
nginx        ClusterIP   None         <none>        80/TCP    16s

[root@k8s-master01 2.2.7]# kubectl get po -l app=nginx

NAME    READY   STATUS    RESTARTS   AGE
web-0   1/1     Running   0          2m5s
web-1   1/1     Running   0          115s

4.4 StatefulSet 扩容和缩容

和 Deployment 类似,可以通过更新 replicas 字段扩容/缩容 StatefulSet,也可以使用 kubectl scale 或者 kubectl patch 来扩容/缩容一个 StatefulSet。

4.4.1 扩容

将上述创建的 sts 副本增加到5个(扩容之前必须保证有创建完成的静态PV,动态PV和emptyDir):

[root@k8s-master01 2.2.7]# kubectl scale sts web --replicas=5

statefulset.apps/web scaled

查看 Pod 状态:

[root@k8s-master01 2.2.7]# kubectl get po

NAME    READY   STATUS    RESTARTS   AGE
web-0   1/1     Running   0          2m58s
web-1   1/1     Running   0          2m48s
web-2   1/1     Running   0          116s
web-3   1/1     Running   0          79s
web-4   1/1     Running   0          53s

也可使用以下命令动态查看:

kubectl get pods -w -l app=nginx

4.4.2 缩容

在一个终端动态查看:

[root@k8s-master01 2.2.7]# kubectl get pods -w -l app=nginx

NAME    READY   STATUS    RESTARTS   AGE
web-0   1/1     Running   0          4m37s
web-1   1/1     Running   0          4m27s
web-2   1/1     Running   0          3m35s
web-3   1/1     Running   0          2m58s
web-4   1/1     Running   0          2m32s

在另一个终端将副本数改为3:

[root@k8s-master01 ~]# kubectl patch sts web -p '{"spec":{"replicas":3}}'

statefulset.apps/web patched

此时可以看到第一个终端显示 web-4 和 web-3 的 Pod 正在被删除(或终止):

[root@k8s-master01 2.2.7]# kubectl get pods -w -l app=nginx

NAME    READY   STATUS    RESTARTS   AGE
web-0   1/1     Running   0          4m37s
web-1   1/1     Running   0          4m27s
web-2   1/1     Running   0          3m35s
web-3   1/1     Running   0          2m58s
web-4   1/1     Running   0          2m32s
web-0   1/1   Running   0     5m8s
web-0   1/1   Running   0     5m11s
web-4   1/1   Terminating   0     3m36s
web-4   0/1   Terminating   0     3m38s
web-4   0/1   Terminating   0     3m47s
web-4   0/1   Terminating   0     3m47s
web-3   1/1   Terminating   0     4m13s
web-3   0/1   Terminating   0     4m14s
web-3   0/1   Terminating   0     4m22s
web-3   0/1   Terminating   0     4m22s

4.5 更新策略

4.5.1 On Delete 策略

OnDelete 更新策略实现了传统(1.7版本之前)的行为,它也是默认的更新策略。当我们选择这个更新策略并修改 StatefulSet 的 .spec.template 字段时,StatefulSet 控制器不会自动更新 Pod,我们必须手动删除 Pod 才能使控制器创建新的 Pod。

4.5.2 RollingUpdate 策略

RollingUpdate(滚动更新)更新策略会更新一个 StatefulSet 中所有的 Pod,采用与序号索引相反的顺序进行滚动更新。

比如 Patch 一个名称为web的 StatefulSet 来执行 RollingUpdate 更新:

[root@k8s-master01 2.2.7]# kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate"}}}'

statefulset.apps/web patched

查看更改后的 StatefulSet:

[root@k8s-master01 2.2.7]# kubectl get sts web -o yaml | grep -A 1 "updateStrategy"

  updateStrategy:
    type: RollingUpdate

然后改变容器的镜像进行滚动更新:

[root@k8s-master01 2.2.7]# kubectl patch statefulset web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"dotbalo/canary:v1"}]'

statefulset.apps/web patched

如上所述,StatefulSet 里的 Pod 采用和序号相反的顺序更新。在更新下一个 Pod 前,StatefulSet 控制器会终止每一个 Pod 并等待它们变成 RunningReady 状态。在当前顺序变成 Running 和 Ready 状态之前,StatefulSet 控制器不会更新下一个 Pod,但它仍然会重建任何在更新过程中发生故障的 Pod,使用它们当前的版本。已经接收到请求的 Pod 将会被恢复为更新的版本,没有收到请求的 Pod 则会被恢复为之前的版本。

在更新过程中可以使用 kubectl rollout status sts/<name> 来查看滚动更新的状态:

[root@k8s-master01 2.2.7]# kubectl rollout status sts/web

Waiting for 1 pods to be ready...
waiting for statefulset rolling update to complete 1 pods at revision web-56b5798f76...
Waiting for 1 pods to be ready...
Waiting for 1 pods to be ready...
waiting for statefulset rolling update to complete 2 pods at revision web-56b5798f76...
Waiting for 1 pods to be ready...
Waiting for 1 pods to be ready...
statefulset rolling update complete 3 pods at revision web-56b5798f76...

查看更新后的镜像:

[root@k8s-master01 2.2.7]# for p in 0 1 2; do kubectl get po web-$p --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'; echo; done

dotbalo/canary:v1
dotbalo/canary:v1
dotbalo/canary:v1

4.5.3 分段更新

StatefulSet 可以使用 RollingUpdate 更新策略的 partition 参数来分段更新一个 StatefulSet。分段更新将会使 StatefulSet 中其余的所有 Pod(序号小于分区)保持当前版本,只更新序号大于等于分区的 Pod,利用此特性可以简单实现金丝雀发布(灰度发布)或者分阶段推出新功能等。注:金丝雀发布是指在黑与白之间能够平滑过渡的一种发布方式。

比如我们定义一个分区"partition":3,可以使用 patch 直接对 StatefulSet 进行设置:

# kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":3}}}}'

statefulset "web" patched

然后再次patch改变容器的镜像:

# kubectl patch statefulset web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"k8s.gcr.io/nginx-slim:0.7"}]'

statefulset "web" patched

删除Pod触发更新:

kubectl delete po web-2

pod "web-2" deleted

此时,因为 Pod web-2 的序号小于分区3,所以 Pod 不会被更新,还是会使用以前的容器恢复 Pod。

将分区改为2,此时会自动更新 web-2(因为之前更改了更新策略),但是不会更新 web-0 和 web-1:

# kubectl patch statefulset web -p '{"spec":{"updateStrategy":{"type":"RollingUpdate","rollingUpdate":{"partition":2}}}}'

statefulset "web" patched

按照上述方式,可以实现分阶段更新,类似于灰度/金丝雀发布。查看最终的结果如下:

[root@k8s-master01 2.2.7]# for p in 0 1 2; do kubectl get po web-$p --template '{{range $i, $c := .spec.containers}}{{$c.image}}{{end}}'; echo; done

dotbalo/canary:v1
dotbalo/canary:v1
dotbalo/canary:v2

4.6 删除 StatefulSet

删除 StatefulSet 有两种方式,即级联删除和非级联删除。使用非级联方式删除 StatefulSet 时,StatefulSet 的 Pod 不会被删除;使用级联删除时,StatefulSet 和它的 Pod 都会被删除。

4.6.1 非级联删除

使用 kubectl delete sts xxx 删除 StatefulSet 时,只需提供 --cascade=false 参数,就会采用非级联删除,此时删除 StatefulSet 不会删除它的 Pod:

[root@k8s-master01 2.2.7]# kubectl get po

NAME    READY   STATUS    RESTARTS   AGE
web-0   1/1     Running   0          16m
web-1   1/1     Running   0          16m
web-2   1/1     Running   0          11m

[root@k8s-master01 2.2.7]# kubectl delete statefulset web --cascade=false

statefulset.apps "web" deleted

[root@k8s-master01 2.2.7]# kubectl get sts

No resources found.

[root@k8s-master01 2.2.7]# kubectl get po

NAME    READY   STATUS    RESTARTS   AGE
web-0   1/1     Running   0          16m
web-1   1/1     Running   0          16m
web-2   1/1     Running   0          11m

由于此时删除了 StatefulSet,因此单独删除 Pod 时,不会被重建:

[root@k8s-master01 2.2.7]# kubectl get po

NAME    READY   STATUS    RESTARTS   AGE
web-0   1/1     Running   0          16m
web-1   1/1     Running   0          16m
web-2   1/1     Running   0          11m

[root@k8s-master01 2.2.7]# kubectl delete po web-0

pod "web-0" deleted

[root@k8s-master01 2.2.7]# kubectl get po

NAME    READY   STATUS    RESTARTS   AGE
web-1   1/1     Running   0          18m
web-2   1/1     Running   0          12m

当再次创建此 StatefulSet 时,web-0 会被重新创建,web-1 由于已经存在而不会被再次创建,因为最初此 StatefulSet 的 replicas 是2,所以 web-2 会被删除,如下(忽略AlreadyExists错误):

[root@k8s-master01 2.2.7]# kubectl create -f sts-web.yaml

statefulset.apps/web created
Error from server (AlreadyExists): error when creating "sts-web.yaml": services "nginx" already exists

[root@k8s-master01 2.2.7]# kubectl get po

NAME    READY   STATUS    RESTARTS   AGE
web-0   1/1     Running   0          32s
web-1   1/1     Running   0          19m

4.6.2 级联删除

省略 --cascade=false 参数即为级联删除:

[root@k8s-master01 2.2.7]# kubectl delete statefulset web

statefulset.apps "web" deleted

[root@k8s-master01 2.2.7]# kubectl get po

No resources found.

也可以使用 -f 参数直接删除 StatefulSet 和 Service(此文件将sts和svc写在了一起):

[root@k8s-master01 2.2.7]# kubectl delete -f sts-web.yaml

service "nginx" deleted
Error from server (NotFound): error when deleting "sts-web.yaml": statefulsets.apps "web" not found

5 - DaemonSet

DaemonSet(守护进程集)和守护进程类似,它在符合匹配条件的节点上均部署一个 Pod。

5.1 什么是 DaemonSet

DaemonSet 确保全部(或者某些)节点上运行一个 Pod 副本。当有新节点加入集群时,也会为它们新增一个 Pod。当节点从集群中移除时,这些 Pod 也会被回收,删除 DaemonSet 将会删除它创建的所有 Pod。

使用 DaemonSet 的一些典型用法:

  • 运行集群存储daemon(守护进程),例如在每个节点上运行Glusterd、Ceph等。
  • 在每个节点运行日志收集daemon,例如Fluentd、Logstash。
  • 在每个节点运行监控daemon,比如Prometheus Node Exporter、Collectd、Datadog代理、New Relic代理或 Ganglia gmond。

5.2 编写 DaemonSet 规范

创建一个 DaemonSet 的内容大致如下,比如创建一个 fluentd 的 DaemonSet:

apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: fluentd-es-v2.0.4
  namespace: logging
  labels:
    k8s-app: fluentd-es
    version: v2.0.4
    kubernetes.io/cluster-service: "true"
    addonmanager.kubernetes.io/mode: Reconcile
spec:
  selector:
    matchLabels:
      k8s-app: fluentd-es
      version: v2.0.4
  template:
    metadata:
      labels:
        k8s-app: fluentd-es
        kubernetes.io/cluster-service: "true"
        version: v2.0.4
      # This annotation ensures that fluentd does not get evicted if the node
      # supports critical pod annotation based priority scheme.
      # Note that this does not guarantee admission on the nodes (#40573).
      annotations:
        scheduler.alpha.kubernetes.io/critical-pod: ''
        seccomp.security.alpha.kubernetes.io/pod: 'docker/default'
    spec:
      serviceAccountName: fluentd-es
      containers:
      - name: fluentd-es
        image: k8s.gcr.io/fluentd-elasticsearch:v2.0.4
        env:
        - name: FLUENTD_ARGS
          value: --no-supervisor -q
        resources:
          limits:
            memory: 500Mi
          requests:
            cpu: 100m
            memory: 200Mi
        volumeMounts:
        - name: varlog
          mountPath: /var/log
        - name: varlibdockercontainers
          mountPath: /var/lib/docker/containers
          readOnly: true
        - name: config-volume
          mountPath: /etc/fluent/config.d
      nodeSelector:
        beta.kubernetes.io/fluentd-ds-ready: "true"
      terminationGracePeriodSeconds: 30
      volumes:
      - name: varlog
        hostPath:
          path: /var/log
      - name: varlibdockercontainers
        hostPath:
          path: /var/lib/docker/containers
      - name: config-volume
        configMap:
          name: fluentd-es-config-v0.1.4

5.2.1 必需字段

和其他所有 Kubernetes 配置一样,DaemonSet 需要 apiVersion、kind 和 metadata 字段,同时也需要一个 .spec 配置段。

5.2.2 Pod模板

.spec 唯一需要的字段是 .spec.template。.spec.template 是一个 Pod 模板,它与 Pod 具有相同的配置方式,但它不具有 apiVersion 和 kind 字段。

除了 Pod 必需的字段外,在 DaemonSet 中的 Pod 模板必须指定合理的标签。

在 DaemonSet 中的 Pod 模板必须具有一个 RestartPolicy,默认为 Always。

5.2.3 Pod Selector

.spec.selector 字段表示 Pod Selector,它与其他资源的 .spec.selector 的作用相同。

.spec.selector 表示一个对象,它由如下两个字段组成:

  • matchLabels,与ReplicationController的.spec.selector的作用相同,用于匹配符合条件的Pod。
  • matchExpressions,允许构建更加复杂的Selector,可以通过指定key、value列表以及与key和value列表相关的操作符。

如果上述两个字段都指定时,结果表示的是 AND关系(逻辑与的关系)。

.spec.selector 必须与 .spec.template.metadata.labels 相匹配。如果没有指定,默认是等价的,如果它们的配置不匹配,则会被API拒绝。

5.2.4 指定节点部署Pod

如果指定了 .spec.template.spec.nodeSelector,DaemonSet Controller 将在与 Node Selector(节点选择器)匹配的节点上创建 Pod,比如部署在磁盘类型为ssd的节点上(需要提前给节点定义标签Label):

containers:
  - name: nginx
    image: nginx
    imagePullPolicy: IfNotPresent
  nodeSelector:
    disktype: ssd

提示:
Node Selector 同样适用于其他 Controller。

5.3 创建 DaemonSet

在生产环境中,公司业务的应用程序一般无须使用 DaemonSet 部署,一般情况下只有像 Fluentd(日志收集)、Ingress(集群服务入口)、Calico(集群网络组件)、Node-Exporter(监控数据采集)等才需要使用 DaemonSet 部署到每个节点。本节只演示 DaemonSet 的使用。

比如创建一个 nginx ingress(文件地址:https://github.com/dotbalo/k8s/blob/master/nginx-ingress/ingress.yaml):

# kubectl create -f nginx-ds.yaml

namespace/ingress-nginx created
configmap/nginx-configuration created
configmap/tcp-services created
configmap/udp-services created
serviceaccount/nginx-ingress-serviceaccount created
clusterrole.rbac.authorization.k8s.io/nginx-ingress-clusterrole created
role.rbac.authorization.k8s.io/nginx-ingress-role created
rolebinding.rbac.authorization.k8s.io/nginx-ingress-role-nisa-binding created
clusterrolebinding.rbac.authorization.k8s.io/nginx-ingress-clusterrole-nisa-binding created
daemonset.extensions/nginx-ingress-controller created

此时会在每个节点创建一个 Pod:

# kubectl get po -n ingress-nginx

NAME                                 READY   STATUS    RESTARTS   AGE
nginx-ingress-controller-fjkf2   1/1     Running   0           44s
nginx-ingress-controller-gfmcv   1/1     Running   0           44s
nginx-ingress-controller-j89qc   1/1     Running   0           44s
nginx-ingress-controller-sqsk2   1/1     Running   0           44s
nginx-ingress-controller-tgdt6   1/1     Running   0           44s

[root@k8s-master01 2.2.8]# kubectl get po -n ingress-nginx -o wide

NAME                                 READY   STATUS    RESTARTS   AGE
IP              NODE           NOMINATED NODE
nginx-ingress-controller-fjkf2   1/1     Running   0          50s   192.168.20.30   k8s-node01     <none>
nginx-ingress-controller-gfmcv   1/1     Running   0          50s   192.168.20.21   k8s-master02   <none>
nginx-ingress-controller-j89qc   1/1     Running   0          50s   192.168.20.22   k8s-master03   <none>
nginx-ingress-controller-sqsk2   1/1     Running   0          50s   192.168.20.31   k8s-node02     <none>
nginx-ingress-controller-tgdt6   1/1     Running   0          50s   192.168.20.20   k8s-master01   <none>

5.4 更新和回滚 DaemonSet

如果修改了节点标签(Label),DaemonSet 将立刻向新匹配上的节点添加 Pod,同时删除不能匹配的节点上的 Pod。

在 Kubernetes 1.6 以后的版本中,可以在 DaemonSet 上执行滚动更新,未来的 Kubernetes 版本将支持节点的可控更新。

DaemonSet 滚动更新可参考:https://kubernetes.io/docs/tasks/manage-daemon/update-daemon-set/。

DaemonSet 更新策略和 StatefulSet 类似,也有 OnDeleteRollingUpdate 两种方式。

查看上一节创建的 DaemonSet 更新方式:

# kubectl get ds/nginx-ds -o go-template='{{.spec.updateStrategy.type}}{{"\n"}}'

RollingUpdate

提示
如果是其他 DaemonSet,请确保更新策略是 RollingUpdate(滚动更新)。

5.4.1 命令式更新

kubectl edit ds/<daemonset-name>

kubectl patch ds/<daemonset-name> -p=<strategic-merge-patch>

5.4.2 更新镜像

kubectl set image ds/<daemonset-name><container-name>=<container-new-image>--record=true

5.4.3 查看更新状态

kubectl rollout status ds/<daemonset-name>

5.4.4 列出所有修订版本

kubectl rollout history daemonset <daemonset-name>

5.4.5 回滚到指定revision

kubectl rollout undo daemonset <daemonset-name> --to-revision=<revision>

DaemonSet 的更新和回滚与 Deployment 类似,此处不再演示。

6 - Label 和 Selector

当 Kubernetes 对系统的任何API对象如 Pod 和节点进行“分组”时,会对其添加 Label(key=value形式的“键-值对”)用以精准地选择对应的API对象。而 Selector(标签选择器)则是针对匹配对象的查询方法。注:键-值对就是key-value pair。

例如,常用的标签 tier 可用于区分容器的属性,如frontend、backend;或者一个 release_track 用于区分容器的环境,如canary、production等。

6.1 定义 Label

应用案例:

公司与xx银行有一条专属的高速光纤通道,此通道只能与 192.168.7.0 网段进行通信,因此只能将与xx银行通信的应用部署到 192.168.7.0 网段所在的节点上,此时可以对节点进行 Label(即加标签):

[root@k8s-master01 ~]# kubectl label node k8s-node02 region=subnet7

node/k8s-node02 labeled

然后,可以通过 Selector 对其筛选:

[root@k8s-master01 ~]# kubectl get no -l region=subnet7

NAME         STATUS   ROLES    AGE     VERSION
k8s-node02   Ready    <none>   3d17h   v1.17.3

最后,在 Deployment 或其他控制器中指定将 Pod 部署到该节点:

containers:
  ......
dnsPolicy: ClusterFirst
nodeSelector:
  region: subnet7
restartPolicy: Always
......

也可以用同样的方式对 Service 进行 Label:

[root@k8s-master01 ~]# kubectl label svc canary-v1 -n canary-production env=canary version=v1

service/canary-v1 labeled

查看 Labels:

[root@k8s-master01 ~]# kubectl get svc -n canary-production --show-labels

NAME        TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE   LABELS
canary-v1   ClusterIP   10.110.253.62   <none>        8080/TCP   24h   env=canary,version=v1

还可以查看所有 Version 为 v1 的 svc:

[root@k8s-master01 canary]# kubectl get svc --all-namespaces -l version=v1

NAMESPACE           NAME        TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
canary-production   canary-v1   ClusterIP   10.110.253.62   <none>        8080/TCP   25h

其他资源的 Label 方式相同。

6.2 Selector 条件匹配

Selector 主要用于资源的匹配,只有符合条件的资源才会被调用或使用,可以使用该方式对集群中的各类资源进行分配。

假如对 Selector 进行条件匹配,目前已有的 Label 如下:

[root@k8s-master01 ~]# kubectl get svc --show-labels

NAME          TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE     LABELS
details       ClusterIP   10.99.9.178      <none>        9080/TCP   45h     app=details
kubernetes    ClusterIP   10.96.0.1        <none>        443/TCP    3d19h   component=apiserver,provider=kubernetes
nginx         ClusterIP   10.106.194.137   <none>        80/TCP     2d21h   app=productpage,version=v1
nginx-v2      ClusterIP   10.108.176.132   <none>        80/TCP     2d20h   <none>
productpage   ClusterIP   10.105.229.52    <none>        9080/TCP   45h     app=productpage,tier=frontend
ratings       ClusterIP   10.96.104.95     <none>        9080/TCP   45h     app=ratings
reviews       ClusterIP   10.102.188.143   <none>        9080/TCP   45h     app=reviews

选择app为 reviews 或者 productpage 的 svc:

[root@k8s-master01 ~]# kubectl get svc -l 'app in (details, productpage)' --show-labels

NAME          TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE     LABELS
details       ClusterIP   10.99.9.178      <none>        9080/TCP   45h     app=details
nginx         ClusterIP   10.106.194.137   <none>        80/TCP     2d21h   app=productpage,version=v1
productpage   ClusterIP   10.105.229.52    <none>        9080/TCP   45h     app=productpage,tier=frontend

选择app为 productpage 或 reviews 但不包括 version=v1 的 svc:

[root@k8s-master01 ~]# kubectl get svc -l version!=v1,'app in (details, productpage)' --show-labels

NAME          TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE   LABELS
details       ClusterIP   10.99.9.178     <none>        9080/TCP   45h   app=details
productpage   ClusterIP   10.105.229.52   <none>        9080/TCP   45h   app=productpage,tier=frontend

选择 label key 名为 app 的 svc:

[root@k8s-master01 ~]# kubectl get svc -l app --show-labels

NAME          TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)    AGE     LABELS
details       ClusterIP   10.99.9.178      <none>        9080/TCP   45h     app=details
nginx         ClusterIP   10.106.194.137   <none>        80/TCP     2d21h   app=productpage,version=v1
productpage   ClusterIP   10.105.229.52    <none>        9080/TCP   45h     app=productpage,tier=frontend
ratings       ClusterIP   10.96.104.95     <none>        9080/TCP   45h     app=ratings
reviews       ClusterIP   10.102.188.143   <none>        9080/TCP   45h     app=reviews

6.3 修改标签(Label)

在实际使用中,Label 的更改是经常发生的事情,可以使用 --overwrite 参数修改标签。

修改标签,比如将 version=v1 改为 version=v2:

[root@k8s-master01 canary]# kubectl get svc -n canary-production --show-labels

NAME        TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE   LABELS
canary-v1   ClusterIP   10.110.253.62   <none>        8080/TCP   26h   env=canary,version=v1

[root@k8s-master01 canary]# kubectl label svc canary-v1 -n canary-production version=v2 --overwrite

service/canary-v1 labeled

[root@k8s-master01 canary]# kubectl get svc -n canary-production --show-labels

NAME        TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE   LABELS
canary-v1   ClusterIP   10.110.253.62   <none>        8080/TCP   26h   env=canary,version=v2

6.4 删除标签(Label)

删除标签,比如删除 version:

[root@k8s-master01 canary]# kubectl label svc canary-v1 -n canary-production version-

service/canary-v1 labeled

[root@k8s-master01 canary]# kubectl get svc -n canary-production --show-labels

NAME        TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE   LABELS
canary-v1   ClusterIP   10.110.253.62   <none>        8080/TCP   26h   env=canary

推荐阅读