在 Istio 中使用 Kubernetes 原生 Sidecar

使用 Istio 演示新的 SidecarContainers 功能。

Aug 15, 2023 | By John Howard - Google; Translated by Wilson Wu - DaoCloud

如果您曾经听说过有关服务网格的些许信息, 那就会知道它是以 Sidecar 模式工作的:与应用代码并列部署一个代理服务器。 Sidecar 就是这样:它是一种模式。在今日(8 月 15 日,即 Kubernetes 1.28 正式发版之日)之前,Kubernetes 对 Sidecar 容器从未有任何形式的正式支持。

这导致了许多问题:如果您有一个按照预期终止的 Job, 但由于 Sidecar 容器却不能达到这个预期,该怎么办?这是 Kubernetes Issue 跟踪器上最受欢迎的具体使用场景。

在 Kubernetes 中添加 Sidecar 支持的提案于 2019 年正式提出。 一路走来,经历了许多停顿,在去年该项目重新启动后,对 Sidecar 的正式支持将以 Alpha 功能发布在 Kubernetes 1.28 中。 Istio 已经实现了对此功能的支持,在本文中您可以了解如何利用其优势。

Sidecar 的困境

Sidecar 容器提供了强大的功能,但也存在一些问题。 虽然 Pod 内的容器可以共享一些资源,但这些资源的生命周期是完全解耦的。 对于 Kubernetes 来说,这两种容器在功能上是相同的。

然而,在 Istio 中,它们并不相同 — Istio 容器必须以主应用程序容器正常运行为前提, 如果没有主应用程序容器,那么 Istio 容器就没有任何价值。

这种期望的不匹配会导致各种问题:

虽然 Istio 社区内外花费了无数时间来解决这些问题,但取得的成果仍然有限。

从根源解决

虽然 Istio 中日益复杂的变通方案可以帮助减轻 Istio 用户的痛苦, 但理想情况下,所有相关情况下都应该正常运转 - 而不仅仅是针对 Istio。 幸运的是,Kubernetes 社区一直努力直接在 Kubernetes 中解决这些问题。

在 Kubernetes 1.28 中,合并了一项为 Sidecar 添加原生支持的新功能, 这为 5 年多的持续工作画上了句号。通过该功能,我们的所有问题都可以得到解决,而无需其他变通方案!

当我们进入“GitHub Issue 名人堂”时, 这些在所有 Kubernetes Issue 中的 #1 和 #6 的两个 Issue - 终于被关闭了!

特别感谢让这个功能冲过终点线的众多贡献者。

尝试一下

虽然 Kubernetes 1.28 刚刚发布,新的 SidecarContainers 功能还处于 Alpha 阶段(因此默认情况下处于关闭状态),而且 Istio 中对该功能的支持尚未发布, 但我们今天仍然可以尝试一下 - 只是不要在生产环境中尝试!

首先,我们需要启动 Kubernetes 1.28 集群,并启用 SidecarContainers 功能:

$ cat <<EOF | kind create cluster --name sidecars --image gcr.io/istio-testing/kind-node:v1.28.0 --config=-
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
featureGates:
  SidecarContainers: true
EOF

然后我们可以下载最新的 Istio 1.19 预发布版(因为 1.19 尚未发布)。 我使用的是 Linux。这是 Istio 的预发行版,因此再次强调 - 不要在生产环境中尝试此操作! 当我们安装 Istio 时,我们将启用原生 Sidecar 功能的支持标志,并打开访问日志用于帮助后续演示。

$ TAG=1.19.0-beta.0
$ curl -L https://github.com/istio/istio/releases/download/$TAG/istio-$TAG-linux-amd64.tar.gz | tar xz
$ ./istioctl install --set values.pilot.env.ENABLE_NATIVE_SIDECARS=true -y --set meshConfig.accessLogFile=/dev/stdout

最后我们可以部署一个工作负载:

$ kubectl label namespace default istio-injection=enabled
$ kubectl apply -f samples/sleep/sleep.yaml

让我们看看 Pod 情况:

$ kubectl get pods
NAME                     READY   STATUS    RESTARTS   AGE
sleep-7656cf8794-8fhdk   2/2     Running   0          51s

乍一看,一切都很正常……,但如果我们深入观察,就能看到其中的魔力。

$ kubectl get pod -o "custom-columns="\
"NAME:.metadata.name,"\
"INIT:.spec.initContainers[*].name,"\
"CONTAINERS:.spec.containers[*].name"

NAME                     INIT                     CONTAINERS
sleep-7656cf8794-8fhdk   istio-init,istio-proxy   sleep

在这里我们可以看到 Pod 中的所有 containersinitContainers

令人惊喜的是!istio-proxy 现在以一个 initContainer 方式存在。

更具体地说,它是一个被设置了 restartPolicy: AlwaysinitContainer (一个新字段,随着 SidecarContainers 功能被启用)。 该设置告诉 Kubernetes 将其视为 Sidecar。

这意味着在代理容器准备好之前,initContainers 以及 containers 中的所有后续容器将不会被启动。 此外,即使代理容器仍在运行,Pod 也可以被终止。

Init 容器流量

为了测试这一点,我们让 Pod 真正做一些事情。这里我们部署了一个简单的 Pod, 它在 initContainer 中发送请求。通常情况下,这会失败。

apiVersion: v1
kind: Pod
metadata:
  name: sleep
spec:
  initContainers:
  - name: check-traffic
    image: istio/base
    command:
    - curl
    - httpbin.org/get
  containers:
  - name: sleep
    image: istio/base
    command: ["/bin/sleep", "infinity"]

检查代理容器,我们可以看到请求均成功并通过了 Istio Sidecar:

$ kubectl logs sleep -c istio-proxy | tail -n1
[2023-07-25T22:00:45.703Z] "GET /get HTTP/1.1" 200 - via_upstream - "-" 0 1193 334 334 "-" "curl/7.81.0" "1854226d-41ec-445c-b542-9e43861b5331" "httpbin.org" ...

如果我们检验 Pod,我们可以看到 Sidecar 当前在 check-traffic initContainer 之前运行:

$ kubectl get pod -o "custom-columns="\
"NAME:.metadata.name,"\
"INIT:.spec.initContainers[*].name,"\
"CONTAINERS:.spec.containers[*].name"

NAME    INIT                                  CONTAINERS
sleep   istio-init,istio-proxy,check-traffic   sleep

退出 Pod

之前,我们提到当应用程序退出时(常见于 Job),Pod 将永远存在。 幸运的是,这个问题也得到了解决!

首先我们部署一个 Pod,它将在一秒后退出并且不会重新启动:

apiVersion: v1
kind: Pod
metadata:
  name: sleep
spec:
  restartPolicy: Never
  containers:
- name: sleep
  image: istio/base
  command: ["/bin/sleep", "1"]

我们可以观察它的进展:

$ kubectl get pods -w
NAME    READY   STATUS     RESTARTS   AGE
sleep   0/2     Init:1/2   0          2s
sleep   0/2     PodInitializing   0          2s
sleep   1/2     PodInitializing   0          3s
sleep   2/2     Running           0          4s
sleep   1/2     Completed         0          5s
sleep   0/2     Completed         0          12s

在这里我们可以看到应用程序容器退出了,不久之后 Istio 的 Sidecar 容器也退出了。 在此之前,Pod 会停留在 Running 状态,而现在它可以转换为 Completed。不再有僵尸 Pod 存在!

Ambient 模式又当如何?

去年,Istio 宣布了 Ambient 模式 - Istio 的一种新数据平面模式,不依赖 Sidecar 容器。那么随着 Ambient 模式的到来,这一切还重要吗?

我会大声地告诉大家“重要”!

虽然当 Ambient 模式用于工作负载时,Sidecar 的影响会减轻, 但我预计几乎所有大规模 Kubernetes 集群的用户在其部署中都会存在某种 Sidecar。 这可能是他们不想迁移到 Ambient 模式的 Istio 工作负载、尚未完成迁移的工作负载或与 Istio 无关的内容。 因此,虽然这种情况可能较少,但对于使用 Sidecar 的情况来说,这仍然是一个巨大的改进。

您可能想了解的相反情况 - 如果我们所有的 Sidecar 问题都得到解决, 为什么我们还需要 Ambient 模式?解决了这些边车限制后,Ambient 仍然带来了多种好处。 例如,这篇博文详细介绍了将代理与工作负载分离的必要性。

自己尝试一下

我们鼓励有冒险精神的读者在测试环境中亲自尝试!对这些实验性和 Alpha 功能的反馈对于确保它们稳定并在推广之前满足预期至关重要。如果您做了尝试, 请让我们通过 Istio Slack 得知您的想法!

Kubernetes 团队特别有兴趣了解更多有关以下内容的信息: