存储抽象
在使用docker的时候,会将容器中镜像的某些文件挂载到容器上,方便对文件内容进行修改。k8S中也有类似操作,可以将Pod中的文件挂载到外部的文件。但是当节点宕机时,虽然deployment会自动在其他节点重起一个pod,但对应挂载的文件不会转移,pod中的数据在故障后无法被保存。为解决这个问题,k8s有一个单独的存储层,处理各节点文件的挂载。也有一些专业的存储层框架可以使用,如Glusterfs、NFS、CephFS。
当使用NFS存储系统时,一个Pod的文件会多节点备份,并进行同步,即使出现故障转移,也不会影响数据。
在搭建NFS存储系统时,采用主从架构,主节点将数据同步到从节点。
- 安装NFS系统,集群中所有机器都要安装。
yum install -y nfs-utils - 配置主从节点。
# 主节点配置
#nfs主节点 向其他节点以非安全、读写、同步的方式暴露/nfs/data/目录
echo "/nfs/data/ *(insecure,rw,sync,no_root_squash)" > /etc/exports
mkdir -p /nfs/data
systemctl enable rpcbind --now # 启动rpc远程绑定
systemctl enable nfs-server --now
# 检查配置是否生效
exportfs -r
exportfs # 输出共享目录
# 从节点配置
showmount -e 172.31.0.4 # 注意:这里需要主节点机器的私有ip地址
#执行以下命令挂载 nfs 服务器上的共享目录到本机路径 /nfs/data
mkdir -p /nfs/data
# 挂载命令 远程服务器的ip地址 远程服务器的文件夹 本地文件夹
mount -t nfs 172.31.0.4:/nfs/data /nfs/data
# 测试 nfs系统部署成功后,主节点进行如下操作 从节点也会同步该数据
echo "hello nfs server" > /nfs/data/test.txt
- 原生方式数据挂载,使用配置文件的方式应用。
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: nginx-pv-demo
name: nginx-pv-demo
spec:
replicas: 2 # 部署两个pod,两个 pod中文件的修改都会影响到外层文件的内容
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 # 将nginx内部的该路径文件挂载到外部
volumes:
- name: html # 配置命名
nfs: # 挂载方式,使用nfs网络文件系统
server: 172.31.0.4 # nfs服务器主节点ip
path: /nfs/data/nginx-pv # 即nginx镜像到mountPath路径挂在到容器的path路径 挂在前外部目录需要先创建
使用原生挂载的方式,如果将pod节点全部删除,仍会保留挂载的文件,在pod节点过多的情况下,容易造成数据冗余。并且在挂载时,对于pod中原文件的大小没有限制,因此我们可以使用PV&PVC来解决以上问题。
PV&PVC
PV:持久卷,persistent volumn,将应用需要持久化的数据保存在指定位置。如上述的/nfs/data/nginx-pv就是持久卷。
PVC:持久卷声明,persistent volumn claim ,申明需要使用的持久卷规格。
PV池:将固定大小的PV提前创建好,静态供应。
PV和PVC主要用来高效挂载镜像文件。当pod需要挂载某个目录时,需要先进行PVC,声明需要挂载的持久卷以及对应的大小,PV池会根据声明从PV池中分配对应的PV。此时,原始目录和pvc和pv进行了绑定。即使pod宕机,重起pod也会根据pvc找到对应挂载的数据,而pod如果被删除,对应的pv也会被回收。
- 创建PV。PV1名称是pv01-10m,可读可写多节点,容量为10M,路径为/nfs/data/01,PV2名称是pv02-1gi,容量为1Gi,路径为/nfs/data/02,PV3名称是pv03-3gi,容量是3Gi,路径为/nfs/data/03,配置文件应用后PV池就创建成功,可以使用
kubectl get persistentvolumn/pv获取PV资源。
apiVersion: v1
kind: PersistentVolume
metadata:
name: pv01-10m # 名称需要全小写,命名规则和域名规则类似
spec:
capacity:
storage: 10M # 限制PV容量
accessModes:
- ReadWriteMany # 可读可写多节点
storageClassName: nfs # 需要和PVC的name对应
nfs:
path: /nfs/data/01 # 需要提前创建该文件
server: 172.31.0.4 # nfs服务器主节点的私有ip地址
--- # 文档分割,表示该yaml文件由三个独立的文档组成
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
---
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
- PVC和PV的绑定和创建。配置文件应用后,PV池根据storage分配对应的PV,被分配的PV状态由available变为bound,claim属性会显示被绑定的PVC(default/nginx-pvc)。如果删除该文件,被绑定的PV状态会变为Released。
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: nginx-pvc
spec:
accessModes:
- ReadWriteMany
resources:
requests:
storage: 200Mi
storageClassName: nfs # 和PV的spec.storageClassName对应
- 创建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
# nfs: 没有PV和PVC之前的配置
# server: 172.31.0.4
# path: /nfs/data/nginx-pv
persistentVolumeClaim: # 从PV池申请PV
claimName: nginx-pvc
以上使用的是静态供应的PV池,同时也有动态供应的PV池,会根据PVC声明所需要的大小在池中动态创建PV并分配绑定,无需人工手动首先创建。
ConfigMap
目录可以使用PV和PVC来实现挂载,而对于配置文件的挂载和同步更新,可以使用ConfigMap。以下的演示以redis为例。
- 把配置文件做成配置集,之后可以把原始配置文件删除。
# 创建配置,redis保存到k8s的etcd;
kubectl create cm redis-conf --from-file=redis.conf
此时使用kubectl get cm -oyaml可以得到ConfigMap的yaml格式。
apiVersion: v1
data: #data是所有真正的数据
redis.conf: | # key:默认是文件名
appendonly yes # value:配置文件的内容
kind: ConfigMap # 创建ConfigMap
metadata:
name: redis-conf
namespace: default
- 创建Pod
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 # redis中的/data目录
name: data # 挂载名称为name
- mountPath: /redis-master # redis中的/redis-master文件,redis.conf在该文件下
name: config # 挂载名称为config
volumes:
- name: data
emptyDir: {}
- name: config # name=config的挂载
configMap:
name: redis-conf # name=redis-conf的配置集,即第一步创建的
items:
- key: redis.conf # 引入ConfigMap中key=redis.conf的配置
path: redis.conf # 指redis镜像中的redis.conf,/redis-master/redis.conf
- 检查默认配置。
kubectl exec -it redis -- redis-cli。此时修改配置集中的value会对应修改redis中的配置文件,可以在redis中使用CONFIG GET xx获取配置项的值,但是修改的同步有一定延迟。注意:Pod部署的中间件无法热更新,虽然配置文件中进行修改,但是需要重新启动Pod才能应用修改后的配置。
apiVersion: v1
kind: ConfigMap
metadata:
name: example-redis-config
data:
redis-config: | # 修改配置集中redis的配置
maxmemory 2mb
maxmemory-policy allkeys-lru
Secret
Secret对象类型专门保存密码、令牌、密钥等敏感信息,与ConfigMap原理类似。
# 创建Secret
kubectl create secret docker-registry [secret-name] \
--docker-server=<你的镜像仓库服务器> \
--docker-username=<你的用户名> \
--docker-password=<你的密码> \
--docker-email=<你的邮箱地址>
# 以yaml格式查看创建的Secret
kubectl get secret secret-name -oyaml
# 此时再创建镜像,就避免账号密码的泄漏
apiVersion: v1
kind: Pod
metadata:
name: private-nginx
spec:
containers:
- name: private-nginx
image: leifengyang/guignginx:v1.0 # 拉取私有镜像时,避免账号密码的暴露
imagePullSecrets:
- name: secret-name # secret名称
实战小结
- Deployment部署应用,可以实现故障转移,底层运行的是Pod,Pod中运行的才是真正的容器。每一个Pod有分配的ip,可以互相访问,一般使用Service在上层对Pod统一访问,将一组Pod暴露出一个公共的ip地址。Service上层使用Ingress进行访问控制,Ingress可以进行流量控制、服务映射,相当于统一网关。
- Pod可以使用PV和PVC进行数据挂载,对挂载的文件大小进行申请。使用ConfigMap对配置文件进行挂载。一些密钥等私密信息可以存储到Secret,避免私密数据的泄漏。但Secret的内容其实只是base64编码,如果对应base64解码,其实还是有泄漏私密的问题存在。
- 下一步会对KubeSphere进行学习,可以理解为一站式自动化云部署平台,集合了一些日志、动态扩缩容等高级特性。
文章首发: zerlina-ysl.github.io/posts/blog/…
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 26 天,点击查看活动详情