为什么需要数据卷?

容器中的文件在磁盘上是临时存放的,这给容器中运行比较重要的应用程序带来一些问题

问题1:当容器升级或者崩溃时,kubelet会重建容器,容器内文件会丢失

问题2:一个Pod中运行多个容器并需要共享文件

kubenetes卷(Volume)这一抽象概念能够解决这两个问题

常用的数据卷

• 节点本地(hostPath, emptyDir)

• 网络(NFS, Ceph, GlusterFS)

• 公有云(AWS EBS)

• K8S资源(configmap, secret)

k8s(存储)数据卷与数据持久卷_k8s

emptyDir卷

 是一个临时存储卷,与Pod生命周期绑定一起,如果Pod删除了卷也会被删除。

应用场景: Pod中容器之间数据共享

案例

apiVersion: v1
kind: Pod
metadata:
  name: pod-emptydir
spec:
  containers:
  - image: centos
    command: ["bash","-c","for i in {1..100};do echo $i >> /data/hello;sleep 1;done"]
    name: write
    volumeMounts:
    - mountPath: /data
      name: cache-volume
  - image: centos
    command: ["bash","-c","tail -f /data/hello"]
    name: read
    volumeMounts:
    - mountPath: /data
      name: cache-volume
  volumes:
  - name: cache-volume
    emptyDir: {}

节点数据卷: hostPath

hostPath卷:

应用场景:

案例:

apiVersion: v1
kind: Pod
metadata:
  name: pod-emptydir
spec:
  containers:
  - image: centos
    command: ["bash","-c","for i in {1..100};do echo $i >> /data/hello;sleep 1;done"]
    name: write
    volumeMounts:
    - mountPath: /data
      name: cache-volume
  - image: centos
    command: ["bash","-c","tail -f /data/hello"]
    name: read
    volumeMounts:
    - mountPath: /data
      name: cache-volume
  volumes:
  - name: cache-volume
    emptyDir: {}


网络数据卷: NFS

NFS卷: 提供对NFS挂载支持,可以自动将NFS共享路径

挂载到Pod中

NFS: 是一个主流的文件共享服务器。

# yum install nfs-utils

#设置用于同步数据的目录读写权限

# vi /etc/exports

/ifs/kubernetes *(rw,no_root_squash)

# mkdir -p /ifs/kubernetes

# systemctl start nfs

# systemctl enable nfs

k8s(存储)数据卷与数据持久卷_linux_02

注:每个Node上都要安装nfs-utils包,因为会使用到某些依赖。

示例:将Nginx网站程序根目录持久化到

NFS存储,为多个Pod提供网站程序文件

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: web
  name: web-nfs
spec:
  replicas: 3
  selector:
    matchLabels:
      app: web
  strategy: {}
  template:
    metadata:
      labels:
        app: web
    spec:
      containers:
      - image: nginx
        name: nginx
        volumeMounts:
        - name: data
          mountPath: /usr/share/nginx/html
      volumes:
      - name: data
        nfs:
          server: 192.168.40.132
          path: /ifs/kubernetes


持久数据卷概述

PersistentVolume(PV):

PersistentVolumeClaim(PVC):

pvc:申请容量

pv:提供存储

1、pvc与pv的匹配策略

pvc匹配最接近的大于自己申请容量的pv,如果满足不了,pod处于pending

k8s(存储)数据卷与数据持久卷_k8s_03

Pod申请PVC作为卷来使用, Kubernetes通过PVC查找绑定的PV,并Mount给Pod。

PV与PVC使用流程

k8s(存储)数据卷与数据持久卷_数据卷与持久卷_04

 

k8s(存储)数据卷与数据持久卷_k8s_05

PV生命周期

AccessModes(访问模式):

AccessModes是用来对PV进行访问模式的设置,用于描述用户应用对存储资源的访问权限,访问权限包括下面几种方式:

•ReadWriteOnce(RWO):读写权限,但是只能被单个节点挂载

•ReadOnlyMany(ROX):只读权限,可以被多个节点挂载

•ReadWriteMany(RWX):读写权限,可以被多个节点挂载

RECLAIM POLICY(回收策略):

目前PV支持的策略有三种:

•Retain(保留):保留数据,需要管理员手工清理数据

•Recycle(回收):清除PV中的数据,效果相当于执行rm-rf /ifs/kuberneres/*

•Delete(删除):与PV相连的后端存储同时删除

STATUS(状态):

一个PV的生命周期中,可能会处于4中不同的阶段:

•Available(可用):表示可用状态,还未被任何PVC绑定

•Bound(已绑定):表示PV已经被PVC绑定

•Released(已释放):PVC被删除,但是资源还未被集群重新声明

•Failed(失败):表示该PV的自动回收失败

目前PV使用方式称为静态供给,需要K8s运维工程师提前创建一堆PV,供开发者使用。

k8s(存储)数据卷与数据持久卷_kubernetes_06

PV 动态供给(StorageClass)

PV静态供给明显的缺点是维护成本太高了!因此, K8s开始支持PV动态供给,使用StorageClass对象实现。

k8s(存储)数据卷与数据持久卷_运维_07

K8s默认不支持NFS动态供给,需要单独部署社区开发的插件。

项目地址: GitHub - kubernetes-sigs/nfs-subdir-external-provisioner: Dynamic sub-dir volume provisioner on a remote NFS server.

部署

cd deploy
kubectl apply -f rbac.yaml # 授权访问apiserver
kubectl apply -f deployment.yaml # 部署插件,需修改里面NFS服务器地址与共享目录
kubectl apply -f class.yaml # 创建存储类
kubectl get sc # 查看存储类

StorageClass测试案例:在创建pvc时指定存储类名称

k8s(存储)数据卷与数据持久卷_kubernetes_08

基于NFS实现PV动态供给流程图

k8s(存储)数据卷与数据持久卷_kubernetes_09

StatefulSet 控制器介绍

无状态与有状态:

管理的所有Pod一模一样,提供同一个服务,也不考虑在哪台Node运

行,可随意扩容和缩容。这种应用称为“ 无状态”,例如Web服务

这些实例之间往往有依赖关系,例如主从关系、主备关系,这种应用称为“有状态”,例如MySQL主从、 Etcd集群

StatefulSet控制器用于部署有状态应用,满足一些有状态应用的需求:

• Pod有序的部署、扩容、删除和停止

• Pod分配一个稳定的且唯一的网络标识

• Pod分配一个独享的存储

StatefulSet 部署应用实践

• 稳定的网络ID(域名)

使用Headless Service(相比普通Service只是将spec.clusterIP定义为None)来维护Pod网络身份。

并且添加serviceName: “nginx” 字段指定StatefulSet控制器要使用这个Headless Service。

DNS解析名称: <statefulsetName-index>.<service-name> .<namespace-name>.svc.cluster.local

• 稳定的存储

StatefulSet的存储卷使用VolumeClaimTemplate创建,称为卷申请模板,当StatefulSet使用VolumeClaimTemplate创建

一个PersistentVolume时,同样也会为每个Pod分配并创建一个编号的PVC。

k8s(存储)数据卷与数据持久卷_k8s_10

有身份的!

身份三要素:

• 域名

• 主机名

• 存储(PVC)

应用程序数据存储

• ConfigMap:存储配置文件

• Secret:存储敏感数据

k8s(存储)数据卷与数据持久卷_linux_11

ConfigMap 存储应用配置

创建ConfigMap后,数据实际会存储在K8s中Etcd,然后通过创建Pod时引用该数据。

应用场景:应用程序配置

Pod使用configmap数据有两种方式:

• 变量注入

• 数据卷挂载

ConfigMap 存储应用配置

k8s(存储)数据卷与数据持久卷_linux_12

Secret 存储敏感信息

与ConfigMap类似,区别在于Secret主要存储敏感数据,所有的数据要经过base64编码。

应用场景:凭据

kubectl create secret 支持三种数据类型:

• docker-registry:存储镜像仓库认证信息

• generic:存储用户名、密码

• tls:存储证书

Secret 存储敏感信息案例

k8s(存储)数据卷与数据持久卷_运维_13

当创建容器时出现Pending状态,可以通过以下命令查看

kubectl describe pod pod名称

k8s(存储)数据卷与数据持久卷_数据卷与持久卷_14

k8s(存储)数据卷与数据持久卷_运维_15

k8s(存储)数据卷与数据持久卷_kubernetes_16

1、pvc与pv匹配条件

主要参考存储容量和访问模式

2、pvc与pv的关系

一对一

3、存储容量能限制嘛?

目前不能,主要用于匹配,限制主要取决于后端存储。

存储类型:

1、共享存储,例如NFS,直接能多台机器挂载

2、块存储,例如硬盘、Ceph,只能挂载到单个机器上,并且需要先格式化

3、对象存储,例如阿里云OSS,通过API访问

每个pod不等对,怎么体现的不对等(角色)?

配置文件(节点标识、IP唯一、数据存储)

部署一个etcd,3个pod,肯定是一个镜像。

如何区分3个pod的角色?

启动容器时候,启动不同的配置文件,并且这一步是自动化的。

自动化如何去做?如何自适应k8s机制?

主要是连接另一个pod的域名、决定自身角色的条件

怎么决定自身角色?

可以根据pod主机名决定(编号)。

假设当前起的第一个pod,编号肯定是0,容器启动时执行自动化脚本,脚本就可以根据编号角色启动的配置。