数据存储
容器的生命周期可能很短,会被频繁地创建和销毁。那么容器在销毁时,保存在容器中的数据也会被清除。这种结果对用户来说,在某些情况下是不乐意看到的。为了持久化保存容器的数据,kubernetes 引入了 Volume 的概念。
Volume 是 Pod 中能够被多个容器访问的共享目录,它被定义在 Pod 上,然后被一个 Pod 里的多个容器挂载到具体的文件目录下,kubernetes 通过 Volume 实现同一个 Pod 中不同容器之间的数据共享以及数据的持久化存储。Volume 的生命容器不与 Pod 中单个容器的生命周期相关,当容器终止或者重启时,Volume 中的数据也不会丢失。
kubernetes 的 Volume 支持多种类型,比较常见的有下面几个:
- 简单存储:EmptyDir、HostPath、NFS
- 高级存储:PV、PVC
- 配置存储:ConfigMap、Secret

1 基本存储
1.1 EmptyDir
1.2 HostPath
1.3 NFS
HostPath 可以解决数据持久化的问题,但是一旦 Node 节点故障了,Pod 如果转移到了别的节点,又会出现问题了,此时需要准备单独的网络存储系统,比较常用的用 NFS、CIFS。
NFS 是一个网络文件存储系统(可以理解为“共享文件夹”),搭建一台 NFS 服务器,然后将 Pod 中的存储直接连接到 NFS 系统上,这样的话,无论 Pod 在节点上怎么转移,只要 Node 跟 NFS 的对接没问题,数据就可以成功访问。

1.3.1 新版步骤
所有机器安装 nfs
# 所有机器安装
yum install -y nfs-utils主节点配置 nfs
echo "/nfs/data/ *(insecure,rw,sync,no_root_squash)" > /etc/exports # nfs主节点
mkdir -p /nfs/data
systemctl enable rpcbind --now
systemctl enable nfs-server --now
exportfs -r # 配置生效
exportfs # 查看 nfs 信息从节点配置 nfs
# 查看可以挂载的远程目录(IP 更改为 master IP)
showmount -e 172.31.0.4
mkdir -p /nfs/data
# 挂载 nfs 服务器上的共享目录到本机路径
mount -t nfs 172.31.0.4:/nfs/data /nfs/data
# 写入一个测试文件,查看共享情况
echo "hello nfs server" > /nfs/data/test.txt通过原生方式进行容器的数据挂载
步骤一:创建 mount.yaml 文件,并进行修改:
- 修改 IP 地址,更改为 NFS 主节点 IP 地址
- 对应节点上创建对应的目录
/nfs/data/nginx-pv
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx-pv-demo
name: nginx-pv-demo
spec:
replicas: 2
selector:
matchLabels:
app: nginx-pv-demo
template:
metadata:
labels:
app: nginx-pv-demo
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
volumes:
- name: html
nfs:
server: 172.31.0.4 # 修改 IP 地址
path: /nfs/data/nginx-pv步骤二:kubectl apply -f amount.yaml
步骤三:验证
# 进入pod容器内部
kubectl exec -it nginx-pv-demo-5b74676b65-cb9mh -- /bin/bash
# 查看nginx存放页面的信息,此时应该没有数据
ls /usr/share/nginx/html/
# 新建连接,写一个测试文件
echo 111 > /nfs/data/nginx-pv/index.html
# 在 另一个节点上 或者 容器内部 查看是否有对应的数据
ls /usr/share/nginx/html/1.3.2 旧版步骤
1)首先要准备 nfs 的服务器,这里为了简单,直接是 master 节点做 nfs 服务器
# 在 node 上安装 nfs 服务
[ root@nfs ~]# yum install nfs-utils -y
# 准备一个共享目录
[ root@nfs ~]# mkdir /root/data/nfs -pv
# 将共享目录以读写权限暴露给 192.168.5.0/24 网段中的所有主机
[ root@nfs ~]# vim /etc/exports
[ root@nfs ~]# more /etc/exports
/root/data/nfs 192.168.5.0/24(rw,no_root_squash)
# 启动 nfs 服务
[ root@nfs ~]# systemctl restart nfs2)接下来,要在的每个 node 节点上都安装下 nfs,这样的目的是为了 node 节点可以驱动 nfs 设备
# 在 node 上安装 nfs 服务,注意不需要启动
[ root@k8s-master01 ~]# yum install nfs-utils -y3)接下来,就可以编写 pod 的配置文件了,创建 volume-nfs.yaml
apiVersion: v1
kind: Pod
metadata:
name: volume-nfs
namespace: dev
spec:
containers:
- name: nginx
image: nginx:1.17.1
ports:
- containerPort: 80
volumeMounts:
- name: logs-volume
mountPath: /var/log/nginx
- name: busybox
image: busybox:1.30
command: ["/bin/sh", "-c", "tail -f /logs/access.log"]
volumeMounts:
- name: logs-volume
mountPath: /logs
volumes:
- name: logs-volume
nfs:
server: 192.168.5.6 #nfs服务器地址
path: /root/data/nfs #共享文件路径4)最后,运行下 pod,观察结果
# 创建 pod
[ root@k8s-master01 ~]# kubectl create -f volume-nfs.yaml
pod/volume-nfs created
# 查看 pod
[ root@k8s-master01 ~]# kubectl get pods volume-nfs -n dev
NAME READY STATUS RESTARTS AGE
volume-nfs 2/2 Running 0 2m9s
# 查看 nfs 服务器上的共享目录,发现已经有文件了
[ root@k8s-master01 ~]# ls /root/data/
access.log error.log1.3.3 仍然存在的弊端
- 文件夹是必须自己创建好。
- pod / dep 删除后,节点上的文件夹是不会随之删除的。随着后续创建删除的 pod /dep 增加,废弃的文件夹会越来越多。
- 对能使用的空间没有限制,可能会导致占用空间过多,影响其他使用。
2 高级存储
前面已经学习了使用 NFS 提供存储,此时就要求用户会搭建 NFS 系统,并且会在 yaml 配置 nfs。由于 kubernetes 支持的存储系统有很多,要求客户全都掌握,显然不现实。为了能够屏蔽底层存储实现的细节,方便用户使用, kubernetes 引入 PV 和 PVC 两种资源对象。
-
PV(Persistent Volume)是持久化卷的意思,是对底层的共享存储的一种抽象。一般情况下 PV 由 kubernetes 管理员进行创建和配置,它与底层具体的共享存储技术有关,并通过插件完成与共享存储的对接。
-
PVC(Persistent Volume Claim)是持久卷声明的意思,是用户对于存储需求的一种声明。换句话说,PVC 其实就是用户向 kubernetes 系统提交的 PV 申请书。

2.1 PV
预先创建文件夹
# nfs 主节点
mkdir -p /nfs/data/01
mkdir -p /nfs/data/02
mkdir -p /nfs/data/03创建 PV
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv01-10m # 名字只能小写
spec:
capacity:
storage: 10M
accessModes:
- ReadWriteMany
storageClassName: nfs # 这个是随便取的名字
nfs:
path: /nfs/data/01
server: 172.31.0.4 # 改一下 IP 地址
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv02-1gi # 名字只能小写
spec:
capacity:
storage: 1Gi
accessModes:
- ReadWriteMany
storageClassName: nfs # 这个是随便取的名字
nfs:
path: /nfs/data/02
server: 172.31.0.4 # 改一下 IP 地址
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv03-3gi # 名字只能小写
spec:
capacity:
storage: 3Gi
accessModes:
- ReadWriteMany
storageClassName: nfs # 这个是随便取的名字
nfs:
path: /nfs/data/03
server: 172.31.0.4 # 改一下 IP 地址查看 PV

2.2 PVC
创建 PVC
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: nginx-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 200Mi
storageClassName: nfs # 和上面的对应部署和查看 PVC
# 部署
kubectl apply -f pvc.yaml
# 查看 PVC(选择了 pv02-1gi 这个 PV)
kubectl get pvc
# 查看 PV
kubectl get pv

删除后重启部署与查看 PVC
# 删除
kubectl delete -f pvc.yaml
# 重新部署
kubectl apply -f pvc.yaml
# 查看(选择了 pv03-3gi 这个 PV)
kubectl get pvc

总结:会选用大于 200M 的 pv,正在使用的 pv 会被 Bound,之前使用的,后面删除了,就会释放。
创建 Pod 绑定 PVC
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx-deploy-pvc
name: nginx-deploy-pvc
spec:
replicas: 2
selector:
matchLabels:
app: nginx-deploy-pvc
template:
metadata:
labels:
app: nginx-deploy-pvc
spec:
containers:
- image: nginx
name: nginx
volumeMounts:
- name: html
mountPath: /usr/share/nginx/html
volumes:
- name: html
persistentVolumeClaim:
claimName: nginx-pvc # 和 PVC 名称对应# 部署
kubectl apply -f pod-pvc.yaml
# 查看 pvc 和 pv 绑定关系
kubectl get pvc,pv
PV 还有动态池,创建正正好好大小的。
3 配置存储
3.1 ConfigMap
抽取应用配置,并且可以自动更新。
3.1.1 基于配置文件创建 ConfigMap
基于配置文件创建 ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: configmap
namespace: dev
data: # data 下面,key 是配置文件名,value 是配置文件内容
info: |
username:admin
password:123456# 创建 configmap
kubectl create -f configmap.yaml创建 Pod,将 ConfigMap 挂载进去
apiVersion: v1
kind: Pod
metadata:
name: pod-configmap
namespace: dev
spec:
containers:
- name: nginx
image: nginx:1.17.1
volumeMounts: # 将 configmap 挂载到目录
- name: config
mountPath: /configmap/config
volumes: # 引用 configmap
- name: config
configMap:
name: configmap# 创建 pod
kubectl create -f pod-configmap.yaml
# 进入容器
kubectl exec -it pod-configmap -n dev /bin/sh
# 进入容器内挂载目录
cd /configmap/config/
# 查看 configmap
more info3.1.2 基于现有配置文件创建 ConfigMap(Redis 示例)
基于现有配置文件创建 ConfigMap
# 基于 redis.conf 直接创建 configmap (存放在 etcd 中)
kubectl create cm redis-conf --from-file=redis.conf
kubectl create configmap redis-conf --from-file=redis.conf
# 查看 configmap
kubectl get cm
# 查看 redis-conf configmap (内容如下)
kubectl get cm redis-conf -o yamlapiVersion: v1
kind: ConfigMap
metadata:
name: redis-conf
namespace: default
data:
redis.conf: |
appendonly yes创建 Pod,将 ConfigMap 挂载进去
apiVersion: v1
kind: Pod
metadata:
name: redis
spec:
containers:
- name: redis
image: redis
command:
- redis-server
- "/redis-master/redis.conf" # 指的是redis容器内部的位置
ports:
- containerPort: 6379
volumeMounts:
- mountPath: /data
name: data
- mountPath: /redis-master
name: config
volumes:
- name: data
emptyDir: {}
- name: config
configMap:
name: redis-conf # 对应上面创建的 configmap 名字
items:
- key: redis.conf # configmap 中的 key
path: redis.conf # 这个 item 放在什么文件中容器内的 volumeMounts.mountPath 加上挂在卷的 configMap.path 组成 configmap item 真正对应的容器内目录
# 创建 pod
kubectl create -f redis.yaml
# 查看 pod
kubectl get pod检查默认配置
kubectl exec -it redis -- redis-cli
127.0.0.1:6379> CONFIG GET appendonly
127.0.0.1:6379> CONFIG GET requirepass修改 ConfigMap
apiVersion: v1
kind: ConfigMap
metadata:
name: example-redis-config
data:
redis-config: |
maxmemory 2mb
maxmemory-policy allkeys-lru检查是否更新
kubectl exec -it redis -- redis-cli
127.0.0.1:6379> CONFIG GET maxmemory
127.0.0.1:6379> CONFIG GET maxmemory-policy
发现配置文件内容变了,但是 Redis 内部的配置没有变。这是因为 Redis 没有热更新的能力。
重启 Pod
# 重启 redis pod
kubectl replace --force -f redis-pod.yaml3.2 Secret
Secret 对象类型用来保存敏感信息,例如密码、OAuth 令牌和 SSH 密钥。将这些信息放在 secret 中比放在 Pod 的定义或者 容器镜像 中来说更加安全和灵活。
kubectl create secret docker-registry leifengyang-docker \
--docker-username=leifengyang \
--docker-password=Lfy123456 \
--docker-email=534096094@qq.com
##命令格式
kubectl create secret docker-registry regcred \
--docker-server=<你的镜像仓库服务器> \
--docker-username=<你的用户名> \
--docker-password=<你的密码> \
--docker-email=<你的邮箱地址>拉取自己的私有镜像,基于上述的 secret 就可以拉取了。
apiVersion: v1
kind: Pod
metadata:
name: private-nginx
spec:
containers:
- name: private-nginx
image: leifengyang/guignginx:v1.0
imagePullSecrets: # 使用 secret 登录
- name: leifengyang-docker