本系列文章记录了企业客户在应用Kubernetes时的一些常见问题

  • 第一篇:Java应用资源限制的迷思
  • 第二篇:利用LXCFS提升容器资源可见性
  • 第三篇:解决服务依赖

这是本系列的第2篇内容,将介绍在Docker和Kubernetes环境中解决遗留应用无法识别容器资源限制的问题。

Linuxs利用Cgroup实现了对容器的资源限制,但在容器内部依然缺省挂载了宿主机上的procfs/proc目录,其包含如:meminfo, cpuinfo,stat, uptime等资源信息。一些监控工具如free/top或遗留应用还依赖上述文件内容获取资源配置和使用情况。当它们在容器中运行时,就会把宿主机的资源状态读取出来,引起错误和不便。

LXCFS简介

社区中常见的做法是利用 lxcfs来提供容器中的资源可见性。lxcfs 是一个开源的FUSE(用户态文件系统)实现来支持LXC容器,它也可以支持Docker容器。

LXCFS通过用户态文件系统,在容器中提供下列 procfs 的文件。

/proc/cpuinfo
/proc/diskstats
/proc/meminfo
/proc/stat
/proc/swaps
/proc/uptime

LXCFS的示意图如下

比如,把宿主机的 /var/lib/lxcfs/proc/memoinfo 文件挂载到Docker容器的/proc/meminfo位置后。容器中进程读取相应文件内容时,LXCFS的FUSE实现会从容器对应的Cgroup中读取正确的内存限制。从而使得应用获得正确的资源约束设定。

Docker环境下LXCFS使用

注:

  • 本文采用CentOS 7.4作为测试环境,并已经开启FUSE模块支持。
  • Docker for Mac/Minikube等开发环境由于采用高度剪裁过的操作系统,无法支持FUSE,并运行LXCFS进行测试。

安装 lxcfs 的RPM包

wget https://copr-be.cloud.fedoraproject.org/results/ganto/lxd/epel-7-x86_64/00486278-lxcfs/lxcfs-2.0.5-3.el7.centos.x86_64.rpm
yum install lxcfs-2.0.5-3.el7.centos.x86_64.rpm  

启动 lxcfs

lxcfs /var/lib/lxcfs &  

测试

$docker run -it -m 256m \-v /var/lib/lxcfs/proc/cpuinfo:/proc/cpuinfo:rw \-v /var/lib/lxcfs/proc/diskstats:/proc/diskstats:rw \-v /var/lib/lxcfs/proc/meminfo:/proc/meminfo:rw \-v /var/lib/lxcfs/proc/stat:/proc/stat:rw \-v /var/lib/lxcfs/proc/swaps:/proc/swaps:rw \-v /var/lib/lxcfs/proc/uptime:/proc/uptime:rw \ubuntu:16.04 /bin/bashroot@f4a2a01e61cd:/# freetotal        used        free      shared  buff/cache   available
Mem:         262144         708      261436        2364           0      261436
Swap:             0           0           0

我们可以看到total的内存为256MB,配置已经生效。

lxcfs 的 Kubernetes实践

一些同学问过如何在Kubernetes集群环境中使用lxcfs,我们将给大家一个示例方法供参考。

首先我们要在集群节点上安装并启动lxcfs,我们将用Kubernetes的方式,用利用容器和DaemonSet方式来运行 lxcfs FUSE文件系统。

本文所有示例代码可以通过以下地址从Github上获得

git clone https://github.com/denverdino/lxcfs-initializer
cd lxcfs-initializer

其manifest文件如下

apiVersion: apps/v1beta2
kind: DaemonSet
metadata:name: lxcfslabels:app: lxcfs
spec:selector:matchLabels:app: lxcfstemplate:metadata:labels:app: lxcfsspec:hostPID: truetolerations:- key: node-role.kubernetes.io/mastereffect: NoSchedulecontainers:- name: lxcfsimage: registry.cn-hangzhou.aliyuncs.com/denverdino/lxcfs:2.0.8-1imagePullPolicy: AlwayssecurityContext:privileged: truevolumeMounts:- name: cgroupmountPath: /sys/fs/cgroup- name: lxcfsmountPath: /var/lib/lxcfsmountPropagation: Bidirectional- name: usr-localmountPath: /usr/localvolumes:- name: cgrouphostPath:path: /sys/fs/cgroup- name: usr-localhostPath:path: /usr/local- name: lxcfshostPath:path: /var/lib/lxcfstype: DirectoryOrCreate

注: 由于 lxcfs FUSE需要共享系统的PID名空间以及需要特权模式,所有我们配置了相应的容器启动参数。

可以通过如下命令在所有集群节点上自动安装、部署完成 lxcfs,是不是很简单?:-)

kubectl apply -f lxcfs-daemonset.yaml

那么如何在Kubernetes中使用 lxcfs 呢?和上文一样,我们可以在Pod的定义中添加对 /proc 下面文件的 volume(文件卷)和对 volumeMounts(文件卷挂载)定义。然而这就让K8S的应用部署文件变得比较复杂,有没有办法让系统自动完成相应文件的挂载呢?

Kubernetes提供了 Initializer 扩展机制,可以用于对资源创建进行拦截和注入处理,我们可以借助它优雅地完成对lxcfs文件的自动化挂载。

注: 阿里云Kubernetes集群,已经默认开启了对 Initializer 的支持,如果是在自建集群上进行测试请参见文档开启相应功能

其 manifest 文件如下

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:name: lxcfs-initializer-defaultnamespace: default
rules:
- apiGroups: ["*"]resources: ["deployments"]verbs: ["initialize", "update", "patch", "watch", "list"]
---
apiVersion: v1
kind: ServiceAccount
metadata:name: lxcfs-initializer-service-accountnamespace: default
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:name: lxcfs-initializer-role-binding
subjects:
- kind: ServiceAccountname: lxcfs-initializer-service-accountnamespace: default
roleRef:kind: ClusterRolename: lxcfs-initializer-defaultapiGroup: rbac.authorization.k8s.io
---
apiVersion: apps/v1
kind: Deployment
metadata:initializers:pending: []labels:app: lxcfs-initializername: lxcfs-initializer
spec:replicas: 1selector:matchLabels:app: lxcfs-initializertemplate:metadata:labels:app: lxcfs-initializerspec:serviceAccountName: lxcfs-initializer-service-accountcontainers:- name: lxcfs-initializerimage: registry.cn-hangzhou.aliyuncs.com/denverdino/lxcfs-initializer:0.0.3imagePullPolicy: Alwaysargs:- "-annotation=initializer.kubernetes.io/lxcfs"- "-require-annotation=true"
---
apiVersion: admissionregistration.k8s.io/v1alpha1
kind: InitializerConfiguration
metadata:name: lxcfs.initializer
initializers:- name: lxcfs.initializer.kubernetes.iorules:- apiGroups:- "*"apiVersions:- "*"resources:- deployments

注: 这是一个典型的 Initializer 部署描述,首先我们创建了service account lxcfs-initializer-service-account,并对其授权了 "deployments" 资源的查找、更改等权限。然后我们部署了一个名为 "lxcfs-initializer" 的Initializer,利用上述SA启动一个容器来处理对 "deployments" 资源的创建,如果deployment中包含 initializer.kubernetes.io/lxcfstrue的注释,就会对该应用中容器进行文件挂载

我们可以执行如下命令,部署完成之后就可以愉快地玩耍了

kubectl apply -f lxcfs-initializer.yaml

下面我们部署一个简单的Apache应用,为其分配256MB内存,并且声明了如下注释 "initializer.kubernetes.io/lxcfs": "true"

其manifest文件如下

apiVersion: apps/v1
kind: Deployment
metadata:annotations:"initializer.kubernetes.io/lxcfs": "true"labels:app: webname: web
spec:replicas: 1selector:matchLabels:app: webtemplate:metadata:labels:app: webspec:containers:- name: webimage: httpd:2.4.32imagePullPolicy: Alwaysresources:requests:memory: "256Mi"cpu: "500m"limits:memory: "256Mi"cpu: "500m"

我们可以用如下方式进行部署和测试

$ kubectl apply -f web.yaml
deployment "web" created$ kubectl get pod
NAME                                 READY     STATUS    RESTARTS   AGE
web-7f6bc6797c-rb9sk                 1/1       Running   0          32s
$ kubectl exec web-7f6bc6797c-rb9sk freetotal       used       free     shared    buffers     cached
Mem:        262144       2876     259268       2292          0        304
-/+ buffers/cache:       2572     259572
Swap:            0          0          0

我们可以看到 free 命令返回的 total memory 就是我们设置的容器资源容量。

我们可以检查上述Pod的配置,果然相关的 procfs 文件都已经挂载正确

$ kubectl describe pod web-7f6bc6797c-rb9sk
...Mounts:/proc/cpuinfo from lxcfs-proc-cpuinfo (rw)/proc/diskstats from lxcfs-proc-diskstats (rw)/proc/meminfo from lxcfs-proc-meminfo (rw)/proc/stat from lxcfs-proc-stat (rw)
...

在Kubernetes中,还可以通过 Preset 实现类似的功能,篇幅有限。本文不再赘述了。

总结

本文介绍了通过 lxcfs 提供容器资源可见性的方法,可以帮助一些遗留系统更好的识别容器运行时的资源限制。

同时,在本文中我们介绍了利用容器和DaemonSet的方式部署lxcfs FUSE,这不但极大简化了部署。也可以方便地利用Kubernetes自身的容器管理能力,支持lxcfs进程失效时自动恢复,在集群伸缩时也可以保证节点部署的一致性。这个技巧对于其他类似的监控或者系统扩展都是适用的。

另外我们介绍了利用Kubernetes的扩展机制 Initializer,实现对 lxcfs 文件的自动化挂载。整个过程对于应用部署人员是透明的,可以极大简化运维复杂度。同时利用类似的方法,我们可以灵活地定制应用部署的行为,满足业务的特殊要求。

阿里云Kubernetes服务 全球首批通过Kubernetes一致性认证,简化了Kubernetes集群生命周期管理,内置了与阿里云产品集成,也将进一步简化Kubernetes的开发者体验,帮助用户关注云端应用价值创新。

Kubernetes之路 2 - 利用LXCFS提升容器资源可见性相关推荐

  1. Kubernetes之路 3 - 解决服务依赖

    摘要: 在容器服务的客户群中,一个经常被问起的问题就是如何处理服务间依赖.本文介绍了常见的解决方法来实现服务的依赖检查,还进一步用示例展示了如何利用init container, liveness/r ...

  2. Kubernetes之路 1 - Java应用资源限制的迷思

    摘要: 随着容器技术的成熟,越来越多的企业客户在企业中选择Docker和Kubernetes作为应用平台的基础.然而在实践过程中,还会遇到很多具体问题.本文分析并解决了Java应用在容器使用过程中关于 ...

  3. Docker安全加固——利用LXCFS增强docker容器隔离性和资源可见性

    前言 lxcfs是一个开源的FUSE(用户态文件系统)实现来支持LXC容器. LXCFS通过用户态文件系统,在容器中提供下列 procfs 的文件: /proc/cpuinfo /proc/disks ...

  4. 容器编排技术 -- Kubernetes 给容器和Pod分配CPU资源

    容器编排技术 -- Kubernetes 给容器和Pod分配CPU资源 1 Before you begin 2 创建一个命名空间 3 声明一个CPU申请和限制 4 CPU 单位 5 请求的CPU超出 ...

  5. 容器编排技术 -- Kubernetes 给容器和Pod分配内存资源

    容器编排技术 -- Kubernetes 给容器和Pod分配内存资源 1 Before you begin 2 创建一个命名空间 3 配置内存申请和限制 4 超出容器的内存限制 5 配置超出节点能力范 ...

  6. 利用网络现有资源 制作 swf动画

    利用网络现有资源 制作 swf动画 想设计一段flash,可是不知无从下手,刚好网上找到一个内容接近的,便把它down下来,利用这个现成的资源进行修改.     问题出现了,就是如何修改swf文件?我 ...

  7. WPF中利用DynamicResource动态资源和资源字典实现软件中英文切换

    在一个项目中,有时候会遇到不同国家或地区的软件用户,这样就需要对软件UI界面进行语言翻译,我们可以利用DynamicResource和资源字典来实现这一需求.我们可以将不同的语言字典封装到一个项目中, ...

  8. 如何利用局域网的资源打内线IP电话

    摘要:本文系统介绍局域网中IP电话的实现原理:在MCU中如何实现Lean TCP/IP协议;对电话的信令和语音信号怎样打成IP包,进行了具体阐述:并给出在实际中如何选出相应的支持芯片及完整的硬件设计模 ...

  9. 无缝融入 Kubernetes 生态 | 云原生网关支持 Ingress 资源

    Kubernetes Ingress 介绍 通常情况下,Kubernetes 集群内的网络环境与外部是隔离的,也就是说 Kubernetes 集群外部的客户端无法直接访问到集群内部的服务,这属于不同网 ...

最新文章

  1. Kendo UI 简单使用
  2. 关于JTAG——韦东山嵌入式Linux视频学习笔记02
  3. JMeter:报错(Content type 'text/plain;charset=UTF-8' not supported)
  4. FarMap诞生了!
  5. 怎么加载文件_Java虚拟机从入门到入土之JVM的类加载机制
  6. 英伟达推出新款“煤气灶”Titan RTX,售价近2万,并开源PhysX SDK
  7. 硬盘格式化后数据能否恢复 硬盘格式化数据恢复方法分享
  8. radius服务器认证系统,TekRadius(RADIUS服务器)
  9. 大数据学习笔记60:构建Spark机器学习系统
  10. 贱人工具箱使用技巧6——制作表格和表格居中
  11. 【一键激活win8.1系统】
  12. 【python学习笔记】Python的六种内置对象
  13. IP地址分类(A类 B类 C类 D类 E类)
  14. IEEE 投稿参考文献格式bib
  15. 羊年祝福语(羊年祝福大全)
  16. 用go来做图像相似性比较
  17. 算法分析----基础知识点
  18. 清明节微信公众号图文排版有哪些经典素材?
  19. keyshot怎么贴logo_KeyShot图文教程,三步教你如何使用添加有织纹的Logo
  20. 计算机网络原理与技术

热门文章

  1. 面试官:RabbitMQ本身不支持延迟队列,那你给我实现一个?
  2. 扒一扒 @SpringBootApplication 注解背后的奥秘!
  3. OMG:为什么用了索引,查询还是慢?
  4. SpringBoot2.0.3之quartz集成,不是你想的那样哦!
  5. 面试官问:Integer 如何实现节约内存和提升性能的?
  6. HttpClient连接池设置引发的一次雪崩
  7. fastjson又被发现漏洞,这次危害可导致服务瘫痪!
  8. 图解:什么是Raft算法?
  9. 终于有人把如何精通C++讲明白了!
  10. 看图学NumPy:掌握n维数组基础知识点,看这一篇就够了