天天看點

OpenKruise :SidecarSet 助力 Mesh 容器熱更新前言背景:如何獨立更新 Mesh 容器SidecarSet 助力 Mesh 容器無損熱更新已知 Mesh 容器熱更新案例

作者| 趙明山(立衡)

OpenKruise :SidecarSet 助力 Mesh 容器熱更新前言背景:如何獨立更新 Mesh 容器SidecarSet 助力 Mesh 容器無損熱更新已知 Mesh 容器熱更新案例

前言

OpenKruise 是阿裡雲開源的雲原生應用自動化管理套件,也是目前托管在 Cloud Native Computing Foundation ( CNCF ) 下的 Sandbox 項目。它來自阿裡巴巴多年來容器化、雲原生的技術沉澱,是阿裡内部生産環境大規模應用的基于 Kubernetes 之上的标準擴充元件,也是緊貼上遊社群标準、适應網際網路規模化場景的技術理念與最佳實踐。

OpenKruise 在 2021.5.20 釋出了最新的 v0.9.0版本( ChangeLog ),上一篇文章我們介紹了

新增 Pod 重新開機、删除防護等重磅功能

,今天向大家介紹另一個核心特性,即 SidecarSet 基于上一個版本擴充了特别針對 Service Mesh 場景的支援。

背景:如何獨立更新 Mesh 容器

SidecarSet 是 Kruise 提供的獨立管理 Sidecar 容器的 workload。使用者通過 SidecarSet 能夠便利的完成對 Sidecar 容器的自動注入和獨立更新,詳情請參考:OpenKruise 官網

預設情況下,Sidecar 的獨立更新順序是先停止舊版本的容器,然後再建立新版本的容器。這種方式尤其适合不影響 Pod 服務可用性的 Sidecar 容器,例如日志收集 agent ,但是對于很多代理或運作時的 Sidecar 容器,如 Istio Envoy,這種更新方法就有問題了。Envoy 作為 Pod 中的一個 Proxy 容器代理了所有的流量,這種場景下如果直接重新開機更新,Pod 服務的可用性必然會受到影響,是以需要考慮應用自身的釋出和容量情況,無法完全獨立于應用做 Sidecar 的釋出。

OpenKruise :SidecarSet 助力 Mesh 容器熱更新前言背景:如何獨立更新 Mesh 容器SidecarSet 助力 Mesh 容器無損熱更新已知 Mesh 容器熱更新案例

阿裡巴巴集團内部擁有上萬的 Pod 都是基于 Service Mesh 來實作互相間的通信,由于 Mesh 容器更新會導緻業務 Pod 的不可用,因而 Mesh 容器的更新将會極大阻礙 Service Mesh 的疊代。針對這種場景,我們同集團内部的 Service Mesh 團隊一起合作實作了 Mesh 容器的熱更新能力。本文将重點介紹在實作 mesh 容器熱更新能力的過程中 SidecarSet 是扮演了怎樣的重要角色。

SidecarSet 助力 Mesh 容器無損熱更新

Mesh 容器不能像日志采集類容器直接原地更新,其原因在于:Mesh 容器必須要不間斷地對外提供服務,而獨立更新方式會導緻 Mesh 服務存在一段不可用時間。雖然社群中已有一些知名的 Mesh 服務如 Envoy 、Mosn 等預設能夠提供平滑更新的能力,但是這些更新方式無法與雲原生進行恰當地結合,且 kubernetes 本身也缺乏對此類 Sidecar 容器的更新方案。

OpenKruise SidecarSet 為此類 Mesh 容器提供了 Sidecar 熱更新機制,能夠通過雲原生的方式助力 Mesh 容器實作無損熱更新。

apiVersion: apps.kruise.io/v1alpha1
kind: SidecarSet
metadata:
  name: hotupgrade-sidecarset
spec:
  selector:
    matchLabels:
      app: hotupgrade
  containers:
    - name: sidecar
      image: openkruise/hotupgrade-sample:sidecarv1
      imagePullPolicy: Always
      lifecycle:
        postStart:
          exec:
            command:
              - /bin/sh
              - /migrate.sh
      upgradeStrategy:
        upgradeType: HotUpgrade
        hotUpgradeEmptyImage: openkruise/hotupgrade-sample:empty           
  • upgradeType : HotUpgrade 代表該 sidecar 容器的類型是 Hot upgrade ,即熱更新方案。
  • HotUpgradeEmptyImage : 當熱更新 Sidecar 容器時,業務須要提供一個 empty 容器用于熱更新過程中的容器切換。Empty 容器同 Sidecar 容器具有相同的配置(鏡像位址除外),例如 command , lifecycle , probe 等。

SidecarSet 熱更新機制主要包含注入熱更新 Sidecar 容器和 Mesh 容器平滑更新兩個過程。

注入熱更新 Sidecar 容器

針對熱更新類型的 Sidecar 容器,在 Pod 建立時 SidecarSet Webhook 将會注入兩個容器:

  • {Sidecar.name} -1: 如下圖所示 envoy -1,這個容器代表正在實際工作的 sidecar 容器,例如:envoy :1.16.0
  • {Sidecar.name} -2: 如下圖所示 envoy-2,這個容器是業務提供的 HotUpgradeEmptyImage 容器,例如:empty :1.0
OpenKruise :SidecarSet 助力 Mesh 容器熱更新前言背景:如何獨立更新 Mesh 容器SidecarSet 助力 Mesh 容器無損熱更新已知 Mesh 容器熱更新案例

上述 Empty 容器在 Mesh 容器運作過程中,并沒有做任何實際的工作。

Mesh 容器平滑更新

熱更新流程主要分為一下三個步驟:

  1. Upgrade: 将 Empty 容器替換為最新版本的 Sidecar 容器,例如:envoy-2.Image = envoy:1.17.0
  2. Migration : 執行 Sidecar 容器的 PostStartHook 腳本,完成 mesh 服務的平滑更新
  3. Reset: Mesh 服務平滑更新後,将老版本 Sidecar 容器替換為 Empty 容器,例如:envoy-1.Image = empty : 1.0

僅需上述三個步驟即可完成熱更新中的全部流程,若對 Pod 執行多次熱更新,則重複執行上述三個步驟即可。

OpenKruise :SidecarSet 助力 Mesh 容器熱更新前言背景:如何獨立更新 Mesh 容器SidecarSet 助力 Mesh 容器無損熱更新已知 Mesh 容器熱更新案例

Migration 核心邏輯

SidecarSet 熱更新機制不僅完成了 Mesh 容器的切換,并且提供了新老版本的協調機制( PostStartHook ),但是至此還隻是萬裡長征的第一步,Mesh 容器同時還需要提供 PostSartHook 腳本來完成 Mesh 服務自身的平滑更新(上述 Migration 過程),如:Envoy 熱重新開機、Mosn 無損重新開機。

Mesh 容器一般都是通過監聽固定端口來對外提供服務,此類 Mesh 容器的migration 過程可以概括為:通過 UDS 傳遞 ListenFD 和停止 Accpet 、開始排水。針對不支援熱重新開機的 Mesh 容器可以參考此過程完成改造,邏輯圖如下:

OpenKruise :SidecarSet 助力 Mesh 容器熱更新前言背景:如何獨立更新 Mesh 容器SidecarSet 助力 Mesh 容器無損熱更新已知 Mesh 容器熱更新案例

熱更新 Migration Demo

不同 Mesh 容器對外提供的服務以及内部實作邏輯各有差異,進而具體的 Migration也有所不同,上述邏輯隻是對其中一些要點做了一些總結,希望能對有需要的各位有所裨益,同時在 Github 上面我們也提供了一個熱更新 Migration Demo 以供參考,下面将對其中的一些關鍵代碼進行介紹。

1. 協商機制

Mesh 容器啟動邏輯首先就需要判斷第一次啟動還是熱更新平滑遷移過程,為了減少Mesh 容器溝通成本,Kruise 在兩個 sidecar 容器中注入了兩個環境變量 SIDECARSET_VERSION 和 SIDECARSET_VERSION_ALT ,通過判斷兩個環境變量的值來判斷是否是熱更新過程以及目前 sidecar 容器是新版本還是老版本。

// return two parameters:
// 1. (bool) indicates whether it is hot upgrade process
// 2. (bool ) when isHotUpgrading=true, the current sidecar is newer or older
func isHotUpgradeProcess() (bool, bool) {
    // 目前sidecar容器的版本
    version := os.Getenv("SIDECARSET_VERSION")
    // 對端sidecar容器的版本
    versionAlt := os.Getenv("SIDECARSET_VERSION_ALT")
    // 當對端sidecar容器version是"0"時,表明目前沒有在熱更新過程
    if versionAlt == "0" {
        return false, false
    }
    // 在熱更新過程中
    versionInt, _ := strconv.Atoi(version)
    versionAltInt, _ := strconv.Atoi(versionAlt)
    // version是單調遞增的int類型,新版本的version值會更大
    return true, versionInt > versionAltInt
}           

2. ListenFD 遷移

通過 Unix Domain Socket 實作 ListenFD 在不同容器間的遷移,此步同樣也是熱更新中非常關鍵的一步,代碼示例如下:

// 為了代碼的簡潔,所有的失敗都将不捕獲

/* 老版本sidecar通過Unix Domain Socket遷移ListenFD到新版本sidecar */
// tcpLn *net.TCPListener
f, _ := tcpLn.File()
fdnum := f.Fd()
data := syscall.UnixRights(int(fdnum))
// 與新版本sidecar容器通過 Unix Domain Socket建立連結
raddr, _ := net.ResolveUnixAddr("unix", "/dev/shm/migrate.sock")
uds, _ := net.DialUnix("unix", nil, raddr)
// 通過UDS,發送ListenFD到新版本sidecar容器
uds.WriteMsgUnix(nil, data, nil)
// 停止接收新的request,并且開始排水階段,例如:http2 GOAWAY
tcpLn.Close()

/* 新版本sidecar接收ListenFD,并且開始對外服務 */
// 監聽 UDS
addr, _ := net.ResolveUnixAddr("unix", "/dev/shm/migrate.sock")
unixLn, _ := net.ListenUnix("unix", addr)
conn, _ := unixLn.AcceptUnix()
buf := make([]byte, 32)
oob := make([]byte, 32)
// 接收 ListenFD
_, oobn, _, _, _ := conn.ReadMsgUnix(buf, oob)
scms, _ := syscall.ParseSocketControlMessage(oob[:oobn])
if len(scms) > 0 {
    // 解析FD,并轉化為 *net.TCPListener 
    fds, _ := syscall.ParseUnixRights(&(scms[0]))
    f := os.NewFile(uintptr(fds[0]), "")
    ln, _ := net.FileListener(f)
    tcpLn, _ := ln.(*net.TCPListener)
    // 基于接收到的Listener開始對外提供服務,以http服務為例
    http.Serve(tcpLn, serveMux)
}           

已知 Mesh 容器熱更新案例

阿裡雲服務網格( Alibaba Cloud Service Mesh,簡稱 ASM)提供了一個全托管式的服務網格平台,相容社群 Istio 開源服務網格。目前,基于 OpenKruise SidecarSet 的熱更新能力,ASM 實作了資料平面 Sidecar 熱更新能力( Beta ),使用者可以在應用無感的情況下完成服務網格的資料平面版本更新,正式版也将于近期上線。除熱更新能力外,ASM 還支援配置診斷、操作審計、通路日志、監控、服務注冊接入等能力,全方位提升服務網格使用體驗,歡迎您前往試用。

總結

雲原生中 Mesh 容器的熱更新一直都是迫切卻又棘手的問題,本文中的方案也隻是阿裡巴巴集團在此問題上的一次探索,在回報社群的同時也希望能夠抛磚引玉,引發各位對此中場景的思考。同時,我們也歡迎更多的同學參與到 OpenKruise 社群來,共同建設一個場景更加豐富、完善的 K8s 應用管理、傳遞擴充能力,能夠面向更加規模化、複雜化、極緻性能的場景。

OpenKruise :SidecarSet 助力 Mesh 容器熱更新前言背景:如何獨立更新 Mesh 容器SidecarSet 助力 Mesh 容器無損熱更新已知 Mesh 容器熱更新案例