一、Label 的定义
Label 是 Kubernetes 系统中的一个核心概念。Label 以 key/value 键值对的形式附加到任何对象上,如 Pod,Service,Node,RC(ReplicationController)/RS(ReplicaSet)等。Label 可以在创建对象时就附加到对象上,也可以在对象创建后通过 API 进行额外添加或修改。
二、Label 的表示
在为对象定义好 Label 后,其他对象就可以通过 Label 来对对象进行引用。Label 的最常见的用法便是通过spec.selector来引用对象。下面是文章:Kubernetes 对象之 ReplicaSet 中新建一个 RC 的例子:
apiVersion: v1
kind: ReplicationController
metadata:
name: nginx
labels:
app: nginx
release: stable
spec:
replicas: 3
selector:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
上面的描述文件为名为 nginx 的 Pod 添加了两个 Label,分别为app: nginx
和release: stable
。
关于 Label 的用法重点在于这两步:
- 通过template.metadata.labels字段为即将新建的 Pod 附加 Label。
- 通过spec.selector字段来指定这个 RC 管理哪些 Pod。在上面的例子中,新建的 RC 会管理所有拥有
app:nginx
Label 的 Pod。这样的spec.selector在 Kubernetes 中被称作Label Selector。
常见的 Label
一般来说,我们会给一个 Pod(或其他对象)定义多个 Label,以便于配置,部署等管理工作。例如:部署不同版本的应用到不同的环境中;或者监控和分析应用(日志记录,监控,报警等)。通过多个 Label 的设置,我们就可以多维度的 Pod 或其他对象进行精细化管理。一些常用的 Label 示例如下:
relase: stable
release: canary
environment: dev
environemnt: qa
environment: production
tier: frontend
tier: backend
tier: middleware
app: nginx
......
Label 是自定义的一些 key/value 对,你可以随心所欲的设置。
三、Label Selector
Label selector是Kubernetes核心的分组机制,通过label selector客户端/用户能够识别一组有共同特征或属性的资源对象。
带有 Label 的对象创建好之后,我们就可以通过 Label Selector 来引用这些对象。
通常我们通过描述文件中的spec.selector字段来指定 Label,从而 Kubernetes 寻找到所有包含你指定 Label 的对象,进行管理。
Kubernetes 目前支持两种类型的 Label Selector:
- 基于等式的 Selector(Equality-based)
- 基于集合的 Selector(Set-based)
RC 只支持基于等式的 Selector,而 RS 两种 Selector 都支持。
基于等式的 Selector
上文中创建 RC 的例子中的使用的就是基于等式的 Selector。基于等式的 Selector 通过等式类的表达式来进行筛选。例如:
- app=nginx 选择所有 Label 中 key 为 app,value 为 nginx 的对象。
- env!=dev 选择所有 Label 中 key 为 env,value 不等于 dev 的对象。
基于集合的 Selector
基于集合的 Selector 通过集合操作的表达式来进行筛选。例如:
- name in (redis-master, redis-slave) 选择所有 Label 中 key 为 name,并且 value 为 redis-master 或 redis-slave 的对象。
- env not in (dev) 选择所有 Label 中 key 为 env,并且 value 不为 dev 的对象。
使用 Label 可以给对象创建一组或多组标签,Service,RC/RS 等组件则通过 Label Selector 来定位需要管理的对象,Label 和 Label Selector 共同构成了 Kubernetes 系统中最核心的应用模型,使得对象能够精细分组,同时实现了集群的高可用性。
Node Selector
Node Selector是指定pod分配到指定node上最简单的方法,使用Pod中的nodeSelector属性来实现。Node Selector会指定key-value pairs,pod会被分配到特定node上,该node具有所有指定key-value pairs对应labels。
matchLables 和 matchExpressions
新出现的管理对象如Deploment、ReplicaSet、DaemonSet和Job则可以在Selector中使用基于集合的筛选条件定义,例如:
selector:
matchLabels:
app: nginx
matchExpressions:
- {key: tier, operator: In, values: [frontend]}
- {key: environment, operator: NorIn, values: [dev]}
在使用这些资源的时候,需要注意以下几点:
- 在deployment中必须写spec.selector.matchLabels
- 在定义pod模板时,必须定义spec.template.metadata.lables,因为spec.selector.matchLabels是必须字段,而它又必须和spec.template.metadata.lables的键值一致。
- spec.template.metadata.lables里面定义的内容,会应用到spec.template.spec下定义的所有pod副本中,在spec.template.spec.containers里面不能定义labels标签
四、对 node 添加标签
使用以下格式的命令对指定的node添加标签:
kubectl label nodes <node-name> <label-key>=<label-value>
示例:
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
k8s-master Ready master 171m v1.14.0
k8s-node1 Ready <none> 169m v1.14.0
k8s-node2 Ready <none> 169m v1.14.0
$ kubectl label nodes k8s-master traefik=proxy
node/k8s-master labeled
$ kubectl get nodes --show-labels
NAME STATUS ROLES AGE VERSION LABELS
k8s-master Ready master 172m v1.14.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,traefik=proxy,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-master,kubernetes.io/os=linux,node-role.kubernetes.io/master=
k8s-node1 Ready <none> 171m v1.14.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-node1,kubernetes.io/os=linux
k8s-node2 Ready <none> 171m v1.14.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-node2,kubernetes.io/os=linux
可以看到,对 k8s-master
添加了 traefik=proxy
标签,再次显示所有节点的标签即可看到。
五、Label 的其他操作
删除 label, 使用 key 与减号相连, 如:
kubectl label nodes k8s-master traefik-
为各种资源添加标签:
kubectl label svc test-svc test=svc -n test
kubectl label rc test-controller test=rc -n test
kubectl label rs test-rs test=rs -n test
六、污点标记
使用 Taint 规则,将拒绝 Pod 在 Node 上运行。
Taint 需要和 Tolerations 配合使用,让 Pod 避开那些不合适的 Node。在 Node 上设置一个或多个 Taint 之后,除非 Pod 明确声明能够容忍这些“污点”,否则无法在这些 Node 上运行。Toleration 是 Pod 的属性,让 Pod 能够运行在标注了 Taint 的 Node 节点上。
- 使用 kubectl taint 命令为 Node 设置 Taint 信息:
kubectl taint nodes nodeName key=value:NoSchedule
# 比如: 禁止 k8s-master1 部署 pod
kubectl taint nodes k8s-master1 node-role.kubernetes.io/master=true:NoSchedule
为 node 节点的 k8s-master 加上一个 Taint, Taint 的键为 Key,值为 value, Taint 的效果是 NoSchedule。这里表示的含义是任何 Pod 都不能调度到这个节点,除非设置了 toleration。
- 删除节点上的 taint
kubectl taint nodes --all key:NoSchedule-
默认的 master 节点是不能调度应用 pod 的,需要给 master 节点消除污点标记
kubectl taint nodes --all node-role.kubernetes.io/master-
七、容忍标记
在 Pod 中定义容忍标记(Tolerate),使得 Pod 可以被调度到具有该污点标记(Taint)的 Node:
tolerations:
- key: "key"
operator: "Equal"
value: "value"
effect: "NoSchedule"
或者:
tolerations:
- key: "key"
operator: "Exists"
effect: "NoSchedule"
tolerationSeconds: 6000
- value 的值可以为 NoSchedule、PreferNoSchedule 或 NoExecute。
- tolerationSeconds 是当 pod 需要被驱逐时,可以继续在 node 上运行的时间。
八、常见错误
node(s) didn’t match node selector
报错如下:
0/3 nodes are available: 3 node(s) didn't match node selector.
如果指定的 label 在所有 node 上都无法匹配,则创建 Pod 失败,会提示无法调度
对应 yaml 的 nodeSelector 字段, 如:
spec:
nodeSelector:
traefik: proxy
需要为 node 指定标签
kubectl label nodes <node-name> <label-key>=<label-value>
比如:
kubectl label nodes k8s-node1 traefik=proxy
如果要删除标签:
kubectl label nodes --all traefik-
missing required field selector
报错如下:
error validating data: ValidationError(Deployment.spec): missing required field "selector" in io.k8s.api.apps.v1.DeploymentSpec; if you choose to ignore these errors, turn validation off with --validate=false
错误原因:如果不写spec.selector.matchLabels字段的内容,直接创建则会报错:缺少必要字段selector。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
需要正确使用 matchLabels
:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
selector:
matchLabels:
app: nginx
replicas: 2
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
selector does not match template labels
报错如下:
spec.template.metadata.labels: Invalid value: map[string]string{"app":"nginx"}: `selector` does not match template `labels`
当 spec.selector.matchLabels 匹配的键值与 spec.template.metadata.lables 键值不相对应,会报此错:选择的和模板标签不匹配。