Kubernetes 挂载网络存储

前情概要

这里引用阿里云的说明文档

  1. 为什么要使用noresvport参数挂载NAS?不重新挂载会有什么后果?

    如果发生网络切换或者后端服务的HA倒换,小概率会造成NFS文件系统阻塞,那就可能需要几分钟时间连接才会自动恢复,极端情况下甚至需要重启ECS才能恢复。使用noresvport参数后,这个恢复几秒就可以自动完成。

  2. 什么情况会引发网络切换或者后端服务的HA倒换?

    NAS服务是稳定的,网络切换或者后端服务的HA倒换都是罕见情况。

    后端服务升级会触发上述切换,但导致客户端阻塞的概率很低,并且在升级之前我们会提前通知相关集群的用户,留出充足时间使用noresvport参数。

    其他可能引发切换的场景,还有负载均衡调整、服务端硬件故障等情况,有一定的不可预测性,所以即使服务端没有升级安排,也请尽快使用noresvport参数避免这样的风险。

  3. 为什么需要重新挂载?还有没有其他的方案?

    需要重新挂载的原因是要把之前没有使用noresvport参数的TCP连接断掉,然后使用noresvport参数挂载时,会建立新的TCP连接。

    为了把老的TCP连接断掉,就必须把NAS相关的业务都停掉,然后执行umount卸载。

    如果不希望重新挂载,可以考虑新建NAS挂载点,使用noresvport参数挂载到新的本地路径,然后把业务进程逐步迁移过去,最后废弃老的挂载路径和挂载点。

挂载NFS

静态存储卷

  • NFS v3版
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-nfs-v3
spec:
accessModes:
- ReadWriteOnce
capacity:
storage: 2Gi
mountOptions:
- vers=3
- nolock,tcp,noresvport
nfs:
path: /nfs-v3
server: nas_server
persistentVolumeReclaimPolicy: Retain
  • NFS v4.0版
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv-nfs-v4.0
spec:
accessModes:
- ReadWriteOnce
capacity:
storage: 2Gi
mountOptions:
- vers=4.0
- noresvport
nfs:
path: /nfs-v4.0
server: nas_server
persistentVolumeReclaimPolicy: Retain

动态存储卷

假设集群已经部署了nfs-client-provisioner用来实现在动态提供PersistentVolume

创建StorageClass

  • NFS v3版
1
2
3
4
5
6
7
8
9
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfsv3-sc
mountOptions:
- vers=3
- nolock,tcp,noresvport
provisioner: fuseim.pri/ifs
reclaimPolicy: Retain
  • NFS v4.0版
1
2
3
4
5
6
7
8
9
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: nfsv4-sc
mountOptions:
- vers=4.0
- nolock,tcp,noresvport
provisioner: fuseim.pri/ifs
reclaimPolicy: Retain

创建PVC

  • NFS v3版
1
2
3
4
5
6
7
8
9
10
11
12
13
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nfsv3-pvc
namespace: default
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: nfsv3-sc
volumeMode: Filesystem
  • NFS v4.0版
1
2
3
4
5
6
7
8
9
10
11
12
13
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: nfsv4-pvc
namespace: default
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
storageClassName: nfsv4-sc
volumeMode: Filesystem

测试挂载PV

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
kind: Pod
apiVersion: v1
metadata:
name: test-nfs-pod
namespace: default
spec:
containers:
- name: test-nfs-pod
image: busybox:1.24
command:
- "/bin/sh"
args:
- "-c"
- "while true; do sleep 99999;done"
volumeMounts:
- name: nfsv3-pvc
mountPath: "/mnt/nfsv3"
- name: nfsv4-pvc
mountPath: "/mnt/nfsv4"
restartPolicy: "Never"
volumes:
- name: nfsv3-pvc
persistentVolumeClaim:
claimName: nfsv3-pvc
- name: nfsv4-pvc
persistentVolumeClaim:
claimName: nfsv4-pvc

验证挂载选项

  • 确认Pod所在宿主机
1
kubectl -n default get pod test-nfs-pod -o wide
  • 登录到宿主机查看mount,关注是否有noresvport
1
2
mount | grep nfs
nas_server:/default on /var/lib/kubelet/pods/a3d10191-04f2-11ea-b668-162fb9b39758/volumes/kubernetes.io~nfs/nfsv4-pvc type nfs4 (rw,relatime,vers=4.0,rsize=1048576,wsize=1048576,namlen=255,hard,noresvport,proto=tcp,timeo=600,retrans=2,sec=sys,clientaddr=192.168.0.146,local_lock=none,addr=192.168.0.128,_netdev)

存量NFS存储卷更新

  • 修改NFS存储卷对应的PV,添加mount参数
  • 重新调度使用NFS存储卷的Pod

注意!

如果服务器上还有其他挂载点使用了同一个NFS存储,有可能无法更新挂载选项

挂载亚马逊 EFS

此过程使用 Amazon EFS Container Storage Interface (CSI) 驱动程序 GitHub 存储库的多 Pod 读取多重写入示例,使用静态预配置的 Amazon EFS 持久性卷,并使用 ReadWriteMany 访问模式从多个 Pod 访问。

  1. Amazon EFS Container Storage Interface (CSI) 驱动程序 GitHub 存储库克隆到您的本地系统。

    1
    git clone https://github.com/kubernetes-sigs/aws-efs-csi-driver.git
  2. 导航到 multiple_pods 示例目录。

    1
    cd aws-efs-csi-driver/examples/kubernetes/multiple_pods/
  3. 检索 Amazon EFS 文件系统 ID。您可以在 Amazon EFS 控制台中查找此信息,或者使用以下 AWS CLI 命令。

    1
    aws efs describe-file-systems --query "FileSystems[*].FileSystemId" --output text

    输出:

    1
    fs-582a03f3
  4. 编辑 specs/pv.yaml 文件并将 volumeHandle 值替换为您的 Amazon EFS 文件系统 ID。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    apiVersion: v1
    kind: PersistentVolume
    metadata:
    name: efs-pv
    spec:
    capacity:
    storage: 5Gi
    volumeMode: Filesystem
    accessModes:
    - ReadWriteMany
    persistentVolumeReclaimPolicy: Retain
    storageClassName: efs-sc
    csi:
    driver: efs.csi.aws.com
    volumeHandle: fs-582a03f3

    注意

    由于 Amazon EFS 是弹性文件系统,它不会强制实施任何文件系统容量限制。在创建系统时,不使用持久性卷和持久性卷声明中的实际存储容量值。但是,由于存储容量是 Kubernetes 中的必需字段,您必须指定有效值,例如,在此示例中为 5Gi。此值不会限制 Amazon EFS 文件系统的大小。

  5. specs 目录部署 efs-sc 存储类、efs-claim 持久性卷声明、efs-pv 持久性卷以及 app1app2 示例应用程序。

    1
    kubectl apply -f specs/
  6. 查看默认命名空间中的 Pod 并等待 app1app2 Pod 进入就绪状态。

    1
    kubectl get pods --watch
  7. 列出默认命名空间中的持久性卷。查找 default/efs-claim 声明中的持久性卷。

    1
    kubectl get pv

    输出:

    1
    2
    NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM               STORAGECLASS   REASON   AGE
    efs-pv 5Gi RWX Retain Bound default/efs-claim efs-sc 2m50s
  8. 描述持久性卷。

    1
    kubectl describe pv efs-pv

    输出:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    Name:            efs-pv
    Labels: <none>
    Annotations: kubectl.kubernetes.io/last-applied-configuration:
    {"apiVersion":"v1","kind":"PersistentVolume","metadata":{"annotations":{},"name":"efs-pv"},"spec":{"accessModes":["ReadWriteMany"],"capaci...
    pv.kubernetes.io/bound-by-controller: yes
    Finalizers: [kubernetes.io/pv-protection]
    StorageClass: efs-sc
    Status: Bound
    Claim: default/efs-claim
    Reclaim Policy: Retain
    Access Modes: RWX
    VolumeMode: Filesystem
    Capacity: 5Gi
    Node Affinity: <none>
    Message:
    Source:
    Type: CSI (a Container Storage Interface (CSI) volume source)
    Driver: efs.csi.aws.com
    VolumeHandle: fs-582a03f3
    ReadOnly: false
    VolumeAttributes: <none>
    Events: <none>

    Amazon EFS 文件系统 ID 将作为 VolumeHandle 列出。

  9. 验证 app1 Pod 成功将数据写入卷。

    1
    kubectl exec -ti app1 -- tail /data/out1.txt

    输出:

    1
    2
    3
    4
    5
    6
    Wed Sep 18 20:30:48 UTC 2019
    Wed Sep 18 20:30:53 UTC 2019
    Wed Sep 18 20:30:58 UTC 2019
    Wed Sep 18 20:31:03 UTC 2019
    Wed Sep 18 20:31:08 UTC 2019
    Wed Sep 18 20:31:13 UTC 2019
  10. 验证 app2 Pod 显示与卷中相同的数据。

    1
    kubectl exec -ti app2 -- tail /data/out1.txt

    输出:

    1
    2
    3
    4
    5
    6
    Wed Sep 18 20:30:48 UTC 2019
    Wed Sep 18 20:30:53 UTC 2019
    Wed Sep 18 20:30:58 UTC 2019
    Wed Sep 18 20:31:03 UTC 2019
    Wed Sep 18 20:31:08 UTC 2019
    Wed Sep 18 20:31:13 UTC 2019
  11. 完成试验时,请删除此示例应用程序来清除资源。

    1
    kubectl delete -f specs/