云原生入门之k8s: 存储抽象

333 阅读7分钟

存储抽象

在使用docker的时候,会将容器中镜像的某些文件挂载到容器上,方便对文件内容进行修改。k8S中也有类似操作,可以将Pod中的文件挂载到外部的文件。但是当节点宕机时,虽然deployment会自动在其他节点重起一个pod,但对应挂载的文件不会转移,pod中的数据在故障后无法被保存。为解决这个问题,k8s有一个单独的存储层,处理各节点文件的挂载。也有一些专业的存储层框架可以使用,如Glusterfs、NFS、CephFS。
当使用NFS存储系统时,一个Pod的文件会多节点备份,并进行同步,即使出现故障转移,也不会影响数据。
在搭建NFS存储系统时,采用主从架构,主节点将数据同步到从节点。

  1. 安装NFS系统,集群中所有机器都要安装。yum install -y nfs-utils
  2. 配置主从节点。
# 主节点配置
#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
  1. 原生方式数据挂载,使用配置文件的方式应用。
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也会被回收。

  1. 创建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
  1. 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对应
  1. 创建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为例。

  1. 把配置文件做成配置集,之后可以把原始配置文件删除。
# 创建配置,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
  1. 创建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
  1. 检查默认配置。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 天,点击查看活动详情