xfs_quota
xfs_quota
由 xfsprogs
提供,安装命令:yum install xfsprogs -y
- 类型:磁盘容量、文件数(Inode)
- 方式:软限制、硬限制。硬限大于等于软限制,否者软限制失效说明:
1
xfs_quota -x -c 'limit [-ug] bsoft=N bhard=N isoft=N ihard=N <name>' <mount-point>
- -x 专家模式,允许对配额系统进行修改
- -c 子命令选项,依赖专家模式
- 子命令:
- df -b (block) -i (inode) -h
- timer 宽限时间
- limit
- -u:对用户限制
- -g:对组限制
- bsoft:磁盘容量软限制
- bhard:磁盘容量硬限制
- isoft:文件数量软限制
- ihard:文件数量硬限制
- report 列出quota项目
- -u:对用户查看
- -g:对组查看
- -a:查看所有可用分区的配额使用报告
- -b:查看磁盘容量
- -i:查看文件数
- print 当前系统参数
- state 列出当前系统信息和相关的启动项
1
2
3
4
5
6
7
8
9
10xfs_quota -x -c "timer [-ug] [-bir] Ndays"
xfs_quota -x -c 'df'
xfs_quota -x -c 'df -b'
xfs_quota -x -c 'df -b -i'
xfs_quota -x -c 'df -b -i -h'
xfs_quota -x -c 'print'
xfs_quota -x -c 'report'
xfs_quota -x -c 'report -ugr' <mount-point> # user/group/project
xfs_quota -x -c 'report -abi' <mount-point>
xfs_quota -x -c 'state'
os设置配额
- 创建用户组及用户
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17# cat myquota.sh
#!/bin/bash
groupadd myquotagrp
for username in myquota1 myquota2 myquota3 myquota4 myquota5
do
useradd -g myquotagrp $username
echo "$username:password" | chpasswd
done
mkdir /home/ruike/quota_test_dir
chgrp myquotagrp /home/ruike/quota_test_dir
chmod 2770 /home/ruike/quota_test_dir
查看
drwxrws--- 2 root myquotagrp 6 Dec 27 16:12 quota_test_dir/
所属myquotagrp组,否则切换到不同用户时,没有权限写入 - 查看挂载目录状况
注意:xfs, usrquota,grpquota
1
2# mount | grep quota_test_dir
/dev/mapper/ubuntu--vg-docker--lv--ext4 on /home/ruike/quota_test_dir type xfs (rw,relatime,attr2,inode64,logbufs=8,logbsize=32k,usrquota,grpquota)
quota限制 for user and group
要求: 5个用户共属一组, 每个用户250/300M的容量限制, 组总容量950M/1G容量, grace time 14天
对用户进行限制
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17xfs_quota -xc 'limit -u bsoft=250M bhard=300M myquota1' /home/ruike/quota_test_dir/
xfs_quota -xc 'limit -u bsoft=250M bhard=300M myquota2' /home/ruike/quota_test_dir/
xfs_quota -xc 'limit -u bsoft=250M bhard=300M myquota3' /home/ruike/quota_test_dir/
xfs_quota -xc 'limit -u bsoft=250M bhard=300M myquota4' /home/ruike/quota_test_dir/
xfs_quota -xc 'limit -u bsoft=250M bhard=300M myquota5' /home/ruike/quota_test_dir/
# xfs_quota -xc 'report -ubih '
User quota on /home/ruike/quota_test_dir (/dev/mapper/ubuntu--vg-docker--lv--ext4)
Blocks Inodes
User ID Used Soft Hard Warn/Grace Used Soft Hard Warn/Grace
---------- --------------------------------- ---------------------------------
root 0 0 0 00 [------] 3 0 0 00 [------]
myquota1 0 250M 300M 00 [------] 0 0 0 00 [------]
myquota2 0 250M 300M 00 [------] 0 0 0 00 [------]
myquota3 0 250M 300M 00 [------] 0 0 0 00 [------]
myquota4 0 250M 300M 00 [------] 0 0 0 00 [------]
myquota5 0 250M 300M 00 [------] 0 0 0 00 [------]对组进行限制
1 | # xfs_quota -xc 'limit -g bsoft=950M bhard=1G myquotagrp' /home/ruike/quota_test_dir/ |
- 设置grace time
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19# xfs_quota -xc 'timer -b -u 14days' /home/ruike/quota_test_dir/
# xfs_quota -xc 'timer -b -g 14days' /home/ruike/quota_test_dir/
# xfs_quota -xc state
User quota state on /home/ruike/quota_test_dir (/dev/mapper/ubuntu--vg-docker--lv--ext4)
Accounting: ON
Enforcement: ON
Inode: #131 (2 blocks, 2 extents)
Group quota state on /home/ruike/quota_test_dir (/dev/mapper/ubuntu--vg-docker--lv--ext4)
Accounting: ON
Enforcement: ON
Inode: #132 (2 blocks, 2 extents)
Project quota state on /home/ruike/quota_test_dir (/dev/mapper/ubuntu--vg-docker--lv--ext4)
Accounting: OFF
Enforcement: OFF
Inode: N/A
Blocks grace time: [14 days]
Inodes grace time: [7 days]
Realtime Blocks grace time: [7 days] - 测试
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23root@ubu2004:/home/ruike/quota_test_dir# su myquota1
# dd if=/dev/zero of=quota1.img bs=1M count=260
切换到root 用户
root@ubu2004:/home/ruike/quota_test_dir# su myquota2
# dd if=/dev/zero of=quota2.img bs=1M count=500
切换到root 用户
root@ubu2004:/home/ruike/quota_test_dir# ll
-rw-r--r-- 1 myquota1 myquotagrp 272629760 Jan 5 12:09 quota1.img
-rw-r--r-- 1 myquota2 myquotagrp 314572800 Jan 5 12:10 quota2.img
root@ubu2004:/home/ruike/quota_test_dir# xfs_quota -xc 'report -bihu'
User quota on /home/ruike/quota_test_dir (/dev/mapper/ubuntu--vg-docker--lv--ext4)
Blocks Inodes
User ID Used Soft Hard Warn/Grace Used Soft Hard Warn/Grace
---------- --------------------------------- ---------------------------------
root 0 0 0 00 [0 days] 3 0 0 00 [------]
myquota1 260M 250M 300M 00 [13 days] 1 0 0 00 [------]
myquota2 300M 250M 300M 00 [13 days] 1 0 0 00 [------]
myquota3 0 250M 300M 00 [------] 0 0 0 00 [------]
myquota4 0 250M 300M 00 [------] 0 0 0 00 [------]
myquota5 0 250M 300M 00 [------] 0 0 0 00 [------]
可以看到,
quota1使用了260M, warn/grace是13天, 13天后, 其hard会变为260m
quota2即使dd了500M, 这里也只用了300M 写超过的部分并不会hang住
针对目录设置quota
更改项目, prjquota
与usr/grpquota
不能同时设置
1 | # cat /etc/fstab |
1 | # echo '11:/home/ruike/quota_test_dir' >> /etc/projects // 指定专案识别码与目录的对应11是识别码, 可以随便取, 一定要放到etc下的这个文件里 |
测试
1 | root@ubu2004:~# fallocate -l 500M /home/ruike/quota_test_dir/500Mfile |
额外指令
1 | // enable/disable |
docker 全局配额设置
开启容器的配额限制
1 | "storage-driver": "overlay2", // 使用哪个存储驱动 |
查看两个容器的都被限制住
1 | root@ubu2004:~# docker exec -it test1 bash |
临时禁用配额限制
1 | # xfs_quota -x -c "disable -up" /home/ruike/quota_test_dir |
此时进入两个容器, 可以看到限制被禁用了
1 | # docker exec -it test2 bash |
所以project
的含义是对不同的目录
删除Quota
限制
1 | root@ubu2004:~# xfs_quota -x -c "off -up" /home/ruike/quota_test_dir |
off后要重新挂载才能进行quota操作
容器粒度配额限制
1 | # docker run -itd --storage-opt size=30M --name ruike2 nginx |
1 | root@ubu2004:~# xfs_quota -xc 'report -bih' |
每个容器是两条project限制, projectID
是怎么关联到哪个容器的?
docker 配额实现
docker创建容器可设置--storage-driver=xxx --storage-opt size=yyy
, 此配置优先级高于全局的配置
daemon/create.go
1 | func (daemon *Daemon) create(opts createOpts) (retC *container.Container, retErr error) { |
github.com/docker/docker/layer/layer_store.go
1 | func (ls *layerStore) initMount(graphID, parent, mountLabel string, initFunc MountInit, storageOpt map[string]string) (string, error) { |
在创建容器可读可写层时,分成了两步
- 创建init层,作为/etc/hosts, resolv.conf等的挂载层,
initiD: <data-root>/overlay/grapthID-init
- 容器的可读可写层
最后调用的都是ls.driver.CreateReadWrite()
docker的storage driver 支持 overlay2,aufs,devicemapper,vfs,zfs等(moby/daemon/graphdriver/
)下,这里选用创建的overlay2
daemon/graphdriver/overlay2/overlay.go
1 | func (d *Driver) CreateReadWrite(id, parent string, opts *graphdriver.CreateOpts) error { |
github.com/docker/docker/quota/projectquota.go
1 | // echo 999:/var/lib/docker/overlay2 >> /etc/projects |
我们可以上面的log查看到对应的打印 journal -u docker | grep projectID | grep <grapthID>
, 以下是查看到的日志
1 | Jan 05 13:19:35 ubu2004 dockerd[176096]: time="2024-01-05T13:19:35.859782918Z" level=debug msg="SetQuota(/home/ruike/quota_test_dir/overlay2/8568b8ee62483dee1f9aa1bb8165e5d5ba3c7b89a78f886a5d93ee9bc2f1c13f-init, 31457280): projectID=21" |
每创建一个容器,docker会在container的可读可写层和init层两个目录设置project quota
<data-root>/overlay2/<grapthID>
和 <data-root>/overlay2/<graphID>-init
k8s 本地临时存储及弱配额实现
- 概况
ephemeral-storage 分成csi管理的临时卷 和 kubelet管理的local 临时卷
前者可以通过csi机制来设置容量,后者
local ephemeral-storage
可以由本地存储设备 或者 ram内存设备来提供。ram emptydir 虽然可以做临时存储(生命周期角度),但是不会统计到临时存储的磁盘(占用的内存),file emptyDir
会占用磁盘空间
统计临时存储的使用量,有两种本地临时性存储的配置
- 单一文件系统:所有临时存储都存放在同一个文件系统中
- 双文件系统: 容器镜像和rootfs单独一个文件系统,前两种另一个文件系统
分文件系统是因为利用文件系统统计临时存储的空间使用量
kubelet 将仅统计临时存储的”根文件系统”。docker data root(/var/lib/docker)必须和kubelet(/var/lib/kubelet/) 位于同一个分区才能统计临时存储。
临时存储容量会影响到pod调度,kubelet会统计当前节点的kubelet分区的可分配的磁盘资源,在创建Pod时会根据存储需求调度到满足存储的节点,当pod实际使用超过申请的临时存储会进行驱逐操作,避免耗尽节点上的存储空间> kubectl describe node 可以看到节点临时存储的总容量
- 设置本地临时存储
1
2
3
4
5resources:
requests:
ephemeral-storage: "200Mi"
limits:
ephemeral-storage: "400Mi"
哪些数据会占用本地临时存储? 一种3种
- 容器日志(/var/log),写入容器 stdout, stderr 流,
- emptyDir volume数据(存放在/var/lib/kubelet/…/volumes/kubernetes.io~emptyDir/…), tmpfs类型因为使用内存,不统计到本地临时存储(
emptyDir:medium: "Memory", sizeLimit: 500Mi
) - 镜像层和容器可写层(/var/lib/docker)
- 如何度量 Pod 的存储用量?
- 周期扫描上面三个路径
- 项目配额(Project Quota,更优,更快)
- 目录下所创建的所有文件都属于该项目,内核只需要跟踪该项目中的文件所使用的存储块个数
k8s使用的project quota IDs
会注册在 /etc/projects
和 /etc/projid
文件中,
3.1 如何开启项目配额上报使用容量
1 | 1. kubelet --feature-gates LocalStorageCapacityIsolationFSQuotaMonitoring=true, 默认false |
项目配额可以帮你监视存储用量,但无法强制执行限制。
pkg/volume/util/fsquota/quota_linux.go
1 | func AssignQuota(m mount.Interface, path string, poduid types.UID, bytes *resource.Quantity) error { |
所以emptyDir
是弱限制配额,不会强制限制写入,但是利用prjQuota
统计临时存储使用量,当超过阈值时,触发pod的驱逐,从而导致临时存储的数据全部丢失,驱逐后的pod不会超过临时了。
1 | guarantee-gpu0-6c-6c5644c9cd-5n88n 1/1 Running 0 7s |
亲测,kubelet和docker data-root 必须同一个分区,否则不会触发eviction
总结
磁盘配额以及volume的大小或者k8s csi挂载的volume的大小,都是通过文件系统的
quota
功能实现的,这个大小是写在host fs
中的,必须是操作系统做限制,否则上层岂不是一直写block了。project quota
特性可以统计磁盘使用量,当超过阈值时写入数据hang住或者直接返回No space left on device
project quota
实际限制的目录是<data-root>/overlay2/<grapthID>
和<data-root>/overlay2/<graphID>-init
, 只有这两个目录是可写的,该目录下的lowerDir
可能有几个G且是只读的, 不在quota配额范围),quota限制的是增量的数据,分成全局配额或者容器粒度的配额。每一个容器对应一条project记录,开启限额, 每个容器/project 互不影响
k8s empty 卷不支持强配额,而只是利用project quota 统计目录卷的存储容量(mount option 带了projQuota, 但是没有setQuota的数值,所以有一个间隙可以写入更多的数据,没在fs侧设置而是在k8s侧进行了数量控制,当超过则驱逐pod)
在容器中
df -Th
会读取/sys/fs/
(共享host侧的)查看container rootfs
的大小, 如果grapthID的目录
设置了quota
, 则显示的就是该quota
, 如果没有配额, 显示的是data root
所在分区,其实就是parent dir 限制了quota时, 其子dir也限制了大小,则优先使用子dir的quota, quota就是普通volume的size概念# xfs_quota -xc print
及xfs_quota -xc 'report -bh'
限制节点所有挂在点的配额即volume size
/etc/projects
和/etc/projid
文件记录project
信息