K8S初级入门系列之九-共享存储

news2024/11/24 15:50:26

一、前言

     Pod里面的容器都有自己独立的文件系统,来自容器镜像,用于保存容器运行的数据,但容器的文件存储有两个弊端,一个是无法持久化,其生命周期与容器一致,一旦容器销毁,相关的数据也就随之一起销毁;二是无法共享,Pod里多个容器之间无法共享数据,会导致无法提供完整的服务,比如监控容器需要读取业务容器提供的日志数据,就无法实现。

     为解决以上问题,K8S提供多种类型存储卷。

二、存储卷类型

  实际上,在前面的章节中,已经接触到各种卷,比如在K8S初级入门系列之四-Namespace/ConfigMap/Secret章节中,ConfigMap与Secret就是K8S公开给Pod的特殊类型的卷。K8S支持的存储卷类型有很多。

1、EmptyDir

     emptyDir用于同一Pod下多个容器间的共享存储,其形式是存储临时数据的简单空目录,既然是临时的,一旦Pod删除,其存储的内容也就丢失了。我们来看下面的场景:

      该Pod中有两个容器,分别为write-app和read-app,其中write-app将数据写入到/wite-app/logs文件下,而read-app容器从/read-app/logs文件读取数据。/write-app/logs与/read-app/logs都指向同一个共享存储卷,其类型为emptyDir,这个完成两个容器的数据共享。其yaml如下:

[root@k8s-master yaml]# cat emptydir-pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: emptydir-pod
spec:
  containers:
  - image: busybox
    name: write-app
    volumeMounts:
    - mountPath: /write-app/logs
      name: shared-dir
    args:
    - /bin/sh
    - -c
    - echo this is  write-app >> /write-app/logs/app.log; sleep 60000
  - image: busybox
    name: read-app
    volumeMounts:
    - mountPath: /read-app/logs
      name: shared-dir
    args:
    - /bin/sh
    - -c
    - cat /read-app/logs/app.log; sleep 60000
  volumes:
  - name: shared-dir
    emptyDir: {}

其yaml模型解析如下:

    在每个容器中定义挂载点,并指定挂载的本地目录,以及指向的卷名称。再定义一个卷,设置卷名称和类型,这样就通过卷名称将容器的挂载点与该卷进行关联。

    执行该文件,创建Pod后,从read-app容器中查看下log数据

[root@k8s-master yaml]# kubectl apply -f emptydir-pod.yaml 
pod/emptydir-pod created
[root@k8s-master yaml]# kubectl exec emptydir-pod -c read-app cat /read-app/logs/app.log
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
this is write-app

可以看到,正确的读取到了write-app容器写入的字符,从而实现了Pod内的存储共享。

2、HostPath

     EmptyDir是实现Pod内容器间的存储共享,HostPath是实现节点内Pod间的文件共享。以上面的场景为例。

       HostPath是Pod所在节点服务器上的文件存储(即/tmp),该节点上的两个Pod容器,共享该文件存储。将上面的例子分拆成两个Pod,其yaml文件如下:

  • hostpath-write-pod.yaml
[root@k8s-master yaml]# cat hostpath-write-pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: hostpath-write-pod
spec:
  containers:
  - image: busybox
    name: write-app
    volumeMounts:
    - mountPath: /write-app/logs
      name: shared-dir
    args:
    - /bin/sh
    - -c
    - echo this is  write-app >> /write-app/logs/app.log; sleep 60000
  volumes:
  - name: shared-dir
    hostPath: 
      path: /tmp
  • hostpath-read-pod.yaml内容如下:
[root@k8s-master yaml]# cat hostpath-read-pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: hostpath-read-pod
spec:
  containers:
  - image: busybox
    name: read-app
    volumeMounts:
    - mountPath: /read-app/logs
      name: shared-dir
    args:
    - /bin/sh
    - -c
    - cat /read-app/logs/app.log; sleep 60000
  volumes:
  - name: shared-dir
    hostPath: 
      path: /tmp

       执行文件,创建Pod成功后,进入到read-app的Pod的容器,查看数据读取。

[root@k8s-master tmp]# kubectl exec hostpath-read-pod -c read-app cat /read-app/logs/app.log
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
this is write-app

        如EmptyDir类型一样,能正确的读取到数据。按照HostPath的定义,这个app.log的实体文件应该位于所在节点服务器的/tmp目录下,我们查看下。

[root@k8s-node1 ~]# cd /tmp
[root@k8s-node1 tmp]# ll
total 12
-rw-r--r-- 1 root root   18 Apr 21 20:53 app.log
[root@k8s-node1 tmp]# cat app.log 
this is write-app

       可以看到,确实在Pod所在的节点(这两个Pod调度到了node1,非master)上的/tmp目录下写入了app.log,内容正是write-app写入的字符串。

      当删除这两个Pod后,该节点上的app.log文件还在,从而也实现了持久化存储。

      由于HostPath可以将容器的文件目录映射到节点的目录,从而无需每次都进入容器查看数据,要方便很多。比如我们在使用Ngnix容器时,就可以将其配置文件和日志文件映射到节点的文件中,直接在节点的文件系统就可以进行配置和查看。

3、NFS

    在多个节点间,如何共享存储卷呢?K8S提供了多种方式:

  • 基于云计算厂商的特定存储,比如Google的GCE持久化存储卷,AWS的EBS,微软的azureDisk等。
  • 基于网络文件存储,如NFS,CephFS,GlusterFS等。

下面就以NFS为例介绍节点间的共享存储,我们来改造上面的例子。

      NFS的服务端安装到master节点上,并配置/nfs/data的作为NFS的挂载路径,安装过程这里就省略了,可以自行查询相关文档。下面看下两个改造后的Pod的yaml文件

  • nfs-write-pod.yaml
[root@k8s-master yaml]# cat nfs-write-pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: nfs-write-pod
spec:
  tolerations:
   - key: "node-role.kubernetes.io/master"
     operator: "Exists"
     effect: "NoSchedule"
  containers:
  - image: busybox
    name: write-app
    volumeMounts:
    - mountPath: /write-app/logs
      name: shared-nfs-dir
    args:
    - /bin/sh
    - -c
    - echo this is  write-app >> /write-app/logs/app.log; sleep 60000
  volumes:
  - name: shared-nfs-dir
    nfs:
      server: 192.168.16.4
      path: /nfs/data

     该pod将volumes的类型改为nfs,并配置nfs的server(master节点ip)和path路径。为了将该Pod调度到master节点,增加了tolerations属性,这方面的内容可以参考K8S初级入门系列之五-Pod的高级特性

  • nfs-read-pod.yaml 
[root@k8s-master yaml]# cat nfs-read-pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: nfs-read-pod
spec:
  containers:
  - image: busybox
    name: read-app
    volumeMounts:
    - mountPath: /read-app/logs
      name: shared-nfs-dir
    args:
    - /bin/sh
    - -c
    - cat /read-app/logs/app.log; sleep 60000
  volumes:
  - name: shared-nfs-dir
    nfs:
      server: 192.168.16.4
      path: /nfs/data

     执行以上yaml文件,创建pod并查看pod状态:

[root@k8s-master yaml]# kubectl get pod -o wide
NAME                                     READY   STATUS             RESTARTS          AGE     IP               NODE         NOMINATED NODE   READINESS GATES
nfs-read-pod                             1/1     Running            0                 23m     10.244.36.72     k8s-node1    <none>           <none>
nfs-write-pod                            1/1     Running            0                 24m     10.244.235.199   k8s-master   <none>           <none>

       可以看到,nfs-write-pod按照要求调度到master节点上,而nfs-read-pod调度到node1节点上,进入nfs-read-pod读取日志文件。

[root@k8s-master data]# kubectl exec nfs-read-pod -c read-app cat /read-app/logs/app.log
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
this is write-app

       可以正确的读取到日志内容。由于NFS配置的是master节点的/nfs/data目录。进入该目录看下内容

[root@k8s-master yaml]# cd /nfs/data
[root@k8s-master data]# ll
total 4
-rw-r--r-- 1 root root 18 Apr 29 20:30 app.log
[root@k8s-master data]# cat app.log 
this is write-app

日志内容也已经写入了该文件。

三、PV/PVC

     前面所介绍的分配存储的方式都是命令式的,按照既定的指令创建存储。这里存在一个问题,在实际工程中,Pod的yaml文件一般是由开发人员维护,而存储卷作为底层资源,一般是由运维管理员维护,这种方式导致各方的工作无法解耦,这显然不符合K8S的设计理念。为了解决该问题,K8S提供了PV和PVC对象。如下图所示:

    管理员根据现有卷资源申明式创建PV(Persisten Volume,持久卷),指定PV的大小和所支持的访问模式,注意的是,这里仅是申明,并没有分配实际的物理存储。开发人员根据需求申请PVC(Persistent VolumeClaim),指定所需的最小容量和访问模式,并将PVC作为卷使用到Pod中。K8S根据PVC的申请找到匹配的PV,并绑定到PVC,此时PVC就可以作为持久卷在Pod中使用了。

     可以将PV看做Class类,而PVC是该Class的Object对象实现。

下面我们就来实现下上面的过程。

1、PV的创建

首先申明一个PV(名为nfs-pv),其yaml如下:

[root@k8s-master yaml]# cat nfs-pv.yaml 
apiVersion: v1
kind: PersistentVolume
metadata:
  name: nfs-pv
  labels:
    pv: nfs-pv
spec:
  capacity:
    storage: 1Gi
  volumeMode: Filesystem
  storageClassName: my-storage
  accessModes:
    - ReadWriteMany
  persistentVolumeReclaimPolicy: Recycle
  nfs:
    path: /nfs/data
    server: 192.168.16.4

我们来看下里面的核心属性:

1、capactity,定义PV的存储容量。

2、volumeMode,卷模式,包括以下两种:

  • Filesystem(文件系统),会被Pod挂载到某个目录,默认的模式。
  • Block(块),将卷作为原始块设备来使用,该模式以块设备的方式交给 Pod 使用,其上没有任何文件系统

3、storageClassName,存储类别,如果PV设定该类别,那么只有请求了该类别的PVC才能与之绑定,关于storyClass我们在第四节将专门介绍。

4、accessModes,访问模式,有以下几种模式,不同的卷插件类型,支持的模式也不同。

  • ReadWriteOnce(RWO),可以被一个节点以读写方式挂载。
  • ReadOnlyMany(ROX),可以被多个节点以只读方式挂载。
  • ReadWriteMany(RWX),可以被多个节点以读写方式挂载。

5、persistentVolumeReclaimPolicy,当PV被释放后,回收策略,包括以下 几种:

  • Retain ,保留,需要手动回收。
  • Recycle ,回收空间,清除相关的文件。仅 NFS 和 HostPath 支持回收。本例的NFS就使用这种模式进行演示。
  • Delete, AWS EBS、GCE PD、Azure Disk 或 OpenStack Cinder 卷这类关联存储资产也被删除。

6、卷插件,目前主要支持以下类型:

  • cephfs - CephFS volume
  • csi - 容器存储接口 (CSI)
  • fc - Fibre Channel (FC) 存储
  • hostPath - HostPath 卷 (仅供单节点测试使用;不适用于多节点集群;请尝试使用 local 卷作为替代)
  • iscsi - iSCSI (SCSI over IP) 存储
  • local - 节点上挂载的本地存储设备
  • nfs - 网络文件系统 (NFS) 存储
  • rbd - Rados 块设备 (RBD) 卷

    其他的卷插件如EBS,azureDisk,gcePersistentDisk等会在未来的版本中移除。本例中我们使用前面创建NFS类型。

    执行该yaml文件,完成PV创建,并查看其状态

[root@k8s-master yaml]# kubectl get pv
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
nfs-pv   1Gi        RWO            Recycle          Available           my-storage              29m

      这里我们关注下字段status为Available,表明当前的状态为可用,后面我们会讲到PV的生命周期。

2、PVC的创建

接下来我们创建PVC(名为nfs-pvc),其yaml内容如下:

[root@k8s-master yaml]# cat nfs-pvc.yaml 
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-pvc
spec:
  storageClassName: my-storage
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Gi
  selector:
    matchLabels:
      pv: nfs-pv

同样,我们也来看下核心属性参数:

1、storageClassName,卷类型,可以指定需要绑定的特定的PV卷类型,比如例子中的my-storage类型的PV,也可以设置为"",则被视为要请求的是没有设置存储类的 PV 卷。

2、accessModes,访问模式,与PV的模式类型一致。

3、resources,请求资源,对所需资源的描述,目前仅支持requests.storage

4、selector,对于PV的选择器,通过对于Label Selector的设置,可以实现对于已存在的PV筛选。

     执行该yaml文件,创建该PVC,并查看状态。

[root@k8s-master yaml]# kubectl get pvc
NAME      STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
nfs-pvc   Bound    nfs-pv   1Gi        RWX            my-storage     7s

      可以看到,K8S已经为该PVC找到到合适的PV(即前面创建的nfs-pv),其PVC的状态的为Bound(绑定状态)。我们再来看下PV(nfs-pv)的状态

[root@k8s-master yaml]# kubectl get pv
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS   CLAIM             STORAGECLASS   REASON   AGE
nfs-pv   1Gi        RWX            Recycle          Bound    default/nfs-pvc   my-storage              16m

此时,PV也变成为Bound状态

3、使用PVC创建Pod

    最后,我们创建Pod,并使用上面创建的PVC作为卷。还以上面的场景为例,对Pod进行改造。

  •  pvc-read-pod.yaml
[root@k8s-master yaml]# cat pvc-read-pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pvc-read-pod
spec:
  containers:
  - image: busybox
    name: read-app
    volumeMounts:
    - mountPath: /read-app/logs
      name: shared-pvc-dir
    args:
    - /bin/sh
    - -c
    - cat /read-app/logs/app.log; sleep 60000
  volumes:
  - name: shared-pvc-dir
    persistentVolumeClaim:
      claimName: nfs-pvc

 将volumes修改为PVC,并指定名称为刚创建的nfs-pvc。

  • pvc-read-pod.yaml
[root@k8s-master yaml]# cat pvc-read-pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: pvc-read-pod
spec:
  containers:
  - image: busybox
    name: read-app
    volumeMounts:
    - mountPath: /read-app/logs
      name: shared-pvc-dir
    args:
    - /bin/sh
    - -c
    - cat /read-app/logs/app.log; sleep 60000
  volumes:
  - name: shared-pvc-dir
    persistentVolumeClaim:
      claimName: nfs-pvc

同样将volumes修改为PVC。执行yaml文件,创建Pod,并查看状态

[root@k8s-master yaml]# kubectl get pod -o wide
NAME                                     READY   STATUS              RESTARTS            AGE    IP               NODE         NOMINATED NODE   READINESS GATES
pvc-read-pod                             1/1     Running             0                   80s    10.244.36.74     k8s-node1    <none>           <none>
pvc-write-pod                            1/1     Running             0                   89s    10.244.235.200   k8s-master   <none>           <none>

Pod成功创建,我们查看下NFS挂载的目录(即master节点的/data/nfs/)

[root@k8s-master yaml]# cd /nfs/data/
[root@k8s-master data]# ll
total 4
-rw-r--r-- 1 root root 18 Apr 30 21:07 app.log
[root@k8s-master data]# cat app.log 
this is write-app

该目录下正确的生成了app.log文件,并写入了正确的内容。

继续进入到nfs-read-pod,读取该文件的内容。

[root@k8s-master data]# kubectl exec pvc-read-pod -c read-app cat /read-app/logs/app.log
kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl exec [POD] -- [COMMAND] instead.
this is write-app

一切正常,至此,创建的PVC已经挂载到Pod上,并正常提供了卷服务。

4、生命周期

我们先总结下前面的生命周期状态的变化:

 接下来,我们删除PVC,看下PV

[root@k8s-master data]# kubectl delete pvc nfs-pvc
[root@k8s-master data]# kubectl get pv
NAME     CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM   STORAGECLASS   REASON   AGE
nfs-pv   1Gi        RWX            Recycle          Available           my-storage              3h27m

在看下之前创建的文件,切换到/nfs/data目录

[root@k8s-master data]# cd /nfs/data/
[root@k8s-master data]# ll
total 0

      由于我们配置PV的persistentVolumeReclaimPolicy: Recycle(回收空间),所以PVC删除后,文件被删除,空间回收,PV重新变为了Available状态,可以再次被利用。补充以上的状态机图

 四、StorageClass

      通过PV和PVC,完美地解耦了运维管理员和开发人员的工作,但是也带来了新的问题,一个K8S集群中,有成千上万的PV,运维人员需要手动创建出来,而且在业务的迭代过程中,需要根据不断提交的PVC来实现PV,否则就可能PVC无法绑定PV,导致创建失败。那有没有方式,能根据PVC的申请来自动创建PV呢?这样就可以进一步解放运维管理员的生产力,投入到更有意义的工作中。

      答案就是StorageClass对象,它可以指定一个可以自动配置存储的插件,我们叫它制备器(Provisioner),根据PVC的资源需求,自动创建一个符合条件的PV,分配实际存储资源,并进行PVC绑定。

    运维管理员仅配置StorageClass,其他的过程都是K8S配合制备器自动完成。上面的协同模型就可以修改为以下:

      这种方式创建存储卷相比手动创建,我们称之为"动态存储卷"。我们看下StorageClass的核心参数。

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: standard
provisioner: kubernetes.io/aws-ebs
parameters:
  type: gp2
  • provisioner,制备器,可以看做是每种卷插件的后端存储驱动。比如EBS的制备器可以制备EBS类型的卷。K8S为常用的卷插件提供内置的provisioner,比如EBS,AzureFile,GCEPersistentDisk,Glusterfs等,一般是以"kubernetes.io"开头,当然用户也可以按照规范自定义三方的制备器。
  • parameters,参数,provisioner的参数,不同的provisioner,参数也不同。

下面就以NFS为例,实现StorageClass的创建和使用过程。

1、创建NFS的StorageClass

       由于NFS没有内置的 Provisioner 对象,需要使用开源的,其以Pod的方式运行,GitHub的地址为:GitHub - kubernetes-sigs/nfs-subdir-external-provisioner: Dynamic sub-dir volume provisioner on a remote NFS server.

      下载deploy目录下的rbac.yaml,class.yaml,deploy.yaml,修改一些内容,使其与我们的NFS环境保持一致。修改后重新命名为 storage-nfs-rbac.yaml,storage-nfs-class.yaml,storage-nfs-deploy.yaml,其内容参见文章后面的附录,执行以上三个yaml文件,完成StorageClass的创建,名称为nfs-client。

kubectl apply -f storage-nfs-rbac.yaml
kubectl apply -f storage-nfs-class.yaml
kubectl apply -f storage-nfs-deployment.yaml

2、创建指定StorageClass的PVC

   接下来我们创建PVC,并指定StorageClass(nfs-client),其yaml内容如下

[root@k8s-master yaml]# cat nfs-storage-pvc.yaml 
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nfs-storage-pvc
spec:
  # 这里使用刚创建的storage name
  storageClassName: nfs-client
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 1Gi

    执行该文件,创建PVC,查看状态:

[root@k8s-master yaml]# kubectl apply -f nfs-storage-pvc.yaml 
persistentvolumeclaim/nfs-storage-pvc created
[root@k8s-master yaml]# kubectl get pvc
NAME              STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS   AGE
nfs-storage-pvc   Bound    pvc-f795e09b-1583-436b-869b-88a68d28ce64   1Gi        RWX            nfs-client     5s

   可以看到已经创建完成,并处于Bound状态,这就说明已经有PV绑定了。在查看下PV的状态

[root@k8s-master yaml]# kubectl get pv
NAME                                       CAPACITY   ACCESS MODES   RECLAIM POLICY   STATUS      CLAIM                     STORAGECLASS   REASON   AGE
pvc-f795e09b-1583-436b-869b-88a68d28ce64   1Gi        RWX            Delete           Bound       default/nfs-storage-pvc   nfs-client              10s

果然,NFS的provisioner已经自动创建PV,并完成了绑定。

3、创建使用PVC的Pod

接下来,使用之前的Pod用例来验证下写入功能,我们修改下yaml内容

[root@k8s-master yaml]# cat storageclass-write-pod.yaml 
apiVersion: v1
kind: Pod
metadata:
  name: storageclass-write-pod
spec:
  tolerations:
   - key: "node-role.kubernetes.io/master"
     operator: "Exists"
     effect: "NoSchedule"
  containers:
  - image: busybox
    name: write-app
    volumeMounts:
    - mountPath: /write-app/logs
      name: shared-storageclass-dir
    args:
    - /bin/sh
    - -c
    - echo this is  write-app >> /write-app/logs/app.log; sleep 60000
  volumes:
  - name: shared-storageclass-dir
    persistentVolumeClaim:
      claimName: nfs-storage-pvc

      将PVC的claimName修改为本次的PVC,名称nfs-storage-pvc,执行该文件,创建Pod成功后,我们是否写入到NFS的挂载目录

[root@k8s-master yaml]# cd /nfs/data
[root@k8s-master data]# ll
total 4
drwxrwxrwx 2 root root 4096 May  1 22:36 default-nfs-storage-pvc-pvc-f795e09b-1583-436b-869b-88a68d28ce64
[root@k8s-master data]# cd default-nfs-storage-pvc-pvc-f795e09b-1583-436b-869b-88a68d28ce64/
[root@k8s-master default-nfs-storage-pvc-pvc-f795e09b-1583-436b-869b-88a68d28ce64]# ll
total 4
-rw-r--r-- 1 root root 18 May  1 22:36 app.log
[root@k8s-master default-nfs-storage-pvc-pvc-f795e09b-1583-436b-869b-88a68d28ce64]# cat app.log 
this is write-app

    可以看到在/nfs/data下,K8S自动创建一个PVC名称加上随机数的文件夹,Pod写入的日志文件app.log位于该目录下。 

五、总结  

本章节我们介绍了K8S的共享存储。

1、同一Pod的容器间共享存储,可以使用EmptyDir。

2、同一节点的Pod的共享存储,可以使用HostPath。

3、不同节点间Pod的共享存储,可以使用云计算厂商提供的特定存储,也可以使用标准的网络文件存储,这里重点介绍了NFS。

4、为了解耦开发和运维人员的工作,K8S设计了PV和PVC,运维人员根据资源总量,申明式创建大量的PV,预先分配,开发人员提交PVC申请,K8S根据申请的资源,自动找到合适的PV,并进行绑定和实际资源分配。

5、为了进一步解放运维的工作,K8S设计了StorageClass对象,实现了动态创建存储卷。根据开发人员提供的PVC需求,K8S配合制备器可以自动完成PV的创建和绑定,从而省去预先创建PV的工作。

 附:

K8S初级入门系列之一-概述

K8S初级入门系列之二-集群搭建

K8S初级入门系列之三-Pod的基本概念和操作

K8S初级入门系列之四-Namespace/ConfigMap/Secret

K8S初级入门系列之五-Pod的高级特性

K8S初级入门系列之六-控制器(RC/RS/Deployment)

K8S初级入门系列之七-控制器(Job/CronJob/Daemonset)

K8S初级入门系列之八-网络

K8S初级入门系列之九-共享存储

K8S初级入门系列之十-控制器(StatefulSet)

K8S初级入门系列之十一-安全

K8S初级入门系列之十二-计算资源管理

附件

  • storage-nfs-rbac.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: default
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: nfs-client-provisioner-runner
rules:
  - apiGroups: [""]
    resources: ["nodes"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["persistentvolumes"]
    verbs: ["get", "list", "watch", "create", "delete"]
  - apiGroups: [""]
    resources: ["persistentvolumeclaims"]
    verbs: ["get", "list", "watch", "update"]
  - apiGroups: ["storage.k8s.io"]
    resources: ["storageclasses"]
    verbs: ["get", "list", "watch"]
  - apiGroups: [""]
    resources: ["events"]
    verbs: ["create", "update", "patch"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: run-nfs-client-provisioner
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    # replace with namespace where provisioner is deployed
    namespace: default
roleRef:
  kind: ClusterRole
  name: nfs-client-provisioner-runner
  apiGroup: rbac.authorization.k8s.io
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: default
rules:
  - apiGroups: [""]
    resources: ["endpoints"]
    verbs: ["get", "list", "watch", "create", "update", "patch"]
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: leader-locking-nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: default
subjects:
  - kind: ServiceAccount
    name: nfs-client-provisioner
    # replace with namespace where provisioner is deployed
    namespace: default
roleRef:
  kind: Role
  name: leader-locking-nfs-client-provisioner
  apiGroup: rbac.authorization.k8s.io
  • storage-nfs-class.yaml 
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: nfs-client
# 这是为provisioner名称,需要与deploy的env的PROVISIONER_NAME保持一致
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner
parameters:
  archiveOnDelete: "false"
  • storage-nfs-deploy.yaml 
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nfs-client-provisioner
  labels:
    app: nfs-client-provisioner
  # replace with namespace where provisioner is deployed
  namespace: default
spec:
  replicas: 1
  strategy:
    type: Recreate
  selector:
    matchLabels:
      app: nfs-client-provisioner
  template:
    metadata:
      labels:
        app: nfs-client-provisioner
    spec:
      serviceAccountName: nfs-client-provisioner
      containers:
      
        - name: nfs-client-provisioner
          # 修改如下镜像地址
          image: chronolaw/nfs-subdir-external-provisioner:v4.0.2
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes
          env:
            # 这是为provisioner名称,需要与StorageClass的PROVISIONER_NAME保持一致
            - name: PROVISIONER_NAME
              value: k8s-sigs.io/nfs-subdir-external-provisioner
            - name: NFS_SERVER
            # 修改此处的ip为nfs server ip
              value: 192.168.16.4
            - name: NFS_PATH
            # 修改此处的path为nfs 挂载的目录 ip
              value: /nfs/data
      volumes:
        - name: nfs-client-root
          nfs:
            server: 192.168.16.4
            path: /nfs/data

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/783009.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

0134 数据的表示和运算3

目录 2.数据的表示和运算 2.3浮点数的表示与运算 2.3部分习题 2.数据的表示和运算 2.3浮点数的表示与运算 2.3部分习题 1.下列关于对阶操作&#xff0c;正确的是&#xff08;&#xff09; A.在浮点加减运算的对阶操作中&#xff0c;若阶码减小&#xff0c;则尾数左移 …

pytorch工具——认识pytorch

目录 pytorch的基本元素操作创建一个没有初始化的矩阵创建一个有初始化的矩阵创建一个全0矩阵并可指定数据元素类型为long直接通过数据创建张量通过已有的一个张量创建相同尺寸的新张量利用randn_like方法得到相同尺寸张量&#xff0c;并且采用随机初始化的方法为其赋值采用.si…

数值线性代数:知识框架

记录数值线性代数研究的知识框架。 软件包线性方程组直接法Guass消元法/LU分解、Cholesky分解 LAPACK oneAPI MKL ARPACK Octave 迭代法Jacobi迭代、SOR迭代、共轭梯度法最小二乘特征值/特征向量非对称幂法、QR、Arnoldi分解对称QR、Jacobi、二分法、分治法、SVD 参考资料 G…

【C语言day03】

参数a是指针&#xff0c;要接收地址&#xff0c;BD错误。参数b可以接收的是char*&#xff0c;而&c的类型是char(*)[10]&#xff0c;C错误全局变量i&#xff0c;在main()中修改为5&#xff0c;第一次在prt()中执行循环输出三次*&#xff0c;i被修改为8&#xff0c;回到main(…

MyBatis学习笔记——3

MyBatis学习笔记——3 一、MyBatis小技巧1.1、#{}和${}1.2、typeAliases1.3、mappers1.4、插入数据时获取自动生成的主键 二、MyBatis参数处理2.1、单个简单类型参数2.2、 Map参数2.3、实体类参数2.4、多参数2.5、 Param注解&#xff08;命名参数&#xff09;2.6、 Param源码分…

网络安全(黑客)就业分析指导

一、针对网络安全市场分析 市场需求量高&#xff1b;则是发展相对成熟入门比较容易。所需要的技术水平国家政策环境 对于国家与企业的地位愈发重要&#xff0c;没有网络安全就没有国家安全 更有为国效力的正义黑客—红客联盟 可见其重视程度。 需要掌握的知识点偏多 外围打点…

【全面解析】Windows 如何使用 SSH 密钥远程连接 Linux 服务器

创建密钥 创建 linux 服务器端的终端中执行命令 ssh-keygen&#xff0c;之后一直按Enter即可&#xff0c;这样会在将在 ~/.ssh/ 路径下生成公钥(id_rsa.pub)和私钥(id_rsa) 注意&#xff1a;也可以在 windows 端生成密钥&#xff0c;只需要保证公钥在服务器端&#xff0c;私钥…

30天自制操作系统 day 1 写一个可以在没有操作系统的计算机上输出字符串的程序,并在计算机上运行

day 1 工具&#xff1a;qemu 模拟器 今日任务 计算机启动后&#xff0c;在屏幕打印一串字符串。 理论 显示字符的原理 把一些机器指令写在第一扇区。通过int 0x10中断&#xff0c;让显卡在屏幕上显示字符。只需要在0x10之前按照规定准备好寄存器&#xff0c;显卡就能正确…

2020年下半年系统架构设计师考试案例分析真题(参考答案)

试题一 1、阅读以下关于软件架构设计与评估的叙述&#xff0c;在答题纸上回答问题1和问题2。 [说明] 某公司拟开发--套在线软件开发系统&#xff0c;支持用户通过浏览器在线进行软件开发活动。该系统的重要功能包括代码编辑、语法高亮显示、代码编译、系统调试、代码仓库管理等…

Spring数据源

⭐作者介绍&#xff1a;大二本科网络工程专业在读&#xff0c;持续学习Java&#xff0c;努力输出优质文章 ⭐作者主页&#xff1a;逐梦苍穹 ⭐所属专栏&#xff1a;JavaEE、Spring 目录 1、简介2、作用3、开发步骤3.1、导入坐标3.2、创建对象c3p0druid提取jdbc.properties读取配…

【iOS】App仿写--3GShare

文章目录 前言一、账号界面二、主页界面二、搜索界面三、文章界面四、活动界面五、我的界面总结 前言 这周写了3GShare的demo&#xff0c;这是一个十分麻烦的demo&#xff0c;比网易云需要设计的知识更多&#xff0c;特此撰写一下博客记录总结 一、账号界面 这里账号界面主要…

SourceTree使用ssh密钥

设置Git的user name和email&#xff1a; $ git config --global user.name "xxx" $ git config --global user.email "xxx.mailxxx.com".检查是不是已经存在密钥&#xff08;能进去说明已经存在&#xff0c;就删掉文件夹&#xff0c;重新创建&#xff09;…

SPSS数据文件的结构重组

前言&#xff1a; 本专栏参考教材为《SPSS22.0从入门到精通》&#xff0c;由于软件版本原因&#xff0c;部分内容有所改变&#xff0c;为适应软件版本的变化&#xff0c;特此创作此专栏便于大家学习。本专栏使用软件为&#xff1a;SPSS25.0 本专栏所有的数据文件可在个人主页—…

python:GEDI 波形数据提取

作者:CSDN @ _养乐多_ 在这篇博客中,我们将介绍如何使用 Python 处理和可视化 GEDI(Global Ecosystem Dynamics Investigation)激光雷达数据。GEDI 是 NASA(美国国家航空航天局)推出的激光雷达地球观测任务,用于获取全球各地生态系统的三维结构信息。本文将以提取研究区…

VSCode同时编译多个C文件

一.环境说明 1.系统&#xff1a;Ubuntu 22.04.2 LTS 2.Visual Studio Code: 1.80.1 二.问题描述 今天使用VSCode编译《Programming Abstractions In C》书中的gymjudge.c代码时遇到错误&#xff0c;错误提示为&#xff1a; (base) codistspc:~/projects/Programming-Abstracti…

Ubuntu下打开QtCreator环境变量LD_LIBRARY_PATH与终端不一致

问题描述&#xff1a; 在unbuntu下使用QtCreator编译、运行程序时&#xff0c;总是出现XXX.so: cannot open shared object file: No such file or directory这类问题&#xff0c;但是在终端中编译或者运行程序则不会出现这些问题。在网上查了好久才明白QtCreator在打开时&…

【Visual Studio】Qt 在其他 cpp 文件中调用主工程下文件中的函数

知识不是单独的&#xff0c;一定是成体系的。更多我的个人总结和相关经验可查阅这个专栏&#xff1a;Visual Studio。 还整了一个如何在其他文件中调用 ui 控件的文章&#xff0c;感兴趣可以看&#xff1a;【Visual Studio】Qt 在其他 cpp 文件中调用操作 ui 界面控件。 文章目…

机器学习实战10-基于spark大数据技术与机器学习的结合应用实战

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下机器学习实战10-基于spark大数据技术与机器学习的结合应用实战&#xff0c;Spark是一种快速、通用的大数据处理框架。它是由加州大学伯克利分校AMPLab开发。Spark提供了一个分布式计算的平台&#xff0c;可以在集群…

计算机组成与体系结构 概述

文章目录 计算机组成与体系结构 概述计算机系统概述计算机系统的组成计算机层次结构 计算机性能评价 计算机组成与体系结构 概述 计算机系统概述 计算机系统的组成 计算机的基本部件&#xff1a; 运算器&#xff1a;ALU、GPRs&#xff08;通用寄存器组&#xff09;、标志寄…

Java编程教程-Java ObjectStreamClass

ObjectStreamClass作为类的序列化描述符。该类包含类的名称和serialVersionUID。 # 方法 # 示例 toString() It returns a string describing this ObjectStreamClass.Exampleimport java.io.ObjectStreamClass; import java.util.Calendar; public class ObjectStreamCl…