Ingress Gateway

除了支持 Kubernetes Ingress,Istio还提供了另一种配置模式,Istio Gateway。与 Ingress 相比,Gateway 提供了更广泛的自定义和灵活性,并允许将 Istio 功能(例如监控和路由规则)应用于进入集群的流量。

本任务描述了如何配置 Istio,以使用 Istio Gateway 来将服务暴露至服务网格之外。

开始之前

  • 遵照安装指南中的文档说明,安装 Istio。

  • 确定当前目录路径为 istio 目录。

  • 启动 httpbin 样例程序。

    如果您启用了 sidecar 自动注入,通过以下命令部署 httpbin 服务:

    Zip
    $ kubectl apply -f @samples/httpbin/httpbin.yaml@
    

    否则,您必须在部署 httpbin 应用程序前进行手动注入,部署命令如下:

    Zip
    $ kubectl apply -f <(istioctl kube-inject -f @samples/httpbin/httpbin.yaml@)
    
  • 根据下文描述,确定 Ingress IP 和端口。

确定 Ingress IP 和端口

执行如下指令,确定您的 Kubernetes 集群是否运行在支持外部负载均衡的环境中:

$ kubectl get svc istio-ingressgateway -n istio-system
NAME                   TYPE           CLUSTER-IP       EXTERNAL-IP      PORT(S)   AGE
istio-ingressgateway   LoadBalancer   172.21.109.129   130.211.10.121   ...       17h

如果 EXTERNAL-IP 值已设置,说明环境正在使用外部负载均衡,可以用其为 Ingress Gateway 提供服务。如果 EXTERNAL-IP 值为 <none> (或持续显示 <pending>),说明环境没有为 Ingress Gateway 提供外部负载均衡,无法使用 Ingress Gateway。在这种情况下,您可以使用服务的 Node Port 访问网关。

选择符合自身环境的指令执行:

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

设置 Ingress IP 和端口:

$ 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}')
$ export TCP_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="tcp")].port}')

使用 Istio Gateway 配置 Ingress

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

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

  1. 创建 Istio Gateway

    $ kubectl apply -f - <<EOF
    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"
    EOF
    
  2. 为通过 Gateway 的入口流量配置路由:

    $ kubectl apply -f - <<EOF
    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
    

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

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

  3. 使用 curl 访问 httpbin 服务:

    $ curl -s -I -HHost:httpbin.example.com "http://$INGRESS_HOST:$INGRESS_PORT/status/200"
    HTTP/1.1 200 OK
    server: istio-envoy
    ...
    

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

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

    $ curl -s -I -HHost:httpbin.example.com "http://$INGRESS_HOST:$INGRESS_PORT/headers"
    HTTP/1.1 404 Not Found
    ...
    

通过浏览器访问 Ingress 服务

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

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

$ kubectl apply -f - <<EOF
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

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

理解原理

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

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

问题排查

  1. 检查环境变量 INGRESS_HOST and INGRESS_PORT。确保环境变量的值有效,命令如下:

    $ kubectl get svc -n istio-system
    $ echo "INGRESS_HOST=$INGRESS_HOST, INGRESS_PORT=$INGRESS_PORT"
    
  2. 检查没有在相同的端口上定义其它 Istio Ingress Gateways:

    $ kubectl get gateway --all-namespaces
    
  3. 检查没有在相同的 IP 和端口上定义 Kubernetes Ingress 资源:

    $ kubectl get ingress --all-namespaces
    
  4. 如果使用了外部负载均衡器,该外部负载均衡器无法正常工作,尝试通过 Node Port 访问 Gateway

清除

删除 GatewayVirtualService 配置,并关闭服务 Httpbin

Zip
$ kubectl delete gateway httpbin-gateway
$ kubectl delete virtualservice httpbin
$ kubectl delete --ignore-not-found=true -f @samples/httpbin/httpbin.yaml@
这些信息有用吗?
Do you have any suggestions for improvement?

Thanks for your feedback!