邊車(Sidecar)容器在不修改既有容器的前提下,擴充並強化它的功能。這是最基礎的容器模式之一,讓單一目的的容器能緊密協作。後續的特化模式「轉接器」與「大使」,是它的兩種變形。

問題#

容器是流行的封裝技術,讓開發者與系統管理員能以統一的方式建置、遞送與執行應用。一個容器代表一個功能單元的自然邊界,擁有獨立的執行期、發布週期、API,以及擁有它的團隊。合格的容器行為像單一 Linux 行程——解決一個問題並把它做好——並且以可替換與可重用為出發點而建立。

最後這點至關重要,因為它讓我們能藉由既有的專門容器,更快地打造應用:今天要發 HTTP 呼叫,我們不必自己寫客戶端函式庫,用現成的就好;同樣地,要提供網站服務,我們不必自己做網頁伺服器容器。這讓開發者避免重造輪子,形成一個「容器數量更少、品質更好」的生態系。

但要擁有單一目的、可重用的容器,就需要擴充容器功能的方式,以及容器之間協作的手段。邊車模式描述的正是這種協作:一個容器強化另一個既有容器的功能。

解法#

Pod 原語讓我們能把多個容器組成單一單元。幕後在執行期,Pod 本身也是一個容器,但它在 Pod 內所有其他容器之前,以一個暫停行程(字面上就是 pause 指令)啟動;它什麼也不做,只是持有所有 Linux 命名空間,供應用容器在 Pod 生命週期中互動之用。

比這個實作細節更有意思的,是 Pod 抽象提供的各種特性。Pod 是如此根本的原語,以至於它在許多雲原生平台上以不同名稱存在,但能力總是相似。作為部署單元,Pod 對其中的容器施加了某些執行期約束——所有容器都被部署到同一節點、共享同一個 Pod 生命週期;同時,Pod 也讓容器能共享 volume,並透過本地網路或主機 IPC 溝通。

「邊車」(有些地方也稱 Sidekick)就是用來描述這種情境:把一個容器放進 Pod,以擴充並強化另一個容器的行為。

展示這個模式的典型例子是「HTTP 伺服器 + Git 同步器」:

  • HTTP 伺服器容器只專注於透過 HTTP 提供檔案,不知道也不在乎檔案從哪來、怎麼來
  • Git 同步器容器唯一的目標是把資料從 Git 伺服器同步到本地檔案系統,同步後檔案發生什麼事它一概不管,只關心讓本地資料夾與遠端 Git 伺服器保持同步。
apiVersion: v1
kind: Pod
metadata:
  name: web-app
spec:
  containers:
    - name: app # 主應用容器:透過 HTTP 提供檔案
      image: docker.io/centos/httpd
      ports:
        - containerPort: 80
      volumeMounts:
        - mountPath: /var/www/html
          name: git
    - name: poll # 邊車容器:平行執行,從 Git 伺服器拉取資料
      image: axeclbr/git
      volumeMounts:
        - mountPath: /var/lib/data
          name: git
      env:
        - name: GIT_REPO
          value: https://github.com/mdn/beginner-html-site-scripted
      command:
        - "sh"
        - "-c"
        - "git clone $(GIT_REPO) . && watch -n 600 git pull"
      workingDir: /var/lib/data
  volumes:
    - emptyDir: {} # 邊車與主應用容器交換資料的共享位置
      name: git

這個範例展示了 Git 同步器如何為 HTTP 伺服器補上要服務的內容、並保持同步。我們也可以說兩個容器是協作關係、同等重要;但在邊車模式中,有一個主容器和一個強化整體行為的輔助容器

慣例上,主容器是 containers 清單中列在第一個的容器,它代表預設容器(例如執行 kubectl exec 時)。

圖 15-1:邊車模式

這個簡單模式讓容器在執行期協作,同時為兩個容器達成關注點分離——它們可能由不同團隊擁有、使用不同程式語言、有不同的發布週期。它也促進了容器的可替換性與重用:HTTP 伺服器與 Git 同步器都能在其他應用與不同組態中重用,可以是 Pod 中的單一容器,也可以再次與其他容器協作。

討論#

我們曾說容器映像檔像類別、容器像物件導向程式設計(OOP)中的物件。延續這個類比:

OOP 對應關係特性
擴充容器以強化其功能繼承(inheritance)is-a容器間耦合較緊
多個容器在 Pod 中協作組合(composition)has-a更靈活,不在建置期把容器綁死,日後可在 Pod 定義中抽換容器

但 Pod 中的組合也意味著你有多個容器(行程)在執行,各自被健康檢查、被重啟、並像主應用容器一樣消耗資源。現代邊車容器都很小、資源消耗極少,但你仍必須判斷:值得多跑一個行程,還是併進主容器更好?

換個角度看,容器組合類似面向切面程式設計(aspect-oriented programming):透過額外的容器,我們為 Pod 引入了正交的能力,而完全不必碰主容器

近年邊車模式的使用越來越普遍,尤其是在處理服務的網路、監控與追蹤面向時——每個服務都會一併帶上邊車容器。

更多資訊#

  • Sidecar Example
  • Design Patterns for Container-Based Distributed Systems
  • Prana: A Sidecar for your Netflix PaaS-based Applications and Services
  • Tin-Can Phone: Patterns to Add Authorization and Encryption to Legacy Applications
  • The Almighty Pause Container