Ingress Gateway

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

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

开始之前

  • 遵照安装指南中的指令,安装 Istio。

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

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

Zip

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

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

Zip

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

确定 ingress IP 和端口

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

  1. $ kubectl get svc istio-ingressgateway -n istio-system
  2. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  3. istio-ingressgateway LoadBalancer 172.21.109.129 130.211.10.121 80:31380/TCP,443:31390/TCP,31400:31400/TCP 17h

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

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

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

设置 ingress IP 和端口:

  1. $ export INGRESS_HOST=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
  2. $ export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].port}')
  3. $ 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 访问。执行如下命令。

设置 ingress 端口:

  1. $ export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}')
  2. $ export SECURE_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="https")].nodePort}')

基于集群供应商,设置 ingress IP:

  • GKE:
  1. $ export INGRESS_HOST=<workerNodeAddress>

需要创建防火墙规则,允许 TCP 流量通过 ingressgateway 服务的端口。执行下面的命令,设置允许流量通过 HTTP 端口、HTTPS 安全端口,或均可:

  1. $ gcloud compute firewall-rules create allow-gateway-http --allow tcp:$INGRESS_PORT
  2. $ gcloud compute firewall-rules create allow-gateway-https --allow tcp:$SECURE_INGRESS_PORT
  • Minikube:
  1. $ export INGRESS_HOST=$(minikube ip)
  • Docker For Desktop:
  1. $ export INGRESS_HOST=127.0.0.1
  • 其他环境(如:IBM Cloud Private 等):
  1. $ export INGRESS_HOST=$(kubectl get po -l istio=ingressgateway -n istio-system -o jsonpath='{.items[0].status.hostIP}')

使用 Istio Gateway 配置 ingress

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

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

  • 创建 Istio Gateway
  1. $ kubectl apply -f - <<EOF
  2. apiVersion: networking.istio.io/v1alpha3
  3. kind: Gateway
  4. metadata:
  5. name: httpbin-gateway
  6. spec:
  7. selector:
  8. istio: ingressgateway # use Istio default gateway implementation
  9. servers:
  10. - port:
  11. number: 80
  12. name: http
  13. protocol: HTTP
  14. hosts:
  15. - "httpbin.example.com"
  16. EOF
  • 为通过 Gateway 的入口流量配置路由:
  1. $ kubectl apply -f - <<EOF
  2. apiVersion: networking.istio.io/v1alpha3
  3. kind: VirtualService
  4. metadata:
  5. name: httpbin
  6. spec:
  7. hosts:
  8. - "httpbin.example.com"
  9. gateways:
  10. - httpbin-gateway
  11. http:
  12. - match:
  13. - uri:
  14. prefix: /status
  15. - uri:
  16. prefix: /delay
  17. route:
  18. - destination:
  19. port:
  20. number: 8000
  21. host: httpbin
  22. EOF

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

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

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

  • 使用 curl 访问 httpbin 服务:
  1. $ curl -I -HHost:httpbin.example.com http://$INGRESS_HOST:$INGRESS_PORT/status/200
  2. HTTP/1.1 200 OK
  3. server: envoy
  4. date: Mon, 29 Jan 2018 04:45:49 GMT
  5. content-type: text/html; charset=utf-8
  6. access-control-allow-origin: *
  7. access-control-allow-credentials: true
  8. content-length: 0
  9. x-envoy-upstream-service-time: 48

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

  • 访问其他没有被显式暴露的 URL 时,将看到 HTTP 404 错误:
  1. $ curl -I -HHost:httpbin.example.com http://$INGRESS_HOST:$INGRESS_PORT/headers
  2. HTTP/1.1 404 Not Found
  3. date: Mon, 29 Jan 2018 04:45:49 GMT
  4. server: envoy
  5. content-length: 0

通过浏览器访问 ingress 服务

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

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

  1. $ kubectl apply -f - <<EOF
  2. apiVersion: networking.istio.io/v1alpha3
  3. kind: Gateway
  4. metadata:
  5. name: httpbin-gateway
  6. spec:
  7. selector:
  8. istio: ingressgateway # use Istio default gateway implementation
  9. servers:
  10. - port:
  11. number: 80
  12. name: http
  13. protocol: HTTP
  14. hosts:
  15. - "*"
  16. ---
  17. apiVersion: networking.istio.io/v1alpha3
  18. kind: VirtualService
  19. metadata:
  20. name: httpbin
  21. spec:
  22. hosts:
  23. - "*"
  24. gateways:
  25. - httpbin-gateway
  26. http:
  27. - match:
  28. - uri:
  29. prefix: /headers
  30. route:
  31. - destination:
  32. port:
  33. number: 8000
  34. host: httpbin
  35. EOF

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

理解原理

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

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

问题排查

  • 检查环境变量 INGRESS_HOST and INGRESS_PORT。确保环境变量的值有效,命令如下:
  1. $ kubectl get svc -n istio-system
  2. $ echo INGRESS_HOST=$INGRESS_HOST, INGRESS_PORT=$INGRESS_PORT
  • 检查没有在相同的端口上定义其它 Istio ingress gateways:
  1. $ kubectl get gateway --all-namespaces
  • 检查没有在相同的 IP 和端口上定义 Kubernetes Ingress 资源:
  1. $ kubectl get ingress --all-namespaces

清除

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

Zip

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

相关内容

把 Istio 作为外部服务的代理

把 Istio 入口网关配置为外部服务的代理。

使用 Cert-Manager 部署一个自定义 Ingress 网关

如何使用 cert-manager 手工部署一个自定义 Ingress 网关。

使用 AWS NLB 配置 Istio Ingress

描述如何在 AWS 上使用网络负载均衡器配置 Istio Ingress。

使用 Cert-Manager 加密 Kubernetes Ingress

演示如何使用 Cert-Manager 为 Kubernetes Ingress 自动获取 Let's Encrypt TLS 证书。

使用 SDS 为 Gateway 提供 HTTPS 加密支持

使用 Secret 发现服务(SDS) 通过 TLS 或者 mTLS 把服务暴露给服务网格外部。

安全网关(文件挂载)

使用文件挂载的证书并通过 TLS 或 mTLS 将服务暴露至服务网格之外。