StatefulSet(有状态)
-
有状态就是对本地有依赖,比如数据库的信息,删除之后,就没有之前的数据信息了,有依赖,如下图:
-
statefulset 命令可以用sts来简写,比如命令
kubectl get sts
定义配置文件
- 配置文件如下:
---
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文件中有关的信息
-
删了之后的为:
---
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常用工具,运行
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,后面省略,下图中的命令行就是用省略的,红框内为完整的格式。
扩容与缩容
- 扩容缩容可以用下面两条命令来实现:
kubectl scale statefulset web --replicas=5
kubectl patch statefulset web -p '{"spec":{"replicas":3}}'
- 扩容缩容后查看sts
kubectl describe sts web
滚动更新
- 镜像更新(目前还不支持直接更新 image,比如set image,需要 patch 来间接实现,或者用kubectl edit sts web), 如
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": 这是要替换的新值,即希望更新成的容器镜像。
- 查看信息
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 更新
也就是先让一小部分更新,确认更新之后,版本稳定不会出问题之后,再将剩下的滚动更新或者多步金丝雀发布。
如图:
- 下面进行操作
# 先将副本扩到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
级联删除和非级联删除
# 删除 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
-
配置文件:
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文件,查看信息
kubectl create -f fluentd-ds.yaml
kubectl get ds
kubectl get daemonset
daemonset# kubectl describe po fluentd-9xl99
-
如下图
-
然后去查看更详细的信息,发现虽然没有指定具体在哪个node部署,但是在每一个非master节点上面都部署有一个
kubectl get po -o wide
kubectl get nodes
kubectl get nodes --show-labels
-
如图:
-
然后我们给node-1加上一个type=microservices标签,然后在yaml文件中编辑,在template中加上nodeSelector,因为是匹配node然后创造一个pod,所以应该是template。然后来测试daemonset。
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
指令用不了
# 下载 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
流程:
创建一个 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:
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个,:
- 然后停止循环,等待缩容