服务可见性
istio 中每个服务默认可以访问网格中的任何服务,因此 istio 下发给每个 sidecar 的配置中会包含全量的服务数据,sidecar 可能会出现负载过高、内存过大的问题,影响业务容器的正常运行。istio 中设置服务可见性,主要有两种方式:
- sidecar 资源:设置负载代理的出入口配置,此 crd 可以设置全局默认配置、命名空间默认配置、针对某个服务负载的特定配置。
- exportTo 字段:包含两个部分,一是 istio 启动时的 meshConfig.defaultXxxExportTo 配置,二是 ServiceEntry、DestinationRule、VirtualService 三个 crd 中的 exportTo 字段和 annotations 中的“networking.istio.io/exportTo”标签。
sidecar 资源
命名空间中的 Sidecar 配置将应用于同一命名空间中的一个或多个工作负载实例,使用 workloadSelector 字段进行选择。
- 没有设置 workloadSelector,应用于同一名称空间中的所有工作负载实例,只能有一个,推荐使用 default 来命名此 Sidecar。
- 设置了 workloadSelector,应用于同一名称空间中具有选择器匹配的工作负载实例。
- 默认情况下,MeshConfig 根命名空间中的 Sidecar 配置将应用于所有没有 Sidecar 配置的命名空间。这个全局默认 Sidecar 配置不应该有任何 workloadSelector。
全局默认配置
在根命名空间 istio-config 中的 Sidecar 配置,配置了所有命名空间下的负载只能访问当前命名空间和 istio-system 命名空间的所有服务。
1
2
3
4
5
6
7
8
9
10
|
apiVersion: networking.istio.io/v1beta1
kind: Sidecar
metadata:
name: default
namespace: istio-config
spec:
egress:
- hosts:
- "./*"
- "istio-system/*"
|
命名空间下的默认配置
在 prod-us1 命名空间下的默认配置,重写了上面的全局默认配置,配置了只能访问 prod-us1、prod-apis、istio-system 空间下的所有服务。
1
2
3
4
5
6
7
8
9
10
11
|
apiVersion: networking.istio.io/v1beta1
kind: Sidecar
metadata:
name: default
namespace: prod-us1
spec:
egress:
- hosts:
- "prod-us1/*"
- "prod-apis/*"
- "istio-system/*"
|
某个服务的负载配置
下面针对 ratings 的所有负载,设置了入向和出向的访问配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
apiVersion: networking.istio.io/v1beta1
kind: Sidecar
metadata:
name: ratings
namespace: prod-us1
spec:
workloadSelector:
labels:
app: ratings
ingress:
- port:
number: 9080
protocol: HTTP
name: somename
defaultEndpoint: unix:///var/run/someuds.sock
egress:
- port:
number: 9080
protocol: HTTP
name: egresshttp
hosts:
- "prod-us1/*"
- hosts:
- "istio-system/*"
|
exportTo 字段
istio 启动配置中,下面三个参数控制了其 CRD 的可见性,值可以为“.”、“*”、“~”:
- defaultServiceExportTo:控制所有 ServiceEntry 和 service 的可见性,默认所有命令空间可见。
- defaultVirtualServiceExportTo: 控制所有 VirtualService 的可见性,默认所有命令空间可见。
- defaultDestinationRuleExportTo:控制所有 DestinationRule 的可见性,默认所有命令空间可见。
至于 crd 中 exportTo 字段和 annotations 的 exportTo 标签,效果和上面差不多,值可以为“.”、“*”:
- ServiceEntry:控制当前 ServiceEntry 的可见性,默认所有命令空间可见。
- DestinationRule:控制当前 DestinationRule 的可见性,默认所有命令空间可见。
- VirtualService:控制当前 VirtualService 的可见性,默认所有命令空间可见。
- networking.istio.io/exportTo:控制当前 k8s service 的可见性,默认所有命令空间可见。
部署示例
使用下面的默认配置安装 istio,设置了“ISTIO_META_DNS_CAPTURE”是因为需要测试 ServiceEntry:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
spec:
hub: docker.io/istio
meshConfig:
accessLogFile: /dev/stdout
defaultConfig:
proxyMetadata:
ISTIO_META_DNS_CAPTURE: "true"
profile: demo
tag: 1.16.1
values:
global:
logging:
level: default:debug
configValidation: true
istioNamespace: istio-system
|
在两个命名空间分布部署服务来进行测试,先在 foo 空间部署 helloworld 服务:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
apiVersion: v1
kind: Namespace
metadata:
name: foo
labels:
istio-injection: enabled
---
apiVersion: v1
kind: Service
metadata:
name: helloworld
namespace: foo
labels:
app: helloworld
service: helloworld
spec:
ports:
- port: 5000
name: http
selector:
app: helloworld
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: helloworld-v1
labels:
app: helloworld
version: v1
spec:
replicas: 1
selector:
matchLabels:
app: helloworld
version: v1
template:
metadata:
labels:
app: helloworld
version: v1
spec:
containers:
- name: helloworld
image: docker.io/istio/examples-helloworld-v1
resources:
requests:
cpu: "100m"
imagePullPolicy: IfNotPresent
ports:
- containerPort: 5000
|
再在 bar 空间部署 sleep 服务:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
apiVersion: v1
kind: Namespace
metadata:
name: bar
labels:
istio-injection: enabled
---
apiVersion: v1
kind: Service
metadata:
name: sleep
namespace: bar
labels:
app: sleep
service: sleep
spec:
ports:
- port: 80
name: http
selector:
app: sleep
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: sleep
namespace: bar
spec:
replicas: 1
selector:
matchLabels:
app: sleep
template:
metadata:
labels:
app: sleep
spec:
containers:
- name: sleep
image: curlimages/curl
command: ["/bin/sleep", "infinity"]
imagePullPolicy: IfNotPresent
|
场景一:不配置 sidecar 和 exportTo
部署 helloworld 和 sleep 服务后,查看 sleep 服务的 pod 的 sidecar 配置,可以看到除了当前命名空间 bar 的服务外,还包含了 istio-system、kube-system、foo 等其他命名空间的服务:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
root@dev:~# istioctl pc cluster sleep-5597f78777-5phkz.bar
SERVICE FQDN PORT SUBSET DIRECTION TYPE DESTINATION RULE
helloworld.foo.svc.cluster.local 5000 - outbound EDS
istio-egressgateway.istio-system.svc.cluster.local 80 - outbound EDS
kube-dns.kube-system.svc.cluster.local 53 - outbound EDS
kubernetes.default.svc.cluster.local 443 - outbound EDS
sleep.bar.svc.cluster.local 80 - outbound EDS
...
root@dev:~# istioctl pc ep sleep-5597f78777-5phkz.bar
ENDPOINT STATUS OUTLIER CHECK CLUSTER
10.42.0.3:53 HEALTHY OK outbound|53||kube-dns.kube-system.svc.cluster.local
10.42.0.41:8080 HEALTHY OK outbound|80||istio-ingressgateway.istio-system.svc.cluster.local
10.42.0.43:80 HEALTHY OK outbound|80||sleep.bar.svc.cluster.local
10.42.0.44:5000 HEALTHY OK outbound|5000||helloworld.foo.svc.cluster.local
192.168.60.113:6443 HEALTHY OK outbound|443||kubernetes.default.svc.cluster.local
...
|
场景二:配置 exportTo 字段,不配置 sidecar
在 istio 的启动配置中增加以下字段,并重新安装:
1
2
3
4
5
6
7
|
meshConfig:
defaultServiceExportTo:
- "."
defaultVirtualServiceExportTo:
- "."
defaultDestinationRuleExportTo:
- "."
|
跟上面一样,部署 helloworld 和 sleep 服务后,查看 sleep 服务的 pod 的 sidecar 配置,可以看到只有当前命名空间下的服务了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
root@dev:~# istioctl pc cluster sleep-5597f78777-ktwkm.bar
SERVICE FQDN PORT SUBSET DIRECTION TYPE DESTINATION RULE
80 - inbound ORIGINAL_DST
BlackHoleCluster - - - STATIC
InboundPassthroughClusterIpv4 - - - ORIGINAL_DST
PassthroughCluster - - - ORIGINAL_DST
agent - - - STATIC
prometheus_stats - - - STATIC
sds-grpc - - - STATIC
sleep.bar.svc.cluster.local 80 - outbound EDS
xds-grpc - - - STATIC
zipkin - - - STRICT_DNS
root@dev:~# istioctl pc ep sleep-5597f78777-ktwkm.bar
ENDPOINT STATUS OUTLIER CHECK CLUSTER
10.42.0.39:80 HEALTHY OK outbound|80||sleep.bar.svc.cluster.local
127.0.0.1:15000 HEALTHY OK prometheus_stats
127.0.0.1:15020 HEALTHY OK agent
unix://./etc/istio/proxy/XDS HEALTHY OK xds-grpc
unix://./var/run/secrets/workload-spiffe-uds/socket HEALTHY OK sds-grpc
|
需要注意的是:sidecar 配置不存在其他命名空间服务,不代表业务程序不能访问,比如在 sleep pods 中通过“curl “http://helloworld.foo:5000/hello"”,仍然能获取到结果,只是这个访问不是通过 sidecar 到 endpoints 访问的,而是通过 istio-proxy 的 iptables 规则到 endpoint 访问的,比如下面的测试:
1
2
3
4
|
// 使用 k8s 原生方式访问的,没有通过 sidecar
root@dev:~# kubectl exec -it -nbar sleep-5597f78777-ktwkm -- sh
/ $ curl "http://helloworld.foo:5000/hello"
Hello version: v1, instance: helloworld-v1-77489ccb5f-rgdl
|
如果要跨命名空间访问,则可以通过在具体的 crd 里面设置 exportTo 字段,比如设置如下的 ServiceEntry,来让所有命名空间可访问:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
name: demo-helloworld
namespace: foo
spec:
addresses:
- 240.240.0.20
exportTo:
- '*'
hosts:
- demo.helloworld
location: MESH_INTERNAL
ports:
- name: http
number: 5000
protocol: HTTP
resolution: STATIC
workloadSelector:
labels:
app: helloworld
|
而对应 k8s 的原生服务,可以通过设置 annotation 来让所有命名空间可见:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
apiVersion: v1
kind: Service
metadata:
name: helloworld
namespace: foo
annotations:
networking.istio.io/exportTo: "*"
labels:
app: helloworld
service: helloworld
spec:
ports:
- port: 5000
name: http
selector:
app: helloworld
|
此时查看 sleep pod 的 cluster 配置,可以看到两种方式的服务都存在了:
1
2
3
4
|
root@dev:~# istioctl pc cluster sleep-5597f78777-ktwkm.bar --port 5000
SERVICE FQDN PORT SUBSET DIRECTION TYPE DESTINATION RULE
demo.helloworld 5000 - outbound EDS
helloworld.foo.svc.cluster.local 5000 - outbound EDS
|
场景三:配置 sidecar,不配置 exportTo
先在 istio-system 空间下设置全局默认的 sidecar 配置:
1
2
3
4
5
6
7
8
9
|
apiVersion: networking.istio.io/v1beta1
kind: Sidecar
metadata:
name: default
namespace: istio-system
spec:
egress:
- hosts:
- "./*"
|
跟上面一样,部署 helloworld 和 sleep 服务后,查看 sleep 服务的 pod 的 sidecar 配置,可以看到只有当前命名空间服务了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
root@dev:~# istioctl pc cluster sleep-5597f78777-7vtj8.bar
SERVICE FQDN PORT SUBSET DIRECTION TYPE DESTINATION RULE
80 - inbound ORIGINAL_DST
BlackHoleCluster - - - STATIC
InboundPassthroughClusterIpv4 - - - ORIGINAL_DST
PassthroughCluster - - - ORIGINAL_DST
agent - - - STATIC
prometheus_stats - - - STATIC
sds-grpc - - - STATIC
sleep.bar.svc.cluster.local 80 - outbound EDS
xds-grpc - - - STATIC
zipkin - - - STRICT_DNS
root@dev:~# istioctl pc ep sleep-5597f78777-7vtj8.bar
ENDPOINT STATUS OUTLIER CHECK CLUSTER
10.42.0.49:80 HEALTHY OK outbound|80||sleep.bar.svc.cluster.local
127.0.0.1:15000 HEALTHY OK prometheus_stats
127.0.0.1:15020 HEALTHY OK agent
unix://./etc/istio/proxy/XDS HEALTHY OK xds-grpc
unix://./var/run/secrets/workload-spiffe-uds/socket HEALTHY OK sds-grpc
|
继续测试 VirtualService 效果是否一样,部署如下配置使请求延迟 2s 返回:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
# kubectl apply -f helloworld_delay.yaml
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: helloworld
namespace: foo
spec:
hosts:
- helloworld
http:
- fault:
delay:
percent: 100
fixedDelay: 2s
route:
- destination:
host: helloworld
|
查看当前空间的 helloworld 代理的 route 配置,设置了 fixedDelay 等于 2s,并且在 pods 中测试也是延迟 2s 返回的,而 bar 命名空间的 sleep 并没有看到对应的 route 配置。
1
2
3
4
|
root@dev:~# kubectl exec -it -nfoo helloworld-v1-7dddc45478-lpmjq -- bash
root@helloworld-v1-7dddc45478-lpmjq:/opt/microservices# curl -w "time:%{time_total}" "http://helloworld:5000/hello"
Hello version: v1, instance: helloworld-v1-7dddc45478-lpmjq
time:2.120
|
继续测试 DestinationRule 效果是否一样,部署如下配置设置 subset,查看当前空间的 helloworld 代理的 cluster 配置,有设置了 v1 subset,而 bar 命名空间的 sleep 并没有看到对应的 cluster 配置。
1
2
3
4
5
6
7
8
9
10
11
|
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: helloworld
namespace: foo
spec:
host: helloworld
subsets:
- name: v1
labels:
version: v1
|
继续测试 ServiceEntry 效果是否一样,部署如下配置,在当前空间 pods 测试访问此 host,可以成功返回,并且在 pod 的 envoy 中也能看到对应的 cluster 和 endpoints 配置。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: demo-helloworld
namespace: foo
spec:
addresses:
- 240.240.0.20
hosts:
- demo.helloworld
ports:
- number: 5000
name: http
protocol: HTTP
resolution: STATIC
location: MESH_INTERNAL
workloadSelector:
labels:
app: helloworld
|
在 bar 命名空间的 sleep pods 的代理配置中,没有看到“demo.helloworld”配置,因此只设置 ServiceEntry 无法实现跨命名空间访问。因为在全局的 sidecar crd 中,只设置了当前命名空间和 istio-system 空间,那考虑在 bar 命名空间新增一个 sidecar crd 配置,增加 ServiceEntry 的 host 配置,来覆盖全局配置:
1
2
3
4
5
6
7
8
9
10
|
apiVersion: networking.istio.io/v1beta1
kind: Sidecar
metadata:
name: default
namespace: bar
spec:
egress:
- hosts:
- "./*"
- "foo/demo.helloworld"
|
此时查看代理的配置,有“demo.helloworld”的 cluster 和 endpoints 配置,并且在 pods 中访问也是正常的。ServiceEntry 有一项配置“exportTo”可以指明导出到哪些命名空间,默认是所有命名空间,因此在 bar 空间设置的 Sidecar 配置能够生效。如果某个 ServiceEntry 只想在当前命名空间生效,可以增加“exportTo:['.']”配置,这样在 sleep 的代理配置中就无法看到此 cluster 了。
命名空间隔离
在 kubernetes 集群规模较大的情况下,或者存在多租户的情况下,使用 istio 网格可能会出现一些问题,比如:
- 性能问题:sidecar 会收到全量服务的数据,导致 cpu 过高和内存过大
- 隔离问题:多个租户的服务需要隔离,不能互相访问,不能互相影响
参考这篇文章 多租户场景下 Istio 部署方案探索,讨论了多租户场景下的一些解决方案,总结在此:
- 每一个用户提供一套 istio 服务网格:istio 官方网站的文章 Istio 的软性多租户支持 给出了方案,为每个产品提供一套 istio 网格,每套 istio 的控制面可以安装到指定的 namespace 中,数据面可以设置为产品部署的 namespace。但存在资源消耗和跨命名空间访问复杂的问题,每套 istio 都是需要消耗一定的资源,namespace 之间互相访问,需要部署 Ingress Gateway 和 Egress Gateway 控制进入和流出命名空间的流量,这样增加了部署复杂度。
- 单控制面多 Gateway 方案:部署一套 istio 控制面,管理多个产品数据面,每个产品以及 Istio 控制面的 namespace 部署一套 Ingress Gateway,相当于产品共用 Istio 控制面,但不共用 Ingress Gateway,一定程度上减少产品的耦合。
- 腾讯云方案:参考文章 腾讯云中间件团队在 Service Mesh 中的实践与探索,腾讯云实现了单控制面多集群网格的多租户方案。在这种场景下,每个租户一个网格,集群管理员控制和监控整个 Istio 控制面以及所有网格,租户管理员只能控制特定的网格,这种场景与云环境下的多租户概念比较稳合。
在官方文档 Istio 部署模型 中,也提到了多租户,给出了几种部署方案,总结如下:
- 命名空间租户:同一个集群中使用不同的命名空间隔离用户,默认情况下,多个命名空间的服务可以相互通信,但可以通过选择将哪些服务暴露给其他命名空间来提高隔离度。
- 集群租户:支持使用集群作为租户单位,给每个租户一个专门的集群或一组集群来部署其工作负载。
- 网格租户:在具有网格联邦的多网格部署中,每个网格可以作为隔离的单位。
从以上内容总结来说,istio 的命名空间隔离或者多租户,常见的形式有:
- 单集群单控制面多命名空间:通过 sidecar 或者 exportTo 字段隔离服务可见性。
- 单集群多控制面多命名空间:istio 跟命名空间为一对一或者一对多关系。
- 多集群多控制面:istio 跟集群为一对一或者一对多关系。
单集群单控制面多命名空间
这篇文章 多租户场景下 Istio 部署方案探索 中提到的单控制面多 Gateway 方案,经过实际测试,只能做到集群入口的隔离,不能做到命名空间服务的隔离,因为这种方案本质上也是单集群单控制面多命名空间,必须通过 sidecar 或者 exportTo 字段才能实现。
如何实现单集群单控制面多命名空间,可参考前面的服务可见性介绍,里面的场景二和场景三都是可行的方案。
单集群多控制面多命名空间
参考官方文档 单个集群中安装多个控制面,是通过“meshConfig.discoverySelectors”和“revision”来实现的,“discoverySelectors”用于 istio 在计算 sidecar 配置时需要考虑的命名空间集合,“istio.io/rev”用于创建命名空间时指定使用的 istio 版本。首先在 usergroup-1 命名空间安装 istio,这里需要验证跨集群,与示例不同的是使用的 demo 配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
kubectl create ns usergroup-1
kubectl label ns usergroup-1 usergroup=usergroup-1
istioctl install -y -f - <<EOF
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
namespace: usergroup-1
spec:
profile: demo
revision: usergroup-1
meshConfig:
discoverySelectors:
- matchLabels:
usergroup: usergroup-1
values:
global:
istioNamespace: usergroup-1
pilot:
env:
ENABLE_ENHANCED_RESOURCE_SCOPING: true
EOF
|
接着在 usergroup-2 命名空间安装 istio:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
kubectl create ns usergroup-2
kubectl label ns usergroup-2 usergroup=usergroup-2
istioctl install -y -f - <<EOF
apiVersion: install.istio.io/v1alpha1
kind: IstioOperator
metadata:
namespace: usergroup-2
spec:
profile: demo
revision: usergroup-2
meshConfig:
discoverySelectors:
- matchLabels:
usergroup: usergroup-2
values:
global:
istioNamespace: usergroup-2
pilot:
env:
ENABLE_ENHANCED_RESOURCE_SCOPING: true
EOF
|
查看安装结果,两个命名空间的 istiod、istio-ingressgateway、istio-egressgateway 都安装成功了:
1
2
3
4
5
6
7
8
|
root@dev:~/tenancy/test# kubectl get pods -A
NAMESPACE NAME READY STATUS RESTARTS AGE
usergroup-1 istiod-usergroup-1-65f5c94ff-spvqv 1/1 Running 0 7m27s
usergroup-1 istio-egressgateway-5744b7bfc4-58pth 1/1 Running 0 7m23s
usergroup-1 istio-ingressgateway-85cc6bd7cb-lxjwn 1/1 Running 0 7m23s
usergroup-2 istiod-usergroup-2-557b7dffff-w65gz 1/1 Running 0 74s
usergroup-2 istio-ingressgateway-79b4445f54-rlskr 1/1 Running 0 70s
usergroup-2 istio-egressgateway-8584d76b68-dkw8x 1/1 Running 0 70s
|
创建两个应用进行测试:
1
2
3
4
5
6
7
8
|
kubectl create ns app-ns-1
kubectl create ns app-ns-2
kubectl label ns app-ns-1 usergroup=usergroup-1 istio.io/rev=usergroup-1
kubectl label ns app-ns-2 usergroup=usergroup-2 istio.io/rev=usergroup-2
kubectl -n app-ns-1 apply -f samples/sleep/sleep.yaml
kubectl -n app-ns-1 apply -f samples/httpbin/httpbin.yaml
kubectl -n app-ns-2 apply -f samples/sleep/sleep.yaml
kubectl -n app-ns-2 apply -f samples/httpbin/httpbin.yaml
|
安装完成查看 pods 的 envoy cluster 配置,只能看到本命名空间和对应的 istio 命名空间的服务:
1
2
3
4
5
6
7
8
9
|
root@dev:~# istioctl pc cluster sleep-bc9998558-twkpb.app-ns-1
SERVICE FQDN PORT SUBSET DIRECTION TYPE DESTINATION RULE
httpbin.app-ns-1.svc.cluster.local 8000 - outbound EDS
sleep.app-ns-1.svc.cluster.local 80 - outbound EDS
istiod-usergroup-1.usergroup-1.svc.cluster.local 443 - outbound EDS
...
// 跨命名空间访问可以成功,没有经过代理,使用原生 k8s 访问的
kubectl -n app-ns-1 exec "$(kubectl -n app-ns-1 get pod -l app=sleep -o jsonpath={.items..metadata.name})" -c sleep -- curl -sIL http://httpbin.app-ns-2.svc.cluster.local:8000
|
加上负载策略,可以禁止跨命名空间访问,比如下面的配置执行后,跨命名空间访问将返回 503:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: "usergroup-1-peerauth"
namespace: "usergroup-1"
spec:
mtls:
mode: STRICT
EOF
kubectl apply -f - <<EOF
apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
name: "usergroup-2-peerauth"
namespace: "usergroup-2"
spec:
mtls:
mode: STRICT
EOF
|
可以在两个命名空间分别部署 gateway,隔离两个命名空间的对外入口,比如在 app-ns-1 空间部署 Gateway 和 VirtualService:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: httpbin-gateway
namespace: app-ns-1
spec:
selector:
istio: ingressgateway # use Istio default gateway implementation
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "httpbin.example.com"
EOF
kubectl apply -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: httpbin
namespace: app-ns-1
spec:
hosts:
- "httpbin.example.com"
gateways:
- httpbin-gateway
http:
- match:
- uri:
prefix: /status
- uri:
prefix: /delay
route:
- destination:
port:
number: 8000
host: httpbin
EOF
|
在集群外部通过 nodeport 访问,可以正常返回:
1
2
3
4
|
export INGRESS_HOST=$(kubectl get po -l istio=ingressgateway -n usergroup-1 -o jsonpath='{.items[0].status.hostIP}')
export INGRESS_PORT=$(kubectl -n usergroup-1 get service "${INGRESS_NAME}" -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}')
// 示例:curl -s -I -HHost:httpbin.example.com "http://172.19.52.61:32115/status/200"
curl -s -I -HHost:httpbin.example.com "http://$INGRESS_HOST:$INGRESS_PORT/status/200"
|
如果需要在 app-ns-2 空间进行访问 app-ns-1 空间的服务,也可通过访问 ingress gateway 的 service 实现:
1
2
3
4
5
6
7
8
9
10
|
root@dev:~/tenancy/test# kubectl exec -it -napp-ns-2 sleep-bc9998558-9x7fn -- sh
/ $ curl -s -I -HHost:httpbin.example.com "http://istio-ingressgateway.usergroup-1:80/status/200"
HTTP/1.1 200 OK
server: envoy
date: Fri, 26 May 2023 07:34:29 GMT
content-type: text/html; charset=utf-8
access-control-allow-origin: *
access-control-allow-credentials: true
content-length: 0
x-envoy-upstream-service-time: 19
|
多集群多控制面
这种方式比较简单,因为集群本身有隔离性,在每个集群独立部署 istio 即可,集群之间通过 ingress gateway 进行访问,这里不再举例说明。
总结
对三种方式命名空间隔离或者多租户方式,可以总结如下:
方案 |
说明 |
实现方式 |
跨命名空间/跨集群 |
优缺点 |
单集群单控制面多命名空间 |
istio 跟命名空间为一对多关系 |
sidecar 或者 exportTo 字段 |
可基于 sidecar 或者 exportTo,也可用 k8s service 方式 |
实现了代理配置的空间隔离,跨命名空间的调用隔离较弱,需配合其他策略,适合私有云场景 |
单集群多控制面多命名空间 |
istio 跟命名空间为一对一或一对多关系 |
meshConfig.discoverySelectors 和 revision |
可基于 ingress gateway,也可用 k8s service 方式 |
实现了代理配置的空间隔离,跨命名空间的调用隔离较弱,需配合其他策略,适合私有云场景 |
多集群多控制面 |
istio 跟集群为一对一或者一对多关系 |
k8s 集群隔离性 |
ingress gateway |
隔离性强,适合公有云场景 |
参考