加载中...

Kubernetes系列(四)--资源调度


1. Labels和Selectors

1.1 标签(Labels)

配置文件配置:可以在 metadata.labels 中进行配置,示例如下:

metadata:      # Pod 相关的元数据,用于描述 Pod 的数据
  name: nginx-demo    # Pod 的名称
  labels:      # 定义 Pod 的标签
    type: app       # 自定义label标签,名字为 type,值为 app
    version: 1.0.0  # 自定义label标签,描述 Pod 版本号
  namespace: 'default'  # 命名空间的配置

kubectl 使用:

查看标签:

# 语法:kubectl get <资源类型> --show-labels
kubectl get po --show-labels
kubectl get nodes --show-labels

临时创建label:

# 语法:kubectl label po <资源名称> <标签名>=<值>

# 根据资源名称创建label
kubectl label po nginx-demo author=wuye
# 根据标签 author值为wuyea 筛选pod并批量创建label;   -l 是label的选择器
kubectl label pods -l author=wuye date=0516

修改已经存在的标签:

# 语法:kubectl label po <资源名称> <标签名>=<值> --overwrite
kubectl label po nginx-demo author=wuyea --overwrite

1.2 选择器(Selectors)

配置文件:在各对象的配置 spec.selector 或其他可以写 selector 的属性中编写。

kubectl 使用:

# 匹配单个值,查找 author=wuyea 的 pod;  -A 查询所有命令空间
kubectl get po -A -l author=wuyea

# 匹配多个值中的任意一个
kubectl get po -A -l 'version in (1.0.0, 1.1.0, 1.2.0)'

# 查找 version!=1 and author=wuyea 的 pod 信息
kubectl get po -l version!=1.1.0,author=wuyea

# 不等值 + 语句
kubectl get po -A -l 'version!=1.1.0,author in (wuyea, wuye)'

2. Deployment

Deployment是对无状态应用的部署及管理(如nginx)。

2.0 Deployment 配置文件详解:

### 注释内容可以删除掉,暂时忽略
apiVersion: apps/v1    # deployment api 版本
kind: Deployment       # 资源类型为 deployment
metadata:              # 元数据
  #annotations:
  #  deployment.kubernetes.io/revision: "2"
  #creationTimestamp: "2025-05-16T07:19:52Z"
  #generation: 2
  labels:              # 标签
    app: nginx-deploy  # 具体的 key:value
  name: nginx-deploy   # deployment 的名字
  namespace: default   # 命名空间
  #resourceVersion: "3624773"
  #uid: a18ff5d6-3380-4e9f-8046-783307413c50
spec:
  #progressDeadlineSeconds: 600
  replicas: 1               # 期望副本数
  revisionHistoryLimit: 10  # 进行滚动更新后,保留的历史版本数
  selector:                 # 选择器,用于找到匹配的 RS
    matchLabels:            # 按照标签匹配
      app: nginx-deploy
  strategy:                 # 更新策略
    rollingUpdate:          # 滚动更新配置
      maxSurge: 25%         # 进行滚动更新时,更新的个数最多可以超过期望副本数的个数/比例(比如期望更新10个,在资源足够时最多更新12个)
      maxUnavailable: 25%   # 进行滚动更新时,最大不可用更新比例;表示在所有副本数中,最多可以有多少个不更新成功
    type: RollingUpdate     # 更新类型,采用滚动更新
  template:                 # pod 模板
    metadata:               # pod 的元信息
      #creationTimestamp: null
      labels:               # pod 标签
        app: nginx-deploy
    spec:                   # pod 期望信息
      containers:           # pod 的容器
      - image: nginx:latest # 镜像
        imagePullPolicy: IfNotPresent  # 拉取策略
        name: nginx         # 容器名称
        #resources: {}
        #terminationMessagePath: /dev/termination-log
        #terminationMessagePolicy: File
      #dnsPolicy: ClusterFirst
      restartPolicy: Always # 重启策略
      #schedulerName: default-scheduler
      #securityContext: {}
      terminationGracePeriodSeconds: 30 # 删除操作最多宽限多长时间

2.1 创建Deployment

如何得到上面的配置文件?可以部署一个nginx示例,然后查看系统的配置即可,命令如下:

# 创建 deployment
kubectl create deploy nginx-deploy --image=nginx:latest

# 可以使用下面命令查看资源名称,通过名称也可以看出三者的关系:deployment包含replicaset,replicaset控制pod副本数
kubectl get deploy,rs,po

# 使用 -o yaml 查看默认的 deployment 配置
kubectl get deploy nginx-deploy -o yaml > nginx-deploy.yaml  # 删除文件中的status块,即可得到上面的yaml文件

# 根据yaml文件创建deployment
kubectl create -f nginx-deploy.yaml

# 更新替换
kubectl replace -f deploy-nginx.yaml

# 查看标签
kubectl get deploy,rs,po --show-labels

2.2 滚动更新

只有修改了 deployment 配置文件中的 template 中的属性后,才会触发更新操作

# 修改 nginx 版本号
kubectl set image deployment/nginx-deployment nginx=nginx:1.9.1
# 或者通过 kubectl edit deployment/nginx-deployment 进行修改

# 查看滚动更新的过程
kubectl rollout status deploy <deployment_name>

# 查看部署描述,最后展示发生的事件列表也可以看到滚动更新过程
kubectl describe deploy <deployment_name>

# 获取部署信息,UP-TO-DATE 表示已经有多少副本达到了配置中要求的数目
kubectl get deployments

# 通过 kubectl get rs 可以看到增加了一个新的 rs

# 通过 kubectl get pods 可以看到所有 pod 关联的 rs 变成了新的

多个滚动更新并行:假设当前有 5 个 nginx:1.7.9 版本,你想将版本更新为 1.9.1,当更新成功第三个以后,你马上又将期望更新的版本改为 1.9.2,那么此时会立马删除之前的三个,并且立马开启更新 1.9.2 的任务

2.3 更新回滚

默认情况下,kubernetes会在系统中保存前两次的Deployment的rollout历史记录,以便你可以随时会退(你可以修改revision history limit来更改保存的revision数)。

案例:这里假设我更新nginx镜像版本为1.9.1,但是不小心输错为 1.91,此时就需要回滚。

kubectl set image deployment/nginx-deploy nginx=nginx:1.91  # 修改deploy的镜像版本

kubectl rollout history deployment nginx-deploy  # 查看历史版本

kubectl rollout history deploy/nginx-deploy --revision=2  # 查看某个版本的信息,这里查看第2个版本

kubectl rollout undo deployment/nginx-deploy --to-revision=2  # 回滚到某个版本

2.4 扩容缩容

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

扩容与缩容只是直接创建副本数,没有更新 pod template 因此不会创建新的 rs。

# 把 nginx-deploy 的副本数扩缩容到6个
kubectl scale deploy nginx-deploy --replicas=6

2.5 暂停恢复

由于每次对 pod template 中的信息发生修改后,都会触发更新 deployment 操作,那么此时如果频繁修改信息,就会产生多次更新,而实际上只需要执行最后一次更新即可,当出现此类情况时我们就可以暂停 deployment 的 rollout

通过 kubectl rollout pause deployment <name> 就可以实现暂停,直到你下次恢复后才会继续进行滚动更新。

kubectl rollout pause deploy nginx-deploy  # 暂停更新

kubectl rollout resume deploy nginx-deploy # 恢复更新

3. StatefulSet

StatefulSet是对有状态应用的部署及管理(如MySQL)。

官方链接:https://kubernetes.io/zh-cn/docs/concepts/workloads/controllers/statefulset/

3.0 StatefulSet 配置文件详解

---                    # 两个 --- 之间代表插入一块yaml内容
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        # StatefulSet 类型的资源
metadata:
  name: web              # StatefulSet 对象的名字
spec:
  serviceName: "nginx"   # 使用哪个service来管理dns
  replicas: 2            # 副本数2个
  selector:
    matchLabels:
      app: nginx         # 必须匹配 .spec.template.metadata.labels
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:latest
        imagePullPolicy: IfNotPresent  # 镜像拉取策略:只有当本地不存在时才会拉取
        ports:           # 容器内要暴漏的端口号
        - containerPort: 80   # 具体暴漏的端口号
          name: web           # 该端口配置的名字
        volumeMounts:    # 加载数据卷
        - name: www           # 指定加载哪个数据卷
          mountPath: /usr/share/nginx/html  # 加载到容器中的哪个目录
  volumeClaimTemplates:  # 数据卷模板
  - metadata:            # 数据卷的描述
      name: www          # 数据卷的名称
      annotations:       # 数据卷的注解
        volume.alpha.kubernetes.io/storage-class: anything
    spec:        # 数据卷的规约
      accessModes: [ "ReadWriteOnce" ]  # 访问模式
      resources:
        requests:
          storage: 1Gi   # 需要 1G 的存储资源

3.1 创建StatefulSet

# 创建StatefulSet
kubectl create -f web.yaml

# 查看 StatefulSet 状态
kubectl get sts  # StatefulSet可以简写为sts

# 查看 service 状态
kubectl get svc

# 查看 挂载 状态
kubectl get pvc
# 查看 挂载 详情
kubectl describe pvc www-web-0

# 检查服务是否可用需要在另一个容器中,因为主机无法访问
kubectl run -it --image busybox dns-test --restart=Never --rm /bin/sh
# 进入容器内后执行命令:ping web-0.nginx

3.2 扩容缩容

# 扩缩容方法一:修改replicas数量即可实现扩缩容,简单直接。
kubectl scale statefulset web --replicas=5

# 方法二:通过patch打补丁的方式实现
kubectl patch statefulset web -p '{"spec":{"replicas":3}}'

3.3 镜像更新

# 镜像更新(目前还不支持直接更新 image,需要 patch 来间接实现)
kubectl patch sts web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"nginx:1.9.1"}]'

更新方式有两种,分别是 RollingUpdateOnDelete

RollingUpdate

StatefulSet 也可以采用滚动更新策略,同样是修改 pod template 属性后会触发更新,但是由于 pod 是有序的,在 StatefulSet 中更新时是基于 pod 的顺序倒序更新的。

基于 RollingUpdate 的特性,我们可以实现灰度发布(金丝雀发布)。

灰度发布:

  • 灰度发布的目标:将项目上线后产生问题的影响尽量降到最低。

  • 灰度发布的原理:利用滚动更新中的 partition 属性,可以实现简易的灰度发布的效果。

    例如我们有 5 个 pod,如果当前 partition 设置为 3,那么此时滚动更新时,只会更新那些 序号 >= 3 的 pod。

    利用该机制,我们可以通过控制 partition 的值,来决定只更新其中一部分 pod,确认没有问题后再主键增大更新的 pod 数量,最终实现全部 pod 更新。

OnDelete

只有在 pod 被删除时会进行更新操作。

3.4 删除

# 删除 StatefulSet 和 Headless Service
# 级联删除:删除 statefulset 时会同时删除 pods
kubectl delete statefulset web
# 非级联删除:删除 statefulset 时不会删除 pods,删除 sts 后,pods 就没人管了,此时再删除 pod 不会重建的
kubectl deelte sts web --cascade=false

# 删除 service
kubectl delete service nginx

4. DaemonSet

为每一个匹配的Node都部署一个守护进程。

官方链接:https://kubernetes.io/zh-cn/docs/concepts/workloads/controllers/daemonset/

4.1 DaemonSet 配置文件详解

apiVersion: apps/v1
kind: DaemonSet                      # 创建 DaemonSet 资源
metadata:
  name: fluentd-elasticsearch        # 名字
spec:
  selector:
    matchLabels:
      name: fluentd-elasticsearch
  template:
    metadata:
      labels:
        name: fluentd-elasticsearch
    spec:
      nodeSelector:                  # 节点选择器,指定守护进程只能运行在label匹配的节点上
        type: compute
      containers:
      - name: fluentd-elasticsearch
        image: quay.io/fluentd_elasticsearch/fluentd:v5.0.1
        resources:
          limits:
            memory: 200Mi
          requests:
            cpu: 100m
            memory: 200Mi
        volumeMounts:               # 加载数据卷,避免数据丢失
        - name: varlog              # 数据卷名字
          mountPath: /var/log       # 将数据卷挂载到容器内的哪个目录
      # it may be desirable to set a high priority class to ensure that a DaemonSet Pod
      # preempts running Pods
      # priorityClassName: important
      terminationGracePeriodSeconds: 30
      volumes:                  # 定义数据卷
      - name: varlog            # 定义的数据卷的名称
        hostPath:               # 数据卷类型,主机路径的模式,也就是与node共享目录
          path: /var/log        # node 中的共享目录

4.2 DaemonSet 常用命令

# 创建 DaemonSet
kubectl create -f fluentd-ds.yaml

# 查看 DaemonSet
kubectl get ds

# 查看节点标签
kubectl get nodes --show-labels

# 给c1节点增加标签 type=compute
kubectl label no c1 type=compute

5. HPA 自动扩/缩容

通过观察 pod 的 cpu、内存使用率或自定义 metrics 指标进行自动的扩容或缩容 pod 的数量。

通常用于 Deployment、StatefulSet,不适用于无法扩/缩容的对象,如 DaemonSet。

控制管理器每隔30s(可以通过–horizontal-pod-autoscaler-sync-period修改)查询metrics的资源使用情况。

5.1 开启指标服务

如果没有指标服务,当使用 kubectl top pods 命令时会提示 Metrics API not available

使用 kubectl top pods 命令能看到pod的资源使用情况,所以需要安装指标服务。

  1. 下载 metrics-server 组件配置文件

    wget https://github.com/kubernetes-sigs/metrics-server/releases/latest/download/components.yaml -O metrics-server-components.yaml
  2. 修改镜像地址为国内的地址

    # 检查:(自行修改,这是我当时的镜像代理)
    [root@head ~]# grep -n "image" metrics-server-components.yaml
    142:        image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/registry.k8s.io/metrics-server/metrics-server:v0.8.0
    143:        imagePullPolicy: IfNotPresent
  3. 修改 metrics-server-components.yaml 文件中容器的 tls 配置,不验证 tls,在 containers 的 args 参数中增加 --kubelet-insecure-tls 参数。

    spec:
      selector:
        matchLabels:
          k8s-app: metrics-server
      strategy:
        rollingUpdate:
          maxUnavailable: 0
      template:
        metadata:
          labels:
            k8s-app: metrics-server
        spec:
          containers:
          - args:
            - --cert-dir=/tmp
            - --secure-port=10250
            - --kubelet-preferred-address-types=InternalIP,ExternalIP,Hostname
            - --kubelet-use-node-status-port
            - --metric-resolution=15s
            - --kubelet-insecure-tls   # 增加了这一行
            image: swr.cn-north-4.myhuaweicloud.com/ddn-k8s/registry.k8s.io/metrics-server/metrics-server:v0.8.0    # 修改成了代理镜像地址
  4. 安装组件

    kubectl apply -f metrics-server-components.yaml
  5. 查看 pod 状态

    kubectl get pods --all-namespaces | grep metrics
    
    # 如果pod没有运行,使用该命令查看原因
    kubectl describe po metrics-server-98ddd7b5d-9wggn -n kube-system

5.2 cpu,内存指标监控

  1. 前提条件

    要想实现 cpu 或内存的监控,首先有个前提条件是该对象必须配置了 resources.requests.cpuresources.requests.memory 才可以,可以配置当 cpu/memory 达到上述配置的百分比后进行扩容或缩容。

    示例:

    spec:
      ......
      template:
        metadata:
          creationTimestamp: null
          labels:
            app: nginx-deploy
        spec:
          containers:
          - image: nginx:latest
            imagePullPolicy: IfNotPresent
            name: nginx
            resources:  # 必须配置资源请求
              limits:
                cpu: 200m
                memory: 128Mi
              requests:   # hpa看的是requests,不是limits!
                cpu: 100m
                memory: 128Mi
  2. 创建一个 HPA

    先准备一个好一个有做资源限制的 deployment,然后执行命令 kubectl autoscale deploy <deploy-name> --cpu-percent=20 --min=2 --max=5 创建HPA。通过 kubectl get hpa 可以获取 HPA 信息。

  3. 测试

    找到对应服务的 service,编写循环测试脚本提升内存与 cpu 负载

    while true; do wget -q -O- http://ip:port > /dev/null ; done

    可以通过多台机器执行上述命令,增加负载,当超过负载后可以查看 pods 的扩容情况 kubectl get pods

    查看 pods 资源使用情况kubectl top pods

    扩容测试完成后,再关闭循环执行的指令,让 cpu 占用率降下来,然后过 5 分钟后查看自动缩容情况。

5.3 自定义指标监控

  • 控制管理器开启–horizontal-pod-autoscaler-use-rest-clients
  • 控制管理器的–apiserver指向API Server Aggregator
  • 在API Server Aggregator中注册自定义的metrics API

end 补充

StatefulSet与Deployment的对比

特性 StatefulSet Deployment
数据持久化 为每个Pod提供独立的持久化存储卷 没有持久化存储,Pod删除时数据丢失
网络标识 每个Pod有稳定的网络标识(如DNS) 没有固定的网络标识
Pod管理 有序启动、终止,Pod编号固定 无序启动、终止
扩展方式 可以水平扩展,但需要更复杂的数据同步 简单的水平扩展
适用场景 有状态应用,如数据库、缓存系统等 无状态应用,如Web服务器、API等

总结

  • 无状态应用:适用于无需持久化状态的应用,它们能在Kubernetes中实现灵活的扩展与调度,适用于处理单次请求的服务。
  • 有状态应用:需要管理应用数据状态,并依赖持久化存储的应用,这类应用的实例通常需要特定的配置、顺序启动和稳定的存储和网络标识。Kubernetes通过StatefulSet来提供这些功能,确保数据一致性和可靠性。

文章作者: 无夜
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 无夜 !
评论
  目录