volume 解决问题:
- 容器磁盘上的新增文件,容器重启后将消失,无法持久化
- Pod中运行的多个容器需求共享文件
当 Pod 中的容器重启时,volume 数据还在。但是当 Pod 不存在时,volume 也将不复存在。
存储卷Volum 是 Pod 中能够被多个容器访问的共享目录
常见的 volume 类型:
- emptyDir: 初始内容为空的卷
- hostPath: 将宿主机上的文件或目录 挂载到 pod
- nfs: 网络文件系统
- secret:使用一个 secret 为 pod 提供加密信息
- configMap: 使用一个 configMap 为 pod 提供配置信息
- gitRepo: 通过挂载一个空目录,并从 git 库 clone 一个 repository 给 pod 使用
- glusterfs: glusterfs 网络文件系统
- awElasticBlockStore
- gcePersistentDisk
- azureDisk & azureFile
Pod 使用存储卷:
- spec.volumes: 声明存储卷
- spec.containers.volumeMounts: 使用存储卷
创建 Pod 时,会自动创建 emptyDir 卷,它最初是空的,Pod 中的容器可以读取和写入 emptyDir 卷中的文件。当删除 Pod 时,emptyDir 中的数据将被永久删。容器崩溃不会导致 Pod 被删除,因此 emptyDir 卷中的数据在容器崩溃时是安全的。
emptyDir 用途:
- 暂存空间,多个容器可共享
- 用于长时间计算崩溃恢复时的检查点
- Web服务器容器提供数据时,保存内容管理容器提取的文件
# 创建一个拥有两个容器,共享存储卷的 Pod $ cat > volume-emptyDir.yml <1.2 hostPath 将主机节点的文件系统中的文件和目录挂载到集群中
hostPath 用途:
- 运行需要访问 Docker 内部的容器,使用 /var/lib/docker 的 hostPath
- 在容器中运行 cAdvisor(猫头鹰,Google提供的一个服务),使用 /dev/cgroups 的 hostPath
hostPath 卷指定 type检查:
值 行为 “” 空字符串(默认),挂载时不做任何检查 DirectoryOrCreate 目录不存在自动创建,权限0755,与kubectl具有相同组和所有权 Directory 目录必须存在 FileOrCreate 文件不存在自动创建,权限0644,与kubectl具有相同组和所有权 File 文件必须存在 Socket Unix 套接字必须存在 CharDevice 字符设备必须存在 BlockDevice 块设备必须存在 $ cat > volume-hostPath.yml <1.3 nfs # 登录主页 echo "Hello World!" > /nfsdata/index.html cat > nginx-nfs.yml <2. 持久卷 集群中,通常不使用 emptyDir 和 hostPath,一般只在测试环境中使用。
PV 作用:屏蔽后端不同存储类型之间,挂载方式不一致等特性差异
PVC 作用: 寻找一个合适的PV进行绑定
2.1 PVPersistentVolume: 由管理员设置的存储,是集群的一种资源。
PV 持久卷和普通的 Volume 一样,也是使用“卷插件”来实现的,只是它们拥有独立于任何使用 PV 的 Pod 的生命周期。
PV 类型:
- 静态 PV:集群管理员创建的 PV,等待 PVC 消费
- 动态 PV:当管理员创建的静态 PV 都不匹配用户的 PersistentVolumeClaim时,集群可能会尝试动态地为 PVC创建卷。此配置基于StorageClasses (PVC必须请求存储类),并且管理员必须创建并配置该类才能够尽兴动态创建。
三种访问模式:
- RWO, ReadWriteOnce:单节点读写模式
- ROX, ReadOnlyMany:多节点只读模式
- RWX, ReadWriteMany:多节点读写模式
Volume Plugin ReadWriteOnce ReadOnlyMany ReadWriteMany CephFS ✓ ✓ ✓ Glusterfs ✓ ✓ ✓ HostPath ✓ - - iSCSI ✓ ✓ - NFS ✓ ✓ ✓ **回收策略:**仅 NFS 和 HostPath 支持回收(Recycle)
Retain:手动回收
Recycle:基本擦除 (rm -rf /thevolume/*),删除PVC时,自动删除PV中的数据,已废弃
Delete:诸如 AWS EBS、GCE PD、Azure Disk 等卷的类关联存储资产也被删除
PV 的状态:
2.2 PVC
Available:资源空闲未被 PVC 绑定
Bound: 已被 PVC 绑定
Released: 已被 PVC 解帮,但还未被集群重新声明
Failed:自动回收失败
PersistentVolumeClaim:用户存储的请求。它消耗 PV 资源。PVC 可以请求特定的大小和访问模式(例如,可以以读/写一次或只读多次模式挂载)
PVC 匹配 PV:
2.3 StorageClass
根据 PVC 声明的容量storage的大小进行筛选匹配
根据 AccessMode 进行匹配
根据 label 匹配
apiVersion: v1 kind: PersistentVolume metadata: name: pv1 labels: app: nfs # 打标签 spec: capacity: storage: 1Gi accessModes: - ReadWriteonce persistentVolumeReclaimPolicy: Recycle nfs: path: /data/volumes server: nfs1 --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: pvc1 spec: accessModes: - ReadWriteonce resources: requests: storage: 1Gi selector: # pvc匹配标签为app=nfs的pv,但它的storage必须小于等于pv的 matchLabels: app: nfsPV 由运维创建,开发操作PVC,但大规模集群中可能会有很多PV,如果这些PV都需要运维手动来处理,会非常繁琐,所以就有了动态供给概念(Dynamic Provisioning)。上面的创建的PV都是静态供给方式(Static Provisioning)。而动态供给的关键就是StorageClass,它的作用就是创建PV模板。如未指定特定 class 的 PVC,会绑定到一个默认的 DefaultStorageClass
kind: StorageClass apiVersion: storage.k8s.io/v1 metadata: name: standard provisioner: kubernetes.io/aws-ebs parameters: type: gp2 reclaimPolicy: Retain mountOptions: - debug延迟绑定:
# 存储类 apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: local-storage provisioner: kubernetes.io/no-provisioner volumeBindingMode: WaitForFirstConsumer --- # PV apiVersion: v1 kind: PersistentVolume metadata: name: nginx-pv spec: capacity: storage: 5Gi volumeMode: Filesystem accessModes: - ReadWriteonce persistentVolumeReclaimPolicy: Delete storageClassName: local-storage local: path: /data/nginx nodeAffinity: # local 类型需要设置节点亲和 required: nodeSelectorTerms: - matchexpressions: - key: kubernetes.io/hostname operator: In values: - k8s-node01 --- # PVC apiVersion: v1 kind: PersistentVolumeClaim metadata: name: local-claim spec: accessModes: - ReadWriteonce resources: requests: storage: 5Gi storageClassName: local-storage --- # Deployment apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deploy spec: replicas: 1 selector: matchLabels: appname: nginx template: metadata: name: nginx labels: appname: nginx spec: containers: - name: nginx image: nginx ports: - name: http containerPort: 8080 protocol: TCP volumeMounts: - name: data mountPath : "/data/nginx" volumes: - name: data persistentVolumeClaim: claimName: local-claim2.4 NFS 实例apiVersion: v1 kind: PersistentVolume metadata: name: nfs-pv spec: capacity: storage: 5Gi accessModes: - ReadWriteMany persistentVolumeReclaimPolicy: Retain nfs: path: /nfsdata server: 192.168.80.240 --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: nfs-pvc spec: accessModes: - ReadWriteMany resources: requests: storage: 5Gi --- apiVersion: apps/v1 kind: Deployment metadata: name: nginx-nfs-pvc labels: app: nginx spec: replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.21.3 ports: - containerPort: 80 volumeMounts: - name: data mountPath: /usr/share/nginx/html volumes: - name: data persistentVolumeClaim: claimName: nfs-pvc3. 安装 NFS 3.1 服务器# 磁盘准备 fdisk /dev/sdb # 分区 mke2fs -t ext4 /dev/sdb1 # 格式化 mkdir -p /nfsdata mount /dev/sdb1 /nfsdata # 挂载 $ blkid /dev/sdb1 /dev/sdb1: UUID="17b60a9a-92a2-4084-aaea-9f1e73d72509" TYPE="ext4" PARTUUID="42cf54d8-01" $ vi /etc/fstab UUID=17b60a9a-92a2-4084-aaea-9f1e73d72509 /nfsdata ext4 defaults 0 2 # 安装 nfs-server $ apt install nfs-kernel-server -y $ vi /etc/exports /nfsdata *(rw,sync,no_root_squash) $ systemctl restart nfs-kernel-server $ showmount -e Export list for k8s-master: /nfsdata *3.2 客户端apt install nfs-common -y mount -t nfs 192.168.80.240:/nfsdata /data3.3 无法启动$ systemctl start nfs-kernel-server A dependency job for nfs-server.service failed. See 'journalctl -xe' for details. $ journalctl -xe Oct 29 19:38:04 k8s-master multipathd[720]: sda: add missing path Oct 29 19:38:04 k8s-master multipathd[720]: sda: failed to get udev uid: Invalid argument Oct 29 19:38:04 k8s-master multipathd[720]: sda: failed to get sysfs uid: Invalid argument Oct 29 19:38:04 k8s-master multipathd[720]: sda: failed to get sgio uid: No such file or directory Oct 29 19:38:06 k8s-master multipathd[720]: sdb: add missing path Oct 29 19:38:06 k8s-master multipathd[720]: sdb: failed to get udev uid: Invalid argument Oct 29 19:38:06 k8s-master multipathd[720]: sdb: failed to get sysfs uid: Invalid argument Oct 29 19:38:06 k8s-master multipathd[720]: sdb: failed to get sgio uid: No such file or directory # 解决 $ vi /etc/multipath.conf defaults { user_friendly_names yes } blacklist { devnode "^(ram|raw|loop|fd|md|dm-|sr|scd|st)[0-9]*" devnode "^sd[a-z]?[0-9]*" } $ systemctl restart multipath-tools # 启动 nfs systemctl start nfs-kernel-server4. 安装 MySQL 4.1 创建 namespace$ mkdir ~/mysql && cd $_ $ cat > mysql-namespace.yml <4.2 创建 RBAC $ cat > mysql-nfs-rbac.yml <4.3 创建 StorageClass $ cat > mysql-nfs-storageclass.yml <4.4 创建 NFS Provisioner cat > mysql-nfs-provisioner.yml <4.5 创建 ConfigMap $ cat > mysql-configmap.yml <4.6 创建 Service (无头服务) $ cat > mysql-headless-svc.yml <4.7 创建 StatefulSet $ vi mysql-statefulset.yml apiVersion: apps/v1 kind: StatefulSet metadata: name: mysql namespace: mysql-cluster spec: selector: matchLabels: app: mysql serviceName: mysql replicas: 3 template: metadata: labels: app: mysql spec: initContainers: - name: init-mysql image: mysql:5.7 command: - bash - "-c" - | set -ex # Generate mysql server-id from pod ordinal index. [[ `hostname` =~ -([0-9]+)$ ]] || exit 1 ordinal=${BASH_REMATCH[1]} echo [mysqld] > /mnt/conf.d/server-id.cnf # Add an offset to avoid reserved server-id=0 value. echo server-id=$((100 + $ordinal)) >> /mnt/conf.d/server-id.cnf # Copy appropriate conf.d files from config-map to emptyDir. if [[ $ordinal -eq 0 ]]; then cp /mnt/config-map/master.cnf /mnt/conf.d/ else cp /mnt/config-map/slave.cnf /mnt/conf.d/ fi volumeMounts: - name: conf mountPath: /mnt/conf.d - name: config-map mountPath: /mnt/config-map - name: clone-mysql image: ist0ne/xtrabackup command: - bash - "-c" - | set -ex # Skip the clone if data already exists. [[ -d /var/lib/mysql/mysql ]] && exit 0 # Skip the clone on master (ordinal index 0). [[ `hostname` =~ -([0-9]+)$ ]] || exit 1 ordinal=${BASH_REMATCH[1]} [[ $ordinal -eq 0 ]] && exit 0 # Clone data from previous peer. ncat --recv-only mysql-$(($ordinal-1)).mysql 3307 | xbstream -x -C /var/lib/mysql # Prepare the backup. xtrabackup --prepare --target-dir=/var/lib/mysql volumeMounts: - name: data mountPath: /var/lib/mysql subPath: mysql - name: conf mountPath: /etc/mysql/conf.d containers: - name: mysql image: mysql:5.7 env: - name: MYSQL_ALLOW_EMPTY_PASSWORD value: "1" ports: - name: mysql containerPort: 3306 volumeMounts: - name: data mountPath: /var/lib/mysql subPath: mysql - name: conf mountPath: /etc/mysql/conf.d resources: requests: cpu: 250m memory: 256Mi limits: cpu: 500m memory: 512Mi livenessProbe: exec: command: ["mysqladmin", "ping"] initialDelaySeconds: 30 periodSeconds: 10 timeoutSeconds: 5 readinessProbe: exec: # Check we can execute queries over TCP (skip-networking is off). command: ["mysql", "-h", "127.0.0.1", "-e", "SELECt 1"] initialDelaySeconds: 5 periodSeconds: 2 timeoutSeconds: 1 - name: xtrabackup image: ist0ne/xtrabackup ports: - name: xtrabackup containerPort: 3307 command: - bash - "-c" - | set -ex cd /var/lib/mysql # Determine binlog position of cloned data, if any. if [[ -s xtrabackup_slave_info ]]; then # XtraBackup already generated a partial "CHANGE MASTER TO" query # because we're cloning from an existing slave. mv xtrabackup_slave_info change_master_to.sql.in # Ignore xtrabackup_binlog_info in this case (it's useless). rm -f xtrabackup_binlog_info elif [[ -f xtrabackup_binlog_info ]]; then # We're cloning directly from master. Parse binlog position. [[ `cat xtrabackup_binlog_info` =~ ^(.*?)[[:space:]]+(.*?)$ ]] || exit 1 rm -f xtrabackup_binlog_info echo "CHANGE MASTER TO MASTER_LOG_FILE='${BASH_REMATCH[1]}', MASTER_LOG_POS=${BASH_REMATCH[2]}" > change_master_to.sql.in fi # Check if we need to complete a clone by starting replication. if [[ -f change_master_to.sql.in ]]; then echo "Waiting for mysqld to be ready (accepting connections)" until mysql -h 127.0.0.1 -e "SELECt 1"; do sleep 1; done echo "Initializing replication from clone position" mysql -h 127.0.0.1 -e "$(4.8 创建 Service (外部访问) $ cat > mysql-service.yml <



