编辑
2022-11-18
Kubernetes
0
请注意,本文编写于 464 天前,最后修改于 463 天前,其中某些信息可能已经过时。

目录

前序准备工作
Ubuntu 安装和配置 nfs server
配置共享文件夹目录
从集群测试访问 nfs 服务
所有集群机器都需要安装 nfs 客户端组件
安装 nfs-subdir-external-provisioner
创建一个 demo 应用使用 nfs
使用 volumeClaimTemplates 动态创建
如何在 nfs 服务器上新增硬盘,然后修改 Kubenertes 动态存储的挂载文件目录?
重启 Ubuntu 之后,挂载的硬盘总是会随机的更改名字,如何解决?

看完本文会得到什么

  1. 自建 NFS 服务器
  2. 配置 NFS 服务器向 Kubernetes 提供动态分配卷的服务
  3. 使用 volumeClaimTemplates 搭配 NFS 实现动态创建卷

前序准备工作

现有 Kubernetes 集群机器如下

hostnameIProle
kube-master192.168.137.100control plane
kube-worker-1192.168.137.101worker
kube-worker-2192.168.137.102worker

而 nfs server 需要区别于上述 3 台机器之外的机器来承担

Ubuntu 安装和配置 nfs server

这里有一个良心建议,如果你打算自建 nfs server 最好是用物理机并且搭配的硬盘做过了 RAID。

我们挑选一台 IP 是 192.168.137.200 的机器做 nfs server(因为我很穷,我为了演示,只能在 Hyper-V 上重新创建一台虚拟机)。

shell
$ ssh root@192.168.137.200 $ sudo apt update $ sudo apt install nfs-kernel-server

配置共享文件夹目录

shell
$ sudo mkdir /mnt/kubedata # 创建目录给 Kubernetes 去使用 $ sudo chmod -R 777 /mnt/kubedata $ sudo chown nobody:nogroup /mnt/kubedata # 设置宽泛的权限,任何进程都可以使用这个目录

修改 nfs4 配置文件

shell
$ sudo vim /etc/exports

在最末尾加上 /mnt/kubedata *(rw,sync,no_root_squash),表示来自任意网段的访问都被允许

config
$ # /etc/exports: the access control list for filesystems which may be exported # to NFS clients. See exports(5). # # Example for NFSv2 and NFSv3: # /srv/homes hostname1(rw,sync,no_subtree_check) hostname2(ro,sync,no_subtree_check) # # Example for NFSv4: # /srv/nfs4 gss/krb5i(rw,sync,fsid=0,crossmnt,no_subtree_check) # /srv/nfs4/homes gss/krb5i(rw,sync,no_subtree_check) # /mnt/kubedata *(rw,sync,no_root_squash)

重启 nfs 服务

shell
$ sudo systemctl restart nfs-kernel-server

从集群测试访问 nfs 服务

shell
$ ssh root@192.168.137.101 # 进入某一个 worker 节点 root@kube-worker-1:~$ sudo apt install nfs-common root@kube-worker-1:~$ sudo mkdir -p /mnt/kubedata # 创建本地目录 root@kube-worker-1:~$ sudo mount 192.168.137.200:/mnt/kubedata /mnt/kubedata # 执行挂载操作

然后我们创建在 192.168.137.101 上创建一个 hello.txt 文件,把他写入到 /mnt/kubedata,然后回到 192.168.137.200 上去查看,这个文件是否成功的被写入到 192.168.137.200/mnt/kubedata

shell
$ root@kube-worker-1:~$ cd /mnt/kubedata/ $ root@kube-worker-1:~$ vi hello.txt hello, nfs!

然后回到 192.168.137.200

shell
$ ssh root@192.168.137.200 $ cat /mnt/kubedata/hello.txt $ root@192.168.137.200:~$ cat /mnt/kubedata/hello.txt hello, nfs!

至此基础服务已经调试通过,接下来我们需要回到 Kubernetes 进行配置。

所有集群机器都需要安装 nfs 客户端组件

如下机器都需要安装

hostnameIProle
kube-master192.168.137.100control plane
kube-worker-1192.168.137.101worker
kube-worker-2192.168.137.102worker

安装脚本如下:

shell
$ sudo apt -y install nfs-common

安装 nfs-subdir-external-provisioner

源码在 -> https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner

进入 集群的 control plane

shell
$ ssh root@192.168.137.100 $ helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner/ $ helm pull nfs-subdir-external-provisioner/nfs-subdir-external-provisioner --untar

然后进入 nfs-subdir-external-provisioner 文件夹,找到 values.yaml 修改如下关键内容:

yaml
nfs: server: 192.168.137.200 path: /mnt/kubedata

使用 helm 安装这个组件

shell
$ helm install nfs-subdir-external-provisioner ./nfs-subdir-external-provisioner

稍等几秒钟之后,查看安装是否成功

shell
$ kubectl get pods NAME READY STATUS RESTARTS AGE nfs-subdir-external-provisioner-67fb6f596d-rm2f2 1/1 Running 0 8m15s

创建一个 demo 应用使用 nfs

首先我们需要创建一个 Persistent Volume Claim

yaml
kind: PersistentVolumeClaim apiVersion: v1 metadata: name: test-claim spec: storageClassName: nfs-client accessModes: - ReadWriteMany resources: requests: storage: 1Mi

然后创建一个 pod,让它在启动之后往挂在的硬盘里面写入一个文本文件

yaml
apiVersion: v1 kind: Pod metadata: name: test-nfs-vol labels: name: test-nfs-vol spec: containers: - name: app image: busybox command: ['sh', '-c', 'echo "The local volume is mounted!" > /mnt/test.txt && sleep 3600'] volumeMounts: - name: nfs-pvc mountPath: "/mnt" volumes: - name: nfs-pvc persistentVolumeClaim: claimName: test-claim

创建完毕之后我们查看一下这个 pod 的状态

shell
$kubectl get pods NAME READY STATUS RESTARTS AGE test-nfs-vol 1/1 Running 1 (1m23s ago) 63m

然后我们可以去 192.168.137.200 机器上,查看它提供的 nfs 服务对外挂在的硬盘是否真的写入了一个文件

shell
$ root@192.168.137.200:/mnt/kubedata$ ls -a default-test-claim-pvc-20c76758-e437-41aa-95eb-a6abd94e7c58 hello.txt

你会发现多出了一个文件夹,没错,这个就是刚才那个 pod 创建的,我们进去看一眼

shell
$ root@192.168.137.200:/mnt/kubedata$ cd default-test-claim-pvc-20c76758-e437-41aa-95eb-a6abd94e7c58 $ root@192.168.137.200:/mnt/kubedata/default-test-claim-pvc-20c76758-e437-41aa-95eb-a6abd94e7c58$ cat test.txt The local volume is mounted!

符合预期,完美挂载。

使用 volumeClaimTemplates 动态创建

创建如下 statefulset

yaml
apiVersion: apps/v1 kind: StatefulSet metadata: name: busybox spec: selector: matchLabels: app: busybox # has to match .spec.template.metadata.labels serviceName: "busybox" replicas: 2 # by default is 1 minReadySeconds: 10 # by default is 0 template: metadata: labels: app: busybox # has to match .spec.selector.matchLabels spec: terminationGracePeriodSeconds: 10 containers: - name: busybox image: busybox command: ['sh', '-c', 'echo "The local volume is mounted!" > /mnt/test.txt && sleep 3600'] volumeMounts: - name: nfs-pvc mountPath: /mnt volumeClaimTemplates: - metadata: name: nfs-pvc spec: accessModes: [ "ReadWriteOnce" ] storageClassName: "nfs-client" resources: requests: storage: 1Mi

执行完毕之后,我们等待几秒,查看一下状态

shell
root@kube-master:~$ kubectl get statefulset busybox NAME READY AGE busybox 2/2 5m21s

然后我们去 192.168.137.200 查看 nfs 文件夹

shell
root@192.168.137.200:/mnt/kubedata$ ls default-nfs-pvc-busybox-0-pvc-674586b1-e64b-4b82-a01d-08134ea724da default-nfs-pvc-busybox-1-pvc-bf66ed12-52ea-484c-b8e1-8e485bb9e156

可以看到我们为 statefulset 设置了 2 个 replica,他们都如期创建了对应的文件夹,并且都写入了一个文本文件。

动态创建持久卷也成功实现。

如何在 nfs 服务器上新增硬盘,然后修改 Kubenertes 动态存储的挂载文件目录?

首先在 nfs 服务器上对新增的硬盘进行如下操作

shell
$ sudo fdisk -l # 这里会显示你所有的硬盘,找到你新增的那个硬盘位置,一般都是 /dev/sdb 或者是 /dev/sdb* 星号代表数字 $ sudo fdisk /dev/sdb # 这里后续只要按回车,按照默认的值操作即可 $ sudo mkfs -t ext4 /dev/sdb # 这是按照 ext4 的格式,格式化这块硬盘 $ sudo mkdir /mnt/sdb # 创建目录 $ sudo mount /dev/sdb /mnt/sdb # 将目录与新增硬盘进行挂载

然后我们需要继续对 nfs 的配置进行修改

shell
$ sudo mkdir /mnt/sdb/kubedata # 在新增的目录下创建新的 kubedata 目录 $ sudo chmod -R 777 /mnt/sdb/kubedata # 修改权限 $ sudo chown nobody:nogroup /mnt/sdb/kubedata $ sudo vim /etc/exports

/etc/exports 改成如下内容,其实就是尾部继续添加一行 /mnt/sdb/kubedata *(rw,sync,no_root_squash)

config
$ # /etc/exports: the access control list for filesystems which may be exported # to NFS clients. See exports(5). # # Example for NFSv2 and NFSv3: # /srv/homes hostname1(rw,sync,no_subtree_check) hostname2(ro,sync,no_subtree_check) # # Example for NFSv4: # /srv/nfs4 gss/krb5i(rw,sync,fsid=0,crossmnt,no_subtree_check) # /srv/nfs4/homes gss/krb5i(rw,sync,no_subtree_check) # /mnt/kubedata *(rw,sync,no_root_squash) /mnt/sdb/kubedata *(rw,sync,no_root_squash)
shell
$ sudo systemctl restart nfs-kernel-server # 重启 nfs 服务

回到 kubernetes 进行操作,找到 nfs-subdir-external-provisioner 的 helm 包,修改如下内容

注意

进行如下操作之前,我更建议你保留之前的 nfs 配置,因为你之前的 nfs 可能已经被使用了,如果你进行 storage class 的覆盖操作,这并不合理,所以你可以实现同一个 nfs 服务器上的 2 个目录提供 2 个 storage class 的服务,这是完全没问题的,你以为云厂商搞的分布式存储能有多高级?

yaml
nfs: server: 192.168.137.200 path: /mnt/sdb/kubedata storageClass: create: true defaultClass: true

重新安装

shell
$ helm upgrade nfs-subdir-external-provisioner ./nfs-subdir-external-provisioner

重启 Ubuntu 之后,挂载的硬盘总是会随机的更改名字,如何解决?

shell
$ lsblk -o NAME,FSTYPE,UUID root@ubuntu-server:# lsblk -o NAME,FSTYPE,UUID NAME FSTYPE UUID loop0 squashfs loop1 squashfs loop2 squashfs loop3 squashfs loop4 squashfs loop5 squashfs sda ext4 0f0860be-0a79-421d-8dca-104d4c66c20c sdb ├─sdb1 vfat 4A52-1A96 ├─sdb2 ext4 354800a2-9b08-4f00-b20a-a6fdf8fa3050 └─sdb3 LVM2_member C9ls23-vBbY-MJxi-jEXa-ZzfT-Cf5R-LZ4Khs └─ubuntu--vg-ubuntu--lv ext4 51489b65-5930-48a8-8429-c6f7b7f0e6c2

修改配置文件 /etc/fstab

shell
$ vi /etc/fstab # /etc/fstab: static file system information. # # Use 'blkid' to print the universally unique identifier for a # device; this may be used with UUID= as a more robust way to name devices # that works even if disks are added and removed. See fstab(5). # # <file system> <mount point> <type> <options> <dump> <pass> # / was on /dev/ubuntu-vg/ubuntu-lv during curtin installation /dev/disk/by-id/dm-uuid-LVM-pW0tAc3Lt7C8B3xQ8Y2gSVQbFDPdyOiltYsSNNkBDbNzKpv5kCHIFV3X7DgEE8w4 / ext4 defaults 0 1 # /boot was on /dev/sda2 during curtin installation /dev/disk/by-uuid/354800a2-9b08-4f00-b20a-a6fdf8fa3050 /boot ext4 defaults 0 1 # /boot/efi was on /dev/sda1 during curtin installation /dev/disk/by-uuid/4A52-1A96 /boot/efi vfat defaults 0 1 /swap.img none swap sw 0 0 UUID=0f0860be-0a79-421d-8dca-104d4c66c20c /mnt/sdb/kubedata ext4 defaults 0 1 # 添加这一行