栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

K8S 存储 PV和PVC

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

K8S 存储 PV和PVC

1. 卷

volume 解决问题:

  1. 容器磁盘上的新增文件,容器重启后将消失,无法持久化
  2. 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: 使用存储卷
1.1 emptyDir

创建 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文件必须存在
SocketUnix 套接字必须存在
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 PV

PersistentVolume: 由管理员设置的存储,是集群的一种资源。

PV 持久卷和普通的 Volume 一样,也是使用“卷插件”来实现的,只是它们拥有独立于任何使用 PV 的 Pod 的生命周期。

PV 类型:

  • 静态 PV:集群管理员创建的 PV,等待 PVC 消费
  • 动态 PV:当管理员创建的静态 PV 都不匹配用户的 PersistentVolumeClaim时,集群可能会尝试动态地为 PVC创建卷。此配置基于StorageClasses (PVC必须请求存储类),并且管理员必须创建并配置该类才能够尽兴动态创建。

三种访问模式:

  • RWO, ReadWriteOnce:单节点读写模式
  • ROX, ReadOnlyMany:多节点只读模式
  • RWX, ReadWriteMany:多节点读写模式
Volume PluginReadWriteOnceReadOnlyManyReadWriteMany
CephFS
Glusterfs
HostPath--
iSCSI-
NFS

**回收策略:**仅 NFS 和 HostPath 支持回收(Recycle)

  • Retain:手动回收

  • Recycle:基本擦除 (rm -rf /thevolume/*),删除PVC时,自动删除PV中的数据,已废弃

  • Delete:诸如 AWS EBS、GCE PD、Azure Disk 等卷的类关联存储资产也被删除

PV 的状态:

  • Available:资源空闲未被 PVC 绑定

  • Bound: 已被 PVC 绑定

  • Released: 已被 PVC 解帮,但还未被集群重新声明

  • Failed:自动回收失败

2.2 PVC

PersistentVolumeClaim:用户存储的请求。它消耗 PV 资源。PVC 可以请求特定的大小和访问模式(例如,可以以读/写一次或只读多次模式挂载)

PVC 匹配 PV:

  • 根据 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: nfs
    
2.3 StorageClass

PV 由运维创建,开发操作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-claim
2.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-pvc
3. 安装 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   /data
3.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-server
4. 安装 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 <
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/677465.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号