在一个k8s环境中, Kubernetes Ingress Resource 被用于指定一个应被暴露在集群外的服务。在一个Istio服务网格中,一个更好的方法(在k8s和其他环境都可以工作)是使用一种不同的配置模型,称作 Istio Gateway. Gateway
允许Istio功能(例如监控和路由规则)应用于进入集群的流量。
这个task描述如何使用Istio Gateway
配置Istio在服务网格外暴露一个服务。
Before you begin
- 安装Isito
- 确认你的当前目录是
istio
Ŀ¼ - 开启 httpbin 示例,它将被用作暴露在外部的目标服务。
如果你开启了自动注入sidecar,执行
kubectl apply -f samples/httpbin/httpbin.yaml
否则,你需要在部署httpbin
应用前手动注入sidecar:
kubectl apply -f <(istioctl kube-inject -f samples/httpbin/httpbin.yaml)
- 为了测试,使用 OpenSSL 新建一个密钥和证书。
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /tmp/tls.key -out /tmp/tls.crt -subj "/CN=httpbin.example.com"
- 确定ingress的IP和端口,看下节。
Determining the ingress IP and ports
执行如下命令来判断你的k8s集群运行环境是否支持外部负载均衡。
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网关。如果EXTERNAL-IP
的值为 <none>
(或一直为<pending>
),你的环境没有为ingress网关提供一个外部负载均衡。这种情况下,你可以通过使用服务的 node port 进入网关。
Determining the ingress IP and ports for a load balancer ingress gateway
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=="http")].port}') export SECURE_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="https")].port}')
Determining the ingress IP and ports for a NodePort ingress gateway
确认端口:
export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http")].nodePort}') export SECURE_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="https")].nodePort}')
确认ingress IP取决于集群供应商。
见here.
Configuring ingress using an Istio Gateway
一个ingress 网关描述负载均衡,它位于接受进入的HTTP/TCP连接的网格边缘。它配置暴露端口,协议等,但不像 Kubernetes Ingress Resources, 它不包含任何流量路由配置。入口流量的流量路由使用Istio路由规则进行配置,与内部服务请求完全相同。
下面小节中,我们首先在端口80上配置一个网关,用于未加密的HTTP流量。然后我们为HTTPS流量添加一个安全端口443.
Configuring a gateway for HTTP
1.创建一个Istio Gateway
cat <<EOF | istioctl create -f - 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
输入的流量配置路由
cat <<EOF | istioctl create -f - 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响应拒绝。
注意,在此配置中,来自网格中其他服务的内部请求不受这些规则约束,而是简单地默认为循环路由。要将这些(或其他规则)应用于内部调用,我们可以将特殊值mesh
添加到gateways
列表中。
Verifying the gateway for HTTP
1.使用curl访问httpbin服务。注意curl的 --resolve
标志,允许任意域名访问IP地址。在我们的例子中,我们通过 “httpbin.example.com”来访问我们的入口网关,我们将其指定为我们的 Gateway
处理的host 。同时注意--HHost:httpbin.example.com
标志设置Host 的 HTTP Header 为“httpbin.example.com”。
curl --resolve httpbin.example.com:$INGRESS_PORT:$INGRESS_HOST -HHost:httpbin.example.com -I http://httpbin.example.com:$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
2.访问其他没有明确暴露的URL。你会看到HTTP 404错误:
curl --resolve httpbin.example.com:$INGRESS_PORT:$INGRESS_HOST -HHost:httpbin.example.com -I http://httpbin.example.com:$INGRESS_PORT/headers
HTTP/1.1 404 Not Found date: Mon, 29 Jan 2018 04:45:49 GMT server: envoy content-length: 0
Add a secure port (HTTPS) to our gateway
在这节中,我们为网关田间443端口以处理HTTPS流量。我们创建了一个带证书和私钥的密钥。之后,我们将之前的网关定义替换为在servers标签包含443端口的定义,以及之前定义的在servers标签包含端口80。
1.创建一个k8s Secret
保存密钥/证书
使用kubectl
在命名空间 istio-system
创建secret istio-ingressgateway-certs
。这个Istio网关将自动加载secret。
这个secret必须在命名空间istio-system 中被命名为
istio-ingressgateway-certs
,否则它将不能被Istio gateway安装及使用。
kubectl create -n istio-system secret tls istio-ingressgateway-certs --key /tmp/tls.key --cert /tmp/tls.crt
注意,默认所有在命名空间 istio-system
的服务都可以访问这个ingress 密钥/证书,这可能会泄漏密钥/证书。你可以改变RBAC规则来保护它们。
2.在之前定义的Gateway
的server 小节中添加端口443.
本地的证书和私钥必须在
/etc/istio/ingressgateway-certs
, 否则网关无法加载
cat <<EOF | istioctl replace -f - apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: httpbin-gateway spec: selector: istio: ingressgateway # use istio default ingress gateway servers: - port: number: 80 name: http protocol: HTTP hosts: - "httpbin.example.com" - port: number: 443 name: https protocol: HTTPS tls: mode: SIMPLE serverCertificate: /etc/istio/ingressgateway-certs/tls.crt privateKey: /etc/istio/ingressgateway-certs/tls.key hosts: - "httpbin.example.com" EOF
Verifying the gateway for HTTPS
1.确认我们的网关在80端口依然工作,并且像之前一样接受未加密HTTP流量。我们可以通过访问httpbin服务80端口来实现,就像Verifying the gateway for HTTP 那节那样。
2.通过HTTPS访问httpbin服务,通过curl发送一个HTTPS请求到 SECURE_INGRESS_PORT
. 这里我们使用了curl的-k
选项通知curl不检查我们的证书(因为这仅仅是我们为了测试网关新建的假证书,curl不能察觉到它)。
curl --resolve httpbin.example.com:$SECURE_INGRESS_PORT:$INGRESS_HOST -HHost:httpbin.example.com -I -k https://httpbin.example.com:$SECURE_INGRESS_PORT/status/200
HTTP/2 200 server: envoy date: Mon, 14 May 2018 13:54:53 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: 6
注意,新的网关定义可能需要时间传播,并且你可能受到如下错误:
Failed to connect to httpbin.example.com port <your secure port>: Connection refused
. 等几分钟,再次尝试curl 调用。
Disable the HTTP port
如果我们只想在服务网格中使用HTTPS流量,我们可以从我们的网关中移除HTTP端口。
1.重新定义不带HTTP端口的Gateway
:
cat <<EOF | istioctl replace -f - apiVersion: networking.istio.io/v1alpha3 kind: Gateway metadata: name: httpbin-gateway spec: selector: istio: ingressgateway # use istio default ingress gateway servers: - port: number: 443 name: https protocol: HTTPS tls: mode: SIMPLE serverCertificate: /etc/istio/ingressgateway-certs/tls.crt privateKey: /etc/istio/ingressgateway-certs/tls.key hosts: - "httpbin.example.com" EOF
2.访问HTTP端口,确定它不可用(会返回错误):
curl --resolve httpbin.example.com:$INGRESS_PORT:$INGRESS_HOST -HHost:httpbin.example.com -I http://httpbin.example.com:$INGRESS_PORT/status/200
Accessing Istio service mesh by a browser
目前,只有负载均衡ingress网关才支持通过浏览器访问网格,并且仅支持标准端口(80和443).指定网关的URL时,你必须省略端口。
对于NodePort
ingress 网关,部分支持浏览器访问:仅用于VirtualService
中定义的*
hosts。
Understanding what happened
Gateway
配置资源允许外部流量进入Istio服务网格,并使Istio的流量管理和策略功能可用于边缘服务。
在之前的步骤中,我们创建了一个Istio服务网格内部的服务,并展示如何将服务的HTTP和HTTPS端点公开给外部流量。
Cleanup
删除Gateway
的配置,VirtualService
以及secret,然后关闭httpbin服务:
istioctl delete gateway httpbin-gateway istioctl delete virtualservice httpbin kubectl delete --ignore-not-found=true -n istio-system secret istio-ingressgateway-certs kubectl delete --ignore-not-found=true -f samples/httpbin/httpbin.yaml