OpenKruise :SidecarSet 助力 Mesh 容器热升级

简介: SidecarSet 基于上一个版本扩展了特别针对 Service Mesh 场景的支持。

作者| 赵明山(立衡)

头图.jpg

前言


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 的发布。
1--1.png

阿里巴巴集团内部拥有上万的 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

2-2.png

上述 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 执行多次热升级,则重复执行上述三个步骤即可。

3-3.png

Migration 核心逻辑

SidecarSet 热升级机制不仅完成了 Mesh 容器的切换,并且提供了新老版本的协调机制( PostStartHook ),但是至此还只是万里长征的第一步,Mesh 容器同时还需要提供 PostSartHook 脚本来完成 Mesh 服务自身的平滑升级(上述 Migration 过程),如:Envoy 热重启、Mosn 无损重启。

Mesh 容器一般都是通过监听固定端口来对外提供服务,此类 Mesh 容器的migration 过程可以概括为:通过 UDS 传递 ListenFD 和停止 Accpet 、开始排水。针对不支持热重启的 Mesh 容器可以参考此过程完成改造,逻辑图如下:
4-4.png

热升级 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 应用管理、交付扩展能力,能够面向更加规模化、复杂化、极致性能的场景。

5-5.png

相关文章
|
人工智能 弹性计算 运维
阿里云容器服务 Serverless 版(ACK Serverless)全新升级
阿里云容器服务 Serverless 版(ACK Serverless)全新升级
1808 10
|
人工智能 运维 Kubernetes
阿里云 Serverless 容器服务全面升级:新增组件全托管、AI 镜像秒级拉取能力
阿里云 Serverless 容器服务全面升级:新增组件全托管、AI 镜像秒级拉取能力
|
人工智能 Kubernetes Cloud Native
【热点追踪】从价值到架构,走近全新升级的阿里云 Serverless 容器服务 ASK
【热点追踪】从价值到架构,走近全新升级的阿里云 Serverless 容器服务 ASK
|
Kubernetes 监控 Cloud Native
《云原生架构容器&微服务优秀案例集》——03 零售/电商——波司登 云原生架构升级,实现数字化业务创新
《云原生架构容器&微服务优秀案例集》——03 零售/电商——波司登 云原生架构升级,实现数字化业务创新
441 0
《云原生架构容器&微服务优秀案例集》——03 零售/电商——波司登 云原生架构升级,实现数字化业务创新
H8
|
安全 网络协议 Shell
Docker 枚举、特权升级和容器逃逸 (DEEPCE)
为了使其与最大数量的容器兼容,DEEPCE 是纯编写的sh,没有依赖性。如果可用,它将使用其他工具,例如 curl、nmap、nslookup 和 dig,但在大多数情况下不依赖于它们进行枚举。 枚举都不应该触及磁盘,但是大多数漏洞利用会创建新的容器,这将导致磁盘写入,并且一些漏洞利用会覆盖 runC,这可能具有破坏性,所以要小心!
H8
374 0
|
资源调度 负载均衡 Kubernetes
Koordinator 助力 ACK 容器调度升级,提升应用性能,节约资源成本
Koordinator 助力 ACK 容器调度升级,提升应用性能,节约资源成本
Koordinator 助力 ACK 容器调度升级,提升应用性能,节约资源成本
|
Prometheus Kubernetes 监控
万兴科技应用容器化改造实现云原生转型升级
“在项目过程中,项目团队充分体现了阿里的专业素养与精神,高效高质的完成了项目交付,使万兴的技术架构往云原生化方向迈进了坚实的一步。”
1036 0
万兴科技应用容器化改造实现云原生转型升级
|
Kubernetes Cloud Native Dubbo
Meetup 报名丨 共话云原生架构升级,微服务x容器开源 Meetup 北京站来啦!
聆听精彩分享,零距离对话热门开源项目核心维护者。2023 年 02 月 25 日,微服务x容器开源开发者 Meetup 北京站来啦!
65133 0
Meetup 报名丨 共话云原生架构升级,微服务x容器开源 Meetup 北京站来啦!
|
容器
openGauss容器版本升级指南——抽丝剥茧(二)
openGauss容器版本升级指南——抽丝剥茧
410 0