溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Kubernetes容器隔離問題實例分析

發(fā)布時間:2022-01-11 17:58:22 來源:億速云 閱讀:122 作者:iii 欄目:云計算

這篇文章主要講解了“Kubernetes容器隔離問題實例分析”,文中的講解內(nèi)容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“Kubernetes容器隔離問題實例分析”吧!

背景

  • 容器中看到的/proc偽文件系統(tǒng)的信息是宿主的/proc,沒有隔離/proc 意味著獲取不到容器中進程相關的proc信息。另外,一些需要讀取proc信息的應用,會獲取到錯誤的數(shù)據(jù)。 /proc/meminfo,/proc/cpuinfo, /proc/stat, /proc/uptime, /proc/loadavg

  • 用戶UID/GID的映射,導致容器中的進程具有宿主上相同uid/gid用戶的權限

需求分析

方案調(diào)研

Docker社區(qū)里有討論過類似的問題,
https://github.com/docker/docker/issues/8427,
可以通過kernel patch或者bind mount /proc 來實現(xiàn)。 

淘寶團隊在幾年前曾經(jīng)發(fā)過一個kernel patch 
https://github.com/alibaba/taobao-kernel/blob/master/patches.taobao/overlayfs-0005-vfs-introduce-clone_private_mount.patch

業(yè)界討論主要有以下幾種方案:

## 方案一、

-  直接修改proc文件系統(tǒng) 

- https://lkml.org/lkml/2012/5/28/299

- mount -t proc -o meminfo-from-cgroup none /path/to/container/proc

缺點:不可能要求并入內(nèi)核




## 方案二、

- Procg 方案: 把文件系統(tǒng)掛載進容器,替代原本的proc文件系統(tǒng)

-  通過讀cgroup指定的信息替代原本的/proc/meminfo信息

- https://github.com/fabiokung/procg/

缺點:內(nèi)核的cgroup中沒有公開讀取內(nèi)存數(shù)據(jù)函數(shù)接口




## 方案三、

基于lxcfs的docker容器procps軟件包升級方案 ——修改free、top、uptime等源碼

缺點:不是一個廣泛接受的方案,不說自己修改命令可能產(chǎn)生的bug 和成本。不同的linux版本,可能會需要不同的補丁。

解決方案

為LXC準備的FUSE文件系統(tǒng), 提供了如下的特性:

* a cgroupfs compatible view for unprivileged containers
* a set of cgroup-aware files:
    * cpuinfo
    * meminfo
    * stat
    * uptime

用戶空間文件系統(tǒng) (Filesystem in Userspace, FUSE)

用戶空間文件系統(tǒng) 是操作系統(tǒng)中的概念,指完全在用戶態(tài)實現(xiàn)的文件系統(tǒng)。

目前Linux通過內(nèi)核模塊對此進行支持。一些文件系統(tǒng)如ZFS,glusterfs使用FUSE實現(xiàn)。

Kubernetes容器隔離問題實例分析

FUSE的工作原理如上圖所示。假設基于FUSE的用戶態(tài)文件系統(tǒng)hello掛載在/tmp/fuse目錄下。當應用層程序要訪問/tmp/fuse下的文件時,通過glibc中的函數(shù)進行系統(tǒng)調(diào)用,處理這些系統(tǒng)調(diào)用的VFS中的函數(shù)會調(diào)用FUSE在內(nèi)核中的文件系統(tǒng);內(nèi)核中的FUSE文件系統(tǒng)將用戶的請求,發(fā)送給用戶態(tài)文件系統(tǒng)hello;用戶態(tài)文件系統(tǒng)收到請求后,進行處理,將結果返回給內(nèi)核中的FUSE文件系統(tǒng);最后,內(nèi)核中的FUSE文件系統(tǒng)將數(shù)據(jù)返回給用戶態(tài)程序。

  • Linux內(nèi)核從2.6.14支持通過FUSE模塊

  • 用戶空間實現(xiàn)文件系統(tǒng)

  • libfuse: 用戶空間的fuse庫, 非特權用戶可訪問。

LXCFS - 基于FUSE實現(xiàn)的用戶空間文件系統(tǒng)

  • 站在文件系統(tǒng)的角度: 通過調(diào)用libfuse庫內(nèi)核的FUSE模塊交互實現(xiàn)

  • 兩個基本功能

  • 讓每個容器有自身的cgroup文件系統(tǒng)視圖,類似 Cgroup Namespace

  • 提供容器內(nèi)部虛擬的proc文件系統(tǒng)

LXCFS 視角

從main函數(shù)可以看出,初始化的過程包括:

  1. 將運行時工作目錄/run/lxcfs/controllers/ 掛載到 tmpfs文件系統(tǒng)

  2. 將當前系統(tǒng)的各個group子系統(tǒng)重新掛載到 /run/lxcfs/controllers/ 目錄

  3. 調(diào)用libfuse庫的主函數(shù) fuse_main(), 指定用戶態(tài)文件系統(tǒng)的目標目錄- /var/lib/lxcfs/

  4. 使用struct fuse_operations 的ops方法, 與內(nèi)核中的FUSE模塊交互。 lxcfs.c:701

Kubernetes容器隔離問題實例分析

容器視角

  • 把虛擬proc文件系統(tǒng)掛載到docker容器

Kubernetes容器隔離問題實例分析

  • 用戶在容器中讀取/proc/meminfo ,cpuinfo 等信息

Kubernetes容器隔離問題實例分析

  • 在 proc_meminfo_read 操作中實現(xiàn) 讀取meminfo

  • 過程: 拿到 meminfo進程的pid傳給 lxcfs --> 拿到pid的cgroup分組 --> host的/cgroup目錄對應進程的cgroup子系統(tǒng)信息

存在的問題以及如何解決

  1. LXCFS的部署問題以及帶來的影響和成本? 見如下補充的 LxcFS - k8s實踐

  2. 故障恢復,如何自動remount? 如果lxcfs進程重啟了,那么容器里的/proc/cpuinfo等等都會報transport connected failed 這個是因為/var/lib/lxcfs會刪除再重建,inode變了。所以參考豆瓣的做法,共享mount事件,重新給容器掛載

  • https://github.com/lxc/lxcfs/issues/193

  • https://github.com/alibaba/pouch/issues/140

User Namespace

解決什么問題?

  • 用戶UID/GID的映射,導致容器中的進程具有宿主上相同uid/gid用戶的權限

  • docker 從1.10版本 開始支持user namespace 隔離。使用參數(shù):DOCKER_OPTS="--userns-remap=default"

Kubernetes容器隔離問題實例分析

相關文檔鏈接:

  1. 基于LXCFS增強docker容器隔離性的分析 2015.12.9

  2. docker容器顯示問題及修復 2017-03-23

  3. lxc-1.0.9 lxcfs-2.0.0 fuse-2.8.7源碼詳細注釋分析

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

  5. Kubernetes Initializers

  6. 看看大阿里pouch怎么解決remount這個問題

lxcfs 的 Kubernetes實踐

注:以下內(nèi)容來自文檔鏈接4,內(nèi)容有稍作修改

首先我們要在集群節(jié)點上安裝并啟動lxcfs,我們將用Kubernetes的方式,用利用容器和DaemonSet方式來運行 lxcfs FUSE文件系統(tǒng)。

本文所有示例代碼可以通過以下地址從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: dockerhub.nie.netease.com/whale/lxcfs:2.0.8
        imagePullPolicy: Always
        securityContext:
          privileged: true
        volumeMounts:
        - name: rootfs
          mountPath: /host
      volumes:
      - name: rootfs
        hostPath:
          path: /

注: 由于 lxcfs FUSE需要共享系統(tǒng)的PID名空間以及需要特權模式,所有我們配置了相應的容器啟動參數(shù)。

可以通過如下命令在所有集群節(jié)點上自動安裝、部署完成 lxcfs,是不是很簡單?:-)

kubectl create -f lxcfs-daemonset.yaml

那么如何在Kubernetes中使用 lxcfs 呢?和上文一樣,我們可以在Pod的定義中添加對 /proc 下面文件的 volume(文件卷)和對 volumeMounts(文件卷掛載)定義。然而這就讓K8S的應用部署文件變得比較復雜,有沒有辦法讓系統(tǒng)自動完成相應文件的掛載呢?

Kubernetes提供了 Initializer 擴展機制,可以用于對資源創(chuàng)建進行攔截和注入處理,我們可以借助它優(yōu)雅地完成對lxcfs文件的自動化掛載。

其 manifest 文件如下

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: lxcfs-initializer-default
  namespace: kube-system
rules:
- apiGroups: ["*"]
  resources: ["deployments"]
  verbs: ["initialize", "patch", "watch", "list"]
---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: lxcfs-initializer-service-account
  namespace: kube-system
---
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: lxcfs-initializer-role-binding
subjects:
- kind: ServiceAccount
  name: lxcfs-initializer-service-account
  namespace: kube-system
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: dockerhub.nie.netease.com/whale/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 部署描述,首先我們創(chuàng)建了service account lxcfs-initializer-service-account,并對其授權了 "deployments" 資源的查找、更改等權限。然后我們部署了一個名為 "lxcfs-initializer" 的Initializer,利用上述SA啟動一個容器來處理對 "deployments" 資源的創(chuàng)建,如果deployment中包含 initializer.kubernetes.io/lxcfs為true的注釋,就會對該應用中容器進行文件掛載

我們可以執(zhí)行如下命令,部署完成之后就可以愉快地玩耍了

kubectl apply -f lxcfs-initializer.yaml

下面我們部署一個簡單的Apache應用,為其分配256MB內(nèi)存,并且聲明了如下注釋 "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 文件都已經(jīng)掛載正確

$ 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 實現(xiàn)類似的功能,篇幅有限。本文不再贅述了。

感謝各位的閱讀,以上就是“Kubernetes容器隔離問題實例分析”的內(nèi)容了,經(jīng)過本文的學習后,相信大家對Kubernetes容器隔離問題實例分析這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

AI