<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          為什么 Kubernetes 要替換 Docker

          共 5646字,需瀏覽 12分鐘

           ·

          2021-03-21 15:37

          為什么這么設計(Why’s THE Design)是一系列關于計算機領域中程序設計決策的文章,我們在這個系列的每一篇文章中都會提出一個具體的問題并從不同的角度討論這種設計的優(yōu)缺點、對具體實現(xiàn)造成的影響。如果你有想要了解的問題,可以在文章下面留言。

          Kubernetes 是今天容器編排領域的事實標準,而 Docker 從誕生之日到今天都在容器中扮演著舉足輕重的地位,也都是 Kubernetes 中的默認容器引擎。然而在 2020 年 12 月,Kubernetes 社區(qū)決定著手移除倉庫中 Dockershim 相關代碼[^1],這對于 Kubernetes 和 Docker 兩個社區(qū)來說都意義重大。

          kubelet-and-containers

          圖 1 - Dockershim

          相信大多數(shù)的開發(fā)者都聽說過 Kubernetes 和 Docker,也知道我們可以使用 Kubernetes 管理 Docker 容器,但是可能沒有聽說過 Dockershim,即 Docker 墊片。如上圖所示,Kubernetes 中的節(jié)點代理 Kubelet 為了訪問 Docker 提供的服務需要先經(jīng)過社區(qū)維護的  Dockershim,Dockershim 會將請求轉發(fā)給管理容器的 Docker 服務。

          其實從上面的架構圖中,我們就能猜測出 Kubernetes 社區(qū)從代碼倉庫移除 Dockershim 的原因:

          • Kubernetes 引入容器運行時接口(Container Runtime Interface、CRI)隔離不同容器運行時的實現(xiàn)機制,容器編排系統(tǒng)不應該依賴于某個具體的運行時實現(xiàn);
          • Docker 沒有支持也不打算支持 Kubernetes 的 CRI 接口,需要 Kubernetes 社區(qū)在倉庫中維護 Dockershim;

          可擴展性

          Kubernetes 通過引入新的容器運行時接口將容器管理與具體的運行時解耦,不再依賴于某個具體的運行時實現(xiàn)。很多開源項目在早期為了降低用戶的使用成本,都會提供開箱即用的體驗,而隨著用戶群體的擴大,為了滿足更多定制化的需求、提供更強的可擴展性,會引入更多的接口。Kubernetes 通過下面的一系列接口為不同模塊提供了擴展性:

          kubernetes-extensions

          圖 2 - Kubernetes 接口和可擴展性

          Kubernetes 在較早期的版本中就引入了 CRD、CNI、CRI 和 CSI 等接口,只有用于擴展調度器的調度框架是 Kubernetes 中比較新的特性。我們在這里就不展開分析其他的接口和擴展了,簡單介紹一下容器運行時接口。

          Kubernetes 早在 1.3 就在代碼倉庫中同時支持了 rkt 和 Docker 兩種運行時,但是這些代碼為 Kubelet 組件的維護帶來了很大的困難,不僅需要維護不同的運行時,接入新的運行時也很困難;容器運行時接口(Container Runtime Interface、CRI)是 Kubernetes 在 1.5 中引入的新接口,Kubelet 可以通過這個新接口使用各種各樣的容器運行時。其實 CRI 的發(fā)布就意味著 Kubernetes 一定會將 Dockershim 的代碼從倉庫中移除。

          CRI 是一系列用于管理容器運行時和鏡像的 gRPC 接口,我們能在它的定義中找到 RuntimeServiceImageService 兩個服務[^2],它們的名字很好地解釋了各自的作用:

          service RuntimeService {
          rpc Version(VersionRequest) returns (VersionResponse) {}

          rpc RunPodSandbox(RunPodSandboxRequest) returns (RunPodSandboxResponse) {}
          rpc StopPodSandbox(StopPodSandboxRequest) returns (StopPodSandboxResponse) {}
          rpc RemovePodSandbox(RemovePodSandboxRequest) returns (RemovePodSandboxResponse) {}
          rpc PodSandboxStatus(PodSandboxStatusRequest) returns (PodSandboxStatusResponse) {}
          rpc ListPodSandbox(ListPodSandboxRequest) returns (ListPodSandboxResponse) {}

          rpc CreateContainer(CreateContainerRequest) returns (CreateContainerResponse) {}
          rpc StartContainer(StartContainerRequest) returns (StartContainerResponse) {}
          rpc StopContainer(StopContainerRequest) returns (StopContainerResponse) {}
          rpc RemoveContainer(RemoveContainerRequest) returns (RemoveContainerResponse) {}
          rpc ListContainers(ListContainersRequest) returns (ListContainersResponse) {}
          rpc ContainerStatus(ContainerStatusRequest) returns (ContainerStatusResponse) {}
          rpc UpdateContainerResources(UpdateContainerResourcesRequest) returns (UpdateContainerResourcesResponse) {}
          rpc ReopenContainerLog(ReopenContainerLogRequest) returns (ReopenContainerLogResponse) {}

          ...
          }

          service ImageService {
          rpc ListImages(ListImagesRequest) returns (ListImagesResponse) {}
          rpc ImageStatus(ImageStatusRequest) returns (ImageStatusResponse) {}
          rpc PullImage(PullImageRequest) returns (PullImageResponse) {}
          rpc RemoveImage(RemoveImageRequest) returns (RemoveImageResponse) {}
          rpc ImageFsInfo(ImageFsInfoRequest) returns (ImageFsInfoResponse) {}
          }

          對 Kubernetes 稍有了解的人都能從上面的定義中找到一些熟悉的方法,它們都是容器運行時需要暴露給 Kubelet 的接口。Kubernetes 將 CRI 墊片實現(xiàn)成 gRPC 服務器與 Kubelet 中的客戶端通信,所有的請求都會被轉發(fā)給容器運行時處理。

          cri-and-container-runtimes

          圖 3 - Kubernetes 和 CRI

          Kubernetes 中的聲明式接口非常常見,作為聲明式接口的擁躉,CRI 沒有使用聲明式的接口是一件聽起來『非常怪異』的事情[^3]。不過 Kubernetes 社區(qū)考慮過讓容器運行時重用 Pod 資源,這樣容器運行時可以實現(xiàn)不同的控制邏輯來管理容器,能夠極大地簡化 Kubelet 和容器運行時之間的接口,但是社區(qū)出于以下兩點考慮,最終沒有選擇聲明式的接口:

          1. 所有的運行時都需要重新實現(xiàn)相同的邏輯支持很多 Pod 級別的功能和機制;
          2. Pod 的定義在 CRI 設計時演進地非常快,初始化容器等功能都需要運行時的配合;

          雖然社區(qū)最終為 CRI 選擇了命令式的接口,但是 Kubelet 仍然會保證 Pod 的狀態(tài)會不斷地向期望狀態(tài)遷移。

          不兼容接口

          與容器運行時相比,Docker 更像是一個復雜的開發(fā)者工具,它提供了從構建到運行的全套功能。開發(fā)者可以很快地上手 Docker 并在本地運行并管理一些 Docker 容器,然而在集群中運行的容器運行時往往不需要這么復雜的功能,Kubernetes 需要的只是 CRI 中定義的那些接口。

          docker-and-cri

          圖 4 - Docker & CRI

          Docker 的官方文檔加起來可能有一本書的厚度,相信沒有任何開發(fā)者可以熟練運用 Docker 提供的全部功能。而作為開發(fā)者工具,雖然 Docker 中包含 CRI 需要的所有功能,但是都需要實現(xiàn)一層包裝以兼容 CRI。除此之外,社區(qū)提出的很多新功能都沒有辦法在 Dockershim 中實現(xiàn),例如 cgroups v2 以及用戶命名空間。

          Kubernetes 作為比較松散的開源社區(qū),每個成員尤其是各個 SIG 的成員都只會在開源社區(qū)上花費有限的時間,而維護 Kubelet 的 sig-node 又尤其繁忙,很多新的功能都因為維護者沒有足夠的精力而被擱置,所以既然 Docker 社區(qū)看起來沒有打算支持 Kubernetes 的 CRI 接口,維護 Dockershim 又需要花費很多精力,那么我們就能理解為什么 Kubernetes 會移除 Dockershim 了。

          總結

          今天的 Kubernetes 已經(jīng)是非常成熟的項目,它的關注點也逐漸從提供更完善的功能轉變到提供更好的擴展性,這樣才能滿足不同場景和不同公司定制化的業(yè)務需求。Kubernetes 在過去因為 Docker 的熱門而選擇 Docker,而在今天又因為高昂的維護成本而放棄 Docker,我們能夠從這個過程中體會到容器領域的發(fā)展和進步。

          移除 Docker 的種子其實從 CRI 發(fā)布時就種下了,Dockershim 一直都是 Kubernetes 為了兼容 Docker 獲得市場采取的臨時決定,對于今天已經(jīng)統(tǒng)治市場的 Kubernetes 來說,Docker 的支持顯得非常雞肋,移除代碼也就順理成章了。我們在這里重新回顧一下 Kubernetes 在倉庫中移除 Docker 支持的兩個原因:

          • Kubernetes 在早期版本中引入 CRI 擺脫依賴某個具體的容器運行時依賴,屏蔽底層的諸多實現(xiàn)細節(jié),讓 Kubernetes 能夠更關注容器的編排;
          • Docker 本身不兼容 CRI 接口,而且官方并沒有實現(xiàn) CRI 的打算,同時也不支持容器的一些新需求,所以 Dockershim 的維護成為了社區(qū)的想要擺脫負擔;

          到最后,我們還是來看一些比較開放的相關問題,有興趣的讀者可以仔細思考一下下面的問題:

          • Kubernetes 中還有哪些模塊提供良好的擴展性?
          • 除了文中提到的 CRI-O、Containerd,還有哪些支持 CRI 的容器運行時?

          如果對文章中的內容有疑問或者想要了解更多軟件工程上一些設計決策背后的原因,可以在博客下面留言,作者會及時回復本文相關的疑問并選擇其中合適的主題作為后續(xù)的內容。

          參考資料

          • Dockershim Deprecation FAQ https://kubernetes.io/blog/2020/12/02/dockershim-faq/
          • Don't Panic: Kubernetes and Docker https://kubernetes.io/blog/2020/12/02/dont-panic-kubernetes-and-docker/

          [^1]: Removing dockershim from kubelet #1985 https://github.com/kubernetes/enhancements/pull/1985

          [^3]: Introducing Container Runtime Interface (CRI) in Kubernetes https://kubernetes.io/blog/2016/12/container-runtime-interface-cri-in-kubernetes/

          [^2]: Container Runtime Interface (CRI) – a plugin interface which enables kubelet to use a wide variety of container runtimes. https://github.com/kubernetes/cri-api/blob/master/pkg/apis/runtime/v1/api.proto

          推薦閱讀


          K8S 進階訓練營


           點擊屏末  | 即刻學習
          瀏覽 52
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  天天操天天久久精品 | 在线国产黄色视频 | 婷婷爱五月 | 成人做爱影片 | 男女无遮无挡一区二区爱豆视频 |