本文介绍如何为 Azure Kubernetes 服务(AKS)群集的 Istio 服务网格加载项部署出口网关。
概述
Istio 出口网关可用作一个集中式点,用于监视和限制来自网格中的应用程序的出站流量。 借助 Istio 加载项,可以跨不同的命名空间部署多个出口网关,从而设置所选的出口网关拓扑:每个群集的出口网关、每个命名空间、每个工作负荷等。虽然 AKS 管理 Istio 加载项出口网关的预配和生命周期,但必须创建 Istio 自定义资源,以便通过出口网关路由来自网格中的应用程序的流量,并应用策略和遥测收集。
Istio 加载项流出量网关也基于静态流出量网关功能构建并且需要该功能,该功能为 Istio 流出量 Pod 分配固定的源 IP 地址前缀。 可以使用此可预测的出站 IP 范围,用于防火墙规则和其他出站流量过滤机制。 通过在静态出口网关的基础上使用 Istio 出口网关,可以应用 Istio L7、基于标识的策略和基于 IP 的限制,以实现深度防御的出口流量控制。 此外,通过 Istio 流出量网关定向出站流量允许多个工作负载通过静态流出量网关节点池路由流量,而无需直接修改这些应用程序 Pod/部署。
限制和要求
- 每个群集最多可启用
500
个 Istio 加载项出口网关。 - Istio 加载项流出量网关名称在每个命名空间中必须是唯一的。
- Istio 加载项流出量网关名称必须在
1-53
个字符之间,只能由小写字母数字字符、“-”和“.”组成,并且必须以字母数字字符开头和结尾。 名称还应是有效的域名系统(DNS)名称。 用于名称验证的正则表达式为^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$
。 - Istio 加载项流出量网关目前不支持网关 API。
先决条件
启用 Istio 加载项
本指南假定你已按照文档的说明在 AKS 群集上启用 Istio 加载项。
安装 aks-preview
Azure CLI 扩展
如果您正在使用 Azure CLI,请安装 aks-preview
扩展。 必须使用 aks-preview
版本 14.0.0b2
或更高版本。
使用
aks-preview
命令安装az extension add
扩展。az extension add --name aks-preview
使用
az extension update
命令更新到扩展的最新版本。az extension update --name aks-preview
启用和配置静态出口网关
按照 静态出口网关文档中 的说明在群集上启用静态出口网关、创建模式 gateway
节点池和创建 StaticGatewayConfiguration
资源。
启用 Istio 流出量网关
注释
Istio 加载项流出量网关 Pod 不会计划到 gateway
节点池。
gateway
节点池仅用于路由出口流量,不提供常规用途工作负荷。 如果需要将出口网关 Pod 调度到特定节点,可以使用 AKS 系统节点 或 azureservicemesh/istio.replica.preferred
节点标签。 Pod 具有节点相关性,对标记为 AKS 系统节点(100
)的节点,具有权重首选项kubernetes.azure.com/mode: system
;对标记为50
的节点,具有权重首选项azureservicemesh/istio.replica.preferred: true
。
使用 az aks mesh enable-egress-gateway
在 AKS 群集上启用 Istio 出口网关。 必须指定 Istio 流出量网关的名称以及你在StaticGatewayConfiguration
步骤中创建的 的名称。 还可以指定要在其中部署 Istio 出口网关的命名空间,该网关必须与在其中创建的命名空间 StaticGatewayConfiguration
相同。 如果未指定命名空间,则将在 aks-istio-egress
命名空间中预配出口网关。
最佳做法是,在使用该网关配置启用 Istio 流出量网关之前,应等待为 StaticGatewayConfiguration
分配 egressIpPrefix
。
az aks mesh enable-egress-gateway --resource-group $RESOURCE_GROUP --name $CLUSTER_NAME --istio-egressgateway-name $ISTIO_EGRESS_NAME --istio-egressgateway-namespace $ISTIO_EGRESS_NAMESPACE --gateway-configuration-name $ISTIO_SGC_NAME
验证是否已为流出量网关创建服务。
kubectl get svc $ISTIO_EGRESS_NAME -n $ISTIO_EGRESS_NAMESPACE
应会看到流出量网关的 ClusterIP
服务:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
asm-egress-test ClusterIP 10.0.128.17 <none> 15021/TCP,80/TCP,443/TCP 6d4h
还可以验证是否已为 Istio 流出量网关创建部署,并且流出量网关 Pod 是否已将 kubernetes.azure.com/static-gateway-configuration
批注设置为 gatewayConfigurationName
。
ASM_REVISION=$(az aks show -g $RESOURCE_GROUP -n $CLUSTER_NAME | jq '.serviceMeshProfile.istio.revisions[0]' | sed 's/"//g')
kubectl get deployment $ISTIO_EGRESS_NAME-$ASM_REVISION -n $ISTIO_EGRESS_NAMESPACE -o jsonpath={.spec.template.metadata.annotations."kubernetes\.azure\.com\/static-gateway-configuration"}
可以再次运行 az aks mesh enable-egress-gateway
该命令以创建另一个 Istio 出口网关。
注释
当对 Istio 加载项执行次要修订升级时,将针对新的控制平面修订为每个流出量网关创建另一个部署。
通过 Istio 流出量网关路由流量
设置 outboundTrafficPolicy.mode
默认情况下,Istio outboundTrafficPolicy.mode
被设置为 ALLOW_ANY
,这意味着 Envoy 将未知服务的请求直接传递处理。 作为安全最佳实践,应将 Istio outboundTrafficPolicy.mode
设置为REGISTRY_ONLY
,以便 Istio 代理阻止对未添加到 Istio 服务注册表中的服务的请求。 可以将群集外部的主机使用 ServiceEntry
添加到 Istio 的服务注册表中。
可以使用 Istio 加载项outboundTrafficPolicy.mode
在网格范围内配置 ,或使用挎斗自定义资源来定位特定的命名空间或工作负载。
apiVersion: v1
kind: ConfigMap
metadata:
name: istio-shared-configmap-asm-1-24
namespace: aks-istio-system
data:
mesh: |-
outboundTrafficPolicy:
mode: REGISTRY_ONLY
部署示例应用程序
在此示例中,我们将应用程序部署 curl
在与 Istio 加载项出口网关相同的命名空间中。 请记得使用 ISTIO_EGRESS_NAMESPACE
标签标记 istio.io/rev
,以便已部署的应用程序 Pod 注入挎斗:
kubectl label namespace $ISTIO_EGRESS_NAMESPACE istio.io/rev=$ASM_REVISION
然后,部署示例应用程序:
kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.24/samples/curl/curl.yaml -n $ISTIO_EGRESS_NAMESPACE
应会看到使用注入的挎斗容器运行 curl
Pod:
NAME READY STATUS RESTARTS AGE
curl-5b549b49b8-bcgts 2/2 Running 0 13s
尝试直接从curl
向edition.cnn.com
发送请求。
SOURCE_POD=$(kubectl get pod -n $ISTIO_EGRESS_NAMESPACE -l app=curl -o jsonpath={.items..metadata.name})
kubectl exec -n $ISTIO_EGRESS_NAMESPACE "$SOURCE_POD" -c curl -- curl -sSL -o /dev/null -D - http://edition.cnn.com/politics
如果将outboundTrafficPolicy.mode
设置为REGISTRY_ONLY
,那么curl
请求应该会失败,因为你没有为ServiceEntry
创建一个edition.cnn.com
。 如果outboundTrafficPolicy.mode
是ALLOW_ANY
,则请求应成功。
若要将请求从 edition.cnn.com
Pod 实际路由至 curl
Istio 插件出口网关,需创建ServiceEntry
并配置其他 Istio 自定义资源。 按照后续部分之一的说明配置 HTTP 出口网关、 HTTPS 出口网关或 源自传输层安全性(TLS)连接的出口网关。
在启动以下任一方案之前,请设置以下环境变量:
ISTIO_EGRESS_DEPLOYMENT=$ISTIO_EGRESS_NAME-$ASM_REVISION
EGRESS_GTW_SELECTOR=$(kubectl get deployment $ISTIO_EGRESS_DEPLOYMENT -n $ISTIO_EGRESS_NAMESPACE -o jsonpath={.metadata.labels.istio})
还可以通过 MeshConfig 或 Telemetry API启用 Envoy 访问日志记录。 启用访问日志记录后,可以通过检查 istio-proxy
容器日志来验证流量是否流经出口网关:
kubectl logs -l istio=$EGRESS_GTW_SELECTOR -n $ISTIO_EGRESS_NAMESPACE
配置 HTTP Istio 出口网关
- 为
ServiceEntry
创建edition.cnn.com
:
kubectl apply -n $ISTIO_EGRESS_NAMESPACE -f - <<EOF
apiVersion: networking.istio.io/v1
kind: ServiceEntry
metadata:
name: cnn
spec:
hosts:
- edition.cnn.com
ports:
- number: 80
name: http-port
protocol: HTTP
- number: 443
name: https
protocol: HTTPS
resolution: DNS
EOF
- 将
Gateway
、VirtualService
和DestinationRule
创建为出口网关,通过它将 HTTP 流量从curl
应用程序路由到edition.cnn.com
。 请务必根据流出量网关部署中的istio
标签选择器相应地设置网关选择器和服务完全限定的域名 (FQDN)。
kubectl apply -n $ISTIO_EGRESS_NAMESPACE -f - <<EOF
apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
name: istio-egressgateway
spec:
selector:
istio: $EGRESS_GTW_SELECTOR
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- edition.cnn.com
---
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: egressgateway-for-cnn
spec:
host: $ISTIO_EGRESS_NAME.$ISTIO_EGRESS_NAMESPACE.svc.cluster.local
subsets:
- name: cnn
---
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: direct-cnn-through-egress-gateway
spec:
hosts:
- edition.cnn.com
gateways:
- istio-egressgateway
- mesh
http:
- match:
- gateways:
- mesh
port: 80
route:
- destination:
host: $ISTIO_EGRESS_NAME.$ISTIO_EGRESS_NAMESPACE.svc.cluster.local
subset: cnn
port:
number: 80
weight: 100
- match:
- gateways:
- istio-egressgateway
port: 80
route:
- destination:
host: edition.cnn.com
port:
number: 80
weight: 100
EOF
- 尝试将 HTTP 请求从
curl
Pod 发送到edition.cnn.com
:
kubectl exec -n $ISTIO_EGRESS_NAMESPACE "$SOURCE_POD" -c curl -- curl -sSL -o /dev/null -D - http://edition.cnn.com/politics
应会看到 HTTP/2 200
响应。
- 清理资源
kubectl delete serviceentry cnn -n $ISTIO_EGRESS_NAMESPACE
kubectl delete gateway istio-egressgateway -n $ISTIO_EGRESS_NAMESPACE
kubectl delete virtualservice direct-cnn-through-egress-gateway -n $ISTIO_EGRESS_NAMESPACE
kubectl delete destinationrule egressgateway-for-cnn -n $ISTIO_EGRESS_NAMESPACE
配置 HTTPS Istio 出口网关
- 为
ServiceEntry
创建 HTTPSedition.cnn.com
:
kubectl apply -n $ISTIO_EGRESS_NAMESPACE -f - <<EOF
apiVersion: networking.istio.io/v1
kind: ServiceEntry
metadata:
name: cnn
spec:
hosts:
- edition.cnn.com
ports:
- number: 443
name: tls
protocol: TLS
resolution: DNS
EOF
- 将
Gateway
、VirtualService
和DestinationRule
创建为出口网关,通过它将 HTTP 流量从curl
应用程序路由到edition.cnn.com
。 请务必根据流出量网关部署中的istio
标签选择器相应地设置网关选择器和服务 FQDN。
kubectl apply -n $ISTIO_EGRESS_NAMESPACE -f - <<EOF
apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
name: istio-egressgateway
spec:
selector:
istio: $EGRESS_GTW_SELECTOR
servers:
- port:
number: 443
name: tls
protocol: TLS
hosts:
- edition.cnn.com
tls:
mode: PASSTHROUGH
---
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: egressgateway-for-cnn
spec:
host: $ISTIO_EGRESS_NAME.$ISTIO_EGRESS_NAMESPACE.svc.cluster.local
subsets:
- name: cnn
---
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: direct-cnn-through-egress-gateway
spec:
hosts:
- edition.cnn.com
gateways:
- mesh
- istio-egressgateway
tls:
- match:
- gateways:
- mesh
port: 443
sniHosts:
- edition.cnn.com
route:
- destination:
host: $ISTIO_EGRESS_NAME.$ISTIO_EGRESS_NAMESPACE.svc.cluster.local
subset: cnn
port:
number: 443
- match:
- gateways:
- istio-egressgateway
port: 443
sniHosts:
- edition.cnn.com
route:
- destination:
host: edition.cnn.com
port:
number: 443
weight: 100
EOF
- 尝试从
curl
发送 HTTPS 请求到edition.cnn.com
:
kubectl exec "$SOURCE_POD" -n $ISTIO_EGRESS_NAMESPACE -c curl -- curl -sSL -o /dev/null -D - https://edition.cnn.com/politics
应会看到 HTTP/2 200
响应。
- 清理资源
kubectl delete serviceentry cnn -n $ISTIO_EGRESS_NAMESPACE
kubectl delete gateway istio-egressgateway -n $ISTIO_EGRESS_NAMESPACE
kubectl delete virtualservice direct-cnn-through-egress-gateway -n $ISTIO_EGRESS_NAMESPACE
kubectl delete destinationrule egressgateway-for-cnn -n $ISTIO_EGRESS_NAMESPACE
配置 Istio 出口网关以执行 TLS 始发功能。
- 为
ServiceEntry
创建edition.cnn.com
:
kubectl apply -n $ISTIO_EGRESS_NAMESPACE -f - <<EOF
apiVersion: networking.istio.io/v1
kind: ServiceEntry
metadata:
name: cnn
spec:
hosts:
- edition.cnn.com
ports:
- number: 80
name: http
protocol: HTTP
- number: 443
name: https
protocol: HTTPS
resolution: DNS
EOF
- 创建
Gateway
、VirtualService
和DestinationRule
,用于将来自curl
应用程序的 HTTP 流量通过出口网关路由至edition.cnn.com
,并在出口网关执行 TLS 发起。 请务必根据流出量网关部署中的istio
标签选择器相应地设置网关选择器和服务 FQDN。
kubectl apply -n $ISTIO_EGRESS_NAMESPACE -f - <<EOF
apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
name: istio-egressgateway
spec:
selector:
istio: $EGRESS_GTW_SELECTOR
servers:
- port:
number: 80
name: https-port-for-tls-origination
protocol: HTTPS
hosts:
- edition.cnn.com
tls:
mode: ISTIO_MUTUAL
---
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: egressgateway-for-cnn
spec:
host: $ISTIO_EGRESS_NAME.$ISTIO_EGRESS_NAMESPACE.svc.cluster.local
subsets:
- name: cnn
trafficPolicy:
loadBalancer:
simple: ROUND_ROBIN
portLevelSettings:
- port:
number: 80
tls:
mode: ISTIO_MUTUAL
sni: edition.cnn.com
---
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
name: direct-cnn-through-egress-gateway
spec:
hosts:
- edition.cnn.com
gateways:
- istio-egressgateway
- mesh
http:
- match:
- gateways:
- mesh
port: 80
route:
- destination:
host: $ISTIO_EGRESS_NAME.$ISTIO_EGRESS_NAMESPACE.svc.cluster.local
subset: cnn
port:
number: 80
weight: 100
- match:
- gateways:
- istio-egressgateway
port: 80
route:
- destination:
host: edition.cnn.com
port:
number: 443
weight: 100
---
apiVersion: networking.istio.io/v1
kind: DestinationRule
metadata:
name: originate-tls-for-edition-cnn-com
spec:
host: edition.cnn.com
trafficPolicy:
loadBalancer:
simple: ROUND_ROBIN
portLevelSettings:
- port:
number: 443
tls:
mode: SIMPLE # initiates HTTPS for connections to edition.cnn.com
EOF
- 尝试发送请求表单
curl
到edition.cnn.com
,其中出口网关执行 TLS 起始过程;
kubectl exec "${SOURCE_POD}" -n $ISTIO_EGRESS_NAMESPACE -c curl -- curl -sSL -o /dev/null -D - http://edition.cnn.com/politics
应会看到 200
状态响应。
- 清理资源
kubectl delete serviceentry cnn -n $ISTIO_EGRESS_NAMESPACE
kubectl delete gateway istio-egressgateway -n $ISTIO_EGRESS_NAMESPACE
kubectl delete virtualservice direct-cnn-through-egress-gateway -n $ISTIO_EGRESS_NAMESPACE
kubectl delete destinationrule originate-tls-for-edition-cnn-com -n $ISTIO_EGRESS_NAMESPACE
kubectl delete destinationrule egressgateway-for-cnn -n $ISTIO_EGRESS_NAMESPACE
禁用 Istio 流出量网关
运行 az aks mesh disable-egress-gateway
命令以禁用创建的 Istio 加载项流出量网关:
az aks mesh disable-egress-gateway --resource-group $RESOURCE_GROUP --name $CLUSTER_NAME --istio-egressgateway-name $ISTIO_EGRESS_NAME --istio-egressgateway-namespace $ISTIO_EGRESS_NAMESPACE
禁用 Istio 流出量网关后,应能够删除流出量网关正在使用的 StaticGatewayConfiguration
、命名空间和 gateway
节点池(如果没有其他 Istio 流出量网关使用它们)。
后续步骤
注释
如果在部署 Istio 出口网关或配置出口流量路由时遇到问题,请参阅 有关排查 Istio 加载项出口网关问题的文章