Ingress Gateway
在 Kubernetes 环境中,使用 Kubernetes Ingress 资源来指定需要暴露到集群外的服务。
在 Istio 服务网格中,更好的选择(同样适用于 Kubernetes 及其他环境)是使用一种新的配置模型,名为 Istio Gateway。
Gateway
允许应用一些诸如监控和路由规则的 Istio 特性来管理进入集群的流量。
本任务描述了如何配置 Istio,以使用 Istio Gateway
来将服务暴露至服务网格之外。
开始之前
遵照安装指南中的指令,安装 Istio。
确定当前目录路径为
istio
目录。
启动 httpbin 样例程序。
如果您启用了 sidecar 自动注入,通过以下命令部署
httpbin
服务:$ kubectl apply -f @samples/httpbin/httpbin.yaml@
否则,您必须在部署
httpbin
应用程序前进行手动注入,部署命令如下:$ 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 80:31380/TCP,443:31390/TCP,31400:31400/TCP 17h
如果 EXTERNAL-IP
值已设置,说明环境正在使用外部负载均衡,可以用其为 ingress gateway 提供服务。
如果 EXTERNAL-IP
值为 <none>
(或持续显示 <pending>
),说明环境没有提供外部负载均衡,无法使用 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}')
若自身环境未使用外部负载均衡器,需要通过 node port 访问。执行如下命令。
设置 ingress 端口:
$ 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:
$ export INGRESS_HOST=<workerNodeAddress>
需要创建防火墙规则,允许 TCP 流量通过 ingressgateway 服务的端口。 执行下面的命令,设置允许流量通过 HTTP 端口、HTTPS 安全端口,或均可:
$ gcloud compute firewall-rules create allow-gateway-http --allow tcp:$INGRESS_PORT $ gcloud compute firewall-rules create allow-gateway-https --allow tcp:$SECURE_INGRESS_PORT
Minikube:
$ export INGRESS_HOST=$(minikube ip)
Docker For Desktop:
$ export INGRESS_HOST=127.0.0.1
其他环境(如:IBM Cloud Private 等):
$ 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
:$ 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
为通过
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
服务创建了虚拟服务配置,包含两个路由规则,允许流量流向路径/status
和/delay
。gateways 列表规约了哪些请求允许通过
httpbin-gateway
网关。 所有其他外部请求均被拒绝并返回 404 响应。使用 curl 访问 httpbin 服务:
$ curl -I -HHost:httpbin.example.com http://$INGRESS_HOST:$INGRESS_PORT/status/200 HTTP/1.1 200 OK server: envoy date: Mon, 29 Jan 2018 04:45: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: 48
注意上文命令使用
-H
标识将 HTTP 头部参数 Host 设置为 “httpbin.example.com”。 该操作为必须操作,因为 ingressGateway
已被配置用来处理 “httpbin.example.com” 的服务请求,而在测试环境中并没有为该主机绑定 DNS 而是简单直接地向 ingress IP 发送请求。访问其他没有被显式暴露的 URL 时,将看到 HTTP 404 错误:
$ 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
。
为了在简单的测试和演示中绕过这个问题,请在 Gateway
和 VirtualService
配置中使用通配符 *
。譬如,修改 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
,将显示浏览器发送的所有 headers 信息。
理解原理
Gateway
配置资源允许外部流量进入 Istio 服务网格,并对边界服务实施流量管理和 Istio 可用的策略特性。
事先,在服务网格中创建一个服务并向外部流量暴露该服务的 HTTP 端点。
问题排查
检查环境变量
INGRESS_HOST
andINGRESS_PORT
。确保环境变量的值有效,命令如下:$ kubectl get svc -n istio-system $ echo INGRESS_HOST=$INGRESS_HOST, INGRESS_PORT=$INGRESS_PORT
检查没有在相同的端口上定义其它 Istio ingress gateways:
$ kubectl get gateway --all-namespaces
检查没有在相同的 IP 和端口上定义 Kubernetes Ingress 资源:
$ kubectl get ingress --all-namespaces
如果使用了外部负载均衡器,该外部负载均衡器无法正常工作,尝试通过 node port 访问 gateway。
清除
删除 Gateway
和 VirtualService
配置,并关闭服务 httpbin:
$ kubectl delete gateway httpbin-gateway
$ kubectl delete virtualservice httpbin
$ kubectl delete --ignore-not-found=true -f @samples/httpbin/httpbin.yaml@