將 Sidecar 容器帶入新的階段 | KubeCon NA 2019

36f73ea3-b0ff-4b4b-aa30-5a4f38c70793.png圖爲 KubeCon NA 2019 大會分享現場照

Speaker:

  • 徐迪 螞蟻金服技術專家:負責螞蟻金融雲PaaS平臺建設,Kubernetes 社區老兵,核心代碼庫貢獻量社區前50;

  • 張曉宇 阿里雲技術專家:負責阿里巴巴雲原生應用容器平臺的生態建設,主要設計和研發節點穩定性和資源利用率相關解決方案,同時也是 Kubernetes 社區熱心的成員和貢獻者。

本文根據徐迪和張曉宇在 KubeCon NA2019 大會分享整理。分享將會從以下幾個方面進行切入:首先會簡單介紹一下什麼是 Sidecar 容器;其次,我們會分享幾個螞蟻金服和阿里巴巴集團的通用場景,以及我們是如何解決這些挑戰的。當然,現在還是有很多的挑戰需要後續繼續解決,邀請大家與我們一同努力。

Sidecar 簡介

Sidecar 容器並不是一個新鮮事物。它是一種設計模式,主要用來做一些輔助的工作,比如網絡連通性、下載拷貝文件之類的事情;如果大家熟悉 Docker Swarm 的話,就會發現 Docker Ambassador 其實就是 Sidecar。

2c4d7b09-7d97-4ff8-b378-c757ea012980.png

看看如上這個例子,Service Consumer 和 Redis Provider 強耦合,部署在同一個節點上。如果這個時候,Redis Provider 出現問題,需要連接到另外一個 Redis 實例上,需要重新配置,並重啓 Service Provider。

d33ffda7-993f-4472-bd51-82dc89ee213e.png

那麼在引入了 Ambassador 以後,問題變得相對簡單些,只需要重啓這裏的 Redis Ambassador 即可,並不需要 Service Consumer 進行任何變動。

當然這種模式,還可以進行跨節點通信,比如下圖。這樣 Service Consumer 和 Redis Provider 就可以部署在不同的節點上。在某種程度上,很容易地就將兩種服務進行了解耦。

3700cb95-7fa9-4ac5-849c-ecd67bad4b23.png

Sidecar 案例分享

Sidecar 容器能用來幹什麼?

一般來講,Sidecar 容器可以:

  • 日誌代理/轉發,例如 fluentd;

  • Service Mesh,比如 Istio,Linkerd;

  • 代理,比如 Docker Ambassador;

  • 探活:檢查某些組件是不是正常工作;

  • 其他輔助性的工作,比如拷貝文件,下載文件等;

  • ...


僅此而已?


事實上,Sidecar 越來越被大家接受,並且使用越來越廣泛。Sidecar 容器通常和業務容器(非 Sidecar 容器)部署在同一個 Pod 裏,共享相同的生命週期,爲業務容器提供輔助功能。這是一個非常好的模式,能夠極大程度解耦應用,並且支持異構組件,降低技術壁壘。

但目前 Kubernetes 對 Sidecar 的管理還不完善,越來越不滿足我們的使用,尤其是在生產環境中使用 Sidecar。

幾個典型案例

1. 順序依賴

假設我們在一個 Pod 內注入了多個 Sidecar,但是 Sidecar 之間或者 Sidecar 和業務容器之間有相互依賴關係。

如下這個例子,我們需要先啓動 proxy Sidecar 容器用於建立網絡連接,這樣 mysql client 才能連接到遠端的 mysql 集羣,並在本地暴露服務。而後主的業務容器才能正常工作。

   #1 proxy_container (sidecar)
   #2 mysql_client
   #3 svc_container

當然,有的人會覺得這個地方,可以通過諸如更改鏡像啓動腳本延遲啓動等方法來解決。但是這些方法侵入性太強,不利於擴展,還很難進行準確的配置。

2. Sidecar 管理

我們來看看另外一個案例。Sidecar 容器和業務容器耦合在同一個 Pod 內,共享相同的生命週期。因此,單獨來管控 Sidecar 容器非常不方,比如更新 Sidecar 的鏡像。

5506e11b-778c-4b3d-9159-e9dca17d96ca.png

比如,我們已經給很多 Pod 注入了 Istio Proxy 這樣的 Sidecar 容器,目前運行狀態良好。但是如果這個時候我們想升級這個 Proxy 鏡像的話,該怎麼辦?

如果按照 Istio 社區官方的文檔,我們需要重新注入這些 Sidecar 容器。具體來說,需要刪除原有 Pod,重新生成一份新的 Pod(有些 workload 關聯的 Pod,會由相應的 workload 控制器自動生成)。

那如果我們有很多個這樣的 Pod 需要處理的話,怎麼辦?通過命令行的話,太不方便,而且容易出錯。通過自己單獨寫的代碼的話,可擴展性是個問題,需要頻繁更改這些代碼。

而且這裏還有另外一個問題,我們肯定不會一下子升級所有的 Sidecar,肯定要有個灰度的過程,也就是隻升級一部分 Sidecar,這個時候又該怎麼辦呢?

社區進展

上游社區

這裏我們非常感謝 Joseph Irving (@Joseph-Irving) 提出了一個 Sidecar kep,通過定義 LifecycleType 來區分是否是 Sidecar 容器。

type Lifecycle struct {// Type// One of Standard, Sidecar.// Defaults to Standard// +optional
  Type LifecycleType `json:"type,omitempty" protobuf:"bytes,3,opt,name=type,casttype=LifecycleType"`
}// LifecycleType describes the lifecycle behaviour of the containertype LifecycleType stringconst (  // LifecycleTypeStandard is the default container lifecycle behaviour
  LifecycleTypeStandard LifecycleType = "Standard"// LifecycleTypeSidecar means that the container will start up before standard containers and be terminated after
  LifecycleTypeSidecar LifecycleType = "Sidecar")

未來只需要在 Pod Spec 中,按如下方式標記即可:

name: sidecarContainerimage: foolifecycle:  type: Sidecar

Pod 內容器的啓動順序按照:初始化容器->Sidecar 容器->業務容器 的順序依次啓動。

其中上述 kep 的 kubelet 端實現 正在進行中。

爲了支持 Sidecar 更多的使用場景,我們以此爲基礎提出了 PreSidecar 和 PostSidecar,分別用於在業務容器之前和之後啓動。具體的使用場景見 我們的 PR

爲什麼我們覺得 Sidecar 應該區分前置和後置呢?

這是因爲在一些場景下,我們需要 Sidecar 容器優先於應用容器啓動,幫助做一些準備工作。例如分發證書,創建共享卷,或者拷貝下載一些其他文件等。

614217c6-5cc1-40f7-8911-482bc1df7b8e.png

而在另外一些場景下,我們需要一些 Sidecar 容器在應用容器之後啓動。考慮到解耦和版本管理的因素,我們將應用分爲兩部分,應用容器專注於業務本身,而一些數據和個性化的配置放在 Sidecar 容器中。通常情況下,這兩個容器將會共享一個存儲卷,後置的 Sidecar 容器會更新替換掉一些默認和過時數據。

f6c0a786-7bbc-4425-bca6-4a30876b8878.png

當然考慮到未來更復雜的場景,我們可能還會對容器的啓動順序做 DAG 編排,當然這個需要視生產實際需要而定。

e9433ca6-6d9f-4e29-8b74-e480def6b5c0.png

螞蟻金服及阿里巴巴如何應對


爲了解決 Sidecar 的管理工作,我們需要一個更細粒度的 workload 方便我們進行管理。這個 workload 我們命名爲 SidecarSet,目前已經開源,生產可用。大家可以訪問 OpenKruise 這個項目,可以在項目的 roadmap 裏瞭解我們目前的一些新進展。OpenKruise 這個項目目前有三個生產可用的 workload,分別是 Advanced StatefulSet、

BroadcastJob、SidecarSet。另外2個 workload(AdvancedHPA 和 PodHealer)正在加緊開發中, 很快會開源出來,敬請期待。

OpenKruisehttps://openkruise.io/

OpenKruise roadmaphttps://github.com/openkruise/kruise/projects

相關使用 Demo,大家可以觀看 Lachlan Evenson 的嚐鮮視頻

以下是我們 SidecarSet 的定義,

// SidecarSetSpec defines the desired state of SidecarSettype SidecarSetSpec struct {
    // selector is a label query over pods that should be injected
    Selector *metav1.LabelSelector `json:"selector,omitempty"`

    // Containers is the list of sidecar containers to be injected into the selected pod
    Containers []SidecarContainer `json:"containers,omitempty"`

    // List of volumes that can be mounted by sidecar containers
    Volumes []corev1.Volume `json:"volumes,omitempty"`

    // Paused indicates that the sidecarset is paused and will not be processed by the sidecarset controller.
    Paused bool `json:"paused,omitempty"`

    // The sidecarset strategy to use to replace existing pods with new ones.
    Strategy SidecarSetUpdateStrategy `json:"strategy,omitempty"`
}

// SidecarContainer defines the container of Sidecartype SidecarContainer struct {
    corev1.Container
}

// SidecarSetUpdateStrategy indicates the strategy that the SidecarSet
// controller will use to perform updates. It includes any additional parameters
// necessary to perform the update for the indicated strategy.type SidecarSetUpdateStrategy struct {
    RollingUpdate *RollingUpdateSidecarSet `json:"rollingUpdate,omitempty"`
}

// RollingUpdateSidecarSet is used to communicate parametertype RollingUpdateSidecarSet struct {
    MaxUnavailable *intstr.IntOrString `json:"maxUnavailable,omitempty"`
}

spec 中的 SidecarContainer 的定義就是 Kubernetes 代碼庫中的 corev1.Container 定義。通過額外的一個 labelSelector,可以很方便地對指定的容器組進行操作。通過我們支持 RollingUpdate ,方便用戶一點點升級 Sidecar。同時提供了 pause 功能,可以在緊急情況下暫停 Sidecar 的升級。

如果只是簡單升級 Sidecar 的鏡像, SidecarSet 控制器僅僅會 patch 原有 pod 的,非常方便的就可以一鍵升級鏡像。

其他的挑戰

我們在生產實踐過程中,還發現了一些其他的挑戰,目前還在尋找比較好的解法。如果大家有什麼好的方法或者建議,歡迎一起討論共建。

1. Sidecar 容器的資源管理

一般來講 Sidecar 容器佔用的資源都比較小,那麼這個資源要不要計算到整個 pod 當中?還是可以直接共享業務容器的資源即可?相同的 Sidecar 在和不同的應用容器搭配使用,如何準確給 Sidecar 容器分配資源這些都需要進行考慮。

b787a62d-b5d3-47bc-9d19-584c2a7de386.png

2. Sidecar 容器的容錯性


一般來講,Sidecar 容器都是非主要容器,那麼這類容器出現問題時,比如 liveness 探活,要不要對主容器的狀態或者整個 pod 的狀態也產生影響。再或者,Sidecar 鏡像更新出現問題時,要不要直接標記整個 pod 出現問題。

當然,還有一些其他的挑戰,我們只是列舉了幾個通用的。對於這些挑戰,我們需要大家一起集思廣益,找到比較合理的解法。

小結

隨着 Sidecar 在生產環境使用越來越廣泛,對其的管理愈發需要重視。Sidecar 雖然和業務容器部署在同一個 Pod 內,但是其本質上只是輔助性的容器。本文介紹了目前 Sidecar 的典型使用案例,以及面臨的挑戰,同時跟上游社區一起合作,將阿里經濟體的技術解決方案在社區落地,幫助更多的用戶。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章