Kubernetes之Controller认识
Label是kubernetes系统中的一个重要概念。它的作用就是在资源上添加标识,用来对它们进行区分和选择
-
Label的特点
-
一个Label会以key:value键值对的形式附加到各种资源对象上,如Node、Pod、Service等等
-
一个资源对象可以定义任意数量的Label ,同一个Label也可以被添加到任意数量的资源对象上去
-
Label通常在资源对象定义时确定,当然也可以后期动态的添加或者删除
-
Selector即用于查询和筛选拥有某些Label的资源对象
Label的维护
在各类资源清单的定义文件中进行维护:metadata.labels
apiVersion: v1 kind: Pod metadata: name: nginx namespace: dev labels: version: "1.0" env: "test"
通过kubectl命令行工具的方式进行维护
# 为 dev 命名空间下名为 nginx-pod 的 pod 资源添加一个 version=1.0 的标签 kubectl label pod nginx-pod version=1.0 -n dev # 为 dev 命名空间下名为 nginx-pod 的 pod 资源更新标签的 value 为 2.0 kubectl label pod nginx-pod version=2.0 -n dev --overwrite # 查看 dev 命名空间下名为 nginx-pod 的 pod 资源的所有标签信息 kubectl get pod nginx-pod -n dev --show-labels # 获取 dev 命名空间下配置了标签 key 为 version , value为2.0 的Pod资源,并展示其资源的所有标签 kubectl get pod -n dev -l version=2.0 --show-labels # 获取 dev 命名空间下配置了标签 key 为 version , value不为2.0 的Pod资源,并展示其资源的所有标签 kubectl get pod -n dev -l version!=2.0 --show-labels # 删除 dev 命名空间下名为 nginx-pod 的 pod 资源的 tier 标签 kubectl label pod nginx-pod -n dev tier-
什么是Controller
Pod是最小的控制单元, 但kubernetes很少直接控制Pod,一般都是通过Pod控制器来完成的。
Pod控制器用于pod的管理,确保pod资源符合预期的状态,当pod的资源出现故障时,会尝试进行重启或重建pod
在理解Pod控制器之前我们需要理解一下有状态服务和无状态服务的定义
-
有状态服务
-
会储存数据到本地,对本地数据产生依赖,比如MySQL、Redis等应用就会有数据管理的需求
-
-
无状态服务
-
不会对本地环境产生任何依赖,随便在某个节点上都能运行,完全独立的个体,可以随时高效的进行扩容/迁移的服务,比如Nginx
-
Pod和Controller之间是通过labei标签建立联系
yaml文件字段说明
Deployment
Deployment作为目前部署无状态服务的第一控制器,在它之前还有两个,在这里简单说明一下
-
RC ((Replication Controller)
-
帮助我们动态的更新Pod的运行副本数到我们的预期副本数
-
-
RS(Replica Set)
-
帮助我们动态的更新Pod的运行副本数到我们的预期副本数,
-
和RC区别不大,只是支持了通过selector来关联Pod的label,实现动态的更新关联pod的副本数
-
-
Deployment
-
对RS做了更好的包装 , 包括但不限于:自动伸缩(RS) 、滚动升级&回滚 、 平滑伸缩 、 暂停与恢复
-
创建
# 创建一个的deployment资源 并导出为资源清单文件 ,
# 通过资源清单的方式创建 [root@master /]# kubectl create deployment web1 --image=nginx:1.7.9 --dry-run -o yaml > web1.yaml [root@master /]# kubectl apply -f web1.yaml # 或者直接执行简易命令进行快速创建 [root@master /]# kubectl create deploy web1 --image=nginx:1.7.9
然后我们一直等待,等待他运行成功
# 获取Deployment的信息 [root@master /]# kubectl get deployment NAME READY UP-TO-DATE AVAILABLE AGE web1 1/1 1 1 17s # 获取RS的信息 ,因为我们上面说了 Deployment 是对 RS 的更好的封装 , 然后再看看他的标签 [root@master /]# kubectl get rs --show-labels NAME DESIRED CURRENT READY AGE LABELS web1-7c4bb5b674 1 1 1 16m app=web1,pod-template-hash=7c4bb5b674 # 然后再看看他的标签 , 可以看到是关联的那个 rs [root@master /]# kubectl get pods --show-labels NAME READY STATUS RESTARTS AGE LABELS web1-7c4bb5b674-29vjk 1/1 Running 0 14m app=web1,pod-template-hash=7c4bb5b674
对外发布(暴露端口)
[root@master /]# kubectl expose deployment web1 --port=80 --type=NodePort --target-port=80 --name=web1 -o yaml > web1Expose.yaml
然后我们可以看到一个部署文件:web1Expose.yaml ,我们将其部署,将Nginx应用进行发布,进行端口暴露
[root@master /]# kubectl apply -f web1Expose.yaml [root@master /]# kubectl get pods,svc
-
这个时候已经发布成功,我们可以通过三个节点,只要是30339端口即可访问Nginx服务
滚动更新
下面我们初始化一下环境,将刚刚部署的pod删掉,先删pod ,再删Deployment
[root@master /]# kubectl delete pod <PodName> [root@master /]# kubectl delete deployment <DeploymentName>
只有修改了 deployment 配置文件中的 template 中的属性后,才会触发更新操作
-
当上一次滚动更新尚未完成时我们又触发了新的滚动跟新,此时K8S会停止上一次的更新并执行当前最新的更新
-
修改刚刚我们导出的web1.yaml文件 ,副本数量修正为2 , Nginx的镜像指定版本为1.14 , 然后再次部署
-
现在我们通过命令行的方式要对其进行升级到1.15
[root@master /]# kubectl set image deployment web1 nginx=nginx:1.15
我们可以查看升级状态 , 显示已经升级成功了
[root@master /]# kubectl rollout status deployment <name>
过程分析:升级过程中为什么对外暴露的服务不会停止
回滚
有时候你可能配置错误 , 想回退一个Deployment的部署版本
-
默认情况下,k8s会保存前两次Deployment的rollout历史记录,以便你随时回退
-
可以修改revision history limit来更改保存的revision数 , 设置为0 ,则不允许回滚了
# 查看该资源的历史升级信息
[root@master /]# kubectl rollout history deployment web1.
版本回滚到上一个版本
[root@master /]# kubectl rollout undo deployment web1
版本回滚到指定版本
[root@master /]# kubectl rollout undo deployment web1 --to-reversion=2
扩容与缩容
通过 kube scale 命令可以进行自动扩容/缩容,以及通过 kube edit 编辑 replcas 也可以实现扩容/缩容
就使用我们刚刚部署的Nginx做列子,我们对其副本伸缩
[root@master /]# kubectl scale deployment web1 --replicas=10
或者通过编辑该资源的资源清单文件进行实现
# 通过 kube edit 编辑该 deployment 的资源清单文件,找到 replicas 并设置为 10 [root@master /]# kubectl edit deployment web1 deployment.apps/nginx-deploy edited
StatefulSet
上面我们了解到到的Deployment 是针对无状态服务的,StatefulSet 则是专门用控制有状态服务的控制器,除此之外还有一点特殊的
-
StatefulSet类型的资源,不能通过create 命令直接创建,而是只有通过资源清单文件的方式进行创建
-
StatefulSet的资源拥有稳定的持久化储存
-
依靠 volumeClaimTemplate 实现,用于创建持久化卷PV
-
-
StatefulSet的资源拥有稳定的网络标识
-
依靠 headless Service 实现 DNS ,服务名与集群内IP进行绑定
-
-
StatefulSet的资源有序部署、有序扩展
-
Pod的副本是有顺序的,在部署或者扩容的时候也是定义了顺序的,即从0 ~ (n-1),在下一个Pod运行之前所有的Pod都必须为Running 或者 Ready状态
-
-
StatefulSet的资源有序收缩、有序删除
-
Pod的创建因为是有顺序的,在收缩或删除的时候根据顺序删除,即从(n-1) ~ 0
-
这里会涉及到Service以及PV这两个短期还没介绍的东西,这里就简单说说,后面再部署应用进行演示
扩容 & 缩容
[root@master /]# kubectl scale statefulset web --replicas=5 [root@master /]# kubectl patch statefulset web -p '{"spec":{"replicas":3}}'
删除
# 级联删除 , 删除 statefulset 时会同时删除 pods [root@master /]# kubectl delete statefulset <name> # 非级联删除 , 删除 statefulset 时不会删除 pods , pods 就没人管了,此时如果再手动删除Pod , pod即使配置了重启策略也不会重建的 [root@master /]# kubectl deelte statefulset <name> --cascade=false # StatefulSet删除后PVC还会保留着,数据不再使用的话也需要删除 [root@master /]# kubectl delete pvc <name>
更新
# 目前还不支持直接更新 image,需要 patch 来间接实现
kubectl patch sts <name> --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"nginx:1.9.1"}]'
-
在这里StatefulSet的更新又有两种方式
-
滚动更新:同样是修改 pod template 属性后会触发更新,但是由于 pod 是有序的,在 StatefulSet 中更新时是基于 pod 的顺序倒序更新的
-
利用滚动更新中的 partition 属性,可以实现简易的灰度发布的效果
-
例如我们有 5 个 pod,如果当前 partition 设置为 3,那么此时滚动更新时,只会更新那些 序号 >= 3 的 pod
-
利用该机制,我们可以通过控制 partition 的值,来决定只更新其中一部分 pod,确认没有问题后再主键增大更新的 pod 数量,最终实现全部 pod 更
-
-
删除时更新:只有在 pod 被删除时会进行更新操作
-
你想更新哪个 , 你就删除哪个,然后删除后自动重启,根据最新的资源清单文件,做到更新效果
-
-
DaemonSet
Pod的控制器之一 , 适用于部署每一个Node上都需要部署该容器的的环境
典型的应用比如:
-
日志收集: fluents 、 logstash ...
-
系统监控: 普罗米修斯 ...
-
系统程序: kube-proxy 、 kube-dns ...
DaemonSet 会忽略 Node 的 unschedulable 状态,指定该 Pod 只运行在指定的 Node 节点上有以下方式:
-
nodeSelector:只调度到匹配指定 label 的 Node 上
# 先为 Node 打上标签 [root@master /]# kubectl label nodes node1 svc_type=microsvc # 然后再 daemonset 配置中设置 nodeSelector spec: template: spec: nodeSelector: svc_type: microsvc
-
nodeAffinity:功能更丰富的 Node 选择器,比如支持集合操作
-
nodeAffinity 目前支持两种模式:必须满足条件、优选条件
-
apiVersion: v1 kind: Pod metadata: name: with-node-affinity spec: affinity: nodeAffinity: # 必须满足: 包含标签 must-meet 且值为test1 或 test2的节点上 requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: must-meet operator: In values: - test1 - test2 # 优选条件:并且还优选标签another-meet , 值为another-node 的节点 preferredDuringSchedulingIgnoredDuringExecution: - weight: 1 preference: matchExpressions: - key: another-meet operator: In values: - another-node containers: - name: with-node-affinity image: pauseyyf/pause
-
podAffinity:调度到满足条件的 Pod 所在的 Node 上
-
podAffinity 基于 Pod 的标签来选择 Node,仅调度到满足条件Pod 所在的 Node 上
-
支持 podAffinity 和 podAntiAffinity
-
apiVersion: v1 kind: Pod metadata: name: with-pod-affinity spec: affinity: # 如果一个 “Node 所在空间中包含至少一个带有 auth=oauth2 标签且运行中的 Pod”,那么可以调度到该 Node podAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: auth operator: In values: - oauth2 topologyKey: failure-domain.beta.kubernetes.io/zone # 不调度到 “包含至少一个带有 auth=jwt 标签且运行中 Pod”的 Node 上 podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchExpressions: - key: auth operator: In values: - jwt topologyKey: kubernetes.io/hostname containers: - name: with-pod-affinity image: pauseyyf/pause
HPA自动扩容/缩容
开启指标服务
# 下载 metrics-server 组件配置文件 wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml -O metrics-server-components.yaml # 修改镜像地址为国内的地址 sed -i 's/k8s.gcr.io\/metrics-server/registry.cn-hangzhou.aliyuncs.com\/google_containers/g' metrics-server-components.yaml # 修改容器的 tls 配置,不验证 tls,在 containers 的 args 参数中增加 --kubelet-insecure-tls 参数 # 安装组件 [root@master /]# kubectl apply -f metrics-server-components.yaml # 查看 pod 状态 [root@master /]# kubectl get pods --all-namespaces | grep metrics
监控指标
实现 cpu 或内存的监控,有个前提条件是该对象必须配置了 resources.requests.cpu 或 resources.requests.memory 才可以
可以配置当 cpu/memory 达到上述配置的百分比后进行扩容或缩容
创建一个 HPA:
-
先准备一个做资源限制的 deployment
-
执行命令 kubectl autoscale deploy nginx-deploy --cpu-percent=20 --min=2 --max=5
-
通过 kubectl get hpa 可以获取 HPA 信息
测试:找到对应服务的 service,编写循环测试脚本提升内存与 cpu 负载 while true; do wget -q -O- http://ip:port > /dev/null ; done
可以通过多台机器执行上述命令,增加负载,当超过负载后可以查看 pods 的扩容情况 kubectl get pods
查看 pods 资源使用情况
[root@master /]# kubectl top pods
扩容测试完成后,再关闭循环执行的指令,让 cpu 占用率降下来,然后过 5 分钟后查看自动缩容情况
job
一次性任务,运行完成后Pod销毁,不再重新启动新容器,下面让我们看看这个资源清单文件
部署这个pod后,因为我们指定了command属性的值,就会执行后面的脚本,进行计算并打印圆周率的后2000位
可以看到这个一次性任务已经是完成状态标识Complated,查看日志数据呢
[root@master /]# kubectl logs podName
# 查看所有一次性任务列表 [root@master /]# kubectl get jobs # 删除一次性任务历史 [root@master /]# kubectl delete -f job.yaml
cronJob
CronJob 是在 Job 基础上加上了定时功能,下面让我们来看看这个资源清单文件
-
我们直接部署这个yaml
[root@master /]# kubectl apply -f cronjob.yaml
# 查看所有定时任务列表 [root@master /]# kubectl get cronjobs # 删除定时性任务 [root@master /]# kubectl delete -f cronjob.yaml
-