02.Kubernetes 和 KubeSphere 集群安装配置持久化存储(nfs)并通过StatefulSet动态为pod生成pv挂载
本章演示如何使用nfs文件系统,配置持久化k8s集群本地文件存储并通过StatefulSet动态为pod生成pv挂载。
Kubernetes 和 KubeSphere 集群安装配置持久化存储(nfs)并通过StatefulSet动态为pod生成pv挂载
简介
持久化存储是安装 KubeSphere 的必备条件。使用 KubeKey 搭建 KubeSphere 集群时,可以安装不同的存储系统作为插件。如果 KubeKey 检测到未指定默认存储类型,则将默认安装 OpenEBS。
同样使用Kubernetes部署我们自己的服务时,也需要为对应的pod挂载pv持久卷,以实现服务数据本地持久化 。
本章演示如何使用nfs文件系统,配置持久化k8s集群本地文件存储并通过StatefulSet动态为pod生成pv挂载。
往期文章参考:
01.使用 KubeKey 在Linux上预配置生产就绪的 Kubernetes 和 KubeSphere 集群
版本如下
名称 | 版本 |
---|---|
CentOS | 7.6+ |
Kubernetes | 1.23.8 |
KubeSphere | 3.3.1 |
主机分配
主机名称 | IP | 角色 | 容器运行时 | 容器运行时版本 |
---|---|---|---|---|
master01 | 192.168.0.3 | control plane, etcd, worker | docker | 19.3.8+ |
node01 | 192.168.0.5 | worker | docker | 19.3.8+ |
node02 | 192.168.0.7 | worker | docker | 19.3.8+ |
node03 | 192.168.0.8 | worker | docker | 19.3.8+ |
1. 安装配置前置环境
1.1 安装nfs文件系统
1.1.1 安装nfs-server
# 集群每台主机执行以下命令,启动 nfs 服务;创建共享目录
yum install -y nfs-utils
mkdir -p /nfs/data
# 在master01 执行以下命令 可以根据实际情况选择硬盘存储量比较大的作为nfs服务器
echo "/nfs/data/ *(rw,insecure,sync,no_subtree_check,no_root_squash)" > /etc/exports
# 在master01执行
systemctl enable rpcbind
systemctl enable nfs # systemctl enable nfs-server
systemctl start rpcbind
systemctl start nfs
exportfs -r # 使配置生效
exportfs #检查配置是否生效
# 指定网段共享可参考如下
# mkdir -p /data/volumes/{v1,v2,v3}
# 编辑master节点/etc/exports文件,将目录共享到192.168.0.0/24这个网段中(网段可根据自己环境来填写,exports文件需要在每台master节点上进行配置)
# vim /etc/exports
# /data/volumes/v1 192.168.0.0/24(rw,no_root_squash,no_all_squash)
# 发布
# exportfs -arv
# exporting 192.168.0.0/24:/data/volumes/v1
# 查看
# showmounte -e
# Export list for master01:
# /data/volumes/v1 192.168.0.0/24
常见的参数则有:
**rw** read-write 读写
**ro** read-only 只读
**sync** 请求或写入数据时,数据同步写入到NFS server的硬盘后才返回。数据安全,但性能降低了
**async** 优先将数据保存到内存,硬盘有空档时再写入硬盘,效率更高,但可能造成数据丢失。
**root_squash** 当NFS 客户端使用root用户访问时,映射为NFS 服务端的匿名用户
**no_root_squash** 当NFS 客户端使用root 用户访问时,映射为NFS服务端的root 用户
**all_squash** 不论NFS 客户端使用任何帐户,均映射为NFS 服务端的匿名用户
1.1.2 配置nfs-client
IP地址为master(nfs服务器)的IP地址
# 查看
showmount -e 192.168.0.3
# 除了nfs服务器节点,其他节点都要执行
# 挂载到nfs服务器
mount -t nfs 192.168.0.3:/nfs/data /nfs/data
# 设置开机自动挂载
echo "192.168.0.3:/nfs/data /nfs/data nfs defaults 0 0" >> /etc/fstab
1.1.3 测试nfs
# 在master01的/home目录下新建test-nfs.yml
apiVersion: v1
kind: Pod
metadata:
name: test-nfs-pod
spec:
containers:
- name: busybox
image: busybox
command:
- sh
- -c
- 'echo hello world > /mnt/hello'
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: "/mnt"
name: nfs
volumes:
- name: nfs
nfs: # 使用NFS存储
path: /nfs/data # NFS存储路径
server: 192.168.0.3 # NFS服务器地址
# 上面busybox的逻辑就是将“hello world”写入/mnt/hello文件中,而/mnt目录和NFS挂载,所以理论上,nfs虚拟机的/nfs目录下也会有个hello文件。
# 创建后,运行kubectl apply -f test-nfs.yml
# 查看nfs虚拟机(master),查看/nfs/data目录下是否有hello文件
# 测试成功后,可以删除hello文件:rm -rf /nfs/hello
# 执行以下命令删除刚刚的测试Pod:kubectl delete -f test-nfs.yml
2. 配置默认存储(Storageclass)
Storageclass解决PV手动创建需求,当每次创建 PVC 声明使用存储时,都需要去手动的创建 PV,来满足 PVC 的使用。
可以用一种机制来根据用户声明的存储使用量(PVC)来动态的创建对应的持久化存储卷(PV),k8s 用 StorageClass 来实现动态创建 持久化存储。
目前支持的类参考:https://kubernetes.io/zh-cn/docs/concepts/storage/storage-classes/
在NFS StorageClass中最核心概念为Provisioner,那什么是Provisioner?
Provisioner是StorageClass中必须的一个资源,它是存储资源自动调配器,可以将其看作是后端存储驱动。对于NFS类型,K8S没有提供内部Provisioner,但可以使用外部的Provisioner。Provisioner必须符合存储卷的开发规范(CSI)。本文档中使用NFS提供的Provisioner。
流程分解:
①pod挂载pvc
②pvc配置存储类请求pv
③storageclass找到provisioner申请pv
④nfs provisioner生成pvc需要的pv,提供给pod做存储
2.1 创建默认公共存储类
以下操作在master01主节点执行即可
需注意,StorageClass为全局资源,所以命名空间为default,不影响其他命名空间调用 如果*K8s版本为1.20.x *
且nfs-subdir-external-provisioner(nfs-client)的版本低于4.0
在/etc/kubernetes/manifests/kube-apiserver.yaml的command中添加:
- –feature-gates=RemoveSelfLink=false 否则会报错: Kubernetes v1.20.13 报"unexpected error getting claim reference: selfLink was
empty, can’t make reference"
2.1.1 创建nfs-storage存储类
# 创建 sc.yaml 并执行 kubectl apply -f sc.yaml 创建名为nfs-storage的存储类
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfs-storage ## 可以改成自己的存储名称
annotations:
storageclass.beta.kubernetes.io/is-default-class: 'true'
storageclass.kubernetes.io/is-default-class: "true" ## true 默认空间,false 不是默认空间
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner ## 这里指定存储供应者来源名称
reclaimPolicy: Delete ## 指定回收策略,在这里选择的是Delete,与PV相连的后端存储完成Volume的删除操作
volumeBindingMode: Immediate ## 指定绑定模式,在这里选择的是即刻绑定,也就是存储卷声明创建之后,立刻动态创建存储卷饼将其绑定到存储卷声明,另外还有"WaitForFirstConsumer",直到存储卷声明第一次被容器组使用时,才创建存储卷,并将其绑定到存储卷声明
parameters:
archiveOnDelete: "true" ## 删除pv的时候,pv的内容是否要备份
##pathPattern: "${.PVC.namespace}/${.PVC.annotations.nfs.io/storage-path}" ## 配置默认没有,支持NFS创建子目录,用于不同应用使用NFS的不同目录
# kubectl get sc 查看
# local为KubeKey默认安装的 OpenEBS 类型存储
# nfs-storage为我们刚才生成的
[root@master01 ~]# kubectl get sc
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
local (default) openebs.io/local Delete WaitForFirstConsumer false 3d22h
nfs-storage (default) k8s-sigs.io/nfs-subdir-external-provisioner Delete Immediate false 17h
2.1.2 创建RBAC权限
创建Service Account,用来管控NFS provisioner在k8s集群中的运行权限 rbac (Role-Based Access Control 基于角色的访问控制,就是用户通过角色与权限进行关联),是一个从认证—>授权—>准入机制
# 创建 rbac.yaml 并执行 kubectl apply -f rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: nfs-client-provisioner-runner
rules:
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["get", "list", "watch", "create", "delete"]
- apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get", "list", "watch", "update"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["events"]
verbs: ["create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: run-nfs-client-provisioner
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
roleRef:
kind: ClusterRole
name: nfs-client-provisioner-runner
apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: leader-locking-nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
rules:
- apiGroups: [""]
resources: ["endpoints"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: leader-locking-nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
subjects:
- kind: ServiceAccount
name: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
roleRef:
kind: Role
name: leader-locking-nfs-client-provisioner
apiGroup: rbac.authorization.k8s.io
2.1.3 创建PV的Provisioner(存储插件)
创建PV存储插件,这样才能实现自动创建PV,一是在NFS共享目录下创建挂载点(volume),二是建立PV并将PC与NFS挂载建立关联。
本文采用高可用配置 如不需要可将replicas设置为1,env中ENABLE_LEADER_ELECTION高可用选举环境变量注释掉
# 创建 rbac.yaml 并执行 kubectl apply -f rbac.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nfs-client-provisioner
labels:
app: nfs-client-provisioner
# replace with namespace where provisioner is deployed
namespace: default
spec:
replicas: 3 # 想做高可用的话这里可以改成3,一般为大于等于3的奇数
strategy:
type: Recreate
selector:
matchLabels:
app: nfs-client-provisioner
template:
metadata:
labels:
app: nfs-client-provisioner
spec:
serviceAccountName: nfs-client-provisioner
containers:
- name: nfs-client-provisioner
# 注意该NFS-client镜像一定要与k8s版本相匹配,如果不兼容那么就无法绑定
image: registry.cn-hangzhou.aliyuncs.com/lfy_k8s_images/nfs-subdir-external-provisioner:v4.0.2
# resources:
# limits:
# cpu: 10m
# requests:
# cpu: 10m
volumeMounts:
- name: nfs-client-root
mountPath: /persistentvolumes
env:
- name: PROVISIONER_NAME
value: k8s-sigs.io/nfs-subdir-external-provisioner
- name: ENABLE_LEADER_ELECTION
value: "True" ## 设置高可用允许选举
- name: NFS_SERVER
value: 192.168.0.5 ## 指定自己nfs服务器地址
- name: NFS_PATH
value: /nfs/data ## nfs服务器共享的目录
volumes:
- name: nfs-client-root
nfs:
server: 192.168.0.3
path: /nfs/data
# 通过检查容器日志查看启动的NFS插件是否正常
# 如果出现error等相关信息一定仔细排查,否则会导致NFS-celient一直处于pending状态
# https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner/issues/25
[root@master01 ~]# kubectl get pod | grep nfs
nfs-client-provisioner-86b55c565d-fqmm5 1/1 Running 0 20h
nfs-client-provisioner-86b55c565d-p2sks 1/1 Running 0 20h
nfs-client-provisioner-86b55c565d-r5stq 1/1 Running 0 20h
2.1.4 创建PVC持久化卷
# # 创建 pvc.yaml 并执行 kubectl apply -f pvc.yaml
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: test-pvc
namespace: default
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 200Mi
storageClassName: nfs-storage ## 这里不加就是默认存储
# kubectl get pvc 查看
[root@master01 nfs]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
test-pvc Bound pvc-dd852bab-8b86-4d42-8666-9b2b550597aa 200Mi RWX nfs-storage 8s
[root@master01 nfs]# kubectl delete -f pvc.yaml
2.2 使用statefulset动态为pod生成pv
RC、Deployment、DaemonSet都是面向无状态的服务,它们所管理的Pod的IP、名字,启停顺序等都是随机的,而StatefulSet是什么?顾名思义,有状态的集合,管理所有有状态的服务,比如MySQL、MongoDB集群等。
StatefulSet本质上是Deployment的一种变体,在v1.9版本中已成为GA版本,它为了解决有状态服务的问题,它所管理的Pod拥有固定的Pod名称,启停顺序,在StatefulSet中,Pod名字称为网络标识(hostname),还必须要用到共享存储。
在Deployment中,与之对应的服务是service,而在StatefulSet中与之对应的headless
service,headless service,即无头服务,与service的区别就是它没有Cluster
IP,解析它的名称时将返回该Headless Service对应的全部Pod的Endpoint列表。
除此之外,StatefulSet在Headless Service的基础上又为StatefulSet控制的每个Pod副本创建了一个DNS域名,这个域名的格式为:
$(podname).(headless server name)
FQDN:$(podname).(headless server name).namespace.svc.cluster.local
2.2.1 创建测试pod
# 创建 test.yaml 并执行 kubectl apply -f test.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
metadata:
name: nfs-web
spec:
serviceName: "nginx"
replicas: 3
selector:
matchLabels:
app: nfs-web # has to match .spec.template.metadata.labels
template:
metadata:
labels:
app: nfs-web
spec:
terminationGracePeriodSeconds: 10
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates: # pvc模板
- metadata:
name: www
namespace: default # 要和pod的namspace一致
annotations:
volume.beta.kubernetes.io/storage-class: nfs-storage
spec:
accessModes: [ "ReadWriteOnce" ]
resources:
requests:
storage: 10Mi
# kubectl get pvc 查看 可以看到为pod动态生成了pvc,pv
# 在StatefulSet中动态生成的pv不会随着pod的删除而被删除
# 它是和pod一一对应,pod恢复后,数据依然存在
[root@master01 nfs]# kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
www-nfs-web-0 Bound pvc-bdd6ff3e-9524-4e21-8cb6-29aebfd67e6f 10Mi RWO nfs-storage 4s
www-nfs-web-1 Bound pvc-9eea90b4-3ac7-4a7d-a037-301c96eb707e 10Mi RWO nfs-storage 0s
[root@master01 nfs]#
[root@master01 nfs]# kubectl delete -f test.yaml
3. KubeSphere存储持久化和其他组件安装
3.1 存储持久化和其他组件安装
3.1.1 存储持久化和配置其他组件
1、以 admin 用户登录控制台,点击左上角的平台管理,选择集群管理。
2、点击定制资源定义,在搜索栏中输入 ClusterConfiguration,点击搜索结果查看其详细页面。
3、在自定义资源中,点击 ks-installer 右侧的操作,选择编辑 YAML。。
4、在该 YAML 文件中,修改配置内容完成后,点击右下角的确定,保存配置,组件就开始安装,安装需要一定的时间,需要耐心等待。
1、kubesphere平台上操作:metrics_server 改为 true
metrics_server:
enabled: true
2、kubesphere平台上操作:建议将存储配置进行修改: storageClass: “nfs-storage” ,不修改会默认创建一个存储空间 local (default) ,
monitoring:
gpu:
nvidia_dcgm_exporter:
enabled: false
node_exporter:
port: 9100
storageClass: 'nfs-storage'
# 监控如果开启建议修改为nfs-storage
monitoring:
gpu:
nvidia_dcgm_exporter:
enabled: false
node_exporter:
port: 9100
storageClass: 'nfs-storage'
3、kubesphere平台上操作: network配置改为如下:
network:
ippool:
type: calico
networkpolicy:
enabled: true
topology:
type: weave-scope
4、kubesphere平台上操作: 应用商店开启:
openpitrix:
store:
enabled: true
5、在 kubectl 中执行以下命令检查安装过程:
kubectl logs -n kubesphere-system $(kubectl get pod -n kubesphere-system -l 'app in (ks-install, ks-installer)' -o jsonpath='{.items[0].metadata.name}') -f
往期文章参考:
01.使用 KubeKey 在Linux上预配置生产就绪的 Kubernetes 和 KubeSphere 集群
更多推荐
所有评论(0)