天天看點

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的示意圖如下

Kubernetes之路 2 - 利用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"

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的開發者體驗,幫助使用者關注雲端應用價值創新。

本文轉自SegmentFault-

Kubernetes之路 2 - 利用LXCFS提升容器資源可見性