九、Kubernetes-配置与存储

1、总览

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jHfpsjHe-1657519068936)(images/8.Kubernetes-配置与存储/1620441979589.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-k9YA2spQ-1657519068936)(images/8.Kubernetes-配置与存储/1620633822448.png)]

Kubernetes 目前支持多达 28 种数据卷类型(其中大部分特定于具体的云环境如 GCE/AWS/Azure 等),如需查阅所有的数据卷类型,请查阅 Kubernetes 官方文档 Volumes 。如:

  • 非持久性存储
  • emptyDir
  • HostPath
  • 网络连接性存储
  • SAN:iSCSI、ScaleIO Volumes、FC (Fibre Channel)
  • NFS:nfs,cfs
  • 分布式存储
  • Glusterfs
  • RBD (Ceph Block Device)
  • CephFS
  • Portworx Volumes
  • Quobyte Volumes
  • 云端存储
  • GCEPersistentDisk
  • AWSElasticBlockStore
  • AzureFile
  • AzureDisk
  • Cinder (OpenStack block storage)
  • VsphereVolume
  • StorageOS
  • 自定义存储
  • FlexVolume

2、配置

配置最佳实战:

  • 云原生 应用12要素 中,提出了配置分离。https://www.kdocs.cn/view/l/skIUQnbIc6cJ
  • 在推送到集群之前,配置文件应存储在版本控制中。 这允许您在必要时快速回滚配置更改。 它还有助于集群重新创建和恢复。
  • 使用 YAML 而不是 JSON 编写配置文件。虽然这些格式几乎可以在所有场景中互换使用,但 YAML 往往更加用户友好。
  • 建议相关对象分组到一个文件。比如 guestbook-all-in-one.yaml
  • 除非必要,否则不指定默认值:简单的最小配置会降低错误的可能性。
  • 将对象描述放在注释中,以便更好地进行内省。

1、Secret

  • Secret 对象类型用来保存敏感信息,例如密码、OAuth 令牌和 SSH 密钥。 将这些信息放在 secret 中比放在 Pod 的定义或者 容器镜像 中来说更加安全和灵活。
  • Secret 是一种包含少量敏感信息例如密码、令牌或密钥的对象。用户可以创建 Secret,同时系统也创建了一些 Secret。
1、Secret种类

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZFPQEQI4-1657519068937)(images/8.Kubernetes-配置与存储/1620443365394.png)]

  • 细分类型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hQL7bEvK-1657519068937)(images/8.Kubernetes-配置与存储/1620444574342.png)]

jenkin-----》 全局的凭证。 etcd(CP)===redis

2、Pod如何引用

要使用 Secret,Pod 需要引用 Secret。 Pod 可以用三种方式之一来使用 Secret:

Secret 对象的名称必须是合法的 DNS 子域名。 在为创建 Secret 编写配置文件时,你可以设置 data 与/或 stringData 字段。 datastringData 字段都是可选的。data 字段中所有键值都必须是 base64 编码的字符串。如果不希望执行这种 base64 字符串的转换操作,你可以选择设置 stringData 字段,其中可以使用任何字符串作为其取值。

3、实验
1、创建Secret
1、generic 类型
## 命令行
#### 1、使用基本字符串
kubectl create secret generic dev-db-secret \
  --from-literal=username=devuser \
  --from-literal=password='S!B\*d$zDsb='
  
## 参照以下yaml
apiVersion: v1
kind: Secret
metadata:
  name: dev-db-secret  
data:
  password: UyFCXCpkJHpEc2I9  ## base64编码了一下
  username: ZGV2dXNlcg==


#### 2、使用文件内容
echo -n 'admin' > ./username.txt
echo -n '1f2d1e2e67df' > ./password.txt

kubectl create secret generic db-user-pass \
  --from-file=./username.txt \
  --from-file=./password.txt



# 默认密钥名称是文件名。 你可以选择使用 --from-file=[key=]source 来设置密钥名称。如下
kubectl create secret generic db-user-pass-02 \
  --from-file=un=./username.txt \
  --from-file=pd=./password.txt
## 使用yaml
dev-db-secret yaml内容如下

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MVKBJ4mR-1657519068937)(images/8.Kubernetes-配置与存储/1620444050943.png)]

  • 获取Secret内容
kubectl get secret dev-db-secret -o jsonpath='{.data}'
2、使用Secret
1、环境变量引用
apiVersion: v1
kind: Pod
metadata:
  name: secret-env-pod
spec:
  containers:
  - name: mycontainer
    image: redis
    env:
      - name: SECRET_USERNAME
        valueFrom:
          secretKeyRef:
            name: mysecret
            key: username
      - name: SECRET_PASSWORD
        valueFrom:
          secretKeyRef:
            name: mysecret
            key: password
  restartPolicy: Never

环境变量引用的方式不会被自动更新

2、卷挂载
apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
  - name: mypod
    image: redis
    volumeMounts:
    - name: foo
      mountPath: "/etc/foo"
      readOnly: true
  volumes:
  - name: foo
    secret:
      secretName: mysecret

挂载方式的secret 在secret变化的时候会自动更新**(子路径引用除外)**

如果Secret以挂载的方式给容器

  • secret里面的所有key都是文件名。内容就是文件内容
  • 挂载的方式会自动更新文件内容
  • 反向更新????
  • 挂载出来的文件是只读的
  • 容器内volumeMounts调整readOnly权限
  • 容器内的root并不是容器外的root。
  • Pod安全性。超级权限穿透。docker run --privilaged.
  • Pod里面fsGroup ,runAsUser

2、ConfigMap

  • ConfigMap保存的内容就是普通的明文文本,不会编码。
  • ConfigMap 来将你的配置数据和应用程序代码分开。
  • ConfigMap 是一种 API 对象,用来将非机密性的数据保存到键值对中。使用时, Pods 可以将其用作环境变量、命令行参数或者存储卷中的配置文件。
apiVersion: v1
kind: ConfigMap
metadata:
  name: game-demo
data:
  # 类属性键;每一个键都映射到一个简单的值
  player_initial_lives: "3"
  ui_properties_file_name: "user-interface.properties"

  # 类文件键
  game.properties: |
    enemy.types=aliens,monsters
    player.maximum-lives=5    
  user-interface.properties: |
    color.good=purple
    color.bad=yellow
    allow.textmode=true

你可以使用四种方式来使用 ConfigMap 配置 Pod 中的容器:

  1. 在容器命令和参数内
  2. 容器的环境变量
  3. 在只读卷里面添加一个文件,让应用来读取
  4. 编写代码在 Pod 中运行,使用 Kubernetes API 来读取 ConfigMap
apiVersion: v1
kind: Pod
metadata:
  name: configmap-demo-pod
spec:
  containers:
    - name: demo
      image: alpine
      command: ["sleep", "3600"]
      env:
        # 定义环境变量
        - name: PLAYER_INITIAL_LIVES # 请注意这里和 ConfigMap 中的键名是不一样的
          valueFrom:
            configMapKeyRef:
              name: game-demo           # 这个值来自 ConfigMap
              key: player_initial_lives # 需要取值的键
        - name: UI_PROPERTIES_FILE_NAME
          valueFrom:
            configMapKeyRef:
              name: game-demo
              key: ui_properties_file_name
      volumeMounts:
      - name: config
        mountPath: "/config"
        readOnly: true
  volumes:
    # 你可以在 Pod 级别设置卷,然后将其挂载到 Pod 内的容器中
    - name: config
      configMap:
        # 提供你想要挂载的 ConfigMap 的名字
        name: game-demo
        # 来自 ConfigMap 的一组键,将被创建为文件
        items:
        - key: "game.properties"  ### 只把cm的部分key挂载出来成文件
          path: "game.properties" ### 指定在容器中保存的文件名
        - key: "user-interface.properties"
          path: "user-interface.properties"
1、使用挂载ConfigMap
apiVersion: v1
kind: Pod
metadata:
  name: mypod
spec:
  containers:
  - name: mypod
    image: redis
    volumeMounts:
    - name: foo
      mountPath: "/etc/foo"
      readOnly: true
  volumes:
  - name: foo
    configMap:
      name: myconfigmap

ConfigMap的修改,可以触发挂载文件的自动更新

注意::::::::

CM和Secret使用子路径挂载的话是无法热更新。

3、临时存储

1、几种临时存储

Kubernetes 为了不同的目的,支持几种不同类型的临时卷:

2、emptyDir

  • 当 Pod 分派到某个 Node 上时,emptyDir 卷会被创建
  • 在 Pod 在该节点上运行期间,卷一直存在。
  • 卷最初是空的。
  • 尽管 Pod 中的容器挂载 emptyDir 卷的路径可能相同也可能不同,这些容器都可以读写 emptyDir 卷中相同的文件。
  • 当 Pod 因为某些原因被从节点上删除时,emptyDir 卷中的数据也会被永久删除。
  • 存储空间来自本地的 kubelet 根目录(通常是根磁盘)或内存
apiVersion: v1
kind: Pod
metadata:
  name: "multi-container-pod"
  namespace: default
  labels:
    app: "multi-container-pod"
spec:
  volumes:    ### 以后见到的所有名字 都应该是一个合法的域名方式
  - name: nginx-vol
    emptyDir: {}  ### docker匿名挂载,外部创建一个位置  /abc
  containers:  ## kubectl exec -it podName  -c nginx-container(容器名)-- /bin/sh
  - name: nginx-container
    image: "nginx"
    volumeMounts:  #声明卷挂载  -v
      - name: nginx-vol
        mountPath: /usr/share/nginx/html
  - name: content-container
    image: "alpine"
    command: ["/bin/sh","-c","while true;do sleep 1; date > /app/index.html;done;"]
    volumeMounts: 
      - name: nginx-vol
        mountPath: /app

Pod里面是容器,容器无论怎样重启不会导致卷丢失。

Pod真正被删除、重新拉起(比如Pod超出资源限制,kubelet就会杀死Pod,如果要保证副本就重新拉起,此时临时卷就没有)。

3、扩展-hostPath

https://kubernetes.io/zh/docs/concepts/storage/volumes/#hostpath

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h153aI1L-1657519068937)(images/8.Kubernetes-配置与存储/1620631873199.png)]

apiVersion: v1
kind: Pod
metadata:
  name: test-pd
spec:
  containers:
  - image: k8s.gcr.io/test-webserver
    name: test-container
    volumeMounts:
    - mountPath: /test-pd
      name: test-volume
  volumes:
  - name: test-volume
    hostPath:
      # 宿主上目录位置
      path: /data
      # 此字段为可选
      type: Directory
apiVersion: v1
kind: Pod
metadata:
  name: test-webserver
spec:
  containers:
  - name: test-webserver
    image: k8s.gcr.io/test-webserver:latest
    volumeMounts:
    - mountPath: /var/local/aaa
      name: mydir
    - mountPath: /var/local/aaa/1.txt
      name: myfile
  volumes:
  - name: mydir
    hostPath:
      # 确保文件所在目录成功创建。
      path: /var/local/aaa
      type: DirectoryOrCreate
  - name: myfile
    hostPath:
      path: /var/local/aaa/1.txt
      type: FileOrCreate

典型应用

解决容器时间问题

apiVersion: v1
kind: Pod
metadata:
  name: busy-box-test
  namespace: default
spec:
  restartPolicy: OnFailure
  containers:
  - name: busy-box-test
    image: busybox
    imagePullPolicy: IfNotPresent
    volumeMounts:
    - name: date-config
      mountPath: /etc/localtime
    command: ["sleep", "60000"]
  volumes:
  - name: date-config
    hostPath:
      path: /etc/localtime

4、持久化

1、VOLUME

1、基础

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZLZORLxF-1657519068937)(images/8.Kubernetes-配置与存储/1620633782779.png)]

  • Kubernetes 支持很多类型的卷。 Pod 可以同时使用任意数目的卷类型
  • 临时卷类型的生命周期与 Pod 相同,但持久卷可以比 Pod 的存活期长
  • 当 Pod 不再存在时,Kubernetes 也会销毁临时卷;
  • Kubernetes 不会销毁 持久卷。
  • 对于给定 Pod 中任何类型的卷,在容器重启期间数据都不会丢失。
  • 使用卷时, 在 .spec.volumes 字段中设置为 Pod 提供的卷,并在 .spec.containers[*].volumeMounts 字段中声明卷在容器中的挂载位置。

支持的卷类型

https://kubernetes.io/zh/docs/concepts/storage/volumes/#volume-types

2、使用subPath

有时,在单个 Pod 中共享卷以供多方使用是很有用的。 volumeMounts.subPath 属性可用于指定所引用的卷内的子路径,而不是其根路径。

3、使用NFS
1、安装NFS
# 在任意机器
yum install -y nfs-utils
#执行命令 vi /etc/exports,创建 exports 文件,文件内容如下:
# * 代表任意机器 可以写成ip范围
echo "/nfs/data/ *(insecure,rw,sync,no_root_squash)" > /etc/exports
#/nfs/data  172.26.248.0/20(rw,no_root_squash)

# 执行以下命令,启动 nfs 服务;创建共享目录
mkdir -p /nfs/data
systemctl enable rpcbind
systemctl enable nfs-server
systemctl start rpcbind
systemctl start nfs-server
exportfs -r
#检查配置是否生效
exportfs
# 输出结果如下所示 有输出即可
/nfs/data /nfs/data
2、VOLUME进行挂载测试
#测试Pod直接挂载NFS了
apiVersion: v1
kind: Pod
metadata:
  name: vol-nfs
  namespace: default
spec:
  containers:
  - name: myapp
    image: nginx
    volumeMounts:
    - name: html
      mountPath: /usr/share/nginx/html/
  volumes:
  - name: html
    nfs:
      path: /nfs/data   #1000G
      server: 自己的nfs服务器地址
3、扩展-NFS文件同步
#服务器端防火墙开放111、662、875、892、2049的 tcp / udp 允许,否则远端客户无法连接。
# 到别的节点 安装客户端工具
yum install -y nfs-utils

#执行以下命令检查 nfs 服务器端是否有设置共享目录
# showmount -e $(nfs服务器的IP) (ip a 的 eth0 地址)
showmount -e 172.26.165.243
# 输出结果如下所示
Export list for 172.26.165.243
/nfs/data *

#执行以下命令挂载 nfs 服务器上的共享目录到本机路径 /root/nfsmount
mkdir /root/nfsmount
# mount -t nfs $(nfs服务器的IP):/root/nfs_root /root/nfsmount
#高可用备份的方式
mount -t nfs 172.26.165.243:/nfs/data /root/nfsmount
# 写入一个测试文件
echo "hello nfs server" > /root/nfsmount/test.txt

#在 nfs 服务器上执行以下命令,验证文件写入成功
cat /root/nfsmount/test.txt
apiVersion: v1
kind: Pod
metadata:
  name: "pod-nfs-02"
  namespace: default
  labels:
    app: "pod-nfs-02"
spec:
  containers:
  - name: pod-nfs-02
    image: "nginx"
    ports:
    - containerPort:  80
      name:  http
    volumeMounts:
    - name: localtime
      mountPath: /etc/localtime
    - name: html
      mountPath: /usr/share/nginx/html  ## /一定会是文件夹。不带/请指定好类型
      # type: DirectoryOrCreate
  volumes: 
    - name: localtime
      hostPath:  
        path: /usr/share/zoneinfo/Asia/Shanghai
    - name: html
      nfs:  ## 使用nfs存储系统
        server: 10.170.11.8  ## 没type
        path: /nfs/data/abc  ### abc文件夹提前创建

2、PV&PVC&StorageClass

1、基础概念
  • 存储的管理是一个与计算实例的管理完全不同的问题。
  • PersistentVolume 子系统为用户 和管理员提供了一组 API,将存储如何供应的细节从其如何被使用中抽象出来。
  • 为了实现这点,我们引入了两个新的 API 资源:PersistentVolume 和 PersistentVolumeClaim。

持久卷(PersistentVolume ):

  • 持久卷(PersistentVolume,PV)是集群中的一块存储,可以由管理员事先供应,或者 使用存储类(Storage Class)来动态供应。
  • 持久卷是集群资源,就像节点也是集群资源一样。PV 持久卷和普通的 Volume 一样,也是使用 卷插件来实现的,只是它们拥有独立于使用他们的Pod的生命周期。
  • 此 API 对象中记述了存储的实现细节,无论其背后是 NFS、iSCSI 还是特定于云平台的存储系统。

持久卷申请(PersistentVolumeClaim,PVC):

  • 表达的是用户对存储的请求
  • 概念上与 Pod 类似。 Pod 会耗用节点资源,而 PVC 申领会耗用 PV 资源。
  • Pod 可以请求特定数量的资源(CPU 和内存);同样 PVC 申领也可以请求特定的大小和访问模式 (例如,可以要求 PV 卷能够以 ReadWriteOnce、ReadOnlyMany 或 ReadWriteMany 模式之一来挂载,参见访问模式)。

存储类(Storage Class):

  • 尽管 PersistentVolumeClaim 允许用户消耗抽象的存储资源,常见的情况是针对不同的 问题用户需要的是具有不同属性(如,性能)的 PersistentVolume 卷。
  • 集群管理员需要能够提供不同性质的 PersistentVolume,并且这些 PV 卷之间的差别不 仅限于卷大小和访问模式,同时又不能将卷是如何实现的这些细节暴露给用户。
  • 为了满足这类需求,就有了 存储类(StorageClass) 资源。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-upSMVOz4-1657519068937)(images/8.Kubernetes-配置与存储/1620637231945.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-IjLF9JNC-1657519068938)(images/8.Kubernetes-配置与存储/1620637253227.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3mJ719eH-1657519068938)(images/8.Kubernetes-配置与存储/1620637286643.png)]

2、实战

https://kubernetes.io/zh/docs/tasks/configure-pod-container/configure-persistent-volume-storage/

只要PVC有:

  • PVC先是Pending
  • PV被创建以后(正好是PVC可用的),PVC自动绑定到这个PV卷
  • PVC可以被提前创建并和PV绑定。以后Pod只需要关联PVC即可
  • Pod删除,PVC还在吗?
  • pvc并不会影响。手动删除pvc。
  • 按照以前原则。同一个资源的所有关联东西都应该写在一个文件中,方便管理
  • PVC删除会不会影响PV?
  • 要看pv的回收策略。比如nfs。回收策略是Recycle。pv不会删除,内容会被清空,pva重新变为Available

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-volume-10m
  labels:
    type: local
spec:
  storageClassName: my-nfs-storage
  capacity:
    storage: 10m
  accessModes:
    - ReadWriteOnce 
  nfs:  ## 使用nfs存储系统
    server: 10.170.11.8  ## 没type
    path: /nfs/data/haha  ### abc文件夹提前创建
apiVersion: v1
kind: Pod
metadata:
  name: "nginx-pvc"
  namespace: default
  labels:
    app: "nginx-pvc"
spec:
  containers:
  - name: nginx-pvc
    image: "nginx"
    ports:
    - containerPort:  80
      name:  http
    volumeMounts:
    - name: localtime
      mountPath: /etc/localtime
    - name: html
      mountPath: /usr/share/nginx/html
  volumes:
    - name: localtime
      hostPath:
        path: /usr/share/zoneinfo/Asia/Shanghai
    - name: html
      persistentVolumeClaim:
         claimName:  nginx-pvc  ### 你的申请书的名字
  restartPolicy: Always
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nginx-pvc
  namespace: default
  labels:
    app: nginx-pvc
spec:
  storageClassName: my-nfs-storage  ## 存储类的名字
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 50m
3、细节
1、访问模式

https://kubernetes.io/zh/docs/concepts/storage/persistent-volumes/#access-modes

2、回收策略

https://kubernetes.io/zh/docs/concepts/storage/persistent-volumes/#reclaim-policy

目前的回收策略有:

  • Retain – 手动回收: pv相关的内容,自己删除。(pvc删除,pv分文不动,自己手动控制)
  • pv: pvc删除了。pod.yaml —> pod的部署,pvc —> 部署数据库
  • 开发删除了Pod,希望k8s重新拉起(一旦是Recycle 、Delete ,那就重新关联的pv里面的内容就没有了)
  • Retain :默认规则。Pod重新拉起
  • 即使Pod以及PVC删除。但是pv会记住上次是和哪个pvc建立的绑定关系
  • 只要下次Pod继续使用这个PVC,依然能重新建立连接
  • Recycle – 基本擦除 (rm -rf /thevolume/*):清除卷里面的内容
  • Delete – 诸如 AWS EBS、GCE PD、Azure Disk 或 OpenStack Cinder 卷这类关联存储资产也被删除

目前,仅 NFS 和 HostPath 支持回收(Recycle)。 AWS EBS、GCE PD、Azure Disk 和 Cinder 卷都支持删除(Delete)。: pv自己也跟着删除

apiVersion: v1
kind: PersistentVolume
metadata:
  name: pv-volume-12m-recycle
  labels:
    type: local
spec:
  persistentVolumeReclaimPolicy: Recycle  ## 回收
  storageClassName: my-nfs-storage
  capacity:
    storage: 12m
  accessModes:
    - ReadWriteOnce 
  nfs:  ## 使用nfs存储系统
    server: 10.140.120.18  ## 没type
    path: /nfs/data/recycle  ### abc文件夹提前创建
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pv-12-recycle
  namespace: default
  labels:
    app: pv-12-recycle
spec:
  storageClassName: my-nfs-storage  ### pv分组
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 12m
3、阶段

https://kubernetes.io/zh/docs/concepts/storage/persistent-volumes/#phase

  • Released
  • pv释放。释放了和pvc的关联关系,绑定不存在。新的不同pvc不能重新绑定上来
  • Available
  • pv可用。可以和任意pvc进行绑定

每个卷会处于以下阶段(Phase)之一:

  • Available(可用)-- 卷是一个空闲资源,尚未绑定到任何申领;任意人都能继续使用
  • Bound(已绑定)-- 该卷已经绑定到某申领;别人不能再用
  • Released(已释放)-- 所绑定的申领已被删除,但是资源尚未被集群回收;pvc被删除了,pv没有被回收
  • 自己确认这个pv没用了,自己删除pv;重新创建出这个pv
  • pv还有用,可以重新绑定
  • Failed(失败)-- 卷的自动回收操作失败。

绑定了Pod的PVC,而且Pod正在运行,PVC是不能被删除的,pvc会一直等到pod删除了后再去删除

3、动态供应

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FBzvARHd-1657519068939)(images/8.Kubernetes-配置与存储/image.png)]

静态供应:

  • 集群管理员创建若干 PV 卷。这些卷对象带有真实存储的细节信息,并且对集群 用户可用(可见)。PV 卷对象存在于 Kubernetes API 中,可供用户消费(使用)

动态供应:

  • 集群自动根据PVC创建出对应PV进行使用
1、设置nfs动态供应

https://github.com/kubernetes-retired/external-storage/tree/master/nfs-client

https://github.com/kubernetes-sigs/nfs-subdir-external-provisioner/tree/master/deploy

按照文档部署,并换成 registry.cn-hangzhou.aliyuncs.com/lfy_k8s_images/nfs-subdir-external-provisioner:v4.0.2 镜像即可

## 创建了一个存储类
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: managed-nfs-storage
provisioner: k8s-sigs.io/nfs-subdir-external-provisioner 
#provisioner指定一个供应商的名字。  
#必须匹配 k8s-deployment 的 env PROVISIONER_NAME的值
parameters:
  archiveOnDelete: "false"
---
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: registry.cn-hangzhou.aliyuncs.com/lfy_k8s_images/nfs-subdir-external-provisioner:v4.0.2
          volumeMounts:
            - name: nfs-client-root
              mountPath: /persistentvolumes
          env:
            - name: PROVISIONER_NAME
              value: k8s-sigs.io/nfs-subdir-external-provisioner
            - name: NFS_SERVER
              value: 10.140.120.18 ## 指定自己nfs服务器地址
            - name: NFS_PATH  
              value: /nfs/data  ## nfs服务器共享的目录
      volumes:
        - name: nfs-client-root
          nfs:
            server: 10.140.120.18
            path: /nfs/data
---
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
2、测试nfs动态供应
apiVersion: v1
kind: Pod
metadata:
  name: "nginx-666-pvc-000"
  namespace: default
  labels:
    app: "nginx-666-pvc-000"
spec:
  containers:
  - name: nginx-666-pvc-000
    image: "nginx"
    ports:
    - containerPort:  80
      name:  http
    volumeMounts:
    - name: localtime
      mountPath: /etc/localtime
    - name: html
      mountPath: /usr/share/nginx/html
  volumes:
    - name: localtime
      hostPath:
        path: /usr/share/zoneinfo/Asia/Shanghai
    - name: html
      persistentVolumeClaim:
         claimName:  nginx-666-pvc  ### 你的申请书的名字
  restartPolicy: Always
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nginx-666-pvc
  namespace: default
  labels:
    app: nginx-666-pvc
spec:
  storageClassName: managed-nfs-storage  ## 存储类的名字
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 70m
# ---
# apiVersion: v1
# kind: Service
# metadata:
#   name: MYAPP
#   namespace: default
# spec:
#   selector:
#     app: MYAPP
#   type: ClusterIP
#   ports:
#   - name: MYAPP
#     port: 
#     targetPort: 
#     protocol: TCP
#     nodePort:
kubectl get pv
2、指定一个SC为默认驱动
kubectl patch storageclass managed-nfs-storage -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"false"}}}'

使用动态供应做的nfs挂载的pv

支持delete回收策略了。