Kubernetes手记(10)- POD 存储卷

网友投稿 765 2022-05-29

十 POD 存储卷

大部分有状态的应用都有持久存储,在 Docker 上我们将容器所需要的存储卷放在宿主机上,但是 k8s 上不行,因为 POD 会被在不同的 node 节点上创建删除,所以 k8s 需要一套另外的存储卷机制,它能脱离节点为整个集群提供持久存储。

k8s 提供了多种不同的存储卷,k8s 中存储卷属于 POD 而不是容器,POD 可以挂载,POD 为什么能有存储卷呢?这是因为在所有节点上运行了一个 Pause 的镜像,它是 POD 的基础架构容器,它拥有存储卷,同一个 POD 内的所有容器是一个网络名称空间的。

10.1 卷的类型

查看 POD 支持的存储类型:kubectl explain pods.spec.volumes

HostPath:在节点本地新建一个路径,与容器建立关联关系,但节点挂了的数据也不存在了,所以也不具有持久性,容器被调度到别的 node 时候不能跨节点使用HostPath。

Local:直接使用节点的设备、也支持一个目录类似于 HostPath。

EmptyDir:只在节点本地使用,一旦 POD 删除,存储卷也会删除,它不具有持久性,当临时目录或者缓存。

网络存储:iSCSI、NFS、Cifs、glusterfs、cephfs、EBS(AWS)、Disk(Azone)

10.2 容器挂载选项

在 K8S 中卷是属于 POD 的,而不是容器,所以卷的定义在 POD 中,一个 POD 中可以定义多个卷。

在 POD 中挂载使用,kubectl explain pods.spec.containers.volumeMounts

apiVersion: v1 kind: Pod metadata: name: myapp namespace: default labels: app: myapp spec: containers: - name: myapp image: ikubernetes/myapp:v1 volumeMounts <[]Object> # 卷挂载对象 mountPath # 挂载路径 mountPropagation # 确定挂载如何从主机传播到容器 name # 挂载哪个卷 readOnly # 是否只读挂载 subPath # 挂载在子路径下 subPathExpr # 与 subPath 类似,挂载在子路径下,不同的是可以使用 $(VAR_NAME) 表示容器扩展这个变量

10.3 节点存储

10.3.1 hostpath存储卷

在宿主机的路径挂载到 POD 上,POD 删除后,卷数据是不会随之删除的,但如果 node 节点挂掉,那么数据有可能丢失,如果 POD 被调度到其他的节点,那么原来卷的数据就访问不到了。

https://kubernetes.io/docs/concepts/storage/volumes/#hostpath

定义参数,kubectl explain pods.spec.volumes.hostPath

path # 主机上目录的路径。 如果路径是符号链接,则会跟随真实路径的链接。 type # 见下表

示例

apiVersion: v1 kind: Pod metadata: name: myapp namespace: default labels: app: myapp spec: containers: - name: myapp image: ikubernetes/myapp:v1 volumeMounts: # 容器挂载哪些卷 - name: webstore # 挂载哪个卷 mountPath: /usr/share/nginx/html # 挂载到容器内哪个目录 readOnly: false # 是否只读 volumes: # 存储卷属于POD的(不属于容器) - name: webstore # 存储卷对象名字 hostPath: # hostpath 类型的存储卷对象 path: /data/myapp # 处于宿主机的目录 type: DirectoryOrCreate # 不存在则创建

10.3.2 gitRepo卷

将 git 仓库的内容当作存储使用,在 POD 创建时候连接到仓库,并拉取仓库,并将它挂载到容器内当作一个存储卷。

它其实是建立在 emptyDir 的基础上,但是对卷的操作不会同步到 gitrepo 上。

注意:需要在各运行pod的node节点上安装git工具,用于git的拉取

apiVersion: v1 kind: Pod metadata: labels: run: gitrepo name: gitrepo spec: containers: - image: nginx:latest name: gitrepo volumeMounts: - name: gitrepo mountPath: /usr/share/nginx/html volumes: - name: gitrepo gitRepo: repository: "https://gitee.com/rocket049/mysync.git" revision: "master"

10.3.3 emptyDir缓存卷

它使用宿主机一个目录作为挂载点,随着 POD 生命周期的结束,其中的数据也会丢失,但是它有一个非常大的优点就是可以使用内存当作存储空间挂载使用。

它可以用在 POD 中两个容器中有一些数据需要共享时候选用。

定义 emptyDir 参数,kubectl explain pods.spec.volumes.emptyDir

medium # 使用 "" 表示使用 Disk 来存储,使用 Memory 表示使用内存 sizeLimit # 限制存储空间的大小

使用示例

apiVersion: v1 kind: Pod metadata: name: pod-volume-demo namespace: default labels: app: myapp tier: frontend spec: volumes: - name: html emptyDir: {} # 使用磁盘,且没有容量限制 containers: - name: myapp image: ikubernetes/myapp:v1 imagePullPolicy: IfNotPresent volumeMounts: - name: html mountPath: /usr/share/nginx/html/ ports: - name: http containerPort: 80 - name: https containerPort: 443 - name: busybox image: busybox:latest imagePullPolicy: IfNotPresent volumeMounts: - name: html mountPath: /data/ command: - "/bin/sh" - "-c" - "while true; do date >> /data/index.html; sleep 10; done"

使用示例

apiVersion: v1 kind: Pod metadata: name: pod-volume-demo namespace: default labels: app: myapp tier: frontend spec: containers: - name: myapp image: ikubernetes/myapp:v1 imagePullPolicy: IfNotPresent volumeMounts: - name: html mountPath: /usr/share/nginx/html/ ports: - name: http containerPort: 80 - name: https containerPort: 443 - name: busybox image: busybox:latest imagePullPolicy: IfNotPresent volumeMounts: - name: html mountPath: /data/ command: - "/bin/sh" - "-c" - "while true; do date >> /data/index.html; sleep 10; done" volumes: - name: html emptyDir: medium: "" sizeLimit: 1536Mi

10.4 网络存储

网络存储,就是脱离了节点生命周期的存储设备,即使 pod 被调度到别的 node 节点上,仍然可以挂载使用其中的数据。

10.4.1 nfs

nfs 服务器是存在于集群之外的服务器,它不受 node 节点的影响,因而在 node 节点宕机后仍然能够提供持久存储给其他 POD。

在 k8s 的 node 找一个主机,安装配置 nfs 服务器并启动

$ yum install nfs-utils # 安装 nfs 服务 $ mkdir -p /data/volumes # 创建 volume 卷目录 echo '/data/volumes 172.16.100.0/16(rw,no_root_squash)' >> /etc/exports # 配置 nfs 服务器 $ systemctl start nfs # 启动 nfs 服务器 $ ss -tnl # 确认监听端口,nfs 监听 TCP 2049 端口

在 k8s 集群的 node 节点安装 nfs 驱动,测试挂载是否正常

$ yum install nfs-utils $ mount -t nfs 172.16.100.104:/data/volumes /mnt

定义 nfs 参数,kubectl explain pods.spec.volumes.nfs

path # nfs 服务器的路径 readOnly # 是否只读 server # nfs 服务器地址

使用示例

apiVersion: v1 kind: Pod metadata: name: pod-vol-nfs-demo namespace: default spec: containers: - name: myapp image: ikubernetes/myapp:v1 volumeMounts: - name: html mountPath: /usr/share/nginx/html/ volumes: - name: html nfs: path: /data/volumes server: 172.16.100.104

注意⚠️:各个node节点也需要安装yum install nfs-utils,不让在挂载的时候会出现异常。

10.5 分布式存储

分布式存储能提供脱离节点生命周期的存储,又比网络存储更加健壮,它是分布式的,有很强的高可用性,但是分布式存储配置复杂,在由 NFS 提供的网络储存中,用户需要知道分配给 POD 的 NFS 存储的地址才能使用,而在由分布式提供的存储能力的存储上,用户需要充分了解该分布式存储的配置参数,才能够使用这个分布式存储。

由此 K8S 提供了 PV、PVC 两种机制,让普通用户无需关心底层存储参数的配置,只需要说明需要使用多大的持久存储,就可以了。

一般 PV 与 PVC 是一对绑定的,PV属于全局,PVC 属于某个名称空间,当一个 PV 被一个 PVC 绑定,别的名称空间 PVC 就不可以再绑定了。请求绑定某个 PV 就是由 PVC 来完成的,被 PVC 绑定的 PV 称作 PV 的绑定状态。

PVC 绑定了一个 PV,那么 PVC 所处名称空间定义的 POD 就可以使用 persistentVolumeClaim 类型的 volumes 了,然后容器就可以通过 volumeMounts 挂载 PVC 类型的卷了。

persistentVolumeClaim 卷是否允许多路读写,这取决于 PV 定义时候的读写特性:单路读写、多路读写、多路只读。

如果某个 POD 不在需要了,我们把它删除了、同时也删除了 PVC、那么此时 PV 还可以有自己的回收策略: delete删除PV、Retain什么都不做。

10.5.1 PersistentVolume

由管理员添加的的一个存储的描述,是一个集群级别的全局资源,包含存储的类型,存储的大小和访问模式等。它的生命周期独立于Pod,例如当使用它的 Pod 销毁时对 PV 没有影响。

见:kubectl explain PersistentVolume.spec

在 nfs 上定义存储,/etc/exports,并且导出 nfs 定义

/data/volumes/v1 172.16.100.0/16(rw,no_root_squash) /data/volumes/v2 172.16.100.0/16(rw,no_root_squash) /data/volumes/v3 172.16.100.0/16(rw,no_root_squash) /data/volumes/v4 172.16.100.0/16(rw,no_root_squash) /data/volumes/v5 172.16.100.0/16(rw,no_root_squash)

exportfs -arv

将 nfs 在 k8s 中定义为 PersistentVolume,详见:kubectl explain PersistentVolume.spec.nfs

apiVersion: v1 kind: PersistentVolume metadata: name: pv-001 labels: name: pv001 spec: accessModes: - ReadWriteMany - ReadWriteOnce capacity: storage: 1Gi nfs: path: /data/volumes/v1 server: 172.16.100.104 --- apiVersion: v1 kind: PersistentVolume metadata: name: pv-002 labels: name: pv003 spec: accessModes: - ReadWriteMany - ReadWriteOnce capacity: storage: 2Gi nfs: path: /data/volumes/v2 server: 172.16.100.104 --- apiVersion: v1 kind: PersistentVolume metadata: name: pv-003 labels: name: pv003 spec: accessModes: - ReadWriteMany - ReadWriteOnce capacity: storage: 3Gi nfs: path: /data/volumes/v3 server: 172.16.100.104

kubectl get persistentvolume NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE pv-001 1Gi RWO,RWX Retain Available 3m38s pv-002 2Gi RWO,RWX Retain Available 3m38s pv-003 3Gi RWO,RWX Retain Available 3m38s

10.5.2. PersistentVolumeClaim

是 Namespace 级别的资源,描述对 PV 的一个请求。请求信息包含存储大小,访问模式等。

定义 PVC,kubectl explain PersistentVolumeClaim.spec

accessModes <[]string> # 设置访问模式 ReadWriteOnce # 单个节点以读写方式挂载 ReadOnlyMany # - 多节点以只读方式挂载 ReadWriteMany # - 多节点以读写方式挂载 dataSource # 如果配置程序可以支持 Volume Snapshot 数据源,它将创建一个新卷,并且数据将同时还原到该卷。 resources # 资源表示 PersistentVolume 应具有的最小资源 selector # 选择哪个 PersistentVolume storageClassName # 存储类名称 volumeMode # 定义声明所需的 PersistentVolume 类型才能被选中 volumeName # 后端 PersistentVolume ,就是精确选择 PersistentVolume ,而不是使用 selector 来选定

在 volumes 中使用 PVC,kubectl explain pods.spec.volumes.persistentVolumeClaim

persistentVolumeClaim claimName # 在当前名称空间已经创建号的 PVC 名称 readOnly # 是否只读

定义 PersistentVolumeClaim,详见:kubectl explain PersistentVolumeClaim.spec

apiVersion: v1 kind: PersistentVolumeClaim metadata: name: my-pvc namespace: default spec: accessModes: - ReadWriteMany # 访问模式 resources: # 资源条件 requests: # 挑选 PV 时候必须满足的条件,不满足则一直等待 storage: 2Gi # 存储大小

在 pod 清单中定义 persistentVolumeClaim 类型的 volumes ,并在容器中挂载 volumeMounts。

apiVersion: v1 kind: Pod metadata: name: pod-vol-nfs-demo namespace: default spec: containers: - name: myapp image: ikubernetes/myapp:v1 volumeMounts: - name: html mountPath: /usr/share/nginx/html/ volumes: - name: html persistentVolumeClaim: claimName: my-pvc # 使用的 PVC 的名称

10.5.3 StorageClass

PVC 申请 PV 的时候,未必有符合条件的 PV,k8s 为我们准备了 StorageClass 可以在 PVC 申请 PV 的时候通过 StorageClass 动态生成 PV。

StorageClass 可以动态的到 CephFS 、NFS 等存储(或者云端存储)产生一个 PV,要求存储设备必须支持 RESTfull 风格的接口。

10.6 StorageClass Ceph RBD

10.6.1 配置 Ceph 储存池

创建 ceph 存储池

yum install -y ceph-common # 在所有节点安装 ceph-common

ceph osd pool create kube 4096 # 创建 pool ceph osd pool ls # 查看 pool ceph auth get-or-create client.kube mon 'allow r' osd 'allow rwx pool=kube' -o /etc/ceph/ceph.client.kube.keyring ceph auth list # 授权 client.kube 用户访问 kube 这个 pool scp /etc/ceph/ceph.client.kube.keyring node1:/etc/ceph/ # 将用户 keyring 文件拷贝到各个 ceph 节点 scp /etc/ceph/ceph.client.kube.keyring node1:/etc/ceph/

10.6.2 安装 rbd-provisioner

1.12 版本后 kube-controller-manager 不再内置 rbd 命令,所以 StorageClass 的 provisioner 而是通过外部的插件来实现

https://github.com/kubernetes-incubator/external-storage/tree/master/ceph/rbd/deploy/rbac # rbd-provisioner

$ git clone https://github.com/kubernetes-incubator/external-storage.git # 下载 rbd-provisioner $ cat >>external-storage/ceph/rbd/deploy/rbac/clusterrole.yaml<

10.6.3 使用 StorageClass

创建 CephX 验证 secret

https://github.com/kubernetes-incubator/external-storage/tree/master/ceph/rbd/examples # rbd-provisioner 使用 ceph rbd 的示例

--- apiVersion: v1 kind: Secret metadata: name: ceph-admin-secret namespace: kube-system type: "kubernetes.io/rbd" data: # ceph auth get-key client.admin | base64 # 从这个命令中取得 keyring 认证的 base64 密钥串复制到下面 key: QVFER3U5TmM1NXQ4SlJBQXhHMGltdXZlNFZkUXRvN2tTZ1BENGc9PQ== --- apiVersion: v1 kind: Secret metadata: name: ceph-secret namespace: kube-system type: "kubernetes.io/rbd" data: # ceph auth get-key client.kube | base64 # 从这个命令中取得 keyring 认证的 base64 密钥串复制到下面 key: QVFCcUM5VmNWVDdQRlJBQWR1NUxFNzVKeThiazdUWVhOa3N2UWc9PQ==

创建 StorageClass 指向 rbd-provisioner,

--- kind: StorageClass apiVersion: storage.k8s.io/v1 metadata: name: ceph-rbd provisioner: ceph.com/rbd reclaimPolicy: Retain parameters: monitors: 172.16.100.9:6789 pool: kube adminId: admin adminSecretName: ceph-admin-secret adminSecretNamespace: kube-system userId: kube userSecretName: ceph-secret userSecretNamespace: kube-system fsType: ext4 imageFormat: "2" imageFeatures: "layering"

创建 PersistentVolumeClaim

--- kind: PersistentVolumeClaim apiVersion: v1 metadata: name: ceph-rbd-pvc data-kong-postgresql-0 spec: storageClassName: ceph-rbd accessModes: - ReadWriteOnce resources: requests: storage: 1Gi

Kubernetes手记(10)- POD 存储卷

在 POD 中使用 PVC,最后在容器中挂载 PVC。

--- apiVersion: v1 kind: Pod metadata: name: ceph-sc-pvc-demo namespace: default spec: containers: - name: myapp image: ikubernetes/myapp:v1 volumeMounts: - name: pvc-volume mountPath: /usr/share/nginx/html/ volumes: - name: pvc-volume persistentVolumeClaim: claimName: ceph-rbd-pvc

其他

自己将手记发在:https://github.com/redhatxl/awesome-kubernetes-notes

欢迎一键三连

Kubernetes

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:关系型数据库的外键约束与关联
下一篇:64_Java_常用类2_时间_Compare_System_Math 时间
相关文章