在使用docker的时候,为了限制某个容器使用的资源,常常使用cgroup的资源限制来限制容器最大能使用的CPU和内存资源等。对于一些app,它往往会自动检测当前环境的最大资源数量,然后根据这个数据来合理分配资源。问题就出在这上面,当给容器限制之后,它在容器内能检测到的依然是host相关的资源信息。例如host有16G内存,限制一个容器最多使用2G,在容器里面通过/proc/meminfo看依然是16G内存。这就导致往往app会分配超过2G的内存从而被cgroup杀掉。 LXCFS的出现就是为了解决这个问题,让容器正确的意识到自己被限制的资源。
LXCFS文件系统
lxcfs是一个小型的fuse文件系统(https://github.com/lxc/lxcfs),专门为了处理容器对以下文件路径的请求。
/proc/cpuinfo
/proc/diskstats
/proc/meminfo
/proc/stat
/proc/swaps
/proc/uptime
/sys/devices/system/cpu/online
当容器启动时,/proc/xxx会被挂载成host上lxcfs的目录。app读取/proc/meminfo的信息时,请求就会被导向lxcfs,而lxcfs就会通过cgroup的信息来返回正确的值给容器内的app。整个流程如下图:
在kubernetes中也有同样的问题
同样,kubernetes就算使用了limit限制资源的使用,pod依然不能正确的拿到资源限制信息。例如使用下面的yaml来创建一个pod
apiVersion: v1
kind: Pod
metadata:
name: ubuntu
labels:
name: ubuntu
spec:
containers:
- name: ubuntu
image: ubuntu:18.04
command: [ "/bin/bash", "-c", "--" ]
args: [ "while true; do sleep 30; done;" ]
resources:
limits:
memory: "200Mi"
requests:
memory: "100Mi"
登录到pod之后查看meminfo的信息,可以看到拿到的还是host的信息
[root@k8s-master]# kubectl exec -it ubuntu /bin/bash
root@ubuntu:/# free -m
total used free shared buff/cache available
Mem: 16046 1623 9958 202 4464 13890
Swap: 0 0 0
在kubernetes中安装lxcfs组件
阿里云提供了kubernetes的解决方案,能够通过yaml自动化安装和启用lxcfs。
国外仓库:https://github.com/denverdino/lxcfs-admission-webhook
国内镜像:mirrors_denverdino/lxcfs-admission-webhook
部署:
[root@k8s-master]# git clone https://gitee.com/mirrors_denverdino/lxcfs-admission-webhook
[root@k8s-master lxcfs-admission-webhook]# kubectl apply -f deployment/lxcfs-daemonset.yaml
[root@k8s-master lxcfs-admission-webhook]# deployment/install.sh
然后就能看到在每个节点都会有一个lxcfs的pod,以及一个lxcfs-admission-webhook的pod。后面这个pod就是在kubernetes中通过监听事件来正确处理pod的lxcfs挂载的控制进程。
[root@k8s-master]# kubectl get pods
NAME READY STATUS RESTARTS AGE
lxcfs-2b28f 1/1 Running 0 28h
lxcfs-admission-webhook-deployment-6fbb88b975-xbxdz 1/1 Running 0 27h
lxcfs-h5pnx 1/1 Running 0 28h
如果有lxcfs的pod无法启动,会报如下错误:
[root@k8s-master]# kubectl get pod
NAME READY STATUS RESTARTS AGE
lxcfs-admission-webhook-deployment-845cdc8c6-54r92 1/1 Running 0 6m36s
lxcfs-rnbwn 1/1 Running 6 6m43s
lxcfs-t9qwp 0/1 CrashLoopBackOff 6 6m43s
[root@k8s-master deployment]# kubectl logs lxcfs-t9qwp -f
/usr/local/bin/lxcfs: error while loading shared libraries: libfuse.so.2: cannot open shared object file: No such file or directory
说明node节点没有libfuse.so.2动态库文件,需要在node节点安装fuse组件:
[root@k8s-node03 ~]# yum install fuse fuse-devel fuse-lib -y
在kubernetes环境中验证lxcfs
在安装完之后,还需要针对你想要开启lxcfs的namespace去开启这个机制,用如下命令:
[root@k8s-master]# kubectl label namespace default lxcfs-admission-webhook=enabled
部署一个测试模板pod,测试拿meminfo的信息
[root@k8s-master lxcfs-admission-webhook]# kubectl apply -f deployment/web.yaml
[root@k8s-master]# kubectl get pod
NAME READY STATUS RESTARTS AGE
lxcfs-admission-webhook-deployment-f4bdd6f66-5wrlg 1/1 Running 0 8m29s
lxcfs-pqs2d 1/1 Running 0 55m
lxcfs-zfh99 1/1 Running 0 55m
web-7c5464f6b9-6zxdf 1/1 Running 0 8m10s
web-7c5464f6b9-nktff 1/1 Running 0 8m10s
[root@k8s-master]# kubectl exec -ti web-7c5464f6b9-6zxdf sh
# free
total used free shared buffers cached
Mem: 262144 2744 259400 0 0 312
-/+ buffers/cache: 2432 259712
Swap: 0 0 0
现在再来用之前的模版创建一个pod,并尝试拿meminfo的信息
[root@k8s-master]# kubectl exec -it ubuntu /bin/bash
root@ubuntu:/# free -m
total used free shared buff/cache available
Mem: 200 3 196 0 0 196
Swap: 0 0 0
这一次可以看到pod内部正确的拿到了自己能使用的内存资源总共200M
删除lxcfs组件包
先删除lxcfs-admission-webhook组件
[root@k8s-master lxcfs-admission-webhook]# deployment/uninstall.sh
再从集群中删除lxcfs组件
[root@k8s-master]# kubectl delete -f deployment/lxcfs-daemonset.yaml