Linux——卷
介绍
最近做的项目,涉及到对系统的一些维护,有些盘没有使用,需要创建逻辑盘并挂载到指定目录下。有些软件需要依赖空的逻辑盘(LVM)。
先简单介绍一下卷的一些概念,有分区、物理存储介质、物理卷、卷组、逻辑卷。下面介绍一下概念:
概念介绍参考文章:
- https://cloud.tencent.com/developer/article/2429857
- https://blog.csdn.net/yufuloo/article/details/80929116
- https://blog.csdn.net/qq_37871657/article/details/143209437
- 分区(Partition) :是在物理存储介质上(磁盘)上划分出来的独立存储区域,每个分区可以视为一个独立的磁盘,格式化后可挂载到文件系统目录下使用。
- 物理存储介质(The physical media) :这里指系统的存储设备:硬盘,如:/dev/hda、/dev/sda等等,是存储系统最低层的存储单元。
- 物理卷(physical volume,PV) :物理卷就是指硬盘分区或从逻辑上与磁盘分区具有同样功能的设备(如RAID),是LVM的基本存储逻辑块,但和基本的物理存储介质(如分区、磁盘等)比较,却包含有与LVM相关的管理参数。是用来构建卷组的基本单元,通常不会被直接挂载,而是通过组合成卷组,然后从卷组中创建逻辑卷。
- 卷组(Volume Group,VG) :LVM卷组类似于非LVM系统中的物理硬盘,其由物理卷组成。可以在卷组上创建一个或多个“LVM分区”(逻辑卷),LVM卷组由一个或多个物理卷组成。是逻辑卷的基础。
- 逻辑卷(Logical Volume, LV) :LVM的逻辑卷类似于非LVM系统中的硬盘分区,在逻辑卷之上可以建立文件系统(比如/home或者/usr等)。逻辑卷是卷组中的可分配存储空间,它类似于传统的磁盘分区,提供了更多的灵活性,可以在无需重新分区的情况下,动态调整大小。
- 设备:无论是物理卷还是逻辑卷,都是
/dev
下的块设备,可以通过块设备管理工具来对其直接操作,比如:k8s上的符合OCI标准的块设备Storage Class、PV、PVC
分盘
记录一下分盘实战操作。
第一个场景:VG中分配剩余的磁盘空间创建LVM
场景描述
- OS:ubuntu24.04
- 系统磁盘有500GB,系统默认只给根分区分配了100GB,剩余400GB未分配LVM
- 存在VG:
/dev/mapper/ubuntu--vg
- 存在LVM:
/dev/mapper/ubuntu--vg-ubuntu--lv
,挂载到根分区 - 任务:需要将VG中剩余的空间分配给系统目录使用
操作步骤
-
查看卷组信息:
vgdisplay
-
分出可用空间
如果卷组有可用的未分配空间,可以创建新的 LVM 逻辑卷:
sudo lvcreate -L <size>G -n new_lv_name ubuntu--vg
这里
<size>
是要分配的大小(如10
),new_lv_name
是新逻辑卷名字,比如data1
。 -
格式化新的逻辑卷:
sudo mkfs.ext4 /dev/ubuntu--vg/new_lv_name
-
挂载新逻辑卷到文件系统:
sudo mkdir /mnt/new_lv_name sudo mount /dev/ubuntu--vg/new_lv_name /mnt/new_lv_name
-
更新
/etc/fstab
如果想要系统启动时自动挂载,请编辑
/etc/fstab
echo '/dev/ubuntu--vg/new_lv_name /mnt/new_lv_name ext4 defaults 0 2' | sudo tee -a /etc/fstab
<文件系统> <挂载点> <类型> <选项> <转储> <检查>
经过上面步骤的操作,顺利的将剩余磁盘分配出来,创建了新的LVM并挂载到文件系统使用,同时支持开机自动挂载。
可以使用如下命令查看相关信息:
-
LVM信息:
lvdisplay
-
卷的信息:
lsblk
第二个场景:从已存在的LVM中分配出空间,分配给新的LVM
场景描述
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS
loop0 7:0 0 50G 0 loop
sda 8:0 0 447.1G 0 disk
sda1 8:1 0 1G 0 part /boot/efi
sda2 8:2 0 2G 0 part /boot
sda3 8:3 0 444.1G 0 part
ubuntu--vg-ubuntu--lv 252:0 0 100G 0 lvm /
ubuntu--vg-new--lv 252:1 0 344G 0 lvm /data
-
项目需要安装阿里巴巴开源的软件open-local,它需要一块空的逻辑卷,也就是空闲块设备,可以作为存储底座
-
并且对设备的类型有要求,逻辑卷具有更多的功能
不同类型 PV 所支持的存储能力也不同。
类型 动态分配 PV扩容 PV快照 原生块设备 IO限流 临时卷 监控数据 LVM(共享盘类型) 支持 支持 支持 支持 支持 支持 支持 Device(独占盘类型) 支持 不支持 不支持 支持 不支持 不支持 支持 -
同时,机器的VG中没有空闲的空间了,只能从现有的LVM中分离出部分空间
-
同时,保证现有的LVM空间中的数据不丢失
操作步骤
建议提前备份数据,再尝试以下操作
-
查看当前系统卷信息
lsblk
-
umount当前LVM
umount /data
-
杀死占用mount目录的进程
sudo lsof +D /data kill -9 xxx
-
对文件系统检查
sudo e2fsck -f /dev/ubuntu-vg/new-lv
如果有提示被占用,建议重启操作系统,注意把
/etc/fstab
中开机自动挂载的配置注释掉 -
缩小文件系统,确保缩小后的空间还能容纳之前的数据
此操作将文件系统调整为 144GB(344GB - 200GB),确保在缩小逻辑卷时不会丢失数据。现在就有200GB的可用空间。
sudo resize2fs /dev/ubuntu-vg/new-lv 144G
-
缩小逻辑卷
这将把逻辑卷的大小调整为 144GB,释放出 200GB 的空间
sudo lvreduce -L 144G /dev/ubuntu-vg/new-lv
-
创建新的逻辑卷
sudo lvcreate -L 200G -n open-local-lv ubuntu-vg
-
格式化新的逻辑卷
sudo mkfs.ext4 /dev/ubuntu-vg/open-local-lv
-
恢复旧逻辑卷挂载点
mount /dev/ubuntu-vg/new-lv /data lsblk lvdisplay
注:记得把
/etc/fstab
文件中的注释去掉
这样就完成了需求,分离出了200GB的LVM供open-local
使用,且恢复了原来的文件系统和文件。
第三个场景:使用本地持久卷作为k8s集群的块存储
https://kubernetes.io/blog/2019/01/15/container-storage-interface-ga/
场景描述
为k8s集群创建本地的块存储设备
操作步骤
-
创建虚拟磁盘文件,将其绑定到循环设备(循环设备不建议在生产环境中使用,这里只是本地测试使用)
$ loop_file="/tmp/test-image-storage.img" $ sudo dd if=/dev/zero of=$loop_file bs=1M count=2500 $ sudo losetup /dev/loop0 $loop_file
-
创建存储类
apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: local-storage provisioner: kubernetes.io/no-provisioner volumeBindingMode: WaitForFirstConsumer
-
创建持久卷
apiVersion: v1 kind: PersistentVolume metadata: name: test-block-pv spec: capacity: storage: 10Gi volumeMode: Block accessModes: - ReadWriteOnce persistentVolumeReclaimPolicy: Retain storageClassName: local-storage local: path: /dev/loop0 nodeAffinity: required: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/hostname operator: In values: - NODE_NAME
-
创建持久卷claim
apiVersion: v1 kind: PersistentVolumeClaim metadata: name: test-pvc spec: accessModes: - ReadWriteOnce resources: requests: storage: 1Gi volumeMode: Block storageClassName: local-storage
-
测试pod示例
apiVersion: v1 kind: Pod metadata: name: large-image-pod spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/hostname operator: In values: - NODE_NAME volumes: - name: test-image-storage persistentVolumeClaim: claimName: test-pvc containers: - name: app-container image: xxx command: ["/bin/sh", "-c"] args: - sleep 6000 volumeDevices: - devicePath: /dev/xxx name: test-image-storage