Istio 中的 Kubernetes 原生 Sidecar
使用 Istio 演示新的 SidecarContainers 功能。
如果您听说过任何关于服务网格的信息,那就是它们使用 sidecar 模式工作:代理服务器与您的应用程序代码一起部署。sidecar 模式就是这样:一种模式。到目前为止,Kubernetes 完全没有正式支持 sidecar 容器。
这导致了许多问题:如果您有一个按设计终止的作业,但有一个不会终止的 sidecar 容器怎么办?这个确切的用例是Kubernetes 问题跟踪器上最受欢迎的用例。
在 2019 年提出了在 Kubernetes 中添加 sidecar 支持的正式提案。经过一路上的多次启动和停止,以及去年对项目的重启,Kubernetes 1.28 中将正式发布对 sidecar 的 Alpha 支持。Istio 已经实现了对该功能的支持,并且在本篇文章中,您可以了解如何利用它。
Sidecar 难题
Sidecar 容器提供了强大的功能,但也存在一些问题。虽然 Pod 中的容器可以共享某些内容,但它们的生命周期是完全解耦的。对于 Kubernetes 来说,这两个容器在功能上是相同的。
但是,在 Istio 中它们并不相同 - Istio 容器是主应用程序容器运行所必需的,并且如果没有主应用程序容器则没有价值。
这种预期上的不匹配会导致各种问题
- 如果应用程序容器启动速度快于 Istio 的容器,则它无法访问网络。这在 Istio 的 GitHub 上获得了最多的 +1。
- 如果 Istio 的容器在应用程序容器之前关闭,则应用程序容器无法访问网络。
- 如果应用程序容器有意退出(通常来自
Job
中的使用),Istio 的容器仍将运行并使 Pod 不断运行。这也是GitHub 上的一个热门问题。 - 在 Istio 的容器启动之前运行的
InitContainers
无法访问网络。
Istio 社区内外已经花费了无数小时来解决这些问题 - 但收效甚微。
解决根本原因
虽然 Istio 中越来越复杂的解决方法可以帮助减轻 Istio 用户的痛苦,但理想情况下,所有这些都应该正常工作 - 而且不仅仅是针对 Istio。幸运的是,Kubernetes 社区一直在努力直接在 Kubernetes 中解决这些问题。
在 Kubernetes 1.28 中,合并了一项添加对 sidecar 的原生支持的新功能,结束了 5 年多的持续工作。随着它的合并,我们所有的问题都可以在没有解决方法的情况下得到解决!
当我们身处“GitHub 问题名人堂”时,这两个问题占据了 Kubernetes 历时最久的问题的第 1 位和第 6 位 - 并且终于被关闭了!
特别感谢参与将此项目完成的众多个人。
试用
虽然 Kubernetes 1.28 刚刚发布,但新的 SidecarContainers
功能处于 Alpha 阶段(因此默认情况下处于关闭状态),并且 Istio 中对该功能的支持尚未发布,但我们今天仍然可以试用它 - 只是不要在生产环境中尝试!
首先,我们需要启动一个启用了 SidecarContainers
功能的 Kubernetes 1.28 集群
$ 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 中的所有 containers
和 initContainers
。
惊喜!istio-proxy
现在是 initContainer
。
更具体地说,它是一个 initContainer
,并设置了 restartPolicy: Always
(一个新字段,由 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
前面,我们提到当应用程序退出(在 Jobs
中很常见)时,Pod 将永远存在。幸运的是,这也得到了解决!
首先,我们部署一个将在 1 秒后退出并且不会重新启动的 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 了!
环境模式怎么样?
去年,Istio 宣布了环境模式 - Istio 的一种新的数据平面模式,它不依赖于 sidecar 容器。那么,随着环境模式的到来,这一切是否还有意义呢?
我会说一个响亮的“是”!
虽然当环境模式用于工作负载时,sidecar 的影响会减弱,但我预计几乎所有大型 Kubernetes 用户在其部署中都存在某种 sidecar。这可能是他们不想迁移到环境模式的 Istio 工作负载,是他们尚未迁移的工作负载,或者与 Istio 无关的事物。因此,虽然此问题相关的情况可能减少了,但对于使用 sidecar 的情况来说,它仍然是一个巨大的改进。
您可能会好奇相反的情况 - 如果我们所有的 sidecar 难题都得到了解决,我们为什么还需要环境模式呢?即使解决了这些 sidecar 限制,环境模式仍然带来各种好处。例如,这篇博文详细介绍了为什么将代理与工作负载解耦是有利的。
亲自试一试
我们鼓励喜欢冒险的读者在测试环境中亲自尝试!这些实验性和 Alpha 功能的反馈对于确保它们在提升之前是稳定并符合预期的至关重要。如果您试用了它,请在Istio Slack中告诉我们您的想法!
特别是,Kubernetes 团队希望了解更多关于以下方面的信息:
- 处理关闭顺序,尤其是在涉及多个 sidecar 的情况下。
- sidecar 容器崩溃时的回退重启处理。
- 他们尚未考虑到的极端情况。