【架构】k8s中部署etcd集群的快捷实现方式
yaml文件
![](https://img.haomeiwen.com/i29319802/7b00b851d67eed75.jpeg)
![](https://img.haomeiwen.com/i29319802/bccd241a6731cfbf.jpeg)
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: example-pv-1
spec:
capacity:
storage: 20Gi
volumeMode: Filesystem # 存储卷的类型为:文件系统
accessModes:
- ReadWriteOnce # 访问策略:该卷可以被单个节点以读/写模式挂载
persistentVolumeReclaimPolicy: Delete #下面有注释
storageClassName: local-storage
local:
path: /home/paas/etcd/etcd #本地目录
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- k8s-node01
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: example-pv-2
spec:
capacity:
storage: 20Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Delete
storageClassName: local-storage
local:
path: /home/paas/etcd/etcd
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- k8s-node02
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: example-pv-3
spec:
capacity:
storage: 20Gi
volumeMode: Filesystem
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Delete
storageClassName: local-storage
local:
path: /home/paas/etcd/etcd
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- k8s-node03
---
apiVersion: v1
kind: Service
metadata:
name: etcd-headless-svc
namespace: kube-system
labels:
app: etcd
spec:
ports:
- name: etcd-client
port: 2379
protocol: TCP
targetPort: 2379
- name: etcd-peer
port: 2380
protocol: TCP
targetPort: 2380
clusterIP: None
selector:
app: etcd
publishNotReadyAddresses: true #publishNotReadyAddresses 可以控制是否将未就绪的 Pod 发布到 Service 上,一般不建议为 true
---
apiVersion: v1
kind: Service
metadata:
labels:
app: etcd
name: etcd-nodeport
namespace: kube-system
spec:
ports:
- name: etcd-cluster
port: 2379
targetPort: 2379
selector:
app: etcd
sessionAffinity: None #sessionAffinity可以设置会话亲和性:默认是None表示轮询,ClientIP表示会话固定。
type: NodePort
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: etcd
namespace: kube-system
labels:
app: etcd
spec:
podManagementPolicy: Parallel # Pod管理策略,默认的“OrderedReady”表示顺序创建并逆序删除,“Parallel”表示并行模式
replicas: 3
selector:
matchLabels:
app: etcd
serviceName: etcd-headless-svc
template:
metadata:
labels:
app: etcd
name: etcd
spec:
nodeSelector:
app: etcd
containers:
- name: etcd
image: registry.cn-hangzhou.aliyuncs.com/leige24/k8s-etcd:v1 #可以自己制作,下面会写
imagePullPolicy: Always
ports:
- containerPort: 2380
name: peer
protocol: TCP
- containerPort: 2379
name: client
protocol: TCP
env:
- name: MY_POD_NAME #当前pod名
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: MY_POD_IP #当前pod ip
valueFrom:
fieldRef:
fieldPath: status.podIP
- name: CLUSTER_NAMESPACE #名称空间
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: HEADLESS_SERVICE_NAME #内部通信的无头服务名称
value: "etcd-headless-svc"
- name: INITIAL_CLUSTER #initial-cluster的值
value: "etcd-0=http://etcd-0.etcd-headless-svc.kube-system:2380,etcd-1=http://etcd-1.etcd-headless-svc.kube-system:2380,etcd-2=http://etcd-2.etcd-headless-svc.kube-system:2380"
resources:
requests:
memory: "1Gi"
cpu: "2000m"
limits:
memory: "1Gi"
cpu: "2000m"
volumeMounts:
- mountPath: /var/lib/etcd
name: data-etcd
updateStrategy: #滚动更新策略
type: OnDelete # 滚动更新类型,可用值有OnDelete(只有手动删除了pod,新的pod才会被创建)和默认滚动升级Rollingupdate
volumeClaimTemplates: #下面有注释
- metadata:
name: data-etcd
spec:
accessModes: [ "ReadWriteMany" ]
storageClassName: local-storage
resources:
requests:
storage: 2Gi
etcd镜像制作
Dockerfile
FROM eulerx86lib:1.5 #基础镜像随便选
USER root
ADD etcd-v3.5.4-linux-amd/etcd* /usr/bin/
COPY etcd.sh /
RUN chmod 777 /etcd.sh && chmod 777 /usr/bin/etcd
CMD ["/etcd.sh"]
etcd启动脚本
#/bin/bash
etch ${MY_POD_NAME}
echo ${MY_POD_IP}
echo ${HEADLESS_SERVICE_NAME}
echo ${CLUSTER_NAMESPACE}
echo ${INITIAL_CLUSTER}
/usr/bin/etcd --data-dir=/var/lib/etcd --name=${MY_POD_NAME} \
--listen-peer-urls=http://0.0.0.0:2380 \
--listen-client-urls http://0.0.0.0:2379 \
--advertise-client-urls http://${MY_POD_NAME}.${HEADLESS_SERVICE_NAME}.${CLUSTER_NAMESPACE}.svc.cluster.local:2379 \
--initial-advertise-peer-urls http://${MY_POD_NAME}.${HEADLESS_SERVICE_NAME}.${CLUSTER_NAMESPACE}.svc.cluster.local:2380 \
--initial-cluster-state='new' \
--initial-cluster-token='etcd-cluster-token' \
--initial-cluster=${INITIAL_CLUSTER}
注释:
PV、PVC、StorageClass详解参考:
https://kubernetes.io/zh-cn/docs/concepts/storage/persistent-volumes/
PV的访问模式(spec.accessModes)
三种访问模式
访问模式accessModes一共有三种:
ReadWriteOnce: 该卷可以被单个节点以读/写模式挂载
ReadOnlyMany: 该卷可以被多个节点以只读模式挂载
ReadWriteMany: 该卷可以被多个节点以读/写模式挂载
在命令行cli中,三种访问模式可以简写为:
RWO - ReadWriteOnce
ROX - ReadOnlyMany
RWX - ReadWriteMany
但不是所有的类型的底层存储都支持以上三种,每种底层存储类型支持的都不一样!!
PV的回收策略(spec.persistentVolumeReclaimPolicy)
Retain(保留): pv被删除后会保留内存,手动回收
Recycle(回收): 删除卷下的所有内容(rm-rf /thevolume/*)
Delete(删除): 关联的存储资产(例如AWS EBS、GCE PD、Azure Disk 和OpenStack Cinder卷)将被删除。即直接把卷给删除了
回收策略注意事项
当前,只有NFS和HostPath支持Recycle回收策略
最新版本中的Recycle已被废弃,截图如下
附:具体官网文档详细说明链接 点击此处
PersistentVolume(PV)的状态
PV可以处于以下的某种状态:
Available(可用): 块空闲资源还没有被任何声明绑定
Bound(已绑定): 卷已经被声明绑定, 注意:但是不一定不能继续被绑定,看accessModes而定
Released(已释放): 声明被删除,但是资源还未被集群重新声明
Failed(失败): 该卷的自动回收失败
volumeClaimTemplates
volumeClaimTemplates 是 StatefulSet 中的一个字段,它用于定义每个 Pod 所需的持久卷声明(Persistent Volume Claim,PVC)模板。通过使用这个字段,可以自动为 StatefulSet 中的每个 Pod 创建和绑定相应的 PVC。
在 volumeClaimTemplates 字段中,可以定义多个 PVC 模板,每个模板都包含了创建 PVC 所需的属性,如存储类、访问模式、存储资源需求等。StatefulSet 会根据这些模板为每个 Pod 动态创建 PVC,并将其绑定到匹配的持久卷上。
当创建 StatefulSet 的 Pod 时,每个 Pod 将使用与其对应的 PVC,并将其挂载到 Pod 的容器中,从而实现持久化存储的使用
StorageClass的延迟绑定机制
provisioner 字段定义为no-provisioner,这是因为 Local Persistent Volume 目前尚不支持 Dynamic Provisioning动态生成PV,所以我们需要提前手动创建PV。
volumeBindingMode字段定义为WaitForFirstConsumer,它是 Local Persistent Volume 里一个非常重要的特性,即:延迟绑定。延迟绑定就是在我们提交PVC文件时,StorageClass为我们延迟绑定PV与PVC的对应关系。
这样做的原因是:比如我们在当前集群上有两个相同属性的PV,它们分布在不同的节点Node1和Node2上,而我们定义的Pod需要运行在Node1节点上 ,但是StorageClass已经为Pod声明的PVC绑定了在Node2上的PV,这样的话,Pod调度就会失败,所以我们要延迟StorageClass的绑定操作。
也就是延迟到到第一个声明使用该 PVC 的 Pod 出现在调度器之后,调度器再综合考虑所有的调度规则,当然也包括每个 PV 所在的节点位置,来统一决定,这个 Pod 声明的 PVC,到底应该跟哪个 PV 进行绑定。
比如上面的Pod需要运行在node1节点上,StorageClass发现可以绑定的PV后,先不为Pod中的PVC绑定PV,而是等到Pod调度到node1节点后,再为PVC绑定当前节点运行的PV。
所以,通过这个延迟绑定机制,原本实时发生的 PVC 和 PV 的绑定过程,就被延迟到了 Pod 第一次调度的时候在调度器中进行,从而保证了这个绑定结果不会影响 Pod 的正常调度。