k8s-进阶-存储
一、总览Kubernetes 目前支持多达 28 种数据卷类型(其中大部分特定于具体的云环境如 GCE/AWS/Azure 等),如需查阅所有的数据卷类型,请查阅 Kubernetes 官方文档 Volumes二、Secret-实战secret 数据卷可以用来注入敏感信息(例如密码)到容器组。可以将敏感信息存入 kubernetes secret 对象,并通过 Volume(数据卷)以文件的形式挂
一、总览
Kubernetes 目前支持多达 28 种数据卷类型(其中大部分特定于具体的云环境如 GCE/AWS/Azure 等),如需查阅所有的数据卷类型,请查阅 Kubernetes 官方文档 Volumes
二、Secret-实战
secret 数据卷可以用来注入敏感信息(例如密码)到容器组。可以将敏感信息存入 kubernetes secret 对象,并通过 Volume(数据卷)以文件的形式挂载到容器组(或容器)。secret 数据卷使用 tmpfs(基于 RAM 的文件系统)挂载。
mysqpod.yaml
root_password: 123456
适用场景
- 将 HTTPS 证书存入 kubernets secret,并挂载到 /etc/nginx/conf.d/myhost.crt、/etc/nginx/conf.d/myhost.pem 路径,用来配置 nginx 的 HTTPS 证书
1、创建secret
# kubectl create secret --help
Available Commands:
docker-registry :docker仓库准备的秘钥
generic :普通秘钥
tls :tls
Usage:
kubectl create secret [flags] [options]
#准备两个数据
echo -n 'admin' > ./username.txt
echo -n '123456' > ./password.txt
#1、使用文件方式创建(这种要转移文件中的特殊字符,$, \* 和 !)
kubectl create secret generic db-user-pass --from-file=./username.txt --from-file=./password.txt
##可以 kubectl get secret xx -o yaml看看最终定义
#直接看不到明文
#2、使用字符串方式(这种直接写就可以,特殊字符不用提前转义)
kubectl create secret generic db-user-pass –from-literal=username=admin –from-literal=password=123456
#3、手动创建yaml配置文件的方式
##这种要提前把内容使用base64编码好。
echo -n 'admin' | base64 #不加-n会得到admin+换行的编码结果; 使用-n进行不换行输出
echo -n '123456' | base64
#用文件方式创建的
apiVersion: v1
data:
password.txt: MTIzNDU2
username.txt: YWRtaW4=
kind: Secret
metadata:
name: mysql-secret
namespace: default
type: Opaque
#用字符串k=v创建的
apiVersion: v1
data:
pwd: NjY2Ng==
un: aGFoYQ==
kind: Secret
metadata:
name: mysql-secret-02
namespace: default
type: Opaque
# 通过base64编码的
#自己写yaml创建
2、使用Secret
1、环境变量中使用
apiVersion: v1
kind: Pod
metadata:
name: mypod-secret-1
spec:
containers:
- name: nginx
image: nginx
env:
- name: SECRET_USERNAME
valueFrom:
secretKeyRef:
name: mysql-secret
key: username.txt
- name: SECRET_PASSWORD
valueFrom:
secretKeyRef:
name: mysql-secret
key: password.txt
#进入创建好的Pod中进行验证
echo $SECRET_USERNAME
echo $SECRET_PASSWORD
2、以volume的形式挂载到pod的某个目录下
apiVersion: v1
kind: Pod
metadata:
name: mypod-secret-2
spec:
containers:
- name: nginx
image: nginx
volumeMounts:
- name: foo
mountPath: "/etc/foo" #容器内挂载路径
readOnly: true
volumes:
- name: foo
secret:
secretName: mysecret
#进入容器验证测试
cd /etc/foo
ls
#修改secret
kubectl edit secrets mysecret
3、Secret的其他形式
- 可以创建的 Secret 类型有:
- docker 仓库密码
- Opaque (可自定义 key / value)
- TLS (可存放 HTTPS 证书等)
- 可以显示的 Secret 类型有:
- Service Account Token
- Bootstrap Token - 通常由系统创建
#docker secret的使用
kubectl create secret --help
kubectl create secret docker-registry my-secret --docker-server=registry.cn-zhangjiakou.aliyuncs.com --docker-username=lyt_goodtogread@163.com --docker-password=
#在下载镜像的时候声明使用即可
apiVersion: v1
kind: Pod
metadata:
labels:
app: aliyun-app
name: aliyun-app
spec:
imagePullSecrets:
name: my-secret #之前创建的secret的名字
containers:
- image: registry.cn-zhangjiakou.aliyuncs.com/icodingdocker/icoding-java-img:v1.0
imagePullPolicy: Always
name: aliyun-app
ports:
- containerPort: 8080
name: http80
protocol: TCP
Secret也是有namespace的。ConfigMap一样
kubectl api-resources|grep secret。跨名称空间secret不能共享
secret数据是保存到etcd的
三、ConfigMap-实战
配置文件:
挂载到一个位置。docker把配置文件挂载到一个位置修改方便。
ConfigMap:(Volumes)【高可用的】
把cm挂载到容器的一个位置。容器启动的时候。redis-server /etc/config/redis.conf
Secret、ConfigMap把数据保存在etcd;把配置文件放在ConfigMap
配置中心,热更新。其他Pod引用的配置文件也就改了。
与secret类似,区别在于configmap保存的是不需要加密配置的信息;可以看到内容
ConfigMap 提供了一种向容器组注入配置信息的途径。ConfigMap 中的数据可以被 Pod(容器组)中的容器作为一个数据卷挂载。
在数据卷中引用 ConfigMap 时:
- 可以直接引用整个 ConfigMap 到数据卷,此时 ConfigMap 中的每一个 key 对应一个文件名,value 对应该文件的内容
- 也可以只引用 ConfigMap 中的某一个名值对,此时可以将 key 映射成一个新的文件名
适用场景
- 使用 ConfigMap 中的某一 key 作为文件名,对应 value 作为文件内容,替换 nginx 容器中的 /etc/nginx/conf.d/default.conf 配置文件
- cm也是名称空间隔离的。别的namespace用不到其他ns的cm、secret
1、创建
#1、创建配置。
vim redis.conf
redis.host=127.0.0.1
redis.port=6379
redis.password=123456
#2、创建配置
kubectl create configmap redis-config --from-file=redis.conf
cm获取到时明文
#3、yaml的方式是
apiVersion: v1
kind: ConfigMap
data:
# k: v
redis.conf: |
redis.host=127.0.0.1
redis.port=6379
redis.password=123456
metadata:
name: myconfig
namespace: default
#4、查看 configmap简写cm
kubectl describe cm redis-config
#cm的内容可以直接看到
#5、cm使用k=v
#kubectl create cm myconfig-3 --from-literal=hello=123 --from-literal=world=456 -o yaml
apiVersion: v1
data:
hello: "123"
world: "456"
kind: ConfigMap
metadata:
name: myconfig-3
namespace: default
2、使用
1、通过挂载的方式
这种方式key是文件名。value是整个文件内容,我们无法单独获取到整个内容中的指定配置
apiVersion: v1
kind: Pod
metadata:
name: mypod-cm
spec:
containers:
- name: busybox
image: busybox
command: [ "/bin/sh","-c","while true; do sleep 20;cat /etc/config/redis.conf;done;" ]
volumeMounts:
- name: config-volume
mountPath: /etc/config
volumes:
- name: config-volume
configMap:
name: redis-config
restartPolicy: Never
#验证
kubectl logs mypod-cm
#测试同步更新。
kubectl edit cm redis-config
##等一分钟左右看Pod日志,更新是基于内容的事件订阅做的
#容器里面挂载目录内容确实更新的了。redis能不用用到最新的配置。redis-server /etc/config/redis.conf
#虽然有热更新。
一般使用方式。
cm改掉。直接把Pod删了。Pod是通过Deploy部署的。旧Pod删除以后,deploy拉起一个新的,重新引用新的cm。
#修改k8s的资源
kubectl edit pod/deploy/cm/secret... 名字
#如果有yaml。直接修改yaml
kubectl apply -f new.yaml(当前正在运行的Pod的配置输出进行这个文件的对比)
2、通过参数方式
这种方式。cm是kv pair。我们可以在任何位置获取到k,v进行使用
#创建cm vim myconfig.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: myconfig
namespace: default
data:
my.level: info
my.msg: hello
#测试使用
apiVersion: v1
kind: Pod
metadata:
name: ceshicmpod
spec:
containers:
- name: busybox
image: busybox
command: [ "/bin/sh", "-c", "while true; do sleep 20;echo $(LEVEL) $(TYPE);done" ]
env:
- name: LEVEL
valueFrom:
configMapKeyRef:
name: myconfig
key: my.level
- name: TYPE
valueFrom:
configMapKeyRef:
name: myconfig
key: my.msg
restartPolicy: Never
#env环境变量的方式引用的cm。热更新暂时没用。最终希望Deploy-部署的Pod删除了,重新拉起就行。
四、emptyDir与hostPath-实战
1、emptyDir
把容器产生的数据挂载到emptyDir指定的地方;Pod不挂,数据就存储在宿主机的一个目录。docker的匿名卷,因为Pod重新拉起,新的Pod,开一个随机的匿名卷,emptyDir的数据其实是在了。
-
emptyDir类型的数据卷在容器组被创建时分配给该容器组,并且直到容器组被移除(也就是整个Pod移除),该数据卷才被释放。该数据卷初始分配时,始终是一个空目录。同一容器组中的不同容器都可以对该目录执行读写操作,并且共享其中的数据,(尽管不同的容器可能将该数据卷挂载到容器中的不同路径)。当容器组被移除时,emptyDir数据卷中的数据将被永久删除
容器崩溃时,kubelet 并不会删除容器组,而仅仅是将容器重启,因此 emptyDir 中的数据在容器崩溃并重启后,仍然是存在的。
无状态服务,运行期间的一些数据
MySQL
-
适用场景
- 空白的初始空间,例如合并/排序算法中,临时将数据存在磁盘上
- 长时间计算中存储检查点(中间结果),以便容器崩溃时,可以从上一次存储的检查点(中间结果)继续进行,而不是从头开始
- 作为两个容器的共享存储,使得第一个内容管理的容器可以将生成的页面存入其中,同时由一个 webserver 容器对外提供这些页面
- 默认情况下,emptyDir 数据卷被存储在 node(节点)的存储介质(机械硬盘、SSD、或者网络存储)上。此外,您可以设置 emptyDir.medium 字段为 “Memory”,此时 Kubernetes 将挂载一个 tmpfs(基于 RAM 的文件系统)。tmpfs 的读写速度非常快,但是与磁盘不一样,tmpfs 在节点重启后将被清空,且您向该 emptyDir 写入文件时,将消耗对应容器的内存限制。
#一个多容器协同的场景实例
apiVersion: v1
kind: Pod
metadata:
annotations:
hello: world
labels:
app: tomcat
name: nginx-pod-volume-test
spec:
volumes:
- emptyDir: {} #关联宿主机的一个临时目录
name: ourfile
containers:
- image: nginx
imagePullPolicy: Always
name: nginx
ports:
- containerPort: 80
name: http80
protocol: TCP
volumeMounts:
- mountPath: /usr/share/nginx/html
name: ourfile
2、hostPath
把宿主机的文件挂载进容器中
-
警告
使用 hostPath 数据卷时,必须十分小心,因为:
- 不同节点上配置完全相同的容器组(例如同一个Deployment的容器组)可能执行结果不一样,因为不同节点上 hostPath 所对应的文件内容不同;
- Kubernetes 计划增加基于资源的调度,但这个特性将不会考虑对 hostPath 的支持
- hostPath 对应的文件/文件夹只有 root 可以写入。您要么在 privileged Container 以 root 身份运行您的进程,要么修改与 hostPath 数据卷对应的节点上的文件/文件夹的权限,
-
适用场景
绝大多数容器组并不需要使用 hostPath 数据卷,但是少数情况下,hostPath 数据卷非常有用:
- 某容器需要访问 Docker,可使用 hostPath 挂载宿主节点的 /var/lib/docker
- 在容器中运行 cAdvisor,使用 hostPath 挂载宿主节点的 /sys
kubectl explain pod.spec.volumes.hostPath
支持的 type
值如下:
取值 | 行为 |
---|---|
空字符串(默认)用于向后兼容,这意味着在安装 hostPath 卷之前不会执行任何检查。 | |
DirectoryOrCreate | 如果在给定路径上什么都不存在,那么将根据需要创建空目录,权限设置为 0755,具有与 Kubelet 相同的组和所有权。 |
Directory | 在给定路径上必须存在的目录。 |
FileOrCreate | 如果在给定路径上什么都不存在,那么将在那里根据需要创建空文件,权限设置为 0644,具有与 Kubelet 相同的组和所有权。 |
File | 在给定路径上必须存在的文件。 |
Socket | 在给定路径上必须存在的 UNIX 套接字。 |
CharDevice | 在给定路径上必须存在的字符设备。 |
BlockDevice | 在给定路径上必须存在的块设备。 |
apiVersion: v1
kind: Pod
metadata:
name: test-pd-hostpath
spec:
containers:
- image: tomcat:7
name: test-container
volumeMounts:
- mountPath: /test-pd
name: test-volume
volumes:
- name: test-volume
hostPath:
# directory location on host
path: /var/lib/docker
# this field is optional
type: Directory
# pvc:
# 哪个pvc
#进入Pod验证。
但是默认 容器里面的这些文件的执行权限是宿主机定义的。很多容器启动。root(当成普通用户),特权容器的方式;
--privileged Give extended privileges to this container:特权容器的方式。能穿透到宿主机的root
安装CICD平台。Jenkins–》jenkins就得获取到当前机器的运行权限,root。
五、持久化
1、PV与PVC的概念
与管理计算资源相比,管理存储资源是一个完全不同的问题。为了更好的管理存储,Kubernetes 引入了 PersistentVolume 和 PersistentVolumeClaim 两个概念,将存储管理抽象成如何提供存储以及如何使用存储两个关注点。
PersistentVolume(PV 存储卷)
- 是集群中的一块存储空间,由集群管理员管理、或者由 Storage Class(存储类)自动管理。PV(存储卷)和 node(节点)一样,是集群中的资源(kubernetes 集群由存储资源和计算资源组成)。
- PersistentVolume(存储卷)描述了如何提供存储的细节信息(NFS、cephfs等存储的具体参数)。
PersistentVolumeClaim(存储卷声明)
- 是一种类型的 Volume(数据卷),PersistentVolumeClaim(存储卷声明)引用的 PersistentVolume(存储卷)有自己的生命周期,该生命周期独立于任何使用它的容器组。
- (PVC 存储卷声明)代表用户使用存储的请求。Pod 容器组消耗 node 计算资源,PVC 存储卷声明消耗 PersistentVolume 存储资源。Pod 容器组可以请求特定数量的计算资源(CPU / 内存);PersistentVolumeClaim 可以请求特定大小/特定访问模式(只能被单节点读写/可被多节点只读/可被多节点读写)的存储资源。
StorageClass(存储类)
- 根据应用程序的特点不同,其所需要的存储资源也存在不同的要求,例如读写性能等。集群管理员必须能够提供关于 PersistentVolume(存储卷)的更多选择,无需用户关心存储卷背后的实现细节。为了解决这个问题,Kubernetes 引入了 StorageClass(存储类)的概念
存储卷和存储卷声明的关系图说明:
- PersistentVolume 是集群中的存储资源,通常由集群管理员创建和管理
- StorageClass 用于对 PersistentVolume 进行分类,如果正确配置,StorageClass 也可以根据 PersistentVolumeClaim 的请求动态创建 Persistent Volume
- PersistentVolumeClaim 是使用该资源的请求,通常由应用程序提出请求,并指定对应的 StorageClass 和需求的空间大小
- PersistentVolumeClaim 可以做为数据卷的一种,被挂载到容器组/容器中使用
2、Provisioning(供应) - 为PVC提供PV
为pvc供应( Provisioning )pv有两种方式,静态和动态
1、 静态供应 (Static)
集群管理员实现创建好一系列 PersistentVolume,它们包含了可供集群中应用程序使用的关于实际存储的具体信息。
2、动态供应 (Dynamic)
在配置有合适的 **StorageClass(存储类)**且 PersistentVolumeClaim 关联了该 StorageClass 的情况下,kubernetes 集群可以为应用程序动态创建 PersistentVolume。
3、其他概念关系
绑定 (Binding)
1、用户创建了一个 PersistentVolumeClaim 存储卷声明,并指定了需求的存储空间大小以及访问模式。
2、Kubernets master 将立刻为其匹配一个 PersistentVolume 存储卷,并将存储卷声明和存储卷绑定到一起。
3、除动态提供,应用程序将被绑定一个不小于(可能大于)其 PersistentVolumeClaim 中请求的存储空间大小的 PersistentVolume。一旦绑定,PersistentVolumeClaim 将拒绝其他 PersistentVolume 的绑定关系。PVC 与 PV 之间的绑定关系是一对一的映射。
4、PersistentVolumeClaim 将始终停留在 未绑定 unbound 状态,直到有合适的 PersistentVolume 可用。举个例子:集群中已经存在一个 50Gi 的 PersistentVolume,同时有一个 100Gi 的 PersistentVolumeClaim,在这种情况下,该 PVC 将一直处于 未绑定 unbound 状态,直到管理员向集群中添加了一个 100Gi 的 PersistentVolume。
使用 (Using)
对于 Pod 容器组来说,PersistentVolumeClaim 存储卷声明是一种类型的 Volume 数据卷。Kubernetes 集群将 PersistentVolumeClaim 所绑定的 PersistentVolume 挂载到容器组供其使用。
使用中保护 (Storage Object in Use Protection)
-
使用中保护(Storage Object in Use Protection)的目的是确保正在被容器组使用的 PersistentVolumeClaim 以及其绑定的 PersistentVolume 不能被系统删除,以避免可能的数据丢失。
-
如果用户删除一个正在使用中的 PersistentVolumeClaim,则该 PVC 不会立即被移除掉,而是推迟到该 PVC 不在被任何容器组使用时才移除;同样的如果管理员删除了一个已经绑定到 PVC 的 PersistentVolume,则该 PV 也不会立刻被移除掉,而是推迟到其绑定的 PVC 被删除后才移除掉。
回收 (Reclaiming)
当用户不在需要其数据卷时,可以删除掉其 PersistentVolumeClaim,此时其对应的 PersistentVolume 将被集群回收并再利用。Kubernetes 集群根据 PersistentVolume 中的 reclaim policy(回收策略)决定在其被回收时做对应的处理。当前支持的回收策略有:Retained(保留)、Recycled(重复利用)、Deleted(删除)
-
保留 (Retain)
保留策略需要集群管理员手工回收该资源。当绑定的 PersistentVolumeClaim 被删除后,PersistentVolume 仍然存在,并被认为是”已释放“。但是此时该存储卷仍然不能被其他 PersistentVolumeClaim 绑定,因为前一个绑定的 PersistentVolumeClaim 对应容器组的数据还在其中。集群管理员可以通过如下步骤回收该 PersistentVolume:
- 删除该 PersistentVolume。PV 删除后,其数据仍然存在于对应的外部存储介质中(nfs、cefpfs、glusterfs 等)
- 手工删除对应存储介质上的数据
- 手工删除对应的存储介质,您也可以创建一个新的 PersistentVolume 并再次使用该存储介质
-
删除 (Delete)
删除策略将从 kubernete 集群移除 PersistentVolume 以及其关联的外部存储介质(云环境中的 AWA EBS、GCE PD、Azure Disk 或 Cinder volume)。
-
**再利用 (Recycle) **
- 再利用策略将在 PersistentVolume 回收时,执行一个基本的清除操作(rm -rf /thevolume/*),并使其可以再次被新的 PersistentVolumeClaim 绑定。
- Warning: The
Recycle
reclaim policy is deprecated. Instead, the recommended approach is to use dynamic provisioning.(动态供应)
PV字段
PersistentVolume 字段描述如下表所示:
字段名称 | 可选项/备注 |
---|---|
容量 Capacity | 通常,一个 PersistentVolume 具有一个固定的存储容量(capacity) |
Volume Mode | FEATURE STATE: Kubernetes v1.13 beta Kubernetes 1.9 之前的版本,所有的存储卷都被初始化一个文件系统。当前可选项有: block:使用一个 块设备(raw block device) filesystem(默认值):使用一个文件系统 |
Access Modes | 可被单节点读写-ReadWriteOnce【RWO】 可被多节点只读-ReadOnlyMany【ROX】 可被多节点读写-ReadWriteMany【RWX】 注意:不同的存储支持的不同,见下表 |
存储类 StorageClassName | 带有存储类 StorageClassName 属性的 PersistentVolume 只能绑定到请求该 StorageClass 存储类的 PersistentVolumeClaim。 没有 StorageClassName 属性的 PersistentVolume 只能绑定到无特定 StorageClass 存储类要求的 PVC。 |
回收策略 Reclaim Policy | 保留 Retain – 手工回收 再利用Recycle – 清除后重新可用 (rm -rf /thevolume/*) 删除 Delete – 删除 PV 及存储介质 |
Mount Options | 挂载选项用来在挂载时作为 mount 命令的参数 |
状态 Phase | Available – 可用的 PV,尚未绑定到 PVC Bound – 已经绑定到 PVC Released – PVC 已经被删除,但是资源还未被集群回收 Failed – 自动回收失败 |
https://kubernetes.io/docs/concepts/storage/persistent-volumes/#access-modes
Volume Plugin | ReadWriteOnce | ReadOnlyMany | ReadWriteMany |
---|---|---|---|
AWSElasticBlockStore | ✓ | - | - |
AzureFile | ✓ | ✓ | ✓ |
AzureDisk | ✓ | - | - |
CephFS | ✓ | ✓ | ✓ |
Cinder | ✓ | - | - |
CSI | depends on the driver | depends on the driver | depends on the driver |
FC | ✓ | ✓ | - |
FlexVolume | ✓ | ✓ | depends on the driver |
Flocker | ✓ | - | - |
GCEPersistentDisk | ✓ | ✓ | - |
Glusterfs | ✓ | ✓ | ✓ |
HostPath | ✓ | - | - |
iSCSI | ✓ | ✓ | - |
Quobyte | ✓ | ✓ | ✓ |
NFS | ✓ | ✓ | ✓ |
RBD | ✓ | ✓ | - |
VsphereVolume | ✓ | - | - (works when Pods are collocated) |
PortworxVolume | ✓ | - | ✓ |
ScaleIO | ✓ | ✓ | - |
StorageOS | ✓ | - | - |
Important! A volume can only be mounted using one access mode at a time, even if it supports many. For example, a GCEPersistentDisk can be mounted as ReadWriteOnce by a single node or ReadOnlyMany by many nodes, but not at the same time.
PVC相关字段
字段名称 | 可选项/备注 |
---|---|
存储类 | 只有该 StorageClass 存储类的 PV 才可以绑定到此 PVC |
读写模式 Access Modes | 可被单节点读写-ReadWriteOnce可被多节点只读-ReadOnlyMany可被多节点读写-ReadWriteMany |
Volume Modes | blockfilesystem - default |
总量 | 请求存储空间的大小 |
3、实战前准备-安装NFS环境
1、搭建NFS-Server环境
#配置NFS服务器
yum install -y nfs-utils
#执行命令 vi /etc/exports,创建 exports 文件,文件内容如下:
echo "/data/volumes/ *(insecure,rw,sync,no_root_squash)" > /etc/exports
#/data/volumes 172.26.248.0/20(rw,no_root_squash)
#执行以下命令,启动 nfs 服务
# 创建共享目录
mkdir -p /data/volumes
systemctl enable rpcbind
systemctl enable nfs-server
systemctl start rpcbind
systemctl start nfs-server
exportfs -r
#检查配置是否生效
exportfs
# 输出结果如下所示
/data/volumes /data/volumes
#以后就可以直接挂载了
apiVersion: v1
kind: Pod
metadata:
name: vol-nfs
namespace: default
spec:
volumes:
- name: html
nfs:
path: /data/volumes #1000G
server: 自己的nfs服务器地址
containers:
- name: myapp
image: nginx
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html/
#原生的方式整个数据管理不整体。
2、搭建NFS-Client环境(选测)
#服务器端防火墙开放111、662、875、892、2049的 tcp / udp 允许,否则远端客户无法连接。
#安装客户端工具
yum install -y nfs-utils
#执行以下命令检查 nfs 服务器端是否有设置共享目录
# showmount -e $(nfs服务器的IP)
showmount -e 172.26.248.150
# 输出结果如下所示
Export list for 172.26.248.150
/data/volumes *
#执行以下命令挂载 nfs 服务器上的共享目录到本机路径 /root/nfsmount
mkdir /root/nfsmount
# mount -t nfs $(nfs服务器的IP):/root/nfs_root /root/nfsmount
#高可用备份的方式
mount -t nfs 172.26.248.165:/nfs/data /nfs/data
# 写入一个测试文件
echo "hello nfs server" > /root/nfsmount/test.txt
#在 nfs 服务器上执行以下命令,验证文件写入成功
cat /data/volumes/test.txt
4、实战-静态提供 PV
- 缺点:手动创建pv比较繁琐、不适合大工程
- 优点:小规模使用方便灵活
1、准备环境
#1、在nfs服务器上先建立存储卷对应的目录
[root@nfs ~]# cd /data/volumes/
[root@nfs volumes]# mkdir v{1,2,3,4,5}
[root@nfs volumes]# ls
index.html v1 v2 v3 v4 v5
[root@nfs volumes]# echo "<h1>NFS stor 01</h1>" > v1/index.html
[root@nfs volumes]# echo "<h1>NFS stor 02</h1>" > v2/index.html
[root@nfs volumes]# echo "<h1>NFS stor 03</h1>" > v3/index.html
[root@nfs volumes]# echo "<h1>NFS stor 04</h1>" > v4/index.html
[root@nfs volumes]# echo "<h1>NFS stor 05</h1>" > v5/index.html
#2、修改nfs的配置
[root@nfs volumes]# vim /etc/exports
/data/volumes/v1 *(insecure,rw,sync,no_root_squash)
/data/volumes/v2 *(insecure,rw,sync,no_root_squash)
/data/volumes/v3 *(insecure,rw,sync,no_root_squash)
/data/volumes/v4 *(insecure,rw,sync,no_root_squash)
/data/volumes/v5 *(insecure,rw,sync,no_root_squash)
/nfs/data *(insecure,rw,sync,no_root_squash)
#最后的这个nfs/data是给后面预留的
#3、查看nfs的配置
exportfs -arv
#4、查看配置是否生效
showmount -e
2、创建大量PV
#用pv的最大好处,可以直接进行资源限定。
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv001
labels:
name: pv001
spec:
nfs:
path: /data/volumes/v1
server: 172.26.248.150 #说明当前pv是和nfs-server的/data/volumes/v1关联的。
accessModes: ["ReadWriteMany","ReadWriteOnce"]
capacity:
storage: 2Gi # 直接对资源进行了限定
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv002
labels:
name: pv002
spec:
nfs:
path: /data/volumes/v2
server: 172.26.248.150
accessModes: ["ReadWriteOnce"]
capacity:
storage: 5Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv003
labels:
name: pv003
spec:
nfs:
path: /data/volumes/v3
server: 172.26.248.150
accessModes: ["ReadWriteMany","ReadWriteOnce"]
capacity:
storage: 8Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv004
labels:
name: pv004
spec:
nfs:
path: /data/volumes/v4
server: 172.26.248.150
accessModes: ["ReadWriteMany","ReadWriteOnce"]
capacity:
storage: 10Gi
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv005
labels:
name: pv005
spec:
nfs:
path: /data/volumes/v5
server: 172.26.248.150
accessModes: ["ReadWriteMany","ReadWriteOnce"]
capacity:
storage: 15Gi
# 1P 拆分PV。
kubectl get pv
3、创建PVC
apiVersion: v1
# 使用PVC类型
kind: PersistentVolumeClaim
metadata:
# 与容器应用PVC相同
name: my-pvc
spec:
# 定义读写权限
accessModes:
- ReadWriteMany
# 请求资源
resources:
requests:
# 存储空间 6G, 只要pvc创建出来,自己就得找个pv绑定, 1G,找不到。pvc一致的等待,可用pv出来(管理员自己手动声明一堆pv,或者别的pv释放了。)以后自动绑定。
storage: 6Gi
---
apiVersion: v1
kind: Pod
metadata:
name: nginx6-pvc
spec:
containers:
- name: nginx6-pvc
image: nginx
# 挂在点
volumeMounts:
- name: wwwroot
mountPath: /usr/share/nginx/html
ports:
- containerPort: 80
# 挂载来源
volumes:
- name: wwwroot
# 定义PVC
persistentVolumeClaim:
# 定义PVC名称
claimName: my-pvc
#作业
pv:回收策略
pvc:回收策略
自己测试pvc,pv各种回收策略下的产生效果。
删了Pod 以后 Pv,PVC都怎么了。。。
4~5全面结束。大家辛苦。
4、测试
kubectl get pvc
kubectl get pv
curl podIp测试数据
5、Storage Classes
每个 StorageClass 都包含 provisioner
、parameters
和 reclaimPolicy
字段, 这些字段会在 StorageClass 需要动态分配 PersistentVolume
时会使用到。
6、实战-动态提供 PV
基于Storage Class和nfs文件系统,实现存储的动态供给(NFS+PV+PVC)
1、创建存储类(NFS环境前面已经搭好)
字段名称 | 填入内容 | 备注 |
---|---|---|
名称 | nfs-storage | 自定义存储类名称 |
NFS Server | 172.26.248.150 | NFS服务的IP地址 |
NFS Path | /nfs/data | NFS服务所共享的路径 |
# 先创建授权
# vi nfs-rbac.yaml
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: nfs-provisioner
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: nfs-provisioner-runner
rules:
- 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: ["watch", "create", "update", "patch"]
- apiGroups: [""]
resources: ["services", "endpoints"]
verbs: ["get","create","list", "watch","update"]
- apiGroups: ["extensions"]
resources: ["podsecuritypolicies"]
resourceNames: ["nfs-provisioner"]
verbs: ["use"]
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: run-nfs-provisioner
subjects:
- kind: ServiceAccount
name: nfs-provisioner
namespace: default
roleRef:
kind: ClusterRole
name: nfs-provisioner-runner
apiGroup: rbac.authorization.k8s.io
---
#vi nfs-deployment.yaml;创建nfs-client的授权
kind: Deployment
apiVersion: apps/v1
metadata:
name: nfs-client-provisioner
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: nfs-client-provisioner
template:
metadata:
labels:
app: nfs-client-provisioner
spec:
serviceAccount: nfs-provisioner
containers:
- name: nfs-client-provisioner
image: quay.io/external_storage/nfs-client-provisioner:latest
volumeMounts:
- name: nfs-client-root
mountPath: /persistentvolumes
env:
- name: PROVISIONER_NAME #供应者的名字
value: storage.pri/nfs #名字虽然可以随便起,以后引用要一致
- name: NFS_SERVER
value: 172.26.248.150
- name: NFS_PATH
value: /nfs/data
volumes:
- name: nfs-client-root
nfs:
server: 172.26.248.150
path: /nfs/data
##这个镜像中volume的mountPath默认为/persistentvolumes,不能修改,否则运行时会报错
#创建storageclass
# vi storageclass-nfs.yaml
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: storage-nfs
provisioner: storage.pri/nfs
reclaimPolicy: Delete
#扩展"reclaim policy"有三种方式:Retain、Recycle、Deleted。
Retain
#保护被PVC释放的PV及其上数据,并将PV状态改成"released",不将被其它PVC绑定。集群管理员手动通过如下步骤释放存储资源:
手动删除PV,但与其相关的后端存储资源如(AWS EBS, GCE PD, Azure Disk, or Cinder volume)仍然存在。
手动清空后端存储volume上的数据。
手动删除后端存储volume,或者重复使用后端volume,为其创建新的PV。
Delete
删除被PVC释放的PV及其后端存储volume。对于动态PV其"reclaim policy"继承自其"storage class",
默认是Delete。集群管理员负责将"storage class"的"reclaim policy"设置成用户期望的形式,否则需要用
户手动为创建后的动态PV编辑"reclaim policy"
Recycle
保留PV,但清空其上数据,已废弃
2、改变默认sc
##改变系统默认sc
https://kubernetes.io/zh/docs/tasks/administer-cluster/change-default-storage-class/#%e4%b8%ba%e4%bb%80%e4%b9%88%e8%a6%81%e6%94%b9%e5%8f%98%e9%bb%98%e8%ae%a4-storage-class
kubectl patch storageclass storage-nfs-hdd -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
3、创建pvc
#vi pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-claim-01
# annotations:
# volume.beta.kubernetes.io/storage-class: "storage-nfs"
spec:
storageClassName: storage-nfs #这个class一定注意要和sc的名字一样
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Mi
4、使用pvc
#vi testpod.yaml
kind: Pod
apiVersion: v1
metadata:
name: test-pod
spec:
containers:
- name: test-pod
image: busybox
command:
- "/bin/sh"
args:
- "-c"
- "touch /mnt/SUCCESS && exit 0 || exit 1"
volumeMounts:
- name: nfs-pvc
mountPath: "/mnt"
restartPolicy: "Never"
volumes:
- name: nfs-pvc
persistentVolumeClaim:
claimName: pvc-claim-01
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: pvc-claim-01
# annotations:
# volume.beta.kubernetes.io/storage-class: "storage-nfs"
spec:
storageClassName: storage-nfs #这个class一定注意要和sc的名字一样,只要设置了默认,可以省略
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Mi
# 去nfs服务器中验证
更多推荐
所有评论(0)