linux cpu占用率如何看
256
2022-10-27
kubernetes快速入门9-存储卷volumes
kubernetes快速入门9-存储卷volumes
volumes的出现主要解决以下两个问题:
容器中数据的持久化,因容器中的文件是临时存放的,一旦容器崩溃后kubelet将重建容器,容器将以一个干净的状态被重建 一个Pod中多个容器间数据共享
存储大体上可以分为本地类型存储和网络连接类型存储,而网络连接型的存储又可以分为传统意义上的NAS和SAN存储,分布式类型网络连接存储和第三方云端存储
Volume的类型
emptyDir
pods.spec.volumes 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
hostPath
pods.spec.volumes hostPath
nfs
在pod启动时将挂载nfs存储卷,pod被删除时只是卸载已挂载的存储卷,而存储卷中的内容被存储所保留。
pods.spec.volumes 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
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
以前边的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
编写配置清单,应用并测试
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
当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
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:
注意:以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小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~