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 podscpu,内存指标监控
- 实现 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个,:


- 然后停止循环,等待缩容

