看完本文会得到什么
现有 Kubernetes 集群机器如下
hostname | IP | role |
---|---|---|
kube-master | 192.168.137.100 | control plane |
kube-worker-1 | 192.168.137.101 | worker |
kube-worker-2 | 192.168.137.102 | worker |
而 nfs server 需要区别于上述 3 台机器之外的机器来承担
这里有一个良心建议,如果你打算自建 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
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 进行配置。
如下机器都需要安装
hostname | IP | role |
---|---|---|
kube-master | 192.168.137.100 | control plane |
kube-worker-1 | 192.168.137.101 | worker |
kube-worker-2 | 192.168.137.102 | worker |
安装脚本如下:
shell$ sudo apt -y install nfs-common
源码在 -> 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 修改如下关键内容:
yamlnfs: 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
首先我们需要创建一个 Persistent Volume Claim
yamlkind: PersistentVolumeClaim apiVersion: v1 metadata: name: test-claim spec: storageClassName: nfs-client accessModes: - ReadWriteMany resources: requests: storage: 1Mi
然后创建一个 pod,让它在启动之后往挂在的硬盘里面写入一个文本文件
yamlapiVersion: 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!
符合预期,完美挂载。
创建如下 statefulset
yamlapiVersion: 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 服务器上对新增的硬盘进行如下操作
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 的服务,这是完全没问题的,你以为云厂商搞的分布式存储能有多高级?
yamlnfs: 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
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 # 添加这一行