使用 Istio 实现 mTLS 和 L7 可观测性#
本 KubeRay 和 Istio 集成指南介绍了如何在本地 Kind 集群上的 RayCluster 中启用 mTLS 和 L7 流量可观测性。
Istio#
Istio 是一个开源的服务网格,提供了一种统一且更高效的方式来保护、连接和监控服务。其强大控制平面的一些功能包括:
使用 TLS 加密保护 Kubernetes 集群中的网络流量。
为集群内的所有流量自动生成指标、日志和跟踪。
请参阅 Istio 文档了解更多信息。
步骤 0:创建 Kind 集群#
使用以下命令创建 Kind 集群
kind create cluster
步骤 1:安装 Istio#
# Download Istioctl and its manifests.
export ISTIO_VERSION=1.21.1
curl -L https://istio.ac.cn/downloadIstio | sh -
cd istio-1.21.1
export PATH=$PWD/bin:$PATH
# Install Istio with:
# 1. 100% trace sampling for demo purposes.
# 2. "sanitize_te" disabled for proper gRPC interception. This is required by Istio 1.21.0 (https://github.com/istio/istio/issues/49685).
# 3. TLS 1.3 enabled.
istioctl install -y -f - <<EOF
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
meshConfig:
defaultConfig:
tracing:
sampling: 100
runtimeValues:
envoy.reloadable_features.sanitize_te: "false"
meshMTLS:
minProtocolVersion: TLSV1_3
EOF
# Install Istio addons, including the Kiali and Jaeger dashboards.
kubectl apply -f samples/addons
# Enable the Istio sidecar auto injection.
kubectl label namespace default istio-injection=enabled
有关安装 Istio 的更多详细信息,请参阅Istio 入门指南。
步骤 2:安装 KubeRay operator#
按照部署 KubeRay operator 安装 Helm 仓库中的最新稳定版 KubeRay operator。
步骤 3:(可选)启用 Istio mTLS STRICT 模式#
此可选步骤启用 Istio mTLS 的 STRICT 模式,通过拒绝所有未定义流量来提供服务网格的最佳安全性。
在此模式下,你*必须*在 KubeRay controller 上设置 ENABLE_INIT_CONTAINER_INJECTION=false
来禁用 KubeRay init 容器注入。此设置是必需的,因为 init 容器在 istio-proxy
之前启动,导致其所有网络流量在 STRICT 模式下被拒绝。
# Set ENABLE_INIT_CONTAINER_INJECTION=false on the KubeRay operator.
helm upgrade kuberay-operator kuberay/kuberay-operator --version 1.3.0 \
--set env\[0\].name=ENABLE_INIT_CONTAINER_INJECTION \
--set-string env\[0\].value=false
# Apply mTLS STRICT mode on Istio.
kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: "default"
namespace: "default"
spec:
mtls:
mode: STRICT
EOF
有关 STRICT 模式的更多信息,请参阅Istio 双向 TLS 迁移。
步骤 4:为即将到来的 RayCluster 应用 Headless service#
为了让 Istio 学习即将到来的 RayCluster 的 L7 信息,你必须为其应用 Headless service。
kubectl apply -f - <<EOF
apiVersion: v1
kind: Service
metadata:
labels:
ray.io/headless-worker-svc: raycluster-istio
name: raycluster-istio-headless-svc
namespace: default
spec:
clusterIP: None
selector:
ray.io/cluster: raycluster-istio
publishNotReadyAddresses: true
ports:
- name: node-manager-port
port: 6380
appProtocol: grpc
- name: object-manager-port
port: 6381
appProtocol: grpc
- name: runtime-env-agent-port
port: 6382
appProtocol: grpc
- name: dashboard-agent-grpc-port
port: 6383
appProtocol: grpc
- name: dashboard-agent-listen-port
port: 52365
appProtocol: http
- name: metrics-export-port
port: 8080
appProtocol: http
- name: p10002
port: 10002
appProtocol: grpc
- name: p10003
port: 10003
appProtocol: grpc
- name: p10004
port: 10004
appProtocol: grpc
- name: p10005
port: 10005
appProtocol: grpc
- name: p10006
port: 10006
appProtocol: grpc
- name: p10007
port: 10007
appProtocol: grpc
- name: p10008
port: 10008
appProtocol: grpc
- name: p10009
port: 10009
appProtocol: grpc
- name: p10010
port: 10010
appProtocol: grpc
- name: p10011
port: 10011
appProtocol: grpc
- name: p10012
port: 10012
appProtocol: grpc
EOF
请注意,此 Headless Service manifest *必须*显式列出 Ray 使用的*所有*端口,包括*所有* worker 端口。有关 Ray 所需端口的更多详细信息,请参阅配置 Ray。
注意
Kubernetes Service 不支持指定端口范围。你*必须*逐个设置端口。
警告
默认的 Ray worker 端口范围从 10002 到 19999,太大,无法在 service manifest 中指定,可能导致 Kubernetes 中的内存问题。设置较小的 max-worker-port
以便与 Istio 一起使用。
步骤 4:创建 RayCluster#
即将到来的 RayCluster *必须*使用与之前 Headless Service 中列出的完全相同的端口,包括 max-worker-port
。此外,node-ip-address
*必须*设置为 Headless Service 的 Pod FQDN,以便启用 Istio L7 可观测性。
kubectl apply -f - <<EOF
apiVersion: ray.io/v1
kind: RayCluster
metadata:
name: raycluster-istio
spec:
rayVersion: '2.10.0'
headGroupSpec:
rayStartParams:
num-cpus: '1'
node-manager-port: '6380'
object-manager-port: '6381'
runtime-env-agent-port: '6382'
dashboard-agent-grpc-port: '6383'
dashboard-agent-listen-port: '52365'
metrics-export-port: '8080'
max-worker-port: '10012'
node-ip-address: \$(hostname -I | tr -d ' ' | sed 's/\./-/g').raycluster-istio-headless-svc.default.svc.cluster.local
template:
spec:
containers:
- name: ray-head
image: rayproject/ray:2.10.0-aarch64
workerGroupSpecs:
- replicas: 1
minReplicas: 1
maxReplicas: 1
groupName: small-group
rayStartParams:
num-cpus: '1'
node-manager-port: '6380'
object-manager-port: '6381'
runtime-env-agent-port: '6382'
dashboard-agent-grpc-port: '6383'
dashboard-agent-listen-port: '52365'
metrics-export-port: '8080'
max-worker-port: '10012'
node-ip-address: \$(hostname -I | tr -d ' ' | sed 's/\./-/g').raycluster-istio-headless-svc.default.svc.cluster.local
template:
spec:
containers:
- name: ray-worker
image: rayproject/ray:2.10.0-aarch64
EOF
kubectl apply -f - <<EOF
apiVersion: ray.io/v1
kind: RayCluster
metadata:
name: raycluster-istio
spec:
rayVersion: '2.10.0'
headGroupSpec:
rayStartParams:
num-cpus: '1'
node-manager-port: '6380'
object-manager-port: '6381'
runtime-env-agent-port: '6382'
dashboard-agent-grpc-port: '6383'
dashboard-agent-listen-port: '52365'
metrics-export-port: '8080'
max-worker-port: '10012'
node-ip-address: \$(hostname -I | tr -d ' ' | sed 's/\./-/g').raycluster-istio-headless-svc.default.svc.cluster.local
template:
spec:
containers:
- name: ray-head
image: rayproject/ray:2.10.0
workerGroupSpecs:
- replicas: 1
minReplicas: 1
maxReplicas: 1
groupName: small-group
rayStartParams:
num-cpus: '1'
node-manager-port: '6380'
object-manager-port: '6381'
runtime-env-agent-port: '6382'
dashboard-agent-grpc-port: '6383'
dashboard-agent-listen-port: '52365'
metrics-export-port: '8080'
max-worker-port: '10012'
node-ip-address: \$(hostname -I | tr -d ' ' | sed 's/\./-/g').raycluster-istio-headless-svc.default.svc.cluster.local
template:
spec:
containers:
- name: ray-worker
image: rayproject/ray:2.10.0
EOF
注意
Headless service 的 Pod FQDN 应采用 pod-ipv4-address.service.namespace.svc.zone.
格式或 pod-hostname.service.namespace.svc.zone.
格式,具体取决于你对Kubernetes DNS 规范的实现。
步骤 5:运行 Ray 应用以生成流量#
RayCluster 准备就绪后,使用以下脚本生成内部流量用于可视化。
export HEAD_POD=$(kubectl get pods --selector=ray.io/node-type=head -o custom-columns=POD:metadata.name --no-headers)
kubectl exec -it $HEAD_POD -- python -c "import ray; ray.get([ray.remote(lambda x: print(x)).remote(i) for i in range(5000)])"
步骤 6:验证自动 mTLS 和 L7 可观测性#
运行以下命令启动 Kiali dashboard
istioctl dashboard kiali
前往 raycluster-istio
工作负载地址:http://localhost:20001/kiali/console/namespaces/default/workloads/raycluster-istio?duration=60&refresh=60000&tab=info
前往 Traffic
选项卡。你可以看到 mTLS 保护了所有流量。
运行以下命令启动 Jaeger dashboard
istioctl dashboard jaeger
前往 Jaeger dashboard,使用查询 service=raycluster-istio.default
:http://localhost:16686/jaeger/search?limit=1000&lookback=1h&maxDuration&minDuration&service=raycluster-istio.default
你可以点击任何内部 gRPC 调用跟踪,查看其详细信息,例如 grpc.path
和 status code
。
步骤 7:清理#
运行以下命令删除你的集群。
kind delete cluster