Kubernetes Container Runtime 筆記
Container Runtime
Container Runtime 是 K8s cluster 中負責管理並執行 container 的角色,每個 Node 都需要安裝 Container Runtime 才能夠執行 Pod。
常見的 Container Runtime 有 containerd、CRI-O 等。
Container Runtime Interface
Container Runtime Interface (CRI) 用來定義 kubelet 怎麼和 Container Runtime 溝通,讓 K8s 可以透過統一介面使用不同的 runtime。
CRI 本身是一份以 gRPC 定義的介面規範,runtime 必須實作相容的 CRI API,並在 Node 上完成設定,才能讓 K8s 使用。
補充:早期 K8s 透過內建的 dockershim 支援 Docker Engine,dockershim 負責將 CRI 請求轉接給 Docker Engine。從 v1.24 起移除了內建的 dockershim。
Container Sandbox
containerd 等 runtime 會透過底層 runtime 執行 container,常見的搭配是 runc。
為了加強 Node 中 workload 的隔離,發展出了 gVisor、Kata Containers 等 sandbox runtime。它們和 runc 的主要差別,在於隔離邊界,以及應用程式接觸 host kernel 的方式:runc 共用 host kernel,gVisor 在中間加入 application kernel,Kata Containers 則使用 VM 和獨立的 guest kernel。
而在 K8s 中可以透過 RuntimeClass,讓每個 Pod 選用不同的 runtime 設定。RuntimeClass 的 handler 對應到 Node 上 CRI runtime 已設定好的 handler。沒有指定 runtimeClassName 時,就使用預設 handler,實際使用哪個 runtime 取決於 Node 的設定。
建立 RuntimeClass 不會自動安裝 runtime,必須先在 Node 上安裝並設定好對應的 runtime。若只有部分 Node 支援,還需要透過 RuntimeClass 的 scheduling.nodeSelector 等排程設定,讓 Pod 被排到支援的 Node。
1 | |
Pod 可以這樣設定:
1 | |
gVisor
gVisor 提供的 OCI runtime 叫做 runsc,其中處理應用程式 syscall 的 user-space kernel 叫做 Sentry。應用程式的 syscall 由 Sentry 攔截並處理,不會直接轉交給 host kernel;但 Sentry 本身仍會透過受限制的 syscall 使用 host 資源。
這樣可以減少應用程式直接接觸 host kernel 的攻擊面,代價是額外的處理成本與相容性限制,實際效能影響會依 workload 而不同。
Kata Containers
在 K8s 情境中,通常是一個 Pod 對應一台輕量 VM,同一個 Pod 裡的多個 container 共用這台 VM 與 guest kernel。透過硬體虛擬化增加一道隔離邊界,代價則是 VM 帶來的啟動時間與記憶體開銷,實際成本取決於設定和 workload。
runc
常見的 OCI runtime,透過 Linux namespaces 隔離資源視圖、cgroups 管理資源使用,container 直接共用 host kernel。沒有額外的 application kernel 或 VM 層,通常執行開銷較低,但應用程式也更直接接觸 host kernel 造成一些風險。