K8s学习五(资源调度_2)

StatefulSet(有状态)

  • 有状态就是对本地有依赖,比如数据库的信息,删除之后,就没有之前的数据信息了,有依赖,如下图:

  • statefulset 命令可以用sts来简写,比如命令kubectl get sts

定义配置文件
  • 配置文件如下:
bash 复制代码
---
apiVersion: v1 # 上面和后面的---是yaml文件嵌套了一段yaml文件
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
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        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存储资源
  • 创建之后看各个情况,pvc是持久卷声明(Persistent Volume Claim)

  • 但是因为,目前存储卷没有加载成功,后面学到了再加,因此先删掉yaml文件中有关的信息

  • 删了之后的为:

bash 复制代码
---
apiVersion: v1 # 上面和后面的---是yaml文件嵌套了一段yaml文件
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
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx:1.7.9
        ports: # 容器内要暴露的端口
        - containerPort: 80  # 具体暴露的端口号
          name: web # 该端口配置的名字
  • 如果执行替换操作,就是执行这个命令kubectl replace -f sts web web.yaml,但是这里有的不能被替换,系统阻止,因此还是先删再create

  • 然后就已经running

  • 访问两个pod,不能直接在主机上ping通,因为服务是在容器内的,映射到容器的端口。运行一个新的容器去访问

  • 运行一个busybox容器,这个容器包含很多linux常用工具,运行

bash 复制代码
kubectl run -it --image busybox:1.28.4 dns-test /bin/sh

# kubectl run: 这是 kubectl 命令的一部分,用于在集群中运行一个容器。
# -it: 这是两个选项的结合。-i 表示要保持标准输入流 (stdin) 打开,-t 表示要分配一个伪终端 (tty)。这两个选项结合起来允许你与容器进行交互。
# --image busybox:1.28.4: 指定要使用的容器镜像,这里是 BusyBox 的特定版本 1.28.4。
# dns-test: 这是 Pod 的名称,你为 Pod 指定的名称。
# /bin/bash: 这是容器中要运行的命令,这里是启动一个 Bash shell。

# 可加 --restart=Never 为永不重启, --rm为退出就删掉
  • 用这个容器就可以访问到,sts的访问为statefulSetName-{0...N-1}.serviceName.namespace.svc.cluster.local,可以只到statefulSetName-{0...N-1}.serviceName,后面省略,下图中的命令行就是用省略的,红框内为完整的格式。
扩容与缩容
  • 扩容缩容可以用下面两条命令来实现:
bash 复制代码
 kubectl scale statefulset web --replicas=5
 
 kubectl patch statefulset web -p '{"spec":{"replicas":3}}'
  • 扩容缩容后查看stskubectl describe sts web
滚动更新
  • 镜像更新(目前还不支持直接更新 image,比如set image,需要 patch 来间接实现,或者用kubectl edit sts web), 如
bash 复制代码
kubectl patch sts web --type='json' -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"nginx:1.9.1"}]'

# kubectl patch sts web: 这部分表示你要对名为 "web" 的 StatefulSet 执行 patch 操作。

# --type='json': 这个选项指定了使用 JSON 格式的补丁。

# -p='[{"op": "replace", "path": "/spec/template/spec/containers/0/image", "value":"nginx:1.9.1"}]': 这是 JSON 补丁的内容,它包含了一组操作。在这个例子中,操作是 replace,它指示要替换某个路径上的值。具体来说:

# op: replace: 表示执行替换操作。

# path: /spec/template/spec/containers/0/image: 这是 JSON 路径,指定了要替换的目标位置,即 StatefulSet 中第一个容器的镜像路径。

# value: "nginx:1.9.1": 这是要替换的新值,即希望更新成的容器镜像。
  • 查看信息
bash 复制代码
 kubectl describe sts web  
 kubectl rollout history sts web
 kubectl rollout history sts web --revision=1
 kubectl rollout status sts web
  • 更新的策略有两种,RollingUpdate和OnDelete
RollingUpdate
  • StatefulSet 也可以采用滚动更新策略,同样是修改 pod template 属性后会触发更新,但是由于 pod 是有序的,在 StatefulSet 中更新时是基于 pod 的顺序倒序更新的

  • 基于RollingUpdate可以实现灰度发布,又叫金丝雀发布

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

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

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

    也就是先让一小部分更新,确认更新之后,版本稳定不会出问题之后,再将剩下的滚动更新或者多步金丝雀发布。

如图:

  • 下面进行操作
bash 复制代码
# 先将副本扩到5个,方便操作
kubectl scale sts web --replicas=5

#然后修改partition和image镜像版本号
kubectl edit sts web
  • 然后查看,确实只变动了3和4,然后0,1,2都没有更新
OnDelete
  • 只有在 pod 被删除时会进行更新操作

  • 将更新策略改为ondelete,并且修改镜像版本为1.9.1

  • 保存并退出,查看信息,kubectl describe po web-0发现镜像没有更改

  • 当删除web-0时kubectl delete po web-0,然后再查看信息发现,镜像版本变了,也就是发生了更新。

  • 并且刚删除,就会自动更新出来一个pod
级联删除和非级联删除
bash 复制代码
# 删除 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

DaemonSet

  • 介绍

  • DaemonSet 保证在每个 Node 上都运行一个容器副本,常用来部署一些集群的日志、监控或者其他系统管理应用。典型的应用包括:

    • 日志收集,比如 fluentd,logstash 等
    • 系统监控,比如 Prometheus Node Exporter,collectd,New Relic agent,Ganglia gmond 等
    • 系统程序,比如 kube-proxy, kube-dns, glusterd, ceph 等
部署Fluent日志收集程序
  • 指定node节点有三种,分别是nodeSelector,nodeAffinity和podAffinity,后两种后面章节介绍,这节讲nodeSelector

  • 配置文件:

bash 复制代码
apiVersion: apps/v1
kind: DaemonSet # 创建daemonset资源
metadata:
  name: fluentd # 名字
spec:
  selector:
    matchLabels:
      app: logging
  template:
    metadata:
      labels:
        app: logging
        id: fluentd
      name: fluentd
    spec:
      containers:
      - name: fluentd-es
        image: agilestacks/fluentd-elasticsearch:v1.3.0
        env: # 环境变量
         - name: FLUENTD_ARGS # 环境变量的key
           value: -qq # 环境变量的value
        volumeMounts: # 加载数据卷,避免数据丢失
         - name: containers # 数据卷的名字
           mountPath: /var/lib/docker/containers # 将数据卷挂载到容器的哪个目录
         - name: varlog
           mountPath: /varlog
      volumes: # 定义数据卷
         - hostPath: # 数据卷类型,主机路径的模式,也就是与node共享目录
             path: /var/lib/docker/containers # 定义数据卷的名称
           name: containers
         - hostPath:
             path: /var/log
           name: varlog


# 解释一下labels:
# selector 中的标签条件:

# 这些标签条件用于选择在哪些节点上运行 DaemonSet 的 Pod。
# selector 中的标签条件是用来匹配节点上的Pod.
# template 中定义的标签:

# 这些标签是在每个选择的节点上运行的 Pod 的元数据。
# 这些标签在 template 中定义,它们是在创建 Pod 时将分配给 Pod 的标签。
  • 然后运行yaml文件,查看信息
bash 复制代码
kubectl create -f fluentd-ds.yaml

kubectl get ds
kubectl get daemonset

daemonset# kubectl describe po fluentd-9xl99
  • 如下图

  • 然后去查看更详细的信息,发现虽然没有指定具体在哪个node部署,但是在每一个非master节点上面都部署有一个

bash 复制代码
kubectl get po -o wide

kubectl get nodes

kubectl get nodes --show-labels
  • 如图:

  • 然后我们给node-1加上一个type=microservices标签,然后在yaml文件中编辑,在template中加上nodeSelector,因为是匹配node然后创造一个pod,所以应该是template。然后来测试daemonset。

bash 复制代码
kubectl label no node-1 type=microservices

kubectl get nodes --show-labels


kubectl edit ds fluentd

kubectl get ds

get po -l app=logging -o wide
  • 增加如下

  • 发现在yaml文件中配置node选择之后,因为给node-1加入了对应的标签,所以daemonset会自动在node-1上部署pod

  • 然后给node-2也加上标签,会发现立即也会在node-2上部署pod

  • 注:不建议使用 RollingUpdate,建议使用 OnDelete 模式,这样避免频繁更新 ds

HPV 自动扩容/缩容
  • Pod 自动扩容:可以根据 CPU 使用率或自定义指标(metrics)自动对 Pod 进行扩/缩容。

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

  • 支持三种metrics类型

    • 预定义metrics(比如Pod的CPU)以利用率的方式计算
    • 自定义的Pod metrics,以原始值(raw value)的方式计算
    • 自定义的object metrics
  • 支持两种metrics查询方式:Heapster和自定义的REST API

  • 支持多metrics

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

  • 通常用于 Deployment,不适用于无法扩/缩容的对象,如 DaemonSet,也可以用于statefulset

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

开启服务指标
  • 安装服务指标相关东西,要不然下面的kubectl top po指令用不了
bash 复制代码
# 下载 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 参数

# 安装组件
kubectl apply -f metrics-server-components.yaml

# 查看 pod 状态
kubectl get pods --all-namespaces | grep metrics


# 执行完上面的操作之后就可以直接使用kubectl top pods
cpu,内存指标监控
  • 实现 cpu 或内存的监控,首先有个前提条件是该对象必须配置了 resources.requests.cpu 或 resources.requests.memory 才可以,可以配置当 cpu/memory 达到上述配置的百分比后进行扩容或缩容
  • 这里以deploy为例,加入resources的限制之后创建deploy
bash 复制代码
流程:
创建一个 HPA:
先准备一个好一个有做资源限制的 deployment
执行命令 kubectl autoscale deploy nginx-deploy --cpu-percent=20 --min=2 --max=5

可以通过 kubectl top pod来查看cpu,内存使用情况

通过 kubectl get hpa 可以获取 HPA 信息

测试:
自己创建一个svc
找到对应服务的 service,编写循环测试脚本提升内存与 cpu 负载
while true; do wget -q -O- http://<ip:port> > /dev/null ; done

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

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

扩容测试完成后,再关闭循环执行的指令,让 cpu 占用率降下来,然后过 5 分钟后查看自动缩容情况
  • 自己创建的svc:
bash 复制代码
apiVersion: v1 # 上面和后面的---是yaml文件嵌套了一段yaml文件
kind: Service
metadata:
  name: nginx-svc
  labels:
    app: nginx
spec:
  selector:
    app: nginx-deploy # 选择label为这个的pod
  ports:
  - port: 80
    targetPort: 80
    name: web
  type: NodePort
  • 一开始为:
  • 执行循环命令后,自动扩容到了5个,:
  • 然后停止循环,等待缩容
相关推荐
运维开发故事12 小时前
基于 Arthas 的多集群在线诊断系统设计与实现
kubernetes
Patrick_Wilson2 天前
从「改个端口」到 502:Next.js on k8s 的容器端口、Service 映射与 env 覆盖
docker·kubernetes·next.js
探索云原生3 天前
K8s 1.36 这个 GA 特性,把 initContainer 拉模型的 hack 干掉了
ai·云原生·kubernetes
云恒要逆袭3 天前
运行你的第一个Docker容器
后端·docker·容器
Java之美4 天前
一次k8s升级引发的DevicePlugin注册失败
云原生·kubernetes
程序员老赵4 天前
10 分钟部署 OpenCode:Docker 一键安装,浏览器打开就能用 AI 写代码(附完整命令与排错)
docker·容器·ai编程
武子康7 天前
调查研究-183 Apple container:Mac 上用轻量 VM 跑 Linux 容器,Swift 会改写本地容器体验吗?
docker·容器·apple
通信小呆呆10 天前
当算法有了“五感”:多模态数据融合如何向人体感官协同学习?
人工智能·学习·算法·机器学习·机器人
H__Rick10 天前
自动对焦学习-3
人工智能·学习·计算机视觉