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

原创 2018年04月17日 14:10:20
摘要: 这是本系列的第2篇内容,将介绍在Docker和Kubernetes环境中解决遗留应用无法识别容器资源限制的问题。
本系列文章记录了企业客户在应用Kubernetes时的一些常见问题

这是本系列的第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.rpmyum 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/bash root@f4a2a01e61cd:/# free total used free shared buff/cache availableMem: 262144 708 261436 2364 0 261436Swap: 0 0 0

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

lxcfs 的 Kubernetes实践

一些同学问过如何在Kubernetes集群环境中使用lxcfs,我们将给大家一个示例方法供参考。
首先我们要在集群节点上安装并启动lxcfs,我们将用Kubernetes的方式,用利用容器和DaemonSet方式来运行 lxcfs FUSE文件系统。

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

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

其manifest文件如下

apiVersion: apps/v1beta2kind: DaemonSetmetadata: name: lxcfs labels: app: lxcfsspec: selector: matchLabels: app: lxcfs template: metadata: labels: app: lxcfs spec: hostPID: true tolerations: - key: node-role.kubernetes.io/master effect: NoSchedule containers: - name: lxcfs image: registry.cn-hangzhou.aliyuncs.com/denverdino/lxcfs:2.0.8 imagePullPolicy: Always securityContext: privileged: true volumeMounts: - name: rootfs mountPath: /host volumes: - name: rootfs hostPath: path: /
注: 由于 lxcfs FUSE需要共享系统的PID名空间以及需要特权模式,所有我们配置了相应的容器启动参数。

可以通过如下命令在所有集群节点上自动安装、部署完成 lxcfs,是不是很简单?:-)
kubectl create -f lxcfs-daemonset.yaml
那么如何在Kubernetes中使用 lxcfs 呢?和上文一样,我们可以在Pod的定义中添加对 /proc 下面文件的 volume(文件卷)和对 volumeMounts(文件卷挂载)定义。然而这就让K8S的应用部署文件变得比较复杂,有没有办法让系统自动完成相应文件的挂载呢?

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

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

其 manifest 文件如下
apiVersion: rbac.authorization.k8s.io/v1kind: ClusterRolemetadata: name: lxcfs-initializer-default namespace: defaultrules:- apiGroups: ["*"] resources: ["deployments"] verbs: ["initialize", "patch", "watch", "list"]---apiVersion: v1kind: ServiceAccountmetadata: name: lxcfs-initializer-service-account namespace: default---kind: ClusterRoleBindingapiVersion: rbac.authorization.k8s.io/v1metadata: name: lxcfs-initializer-role-bindingsubjects:- kind: ServiceAccount name: lxcfs-initializer-service-account namespace: defaultroleRef: kind: ClusterRole name: lxcfs-initializer-default apiGroup: rbac.authorization.k8s.io---apiVersion: apps/v1beta1kind: Deploymentmetadata: initializers: pending: [] labels: app: lxcfs-initializer name: lxcfs-initializerspec: replicas: 1 template: metadata: labels: app: lxcfs-initializer name: lxcfs-initializer spec: serviceAccountName: lxcfs-initializer-service-account containers: - name: lxcfs-initializer image: registry.cn-hangzhou.aliyuncs.com/denverdino/lxcfs-initializer:0.0.2 imagePullPolicy: Always args: - "-annotation=initializer.kubernetes.io/lxcfs" - "-require-annotation=true"---apiVersion: admissionregistration.k8s.io/v1alpha1kind: InitializerConfigurationmetadata: name: lxcfs.initializerinitializers: - name: lxcfs.initializer.kubernetes.io rules: - apiGroups: - "*" apiVersions: - "*" resources: - deployments

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

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

kubectl apply -f lxcfs-initializer.yaml

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

其manifest文件如下
apiVersion: apps/v1beta1kind: Deploymentmetadata: annotations: "initializer.kubernetes.io/lxcfs": "true" labels: app: web name: webspec: replicas: 1 template: metadata: labels: app: web name: web spec: containers: - name: web image: httpd:2 imagePullPolicy: Always resources: requests: memory: "256Mi" cpu: "500m" limits: memory: "256Mi" cpu: "500m"

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

$ kubectl create -f web.yaml deployment "web" created$ kubectl get podNAME READY STATUS RESTARTS AGEweb-7f6bc6797c-rb9sk 1/1 Running 0 32s$ kubectl exec web-7f6bc6797c-rb9sk free total used free shared buffers cachedMem: 262144 2876 259268 2292 0 304-/+ buffers/cache: 2572 259572Swap: 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的开发者体验,帮助用户关注云端应用价值创新。

阅读更多干货好文,请关注扫描以下二维码: 

基于LXCFS增强docker容器隔离性的分析

1. 背景 容器虚拟化带来轻量高效,快速部署的同时,也因其隔离性不够彻底,给用户带来一定程度的使用不便。Docker容器由于Linux内核namespace本身还不够完善的现状(例如,没有cgr...
  • S1234567_89
  • S1234567_89
  • 2016-02-23 14:40:55
  • 2135

[Docker] Centos 基于 lxcfs 增强 Docker 隔离能力 (docker free 显示问题)

一、 背景介绍         由于 Docker 自身的原因,在容器内执行诸如 free 、top等命令时,看到的却是宿主机的相关状态信息,给监控带来了困扰         本文介绍通过在宿主机安装...
  • shida_csdn
  • shida_csdn
  • 2018-01-29 16:05:44
  • 232

Kubernetes技术分析之资源管理

原文:http://www.open-open.com/lib/view/open1439386169661.html Docker的流行激活了一直不温不火的PaaS,随着而来的是各类Mic...
  • stonexmx
  • stonexmx
  • 2017-05-23 10:50:13
  • 557

kubernetes资源对象--pod和job

pod Pod是K8S的最小操作单元,一个Pod可以由一个或多个容器组成;整个K8S系统都是围绕着Pod展开的,比如如何部署运行Pod、如何保证Pod的数量、如何访问Pod等。 特点 Pod是能够被创...
  • liyingke112
  • liyingke112
  • 2017-08-01 18:03:39
  • 1547

Kubernetes容器编排的三大支柱

资源管理、调度和负载均衡作为K8s的三大支柱,它们是如何在K8s中实现的?它们又是如何相互作用,以提供高效的容器工作负载管理的?...
  • RancherLabs
  • RancherLabs
  • 2017-05-25 08:50:08
  • 2340

kubernetes--资源管理

kubernetes的资源管理分为资源请求(request)和资源限制(limit),资源请求能够保证Pod有足够的资源来运行,而资源限制则是防止某个Pod无限制地使用资源,导致其他Pod崩溃。kub...
  • liyingke112
  • liyingke112
  • 2017-08-21 17:09:28
  • 621

从kubernetes看如何设计超大规模资源调度系统

在大数据时代,为了合理分配大规模集群的资源,满足日益增多的服务和任务的资源需求,出现了诸如Borg,Mesos,YARN,Omega等一系列的集群资源调度系统。从系统的架构来考虑,可以把它们划分为集中...
  • horsefoot
  • horsefoot
  • 2016-06-03 11:13:32
  • 20844

kubernetes调度详解

经过六个月的持续优化,kubernetes宣布1.2版本已经可以支持1000+节点的群集,并且有相当出色的响应能力,这对kubernetes来说是一个重大的改进。随着kubernetes集群规模的扩大...
  • horsefoot
  • horsefoot
  • 2016-04-27 18:19:29
  • 12768

从 Kubernetes 谈容器网络

Pod 首先,Kubernetes 中的基本单元是 Pod,而非 Docker 容器。 Pod 是一组共享了下面资源的容器: 进程命名空间 网络命名空间 IPC 命名空间 UTS 命名空间 简单...
  • yeasy
  • yeasy
  • 2015-06-10 16:54:06
  • 6141

kubernetes1.2如何操作Docker

本次分析的kubernetes版本号:v1.2.1-beta.0。 Kubernetes对Docker的管理是通过一个第三方组件实现的,这个第三方组件就是go-dockerclient,这是一个GO...
  • horsefoot
  • horsefoot
  • 2016-04-27 18:09:17
  • 20398
收藏助手
不良信息举报
您举报文章:Kubernetes之路 2 - 利用LXCFS提升容器资源可见性
举报原因:
原因补充:

(最多只允许输入30个字)