Kubernetes之Controller认识

Label & Selector

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标签建立联系

img

yaml文件字段说明

比较全面的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

img

  • 这个时候已经发布成功,我们可以通过三个节点,只要是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

img

我们可以查看升级状态 , 显示已经升级成功了

[root@master /]# kubectl rollout status deployment <name>

img

过程分析:升级过程中为什么对外暴露的服务不会停止

img

回滚

有时候你可能配置错误 , 想回退一个Deployment的部署版本

  • 默认情况下,k8s会保存前两次Deployment的rollout历史记录,以便你随时回退

  • 可以修改revision history limit来更改保存的revision数 , 设置为0 ,则不允许回滚了

# 查看该资源的历史升级信息
[root@master /]# kubectl rollout history deployment web1.

img

版本回滚到上一个版本

[root@master /]# kubectl rollout undo deployment web1

img

版本回滚到指定版本

[root@master /]# kubectl rollout undo deployment web1 --to-reversion=2

img

扩容与缩容

通过 kube scale 命令可以进行自动扩容/缩容,以及通过 kube edit 编辑 replcas 也可以实现扩容/缩容

就使用我们刚刚部署的Nginx做列子,我们对其副本伸缩

[root@master /]# kubectl scale deployment web1 --replicas=10

img

或者通过编辑该资源的资源清单文件进行实现

# 通过 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:

  1. 先准备一个做资源限制的 deployment

  2. 执行命令 kubectl autoscale deploy nginx-deploy --cpu-percent=20 --min=2 --max=5

  3. 通过 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销毁,不再重新启动新容器,下面让我们看看这个资源清单文件

img

部署这个pod后,因为我们指定了command属性的值,就会执行后面的脚本,进行计算并打印圆周率的后2000位

img

可以看到这个一次性任务已经是完成状态标识Complated,查看日志数据呢

[root@master /]# kubectl logs podName

img

# 查看所有一次性任务列表
[root@master /]# kubectl get jobs
​
# 删除一次性任务历史
[root@master /]# kubectl delete -f job.yaml

cronJob

CronJob 是在 Job 基础上加上了定时功能,下面让我们来看看这个资源清单文件

img

  • 我们直接部署这个yaml

    [root@master /]# kubectl apply -f cronjob.yaml

    img

    # 查看所有定时任务列表
    [root@master /]# kubectl get cronjobs
    ​
    # 删除定时性任务
    [root@master /]# kubectl delete -f cronjob.yaml
  •  
posted @ 2021-01-25 23:18  鞋破露脚尖儿  阅读(345)  评论(0编辑  收藏  举报