kubernetes快速入门9-存储卷volumes

网友投稿 256 2022-10-27

kubernetes快速入门9-存储卷volumes

kubernetes快速入门9-存储卷volumes

volumes的出现主要解决以下两个问题:

容器中数据的持久化,因容器中的文件是临时存放的,一旦容器崩溃后kubelet将重建容器,容器将以一个干净的状态被重建 一个Pod中多个容器间数据共享

存储大体上可以分为本地类型存储和网络连接类型存储,而网络连接型的存储又可以分为传统意义上的NAS和SAN存储,分布式类型网络连接存储和第三方云端存储

Volume的类型

emptyDir

pods.spec.volumes emptyDir 空目录 medium 卷的介质,默认值为"",表示使用节点的磁盘介质,也可以设置为Memory,表示使用内存 sizeLimit 大小上限制,使用磁盘为存储介质时,大小限制取绝于磁盘大小 最佳实践:实际使用中,使用“emptyDir {}”,表示使用磁盘介质,大小也受限于磁盘

emptyDir类型的卷的生生命周期和pod相同,pod一旦被删除,那卷里的数据也被删除。

以一个pod运行两个container,共享emptDir存储卷举一个事例。

k8s@node01:~/my_manifests/volumes$ cat emptydir-pods.yaml apiVersion: v1 kind: Pod metadata: name: myapp namespace: default labels: app: myapp spec: containers: - name: myapp image: ikubernetes/myapp:v1 imagePullPolicy: IfNotPresent ports: - name: http containerPort: 80 volumeMounts: - name: html mountPath: /usr/share/nginx/html/ - name: busybox image: busybox:latest volumeMounts: - name: html mountPath: /data/ command: ["/bin/sh", "-c", "while true; do echo $(date) >> /data/index.html; sleep 2; done"] volumes: - name: html emptyDir: {} # 资源配置清单说明: # pod中两个容器运行后都会先挂载指定类型为emptyDir的存储卷,容器myapp挂载到/usr/share/nginx/html/,覆盖原有的nginx的root目录,此时该目录为空目录;容器busybox启动后也把emptyDir这个存储卷挂载到/data/目录,并每隔2秒种向该目录的index.html文件写数据,而myqpp容器提供的http服务就有了主页文件。 k8s@node01:~/my_manifests/volumes$ kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES myapp 2/2 Running 0 19s 10.244.2.93 node03 # 访问测试 k8s@node01:~/my_manifests/volumes$ curl 10.244.2.93 Tue Jul 28 08:15:12 UTC 2020 Tue Jul 28 08:15:14 UTC 2020 Tue Jul 28 08:15:16 UTC 2020 Tue Jul 28 08:15:18 UTC 2020 Tue Jul 28 08:15:20 UTC 2020 Tue Jul 28 08:15:22 UTC 2020 Tue Jul 28 08:15:24 UTC 2020 Tue Jul 28 08:15:26 UTC 2020 Tue Jul 28 08:15:28 UTC 2020

hostPath

pods.spec.volumes hostPath 在工作节点上挂载一个已存在的文件或目录 path -required- 工作节点上的文件路径 type hostPath的类型,有许多,参考:cat hostpath-pod.yaml apiVersion: v1 kind: Pod metadata: name: myapp-hostpath namespace: default labels: app: myapp spec: containers: - name: myapp image: ikubernetes/myapp:v1 imagePullPolicy: IfNotPresent ports: - name: http containerPort: 80 volumeMounts: - name: html mountPath: /usr/share/nginx/html/ volumes: - name: html hostPath: path: /data/pub/html/ type: DirectoryOrCreate # 目录不存在自动创建 k8s@node01:~/my_manifests/volumes$ kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES myapp-hostpath 1/1 Running 0 8s 10.244.2.95 node03 # pod运行在了node03上,所以在node03上创建一个主页文件 root@node03:~# echo "hello." >> /data/pub/html/index.html # 访问测试 root@node03:~# curl 10.244.2.95 hello.

nfs

在pod启动时将挂载nfs存储卷,pod被删除时只是卸载已挂载的存储卷,而存储卷中的内容被存储所保留。

pods.spec.volumes nfs path -required- nfs的挂载路径 server -required- nfs地址

先准备nfs环境,就在node01主节点上安装nfs服务

# 安装nfs服务 k8s@node01:~$ sudo apt install nfs-kernel-server k8s@node01:~$ ss -tanl | grep 2049 LISTEN 0 64 0.0.0.0:2049 0.0.0.0:* LISTEN 0 64 [::]:2049 [::]:* # 准备nfs共享目录及文件 k8s@node01:~$ cat /data/nfs/volume/index.html this is a test page. k8s@node01:~$ cat /etc/exports /data/nfs/volume 192.168.101.0/24(rw,sync,no_subtree_check,root_squash) k8s@node01:~$ sudo exportfs -ra

在各工作节点上安装nfs-common客户端工具,让mount支持nfs类型的挂载

root@node03:~# apt-get install nfs-common # 测试 root@node03:~# mount -t nfs node01:/data/nfs/volume /mnt root@node03:~# cat /mnt/index.html this is a test page.

编写清单文件并运用

k8s@node01:~/my_manifests/volumes$ cat nfs-pod.yaml apiVersion: v1 kind: Pod metadata: name: myapp-nfs namespace: default labels: app: myapp spec: containers: - name: myapp-nfs image: ikubernetes/myapp:v1 imagePullPolicy: IfNotPresent ports: - name: http containerPort: 80 volumeMounts: - name: html mountPath: /usr/share/nginx/html/ volumes: - name: html nfs: # nfs类型只需要提供挂载目录及服务器地址 path: /data/nfs/volume/ server: node01.k8s.com k8s@node01:~/my_manifests/volumes$ kubectl apply -f nfs-pod.yaml k8s@node01:~/my_manifests/volumes$ kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES myapp-nfs 1/1 Running 0 6s 10.244.2.96 node03 k8s@node01:~/my_manifests/volumes$ curl 10.244.2.96 this is a test page.

PV及PVC

Persistent Volumes简写为PV,译为持久卷;Persistent Volumes Clain简写为PVC,译为持久卷认领。

在k8s集群中,pod中的数据想持久化,一般是需要外部的存储集群来提供该能力,而存储集群可以多种,可以是NFS,Ceph RBD,GlsterFS, azureDisk等,要想接入这些存储,需要熟悉使用这些存储的接口API,各种参数,而对于k8s用户来说这十分困难,所以引入了PV和PVC这两个概念。

PV和PVC都是k8s中的资源,PV没有名称空间的概念,它是针对k8s整个集群而言,它运行在各种存储集群之上的一种抽象,对于不同的存储,会具有不同的特性,比如存储的速度,大小等,针对这些特性,管理员需要创建不同特性的PV,PV不直接对用户开放,用户想要使用存储只需要向PVC申请即可,用户在申请存储使用时只需要表明使用存储的一些基本特性,比如要多大的存储设备,要速度快的等,PVC就可以在创建好的PV中寻找一个适合要求的与之建立绑定关系并分配相应的存储空间给用户使用,用户就不需要关心到底使用的何种存储,细节被PVC抹平。PV与PVC是一一对应的关系,PV一旦被一个PVC绑定就不能被其他的PVC绑定。

使用kubectl explain pv查看帮助信息

KIND: PersistentVolume VERSION: v1 属于核心群组中的v1 spec accessModes <[]string> 访问模型,参考:https://kubernetes.io/docs/concepts/storage/persistent-volumes#access-modes nfs nfs类型的pv capacity 定义pv的容量 storage 大小,单位以1000进制时使用(E, P, T, G, M, K, m),以1024进制时使用(Ei, Pi, Ti, Gi, Mi, Ki)

以前边的NFS存储事例来实现使用PVC来请求存储卷功能。

# 修改nfs的导出目录,导出3个目录,相应的目录需要创建 k8s@node01:~$ cat /etc/exports /data/nfs/volume/v1 192.168.101.0/24(rw,sync,no_subtree_check,root_squash) /data/nfs/volume/v2 192.168.101.0/24(rw,sync,no_subtree_check,root_squash) /data/nfs/volume/v3 192.168.101.0/24(rw,sync,no_subtree_check,root_squash) # 给予写权限 k8s@node01:~$ sudo chmod o+w -R /data/nfs/volume/ k8s@node01:~$ sudo exportfs -rav exporting 192.168.101.0/24:/data/nfs/volume/v3 exporting 192.168.101.0/24:/data/nfs/volume/v2 exporting 192.168.101.0/24:/data/nfs/volume/v1 # 创建PV资源 k8s@node01:~/my_manifests/volumes$ cat pv-nfs.yaml apiVersion: v1 kind: PersistentVolume metadata: # PV资源不设置namespace name: pv001 labels: name: pv001 speed: slow spec: nfs: path: /data/nfs/volume/v1 server: node01.k8s.com accessModes: ["ReadWriteMany","ReadWriteOnce"] capacity: storage: 1Gi --- apiVersion: v1 kind: PersistentVolume metadata: # PV资源不设置namespace name: pv002 labels: name: pv002 speed: medium spec: nfs: path: /data/nfs/volume/v2 server: node01.k8s.com accessModes: ["ReadWriteMany","ReadWriteOnce"] capacity: storage: 2Gi --- apiVersion: v1 kind: PersistentVolume metadata: # PV资源不设置namespace name: pv003 labels: name: pv003 speed: medium spec: nfs: path: /data/nfs/volume/v3 server: node01.k8s.com accessModes: ["ReadWriteOnce"] capacity: storage: 3Gi k8s@node01:~/my_manifests/volumes$ kubectl apply -f pv-nfs.yaml persistentvolume/pv001 created persistentvolume/pv002 created persistentvolume/pv003 created k8s@node01:~/my_manifests/volumes$ kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pv001 1Gi RWO,RWX Retain Available 4s pv002 2Gi RWO,RWX Retain Available 4s pv003 3Gi RWO Retain Available 4s

创建一个pod,使用pvc来使用pv提供的存储卷,使用kubectl explain pvc查看帮助信息

KIND: PersistentVolumeClaim VERSION: v1 spec accessModes <[]string> 是pv中定义的访问模型的子集 resources 资源要求 requests 请求资源的大小要求 storge 大小

编写配置清单,应用并测试

k8s@node01:~/my_manifests/volumes$ cat pvc-pod.yaml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: pvc-html namespace: default spec: accessModes: ["ReadWriteMany"] selector: matchLabels: speed: medium resources: requests: storage: 2Gi --- apiVersion: v1 kind: Pod metadata: name: pod-vol-pvc namespace: default spec: containers: - name: myapp image: ikubernetes/myapp:v1 imagePullPolicy: IfNotPresent volumeMounts: - name: nginx-root mountPath: /usr/share/nginx/html/ volumes: - name: nginx-root persistentVolumeClaim: claimName: pvc-html # 配置清单中的pvc资源中使用了标签选择器,pv002和pv003满足条件,又使用了resources来定义空间大小为2Gi,最后挑选出的pv只有pv002 k8s@node01:~/my_manifests/volumes$ kubectl apply -f pvc-pod.yaml persistentvolumeclaim/pvc-html created pod/pod-vol-pvc configured k8s@node01:~/my_manifests/volumes$ kubectl get pvc NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE pvc-html Bound pv002 2Gi RWO,RWX 5s # 连接到pod的容器中创建一个主页文件 k8s@node01:~/my_manifests/volumes$ kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod-vol-pvc 1/1 Running 0 10m 10.244.2.98 node03 k8s@node01:~/my_manifests/volumes$ kubectl exec -it pod-vol-pvc -- /bin/sh / # echo ok > /usr/share/nginx/html/index.html # 访问测试 k8s@node01:~/my_manifests/volumes$ curl 10.244.2.98 ok # 查看nfs服务器上的相应共享目录是否有文件 k8s@node01:~$ cat /data/nfs/volume/v2/index.html ok

当pvc删除后,之前分配给该pvc的pv就处于Released状态,该pv就不能分配给pvc了,此时需要手动处理该pv,

k8s@node01:~/my_manifests/volumes$ kubectl delete -f pvc-pod.yaml persistentvolumeclaim "pvc-html" deleted pod "pod-vol-pvc" deleted k8s@node01:~/my_manifests/volumes$ kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pv001 1Gi RWO,RWX Retain Available 152m pv002 2Gi RWO,RWX Retain Released default/pvc-html 152m pv003 3Gi RWO Retain Available 152m k8s@node01:~/my_manifests/volumes$ kubectl edit pv pv002 # 删除spec.claimRef字段的所有键值 spec: claimRef: apiVersion: v1 kind: PersistentVolumeClaim name: pvc-html namespace: default resourceVersion: "649874" uid: 945c88fe-9513-4b15-83bc-0edebc95ab53 # 保存退出后相应的pv状态即可恢复 k8s@node01:~/my_manifests/volumes$ kubectl get pv NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pv001 1Gi RWO,RWX Retain Available 155m pv002 2Gi RWO,RWX Retain Available 155m pv003 3Gi RWO Retain Available 155m

而在实际生产环境中,pvc申请的存储卷时并不会刚好有符合条件的pv存在,此pvc将不能够有相应的pv与之匹配。k8s在此种情况下引入了StorageClass抽象资源,把后端存储进行分类,pvc在申请存储卷时可以动态创建pv。

Secret和ConfigMap特殊存储卷

配置容器化应用的方式:

直接把配置文件打包到镜像 在定义pod资源清单时传递args,以参数形式传递给程序 使用环境变量 3.1 Cloud Native的应用程序可直接使用环境变量加载配置 3.2 通过entrypoint脚本预处理环境变量为配置文件的配置信息 4. 存储卷

ConfigMap和Secret对象也是k8s中一种特殊的存储卷对象。

ConfigMap

ConfigMap是k8s中的一等公民,它存放一个个“kev/value”形式的数据。

configmap可简写为cm,使用kubectl explain cm查看资源清单配置时的帮助信息。

命令创建ConfigMap对象

## 命令行直接传递key和value值 k8s@node01:~$ kubectl create configmap nginx-port --from-literal=nginx_port=80 --from-literal=server_name=test.k8s.com configmap/nginx-port created k8s@node01:~$ kubectl get cm NAME DATA AGE nginx-port 2 4s # 查看详细信息的两种方式 k8s@node01:~$ kubectl get cm nginx-port -o yaml k8s@node01:~$ kubectl describe cm nginx-port ## 使用本地文件当作数据创建configmap资源 k8s@node01:~/cm$ cat conf server { server_name test.k8s.com; listen 80; root /data/web/html/; } k8s@node01:~/cm$ kubectl create configmap nginx---from-file=./conf configmap/nginx-created k8s@node01:~/cm$ kubectl get cm NAME DATA AGE nginx-port 2 5m8s nginx- 1 5s # 使用文件创建时,如果不给key的名称,那文件名当作key,文件内容当作value

Pod中使用env引用ConfigMap对象

ConfigMap对象创建好后,可以在pod中进行引用,kubectl explain pods.spec.containers.env查看相应的帮助信

KIND: Pod VERSION: v1 FIELDS: spec containers <[]Object> env <[]Object> name -required- valueFrom configMapKeyRef name 表示引用哪个configmap资源 key -required- 表示引用configmap资源中的key名称 optional 该key是否是可选,true表示key必须定义

k8s@node01:~/cm$ kubectl get cm NAME DATA AGE nginx-port 2 62m nginx- 1 57m k8s@node01:~/cm$ kubectl describe cm nginx-port Name: nginx-port Namespace: default Labels: Annotations: Data ==== nginx_port: ---- 80 server_name: ---- test.k8s.com Events: k8s@node01:~/my_manifests/volumes$ cat configmap-pod.yaml apiVersion: v1 kind: Pod metadata: name: pod-vol-configmap namespace: default spec: containers: - name: myapp image: ikubernetes/myapp:v1 imagePullPolicy: IfNotPresent ports: - name: http containerPort: 80 env: - name: NGINX_SERVER_PORT valueFrom: configMapKeyRef: name: nginx-port key: nginx_port - name: NGINX_SERVER_NAME valueFrom: configMapKeyRef: name: nginx-port key: server_name k8s@node01:~/my_manifests/volumes$ kubectl apply -f configmap-pod.yaml pod/pod-vol-configmap created k8s@node01:~/my_manifests/volumes$ kubectl get pods NAME READY STATUS RESTARTS AGE pod-vol-configmap 1/1 Running 0 4s k8s@node01:~/my_manifests/volumes$ kubectl exec -it pod-vol-configmap -- printenv PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin HOSTNAME=pod-vol-configmap TERM=xterm NGINX_SERVER_PORT=80 # 从configmap中获取的变量 NGINX_SERVER_NAME=test.k8s.com # 从configmap中获取的变量 KUBERNETES_PORT_443_TCP=tcp://10.96.0.1:443 KUBERNETES_PORT_443_TCP_PROTO=tcp KUBERNETES_PORT_443_TCP_PORT=443 ...

注意:以env方式引用ConfigMap对象中的变量只在pod启动时获取,如果pod运行后再edit ConfigMap资源,那pod的变量是不能进行更新的。

pod中以存储卷形式挂载ConfigMap对象

k8s@node01:~/my_manifests/volumes$ cat configmap-pod-2.yaml apiVersion: v1 kind: Pod metadata: name: pod-vol-configmap-2 namespace: default spec: containers: - name: myapp image: ikubernetes/myapp:v1 imagePullPolicy: IfNotPresent ports: - name: http containerPort: 80 volumeMounts: - name: nginxconf mountPath: /etc/nginx/conf.d/ readOnly: true volumes: - name: nginxconf configMap: name: nginx-www-conf k8s@node01:~/my_manifests/volumes$ kubectl apply -f configmap-pod-2.yaml pod/pod-vol-configmap-2 created k8s@node01:~/my_manifests/volumes$ kubectl get pods NAME READY STATUS RESTARTS AGE pod-vol-configmap 1/1 Running 0 17m pod-vol-configmap-2 1/1 Running 0 6s # configMap对象以存储卷的形式挂载在容器中 k8s@node01:~/my_manifests/volumes$ kubectl exec -it pod-vol-configmap-2 -- cat /etc/nginx/conf.d/conf server { server_name test.k8s.com; listen 80; root /data/web/html/; } # 修改configmap资源中的数据 k8s@node01:~/my_manifests/volumes$ kubectl edit cm nginx-www-conf # 把 listen 80; # 修改为 listen 8080; # 保存退出 # 需要等一会,容器中挂载的卷内容也会被改变 k8s@node01:~/my_manifests/volumes$ kubectl exec -it pod-vol-configmap-2 -- cat /etc/nginx/conf.d/conf server { server_name test.k8s.com; listen 8080; root /data/web/html/; }

Secret

和ConfigMap类似,但只是用于保存敏感数据。

命令创建Secret资源

$ kubectl create secret --help Available Commands: docker-registry Create a secret for use with a Docker registry 当使用私有仓库拉取镜像时保存认证信息 generic Create a secret from a local file, directory or literal value 其他类型的敏感数据都可以使用此类型 tls Create a TLS secret 服务需要使用证书认证时用于保存证书及key的信息

# 创建一个通用类型的secret对象 k8s@node01:~/my_manifests/volumes$ kubectl create secret generic mysql-password --from-literal=password=passwd@123! secret/mysql-password created k8s@node01:~/my_manifests/volumes$ kubectl get secret NAME TYPE DATA AGE default-token-ndclg kubernetes.io/service-account-token 3 7d ingress- kubernetes.io/tls 2 31h mysql-password Opaque 1 11s k8s@node01:~/my_manifests/volumes$ kubectl get secret mysql-password -o yaml apiVersion: v1 data: password: cGFzc3dkQDEyMyE= # 通过base64编码 kind: Secret metadata: creationTimestamp: "2020-07-29T09:31:59Z" ... # 通过base64可解码,也只是在一定程序上对敏感数据进行保护 k8s@node01:~/my_manifests/volumes$ echo cGFzc3dkQDEyMyE= | base64 -d passwd@123!

pod中使用secret资源

secret资源同样可以使用env的方式注入到pod中

k8s@node01:~/my_manifests/volumes$ cat secret-pod.yaml apiVersion: v1 kind: Pod metadata: name: pod-vol-secret namespace: default spec: containers: - name: myapp image: ikubernetes/myapp:v1 imagePullPolicy: IfNotPresent ports: - name: http containerPort: 80 env: - name: MYSQL_ROOT_PASSWD valueFrom: secretKeyRef: name: mysql-password key: password k8s@node01:~/my_manifests/volumes$ kubectl apply -f secret-pod.yaml pod/pod-vol-secret created k8s@node01:~/my_manifests/volumes$ kubectl get pods NAME READY STATUS RESTARTS AGE pod-vol-secret 1/1 Running 0 3s k8s@node01:~/my_manifests/volumes$ kubectl exec pod-vol-secret -- printenv PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin HOSTNAME=pod-vol-secret MYSQL_ROOT_PASSWD=passwd@123! # 解码后的密码

同样也可以向ConfigMap一样使用卷的方式挂载在Pod中,这里就不举例了。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:DS1302 RTC与8051微控制器的接口
下一篇:带USB接口的短信收发最小系统设计
相关文章

 发表评论

暂时没有评论,来抢沙发吧~