Kubernetes 经常被批评(有些不公平)操作起来过于复杂,促使大多数人依赖托管服务。然而,k3s
某种程度上颠覆了这一点,将完整的 Kubernetes 发行版打包成一个二进制文件。这非常方便,特别是在物联网等小型环境中运行时;虽然隔离组件对非常大规模、先进的部署有好处,但对较小的环境来说,操作微服务可能只是一种负担——这正是 Istio 多年前选择重构为更单体架构的原因。
然而,它还是没有那么“精简”。在一个空集群中运行 k3d cluster create test
后,我们会在集群中看到各种 pod:
$ kubectl get pods --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
kube-system local-path-provisioner-6c86858495-gc9jq 1/1 Running 0 2m18s
kube-system coredns-6799fbcd5-pdf4b 1/1 Running 0 2m18s
kube-system helm-install-traefik-crd-cp9s2 0/1 Completed 0 2m18s
kube-system helm-install-traefik-pch7c 0/1 Completed 1 2m18s
kube-system traefik-f4564c4f4-q4lkj 1/1 Running 0 2m8s
kube-system metrics-server-54fd9b65b-d69w6 1/1 Running 0 2m18s
kube-system svclb-traefik-58c5bb65-sq54b 2/2 Running 0 2m8s
k3d
是一个方便的工具,可以在 Docker 内部部署k3s
,便于测试。
这是怎么回事?我们的“单二进制 Kubernetes”怎么变成了 6 个不同的容器?
虽然 k3s 将许多组件(kube-proxy
、flannel
、containerd
、kubelet
等)嵌入到一个二进制文件中,但其他组件则作为标准 pod 在集群中运行。
此外,一旦我们部署了我们最喜欢的 服务网格,我们将会有更多的 pod,使我们离没有 pod 的目标更远。
那么问题是——我们能否通过进一步推进 k3s
的理念,将完整的集群功能嵌入到一个二进制文件中,来获得一个功能齐全的 Kubernetes 和 Istio 部署?
警告:这些是实验性概念;绝不要在生产环境中尝试!
首先,我们可以直接去除一些不必要的组件,如 servicelb
(负载均衡服务需要)、traefik
(Ingress 需要)、local-storage
(PVC 需要)和 metrics-server
(kubectl top
需要)。
这就剩下 coredns
和 Istio。
如果我们追求极简,我们肯定会希望使用 Istio 的 ambient mode,它完全不需要 sidecar。幸运的是,它开箱即用并且有完整的 DNS 支持。这让我们可以去掉 coredns
。
这样一来,如果我们能运行 Istio ambient,就可以去掉 kube-system
中的所有内容。这相对简单;难点在于不为 Istio 添加更多的 pod。
通过 k3s
的一个分支,我修改了它,使 Istio 本身嵌入到 k3s
中。k3s
可以作为服务器和/或代理运行。通常你会有 1 个服务器,每个其他节点作为代理运行。
在 server
上,我们希望运行 Istiod
(Istio 的控制平面)。在代理上,我们希望运行 istio-cni
(每个节点的控制平面)和 ztunnel
(每个节点的数据平面)。
这三个组件都可以直接嵌入到 k3s
中,只需一些工作!
使用这个自定义构建,我们可以通过一些自定义配置启动一个新的 k3d
集群,禁用我们不再需要的组件:
apiVersion: k3d.io/v1alpha5
kind: Simple
metadata:
name: podless
servers: 1
agents: 1
options:
k3d:
wait: true
timeout: "60s"
disableLoadbalancer: true
disableRollback: true
k3s:
extraArgs:
- arg: --disable-cloud-controller
nodeFilters:
- server:*
- arg: --disable-kube-proxy
nodeFilters:
- server:*
- arg: --disable-network-policy
nodeFilters:
- server:*
- arg: --disable-helm-controller
nodeFilters:
- server:*
- arg: --disable=coredns,servicelb,traefik,local-storage,metrics-server
nodeFilters:
- server:*
这里我们禁用了上面看到的所有 pod,包括一些额外的。
一个显著的例子是 kube-proxy
。像其他一些项目一样(如 Cilium),Istio 的 ztunnel
可以有效地替代大多数用例中的 kube-proxy
。
所有配置就绪后,我们的集群是什么样子?
$ kubectl get pods --all-namespaces
No resources found
到目前为止一切顺利….当然,什么都不运行很容易;真正的挑战是保持集群的功能。
让我们部署一些应用程序 pod。再次强调,这些是集群中的唯一 pod:
$ kubectl get pods --all-namespaces
NAMESPACE NAME READY STATUS RESTARTS AGE
default shell-5fff89ccf5-98kgg 1/1 Running 0 19s
default echo-66d88ff694-9qprp 1/1 Running 0 14s
然后我们可以发送流量:
$ kubectl exec deploy/shell -- curl -s echo
RequestHeader=Accept:*/*
RequestHeader=User-Agent:curl/8.5.0
Hostname=echo-66d88ff694-9qprp
流量完全正常,包括服务流量(以前由 kube-proxy
处理)和 DNS(以前由 coredns
处理)。现在这些全部由 ztunnel
处理,并且所有内容都通过安全的 mTLS 传输。
除了 mTLS 加密,我们还可以基于 mTLS 身份应用策略。同样,这些都由 ztunnel
执行。
apiVersion: security.istio.io/v1
kind: AuthorizationPolicy
metadata:
name: allow-default
spec:
action: ALLOW
selector:
matchLabels:
app: echo
rules:
- from:
- source:
namespace: ["cluster.local/ns/default/sa/shell"]
现在 default
命名空间的流量被允许,但其他流量不被允许。我们可以通过从 shell
发送流量以及我在 other
命名空间中部署的新测试工作负载来验证这一点:
$ kubectl exec deploy/shell -- curl -s echo
RequestHeader=Accept:*/*
RequestHeader=User-Agent:curl/8.5.0
Hostname=echo-66d88ff694-9qprp
$ kubectl exec deploy/shell -n other -- curl -s echo
command terminated with exit code 56
正如预期的那样,我们的其他应用程序被拒绝了!
此外,如果我们愿意,我们可以将流量升级通过完整的 HTTP 代理(“waypoint”):
$ istioctl x waypoint apply --enroll-namespace
waypoint default/waypoint applied
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
echo-66d88ff694-czd65 1/1 Running
0 93m
shell-56bd5dbdbf-f4gh9 1/1 Running 0 93m
waypoint-7cd4dc789f-2s7z2 1/1 Running 0 41s
$ kubectl exec deploy/shell -- curl -s echo
RequestHeader=Accept:*/*
RequestHeader=User-Agent:curl/8.5.0
RequestHeader=X-Request-Id:18d72190-9caa-4162-8bc5-4c11518d7568
Hostname=echo-66d88ff694-czd65
现在我们的 waypoint 已经部署,所有到命名空间的流量会自动转发到它,在那里可以执行完整的 HTTP 策略。这里,我们可以看到 X-Request-Id
被添加到我们的请求中,但我们还可以获得 自动配置的其他功能,以及更多 我们可以配置的内容。
最终,我们能够部署一个完整的 Kubernetes 集群和服务网格,所有基础设施组件嵌入到一个隐藏的节点二进制文件中——集群功能不需要 pod。
这实际操作起来是否实用?不太实用。然而,这确实表明 Kubernetes/Istio 被认为过于臃肿和复杂的看法并不完全准确。
它真的比典型的集群更简单吗?某种程度上是的……我们确实替换了两个组件(kube-proxy
和 coredns
),但其余的我们基本上只是隐藏和打包。这显然不如完全替换有意义,但也不错。话虽如此,隐藏东西对 社交媒体参与度 有好处,而 k3s
通过有效地隐藏和打包取得了巨大成功,因此显然提供了一些实实在在的好处。
最后更新于 2024/11/21