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

目录

前序准备工作
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 [email protected]
$ 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 [email protected] # 进入某一个 worker 节点
[email protected]:~$ sudo apt install nfs-common
[email protected]:~$ sudo mkdir -p /mnt/kubedata # 创建本地目录
[email protected]:~$ 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
$ [email protected]:~$ cd /mnt/kubedata/
$ [email protected]:~$ vi hello.txt

hello, nfs!

然后回到 192.168.137.200

shell
$ ssh [email protected]
$ cat /mnt/kubedata/hello.txt
$ [email protected]:~$ 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 [email protected]
$ 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
$ [email protected]:/mnt/kubedata$ ls -a
default-test-claim-pvc-20c76758-e437-41aa-95eb-a6abd94e7c58  hello.txt

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

shell
$ [email protected]:/mnt/kubedata$ cd default-test-claim-pvc-20c76758-e437-41aa-95eb-a6abd94e7c58
$ [email protected]:/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
[email protected]:~$ kubectl get statefulset busybox
NAME      READY   AGE
busybox   2/2     5m21s

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

shell
[email protected]:/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
[email protected]:# 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 # 添加这一行