简介

在 Kubernetes 环境中,使用 Kubernetes Ingress 资源 来指定需要暴露到集群外的服务。 在 Istio 服务网格中,更好的选择(同样适用于 Kubernetes 及其他环境)是使用一种新的配置模型,名为 Istio GatewayGateway 允许应用一些诸如监控和路由规则的 Istio 特性来管理进入集群的流量。

下面介绍如何配置 Istio,以使用 Istio Gateway 来将服务暴露至服务网格之外。

部署

1.进入istio 目录:

1
cd /root/istio-1.5.0

2.启动 httpbin 样例程序。

1
2
sed -i "s/docker.io/wixr7yss.mirror.aliyuncs.com/g" samples/httpbin/httpbin.yaml
kubectl apply -f samples/httpbin/httpbin.yaml

3.检查服务

1
2
3
4
5
6
7
[root@zz-node1 istio-1.5.0]# kubectl --namespace=default get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
httpbin ClusterIP 10.96.116.209 <none> 8000/TCP 115s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 4h42m
[root@zz-node1 istio-1.5.0]# kubectl --namespace=default get pod
NAME READY STATUS RESTARTS AGE
httpbin-7cf4db564c-6s8sr 2/2 Running 0 118s

确定 ingress IP 和端口

执行如下指令,明确自身 Kubernetes 集群环境支持外部负载均衡:

1
kubectl get svc istio-ingressgateway -n istio-system

2.如果 EXTERNAL-IP 值已设置,说明环境正在使用外部负载均衡,可以用其为 ingress gateway 提供服务。 如果 EXTERNAL-IP 值为 (或持续显示), 说明环境没有提供外部负载均衡,无法使用 ingress gateway。 在这种情况下,你可以使用服务的 node port 访问网关。

  • 外部负载均衡器

    • 若已确定自身环境使用了外部负载均衡器,执行如下指令。

    • 设置 ingress IP 和端口:

      1
      2
      3
      $ export INGRESS_HOST=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
      $ export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].port}')
      $ export SECURE_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="https")].port}')
      • 在特定的环境下,可能会使用主机名指代负载均衡器,而不是 IP 地址。 此时,ingress 网关的 EXTERNAL-IP 值将不再是 IP 地址,而是主机名。前文设置 INGRESS_HOST 环境变量的命令将执行失败。 使用下面的命令更正 INGRESS_HOST 值:

        1
        $ export INGRESS_HOST=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
  • node port

    • 若自身环境未使用外部负载均衡器,需要通过 node port 访问。执行如下命令。

    • 设置 ingress 端口:

      1
      2
      export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}')
      export SECURE_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="https")].nodePort}')
    • 基于集群供应商,设置 ingress IP:GKE/Minikube/Docker For Desktop等多种方式

      1
      export INGRESS_HOST=$(kubectl get po -l istio=ingressgateway -n istio-system -o jsonpath='{.items[0].status.hostIP}')

采用node port最后结果:

使用 Istio Gateway 配置 ingress

Ingress Gateway 描述运行在网格边界的负载均衡器,负责接收入口 HTTP/TCP 连接。 其中配置了对外暴露的端口、协议等。 但是,不像 Kubernetes Ingress 资源,ingress Gateway 不包含任何流量路由配置。Ingress 流量的路由使用 Istio 路由规则来配置,和内部服务请求完全一样。

让我们一起来看如何为 HTTP 流量在80端口上配置 Gateway

1.创建 Istio Gateway并应用:

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
$ cat << EOF > gw.yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: httpbin-gateway
spec:
selector:
istio: ingressgateway # use Istio default gateway implementation
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "httpbin.example.com"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: httpbin
spec:
hosts:
- "httpbin.example.com"
gateways:
- httpbin-gateway
http:
- match:
- uri:
prefix: /status
- uri:
prefix: /delay
route:
- destination:
port:
number: 8000
host: httpbin
EOF
kubectl apply -f gw.yaml

已为 httpbin 服务创建了虚拟服务 配置,包含两个路由规则,允许流量流向路径 /status/delay

gateways 列表规约了哪些请求允许通过 httpbin-gateway 网关。 所有其他外部请求均被拒绝并返回 404 响应。

来自网格内部其他服务的内部请求无需遵循这些规则,而是默认遵守轮询调度路由规则。 你可以为 gateways 列表添加特定的 mesh 值,将这些规则同时应用到内部请求。 由于服务的内部主机名可能与外部主机名不一致(譬如: httpbin.default.svc.cluster.local),你需要同时将内部主机名添加到 hosts 列表中。 详情请参考 操作指南

使用 curl 访问 httpbin 服务:

1
2
3
4
5
6
7
8
9
10
11
[root@zz-node1 istio-1.5.0]# curl -I -HHost:httpbin.example.com http://$INGRESS_HOST:$INGRESS_PORT/status/200
HTTP/1.1 200 OK
server: istio-envoy
date: Sat, 14 Mar 2020 12:12:49 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: 41

[root@zz-node1 istio-1.5.0]#

注意上文命令使用 -H 标识将 HTTP头部参数 Host 设置为 “httpbin.example.com”。 该操作为必须操作,因为 ingress Gateway被配置用来处理 “httpbin.example.com” 的服务请求,而在测试环境中并没有为该主机绑定 DNS 而是简单直接地向 ingress IP 发送请求。

4.访问其他没有被显式暴露的 URL 时,将看到 HTTP 404 错误:

1
2
3
4
5
curl -I -HHost:httpbin.example.com http://$INGRESS_HOST:$INGRESS_PORT/headers
HTTP/1.1 404 Not Found
date: Mon, 29 Jan 2018 04:45:49 GMT
server: envoy
content-length: 0

通过浏览器访问 ingress 服务

在浏览器中输入 httpbin 服务的URL 不能获得有效的响应,因为无法像 curl 那样,将请求头部参数 Host 传给浏览器。在现实场景中,这并不是问题,因为你需要合理配置被请求的主机及可解析的 DNS,从而在 URL 中使用主机的域名,譬如: https://httpbin.example.com/status/200

为了在简单的测试和演示中绕过这个问题,请在 GatewayVirtualService 配置中使用通配符 *。譬如,修改 ingress 配置如下:

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
$ cat << EOF > gw.yaml
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
name: httpbin-gateway
spec:
selector:
istio: ingressgateway # use Istio default gateway implementation
servers:
- port:
number: 80
name: http
protocol: HTTP
hosts:
- "*"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: httpbin
spec:
hosts:
- "*"
gateways:
- httpbin-gateway
http:
- match:
- uri:
prefix: /headers
route:
- destination:
port:
number: 8000
host: httpbin
EOF
kubectl apply -f gw.yaml

此时,便可以在浏览器中输入包含 $INGRESS_HOST:$INGRESS_PORT 的URL。譬如,输入http://$INGRESS_HOST:$INGRESS_PORT/headers,将显示浏览器发送的所有 headers 信息。

Gateway 配置资源允许外部流量进入 Istio 服务网格,并对边界服务实施流量管理和 Istio 可用的策略特性。

事先,在服务网格中创建一个服务并向外部流量暴露该服务的 HTTP 端点。

环境清除

1
2
3
kubectl delete gateway httpbin-gateway
kubectl delete virtualservice httpbin
kubectl delete --ignore-not-found=true -f samples/httpbin/httpbin.yaml

–ignore-not-found=true:忽略不存在的资源


评论