一、基础环境
master:
192.168.1.189
node1:
192.168.1.190
node2:
192.168.1.188
二、NFS服务端部署
本文选择 IP 为 192.168.1.188 的 node2 节点,作为 NFS 存储服务器。
安装 NFS 服务端软件包并创建共享目录
yum install nfs-utils -y
mkdir -p /home/data/k8s
chown nfsnobody:nfsnobody /home/data/k8s
编辑服务配置文件
配置 NFS 服务器数据导出目录及访问 NFS 服务器的客户端机器权限。
编辑配置文件 vi /etc/exports
,添加如下内容
/home/data/k8s 192.168.1.0/24(rw,sync,all_squash,anonuid=65534,anongid=65534,no_subtree_check)
说明:
192.168.1.0/24:可以访问 NFS 存储的客户端 IP 地址
rw:读写操作,客户端机器拥有对卷的读写权限。
sync:内存数据实时写入磁盘,性能会有所限制
all_squash:NFS 客户端上的所有用户在使用共享目录时都会被转换为一个普通用户的权限
anonuid:转换后的用户权限 ID,对应的操作系统的 nfsnobody 用户 anongid:转换后的组权限 ID,对应的操作系统的 nfsnobody 组 no_subtree_check:不检查客户端请求的子目录是否在共享目录的子树范围内,也就是说即使输出目录是一个子目录,NFS 服务器也不检查其父目录的权限,这样可以提高效率。
启动服务并设置开机自启
systemctl enable nfs-server --now
查看共享目录
查看导出目录
[root@k3s-node2 ~]# exportfs -v
/home/data/k8s 192.168.1.0/24(sync,wdelay,hide,no_subtree_check,sec=sys,rw,secure,root_squash,all_squash)
客户端挂载测试
找一台额外的机器作为客户端验证测试,本示例使用 node1节点。
创建测试挂载点
mkdir -p /home/nfs-node2/
安装 NFS 软件包(一定要安装,否则无法识别 nfs 类型的存储)
yum install nfs-utils
挂载 NFS 共享目录
mount -t nfs 192.168.1.188:/home/data/k8s /home/nfs-node2
增删改查测试
# 创建测试目录、创建测试文件、测试文件写入内容、查看写入目录和文件权限、删除目录和文件
[root@k8s-master-1 ~]# cd /home/nfs-node2
[root@k3s-node1 nfs-node2]# mkdir nfs-test
[root@k3s-node1 nfs-node2]# touch nfs-test.txt
[root@k3s-node1 nfs-node2]# echo "nfs-test" > nfs-test.txt
[root@k3s-node1 nfs-node2]# ll
total 4
drwxr-xr-x 2 nfsnobody nfsnobody 6 Nov 29 16:56 nfs-test
-rw-r--r-- 1 nfsnobody nfsnobody 9 Nov 29 16:56 nfs-test.txt
[root@k3s-node1 nfs-node2]# rmdir nfs-test
[root@k3s-node1 nfs-node2]# rm nfs-test.txt
rm: remove regular file ‘nfs-test.txt’? y
[root@k3s-node1 nfs-node2]# ll
total 0
检查 nfs 服务器端是否有设置共享目录
[root@k3s-node1 nfs-node2]# showmount -e 192.168.1.188
Export list for 192.168.1.188:
/home/data/k8s 192.168.1.0/24
其他命令
卸载挂载
df -hT
192.168.1.188:/home/data/k8s nfs4 46G 32M 46G 1% /home/nfs-node2
umount /home/nfs-node2
查看nfs版本
# 查看nfs服务端信息(服务端执行)
nfsstat -s
# 查看nfs客户端信息(客户端执行)
nfsstat -c
三、安装 Kubernetes NFS Subdir External Provisioner
想要 Kubernetes 支持 NFS 存储,我们需要安装 nfs-subdir-external-provisioner ,它是一个存储资源自动调配器,它可将现有的 NFS 服务器通过持久卷声明来支持 Kubernetes 持久卷的动态分配。该组件是对 Kubernetes NFS-Client Provisioner 的扩展, nfs-client-provisioner 已经不提供更新,而且 Github 仓库 也已经处于归档状态,已经迁移到 nfs-subdir-external-provisioner 的仓库。
官方提供的安装方式有三种:
使用 Helm 的方式比较简单,也是现在官方推荐的、使用率最高的方式,本文仅实战演示 Helm 部署方式,其他方式请参考官方文档。
集群节点安装 NFS Client
所有 Kubernetes 集群节点需要提前安装 nfs-utils,否则在部署过程中会报错。
yum install nfs-utils
添加 Helm 源
helm repo add nfs-subdir-external-provisioner https://kubernetes-sigs.github.io/nfs-subdir-external-provisioner
创建 NameSpace
可选配置,主要是方便资源管理。
kubectl create ns nfs-system
命令行快速安装 Kubernetes NFS Subdir External Provisioner
(首选方案,使用命令行设置变量参数)
helm install nfs-subdir-external-provisioner nfs-subdir-external-provisioner/nfs-subdir-external-provisioner --set storageClass.name=nfs-sc --set nfs.server=192.168.9.81 --set nfs.path=/data/k8s -n nfs-system
说明:
--set storageClass.name=nfs-sc:指定 storageClass 的名字
--set nfs.server=192.168.9.81:指定 NFS 服务器的地址
--set nfs.path=/data/k8s:指定 NFS 导出的共享数据目录
--set storageClass.defaultClass=true:指定为默认的 sc,本示例没使用
-n nfs-system:指定命名空间。
这条命令创建了一个名称为nfs-subdir-external-provisioner 的deploy,通过deploy 生成一个名字nfs-subdir-external-provisioner开头的pod。
这里如果有如下报错:
Error: INSTALLATION FAILED: Kubernetes cluster unreachable: Get "http://localhost:8080/version": dial tcp [::1]:8080: connect: connection refused
报错原因: helm v3版本不再需要Tiller,而是直接访问ApiServer来与k8s交互,通过环境变量KUBECONFIG来读取存有ApiServre的地址与token的配置文件地址,默认地址为~/.kube/config
解决方式:
vi /etc/profile
export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
source /etc/profile
再次执行install命令即可。
查看pod状态,如果发现ImagePullBackOff
kubectl describe po nfs-subdir-external-provisioner-79dbb5748c-g96m7 -n nfs-system
nfs-system nfs-subdir-external-provisioner-79dbb5748c-g96m7 0/1 ImagePullBackOff 0 4m30s
将deploy中镜像地址改为国内地址:
kubectl edit deploy nfs-subdir-external-provisioner -n nfs-system
国内地址:
k8s.mirror.nju.edu.cn/sig-storage/nfs-subdir-external-provisioner:v4.0.2
更改后通过deploy方式创建的pod会自动重新部署。
最后查看pod 及deploy 对应状态都running 即可。
[root@k3s-master helm]# kubectl get deploy -n nfs-system
NAME READY UP-TO-DATE AVAILABLE AGE
nfs-subdir-external-provisioner 1/1 1 1 22m
[root@k3s-master helm]# kubectl get po -n nfs-system
NAME READY STATUS RESTARTS AGE
nfs-subdir-external-provisioner-7d4cf6df47-jkv8j 1/1 Running 0 8m15s
[root@k3s-master helm]#
验证测试
查看创建的资源
查看 sc
[root@k3s-master ~]# kubectl get sc nfs-sc -o wide
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
nfs-sc cluster.local/nfs-subdir-external-provisioner Delete Immediate true 66s
查看 Deployment
[root@k3s-master ~]# kubectl get deployment -n nfs-system -o wide
NAME READY UP-TO-DATE AVAILABLE AGE CONTAINERS IMAGES SELECTOR
nfs-subdir-external-provisioner 1/1 1 1 73m nfs-subdir-external-provisioner registry.k8s.io/sig-storage/nfs-subdir-external-provisioner:v4.0.2 app=nfs-subdir-external-provisioner,release=nfs-subdir-external-provisioner
查看 Pod
[root@k3s-master ~]# kubectl get pod -n nfs-system -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nfs-subdir-external-provisioner-65f66bc6cd-hdpts 1/1 Running 0 4m20s 10.233.85.5 k8s-master-2 <none> <none>
以下测试根据《kubernetes修炼手册》10.2 StatefulSet实战中例子稍加修改。
部署headless svc
headless-svc.yml
# Headless Service for StatefulSet Pod DNS names
apiVersion: v1
kind: Service
metadata:
name: dullahan
labels:
app: web
spec:
ports:
- port: 80
name: web
clusterIP: None
selector:
app: web
部署sts
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: tkb-sts
spec:
replicas: 3
selector:
matchLabels:
app: web
serviceName: "dullahan"
template:
metadata:
labels:
app: web
spec:
terminationGracePeriodSeconds: 10
containers:
- name: ctr-web
image: nginx:latest
ports:
- containerPort: 80
name: web
volumeMounts:
- name: webroot
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: webroot
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "nfs-sc"
resources:
requests:
storage: 1Gi
部署sts的前提是必须先部署svc 和sc 。
sc 我使用本地刚刚创建的nfs-provisioner 名称为:nfs-sc
应用上述配置:
[root@k3s-master sts]# kubectl apply -f headless-svc.yml -n nfs-system
[root@k3s-master sts]# kubectl apply -f sts.yml -n nfs-system
查看部署情况:
[root@k3s-master sts]# kubectl get sts -n nfs-system
NAME READY AGE
tkb-sts 3/3 118m
[root@k3s-master sts]# kubectl get svc -n nfs-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
dullahan ClusterIP None <none> 80/TCP 119m
查看sts配置文件中volumeClaimTemplate字段,它用于在每次创建一个新的Pod副本的时候,自动创建一个PVC。和sc绑定实现动态pvc。
volumeClaimTemplates:
- metadata:
name: webroot
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "nfs-sc"
resources:
requests:
storage: 1Gi
进入node2 nfs服务器端共享数据目录内可以发现,卷的命名方式为:
命名空间(ns)名称+ pvc名称 + pv名称
[root@k3s-node2 k8s]# cd /home/data/k8s/
[root@k3s-node2 k8s]# ll
total 0
drwxrwxrwx. 2 nfsnobody nfsnobody 6 Jun 2 02:52 nfs-system-webroot-tkb-sts-0-pvc-99b2d103-00ff-488b-8486-a0ee6c1bc03f
drwxrwxrwx. 2 nfsnobody nfsnobody 6 Jun 2 02:52 nfs-system-webroot-tkb-sts-1-pvc-09433273-90ef-4755-b01b-59279888839f
drwxrwxrwx. 2 nfsnobody nfsnobody 6 Jun 2 02:53 nfs-system-webroot-tkb-sts-2-pvc-f022bacc-e6c2-4bb4-a839-95e5009f145c
一个重要的结论,只要不删除pvc ,数据永远不会随着sts扩缩容消失。sts扩缩容还会使用原先绑定的pvc。
如果删除pvc ,那么对应的卷名称会更改为:
archived + pvc名称 + pv
再次生成相同名称的pvc也不会和原先的卷绑定,因为pv 名称是哈希值,哈希值会改变。
关于域名的测试,可以按照《kuberbetes 修炼手册》 10.2.4 中创建带有测试工具的pod
jump-pod.yml
apiVersion: v1
kind: Pod
metadata:
name: jump-pod
spec:
terminationGracePeriodSeconds: 1
containers:
- image: k8s.mirror.nju.edu.cn/e2e-test-images/jessie-dnsutils:1.7
name: jump-ctr
tty: true
stdin: true
应用pod
$ kubectl apply -f jump-Pod.yml -n nfs-system
进入测试Pod执行命令。
$ kubectl exec -it jump-Pod -n nfs-system -- bash
root@jump-Pod:/#
测试:
root@jump-pod:/# dig dullahan.nfs-system.svc.cluster.local
; <<>> DiG 9.9.5-9+deb8u19-Debian <<>> dullahan.nfs-system.svc.cluster.local
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 5519
;; flags: qr aa rd; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 1
;; WARNING: recursion requested but not available
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;dullahan.nfs-system.svc.cluster.local. IN A
;; ANSWER SECTION:
dullahan.nfs-system.svc.cluster.local. 5 IN A 10.42.2.104
dullahan.nfs-system.svc.cluster.local. 5 IN A 10.42.0.84
dullahan.nfs-system.svc.cluster.local. 5 IN A 10.42.1.92
;; Query time: 1 msec
;; SERVER: 10.43.0.10#53(10.43.0.10)
;; WHEN: Sun Jun 02 09:04:44 UTC 2024
;; MSG SIZE rcvd: 225
该查询命令返回了每个Pod的DNS全限定名和IP。其他应用,当然也包括该应用自身, 都可以使用这种方式来查找StatefulSet的所有Pod。 当然,这种方法能够奏效的前提是,应用必须知道StatefulSet的governing Service的名 字,而且StatefulSet 的Pod 必须匹配该governing Service 的 Label 筛选器。
四、helm 的安装
只需要在master节点上安装即可
curl -fsSL -o get_helm.sh https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3
chmod +x get_helm.sh
./get_helm.sh
查看是否安装成功
[root@k3s-master ~]# helm version
version.BuildInfo{Version:"v3.15.1", GitCommit:"e211f2aa62992bd72586b395de50979e31231829", GitTreeState:"clean", GoVersion:"go1.22.3"}
相关参考:
评论区