containerd 與安全沙箱的 Kubernetes 初體驗

作者 | 易立  阿里雲資深技術專家

containerd 是一個開源的行業標準容器運行時,關注於簡單、穩定和可移植,同時支持 Linux 和 Windows。

  • 2016 年 12 月 14 日,Docker 公司宣布將 Docker Engine 的核心組件 containerd 捐贈到一個新的開源社區獨立發展和運營。阿里雲、AWS、 Google、IBM 和 Microsoft 作為初始成員,共同建設 containerd 社區;

  • 2017 年 3 月,Docker 將 containerd 捐獻給 CNCF(雲原生計算基金會)。containerd 得到了快速的發展和廣泛的支持;

  • Docker 引擎已經將 containerd 作為容器生命周期管理的基礎,Kubernetes 也在 2018 年 5 月,正式支持 containerd 作為容器運行時管理器;

  • 2019 年 2 月,CNCF 宣布 containerd 畢業,成為生產可用的項目。

containerd 從 1.1 版本開始就已經內置了 Container Runtime Interface (CRI) 支持,進一步簡化了對 Kubernetes 的支持。其架構圖如下:

在 Kubernetes 場景下,containerd 與完整 Docker Engine 相比,具有更少的資源佔用和更快的啟動速度。

圖片來源:

紅帽主導的 cri-o 是與 containerd 競爭的容器運行時管理項目。containerd 與 cri-o 項目相比,在性能上具備優勢,在社區支持上也更加廣泛。

圖片來源:

更重要的是 containerd 提供了靈活的擴展機制,支持各種符合 OCI(Open Container Initiative)的容器運行時實現,比如 runc 容器(也是熟知的 Docker 容器)、KataContainer、gVisor 和 Firecraker 等安全沙箱容器。

在 Kubernetes 環境中,可以用不同的 API 和命令行工具來管理容器 / Pod、鏡像等概念。為了便於大家理解,我們可以用下圖說明如何利用不同層次的 API 和 CLI 管理容器生命周期管理。

  • Kubectl:是集群層面的命令行工具,支持 Kubernetes 的基本概念
  • :是針對節點上 CRI 的命令行工具
  • :是針對 containerd 的命令行工具

體驗

Minikube 是體驗 containerd 作為 Kubernetes 容器運行時的最簡單方式,我們下面將其作為 Kubernetes 容器運行時,並支持 runc 和 gvisor 兩種不同的實現。

早期由於網絡訪問原因,很多朋友無法直接使用官方 Minikube 進行實驗。在最新的 Minikube 1.5 版本中,已經提供了完善的配置化方式,可以幫助大家利用阿里雲的鏡像地址來獲取所需 Docker 鏡像和配置,同時支持 Docker/Containerd 等不同容器運行時。我們一個 Minikube 虛擬機環境,注意需要指明 --container-runtime=containerd 參數設置 containerd 作為容器運行時。同時 registry-mirror 也要替換成自己的阿里雲鏡像加速地址。

$ minikube start --image-mirror-country cn \
    --iso-url=https://kubernetes.oss-cn-hangzhou.aliyuncs.com/minikube/iso/minikube-v1.5.0.iso \
    --registry-mirror=https://XXX.mirror.aliyuncs.com \
    --container-runtime=containerd
  Darwin 10.14.6 上的 minikube v1.5.0
  Automatically selected the 'hyperkit' driver (alternates: [virtualbox])
️  您所在位置的已知存儲庫都無法訪問。正在將 registry.cn-hangzhou.aliyuncs.com/google_containers 用作後備存儲庫。
  正在創建 hyperkit 虛擬機(CPUs=2,Memory=2000MB, Disk=20000MB)...
️  VM is unable to connect to the selected image repository: command failed: curl -sS https://k8s.gcr.io/
stdout:
stderr: curl: (7) Failed to connect to k8s.gcr.io port 443: Connection timed out
: Process exited with status 7
  正在 containerd 1.2.8 中準備 Kubernetes v1.16.2…
  拉取鏡像 ...
  正在啟動 Kubernetes ...
⌛  Waiting for: apiserver etcd scheduler controller
  完成!kubectl 已經配置至 "minikube"
$ minikube dashboard
  Verifying dashboard health ...
  Launching proxy ...
  Verifying proxy health ...
  Opening http://127.0.0.1:54438/api/v1/namespaces/kubernetes-dashboard/services/http:kubernetes-dashboard:/proxy/ in your default browser...

部署測試應用

我們通過 Pod 部署一個 nginx 應用:

$ cat nginx.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx
spec:
  containers:
  - name: nginx
    image: nginx
$ kubectl apply -f nginx.yaml
pod/nginx created
$ kubectl exec nginx -- uname -a
Linux nginx 4.19.76 #1 SMP Fri Oct 25 16:07:41 PDT 2019 x86_64 GNU/Linux

然後,我們開啟 minikube 對 gvisor 支持:

$ minikube addons enable gvisor
  gvisor was successfully enabled
$ kubectl get pod,runtimeclass gvisor -n kube-system
NAME         READY   STATUS    RESTARTS   AGE
pod/gvisor   1/1     Running   0          60m
NAME                              CREATED AT
runtimeclass.node.k8s.io/gvisor   2019-10-27T01:40:45Z
$ kubectl get runtimeClass
NAME     CREATED AT
gvisor   2019-10-27T01:40:45Z

當 gvisor pod 進入 Running 狀態的時候,可以部署 gvisor 測試應用。

我們可以看到 K8s 集群中已經註冊了一個 gvisor 的“runtimeClassName”。之後,開發者可以通過在 Pod 聲明中的 “runtimeClassName” 來選擇不同類型的容器運行時實現。比如,如下我們創建一個運行在 gvisor 沙箱容器中的 nginx 應用。

$ cat nginx-untrusted.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-untrusted
spec:
  runtimeClassName: gvisor
  containers:
  - name: nginx
    image: nginx
$ kubectl apply -f nginx-untrusted.yaml
pod/nginx-untrusted created
$ kubectl exec nginx-untrusted -- uname -a
Linux nginx-untrusted 4.4 #1 SMP Sun Jan 10 15:06:54 PST 2016 x86_64 GNU/Linux

我們可以清楚地發現:由於基於 runc 的容器與宿主機共享操作系統內核,runc 容器中查看到的 OS 內核版本與 Minikube 宿主機 OS 內核版本相同;而 gvisor 的 runsc 容器採用了獨立內核,它和 Minikube 宿主機 OS 內核版本不同。

正是因為每個沙箱容器擁有獨立的內核,減小了安全攻擊面,具備更好的安全隔離特性。適合隔離不可信的應用,或者多租戶場景。注意:gvisor 在 minikube 中,通過 ptrace 對內核調用進行攔截,其性能損耗較大,此外 gvisor 的兼容性還有待增強。

使用 ctl 和 crictl 工具

我們現在可以進入進入 Minikube 虛擬機:

$ minikube ssh

containerd 支持通過名空間對容器資源進行隔離,查看現有 containerd 名空間:

$ sudo ctr namespaces ls
NAME   LABELS
k8s.io
# 列出所有容器鏡像
$ sudo ctr --namespace=k8s.io images ls
...
# 列出所有容器列表
$ sudo ctr --namespace=k8s.io containers ls

在 Kubernetes 環境更加簡單的方式是利用 crictl 對 pods 進行操作。

# 查看pod列表
$ sudo crictl pods
POD ID              CREATED             STATE               NAME                                         NAMESPACE              ATTEMPT
78bd560a70327       3 hours ago         Ready               nginx-untrusted                              default                0
94817393744fd       3 hours ago         Ready               nginx                                        default                0
...
# 查看名稱包含nginx的pod的詳細信息
$ sudo crictl pods --name nginx -v
ID: 78bd560a70327f14077c441aa40da7e7ad52835100795a0fa9e5668f41760288
Name: nginx-untrusted
UID: dda218b1-d72e-4028-909d-55674fd99ea0
Namespace: default
Status: Ready
Created: 2019-10-27 02:40:02.660884453 +0000 UTC
Labels:
    io.kubernetes.pod.name -> nginx-untrusted
    io.kubernetes.pod.namespace -> default
    io.kubernetes.pod.uid -> dda218b1-d72e-4028-909d-55674fd99ea0
Annotations:
    kubectl.kubernetes.io/last-applied-configuration -> {"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"name":"nginx-untrusted","namespace":"default"},"spec":{"containers":[{"image":"nginx","name":"nginx"}],"runtimeClassName":"gvisor"}}
    kubernetes.io/config.seen -> 2019-10-27T02:40:00.675588392Z
    kubernetes.io/config.source -> api
ID: 94817393744fd18b72212a00132a61c6cc08e031afe7b5295edafd3518032f9f
Name: nginx
UID: bfcf51de-c921-4a9a-a60a-09faab1906c4
Namespace: default
Status: Ready
Created: 2019-10-27 02:38:19.724289298 +0000 UTC
Labels:
    io.kubernetes.pod.name -> nginx
    io.kubernetes.pod.namespace -> default
    io.kubernetes.pod.uid -> bfcf51de-c921-4a9a-a60a-09faab1906c4
Annotations:
    kubectl.kubernetes.io/last-applied-configuration -> {"apiVersion":"v1","kind":"Pod","metadata":{"annotations":{},"name":"nginx","namespace":"default"},"spec":{"containers":[{"image":"nginx","name":"nginx"}]}}
    kubernetes.io/config.seen -> 2019-10-27T02:38:18.206096389Z
    kubernetes.io/config.source -> api

containerd 與 Docker 的關係

很多同學都關心 containerd 與 Docker 的關係,以及是否 containerd 可以取代 Docker?

containerd 已經成為容器運行時的主流實現,也得到了 Docker 社區和 Kubernetes 社區的大力支持。Docker Engine 底層的容器生命周期管理也是基於 containerd 實現。

但是 Docker Engine 包含了更多的開發者工具鏈,比如鏡像構建。也包含了 Docker 自己的日誌、存儲、網絡、Swarm 編排等能力。此外,絕大多數容器生態廠商,如安全、監控、開發等對 Docker Engine 的支持比較完善,對 containerd 的支持也在逐漸補齊。

所以在 Kubernetes 運行時環境,對安全和效率和定製化更加關注的用戶可以選擇 containerd 作為容器運行時環境;對於大多數開發者,繼續使用 Docker Engine 作為容器運行時也是一個不錯的選擇。

阿里雲容器服務對 containerd 的支持

在阿里雲 Kubernetes 服務 ACK,我們已經採用 containerd 作為容器運行時管理,來支撐安全沙箱容器和 runc 容器的混合部署。在現有產品中,我們和阿里雲操作系統團隊、螞蟻金服一起支持了基於輕量虛擬化的 runV 沙箱容器,4Q 也將和操作系統團隊、安全團隊合作發布基於 Intel SGX 的可信加密沙箱容器。

具體產品信息可以參考。

Serverless Kubernetes(ASK)中,我們也利用 containerd 靈活的插件機制定製和剪裁了面向 nodeless 環境的容器運行時實現。

“ 阿里巴巴雲原生微信公眾號(ID:Alicloudnative)關注微服務、Serverless、容器、Service Mesh等技術領域、聚焦雲原生流行技術趨勢、雲原生大規模的落地實踐,做最懂雲原生開發者的技術公眾號。”

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業 缺乏曝光? 下一步”網站設計“幫您第一時間規劃公司的門面形象

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,網站設計公司幫您達到更多曝光效益

※試算大陸海運運費!

您可能也會喜歡…