Linux运维知识之Kubernetes之路 2 – 利用LXCFS提升容器资源可见性
小标 2019-06-20 来源 : 阅读 1312 评论 0

摘要:本文主要向大家介绍了Linux运维知识之Kubernetes之路 2 – 利用LXCFS提升容器资源可见性,通过具体的内容向大家展现,希望对大家学习Linux运维知识有所帮助。

本文主要向大家介绍了Linux运维知识之Kubernetes之路 2 – 利用LXCFS提升容器资源可见性,通过具体的内容向大家展现,希望对大家学习Linux运维知识有所帮助。

Linux运维知识之Kubernetes之路 2 – 利用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/bash

root@f4a2a01e61cd:/# free
              total        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: lxcfs
  labels:
    app: lxcfs
spec:
  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/v1
kind: ClusterRole
metadata:
  name: lxcfs-initializer-default
  namespace: default
rules:
- apiGroups: ["*"]
  resources: ["deployments"]
  verbs: ["initialize", "patch", "watch", "list"]
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: lxcfs-initializer-service-account
  namespace: default
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: lxcfs-initializer-role-binding
subjects:
- kind: ServiceAccount
  name: lxcfs-initializer-service-account
  namespace: default
roleRef:
  kind: ClusterRole
  name: lxcfs-initializer-default
  apiGroup: rbac.authorization.k8s.io
---
apiVersion: apps/v1beta1
kind: Deployment
metadata:
  initializers:
    pending: []
  labels:
    app: lxcfs-initializer
  name: lxcfs-initializer
spec:
  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/v1alpha1
kind: InitializerConfiguration
metadata:
  name: lxcfs.initializer
initializers:
  - 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/v1beta1
kind: Deployment
metadata:
  annotations:
    "initializer.kubernetes.io/lxcfs": "true"
  labels:
    app: web
  name: web
spec:
  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 pod
NAME                                 READY     STATUS    RESTARTS   AGE
web-7f6bc6797c-rb9sk                 1/1       Running   0          32s
$ kubectl exec web-7f6bc6797c-rb9sk free
             total       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的开发者体验,帮助用户关注云端应用价值创新。


本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注系统运维Linux频道!


本文由 @小标 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式AI+学习就业服务平台 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved