摘要: 這是本系列的第2篇內容,將介紹在Docker和Kubernetes環境中解決遺留應用沒法識別容器資源限制的問題。node
本系列文章記錄了企業客戶在應用Kubernetes時的一些常見問題git
第一篇:Java應用資源限制的迷思
第二篇:利用LXCFS提高容器資源可見性
第三篇:解決服務依賴
這是本系列的第2篇內容,將介紹在Docker和Kubernetes環境中解決遺留應用沒法識別容器資源限制的問題。github
Linuxs利用Cgroup實現了對容器的資源限制,但在容器內部依然缺省掛載了宿主機上的procfs的/proc目錄,其包含如:meminfo, cpuinfo,stat, uptime等資源信息。一些監控工具如free/top或遺留應用還依賴上述文件內容獲取資源配置和使用狀況。當它們在容器中運行時,就會把宿主機的資源狀態讀取出來,引發錯誤和不便。web
LXCFS簡介docker
社區中常見的作法是利用 lxcfs來提供容器中的資源可見性。lxcfs 是一個開源的FUSE(用戶態文件系統)實現來支持LXC容器,它也能夠支持Docker容器。ubuntu
LXCFS經過用戶態文件系統,在容器中提供下列 procfs 的文件。centos
/proc/cpuinfo /proc/diskstats /proc/meminfo /proc/stat /proc/swaps /proc/uptime
LXCFS的示意圖以下api
好比,把宿主機的 /var/lib/lxcfs/proc/memoinfo 文件掛載到Docker容器的/proc/meminfo位置後。容器中進程讀取相應文件內容時,LXCFS的FUSE實現會從容器對應的Cgroup中讀取正確的內存限制。從而使得應用得到正確的資源約束設定。bash
Docker環境下LXCFS使用app
注:
安裝 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的開發者體驗,幫助用戶關注雲端應用價值創新。
閱讀更多幹貨好文,請關注掃描如下二維碼: