Istio Ingress控制器
此任务将演示如何通过配置Istio将服务公开到service mesh集群外部。在Kubernetes环境中,Kubernetes Ingress Resources 允许用户指定某个服务是否要公开到集群外部。然而,Ingress Resource规范非常精简,只允许用户设置主机,路径,以及后端服务。为了利用Istio的高级路由能力,我们建议组合使用 Ingress Resource和Istio的路由规则。
注意: Istio 不支持在ingress resource规范中使用
ingress.kubernetes.io注解(annotations)。除了kubernetes.io/ingress.class: istio之外的注解都会被忽略。
前提条件
参照文档安装指南中的步骤安装Istio。
确保当前的目录是
istio目录。启动 httpbin 示例, 我们会把这个服务作为目标(destination)服务公开到外部。
如果你安装了 Istio-Initializer, 请执行:
kubectl apply -f samples/httpbin/httpbin.yaml
如果没有 Istio-Initializer, 请执行:
kubectl apply -f <(istioctl kube-inject -f samples/httpbin/httpbin.yaml)
配置 ingress (HTTP)
为 httpbin 服务创建一个基本的 Ingress Resource
cat <<EOF | kubectl create -f -apiVersion: extensions/v1beta1kind: Ingressmetadata:name: simple-ingressannotations:kubernetes.io/ingress.class: istiospec:rules:- http:paths:- path: /.*backend:serviceName: httpbinservicePort: 8000EOF
/. 是一个 Istio 特殊表示法,以前缀 / 开始的配置,都表示前缀匹配。上面的配置允许访问 httpbin 服务中的所有 URI。然而,实际上我们只想开放一部分特殊的 URI。我们可以先定义一个默认的 deny all* 路由规则,将所有的请求都拒绝:
cat <<EOF | istioctl create -f -## Deny all access from istio-ingressapiVersion: config.istio.io/v1alpha2kind: RouteRulemetadata:name: deny-routespec:destination:name: httpbinmatch:# Limit this rule to istio ingress pods onlysource:name: istio-ingresslabels:istio: ingressprecedence: 1route:- weight: 100httpFault:abort:percent: 100httpStatus: 403 #Forbidden for all URLsEOF
然后,再定义一个高优先级的路由,允许访问
/status/前缀的 URI。cat <<EOF | istioctl create -f -## Allow requests to /status prefixapiVersion: config.istio.io/v1alpha2kind: RouteRulemetadata:name: status-routespec:destination:name: httpbinmatch:# Limit this rule to istio ingress pods onlysource:name: istio-ingresslabels:istio: ingressrequest:headers:uri:prefix: /statusprecedence: 2 #must be higher precedence than the deny-routeroute:- weight: 100EOF
这里也可以用其他的路由功能,比如重定向,重写,正则表达式匹配 HTTP headers,websocket upgrades,超时,重试等。详情请参看 routing rules 。
验证 ingress
确定 ingress URL:
如果你的集群运行的环境支持外部的负载均衡器,请使用 ingress 的外部地址:
kubectl get ingress simple-ingress -o wide
NAME HOSTS ADDRESS PORTS AGEsimple-ingress * 130.211.10.121 80 1d
export INGRESS_HOST=130.211.10.121
如果你的环境不支持负载均衡器,使用 ingress 控制器的 pod 的主机 IP:
kubectl get po -l istio=ingress -o jsonpath='{.items[0].status.hostIP}'
169.47.243.100
同时也找到 istio-ingress 服务的 80 端口的 nodePort 映射端口:
kubectl get svc istio-ingress
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGEistio-ingress 10.10.10.155 <pending> 80:31486/TCP,443:32254/TCP 32m
export INGRESS_HOST=169.47.243.100:31486
使用 curl 访问 httpbin 服务:
curl -I http://$INGRESS_HOST/status/200
HTTP/1.1 200 OKServer: meinheld/0.6.1Date: Thu, 05 Oct 2017 21:23:17 GMTContent-Type: text/html; charset=utf-8Access-Control-Allow-Origin: *Access-Control-Allow-Credentials: trueX-Powered-By: FlaskX-Processed-Time: 0.00105214118958Content-Length: 0Via: 1.1 vegurConnection: Keep-Alive
如果访问其他的没有明确公开的 URL,应该收到 HTTP 403 错误
curl -I http://$INGRESS_HOST/headers
HTTP/1.1 403 FORBIDDENServer: meinheld/0.6.1Date: Thu, 05 Oct 2017 21:24:47 GMTContent-Type: text/html; charset=utf-8Access-Control-Allow-Origin: *Access-Control-Allow-Credentials: trueX-Powered-By: FlaskX-Processed-Time: 0.000759840011597Content-Length: 0Via: 1.1 vegurConnection: Keep-Alive
配置安全ingress(HTTPS)
-
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /tmp/tls.key -out /tmp/tls.crt -subj "/CN=foo.bar.com"
用
kubectl更新secretkubectl create -n istio-system secret tls istio-ingress-certs --key /tmp/tls.key --cert /tmp/tls.crt
3.为 httpbin服务创建Ingress Resource
cat <<EOF | kubectl create -f -apiVersion: extensions/v1beta1kind: Ingressmetadata:name: secure-ingressannotations:kubernetes.io/ingress.class: istiospec:tls:- secretName: istio-ingress-certs # currently ignoredrules:- http:paths:- path: /.*backend:serviceName: httpbinservicePort: 8000EOF
创建 deny rule ,同时为 /status 前缀创建前文相同的规则。同时,像前面一样,设置 INGRESS_HOST 指向 ingress 服务的 IP 和端口。
注意: Envoy 当前只允许一个 TLS ingress 密钥,因为 SNI 尚未支持。也就是说看,ingress 中的 secretName 字段并没有用,secret 必须叫做
istio-ingress-certs并且在istio-system命名空间(namespace)。
用
curl访问安全httpbin服务curl -I -k https://$INGRESS_HOST/status/200
为gRPC配置ingress
Ingress控制器的path字段当前并不支持. 字符。这会导致使用命名空间的gRPC服务出问题(译注:因为gRPC用 . 分割命名空间和服务名)。为了解决这个问题,可以先把流量导向到一个虚拟(dummy)服务,然后设置路由规则去拦截流量并重定向到期望的服务。
创建一个虚拟ingress服务:
cat <<EOF | kubectl create -f -apiVersion: v1kind: Servicemetadata:name: ingress-dummy-servicespec:ports:- name: grpcport: 1337EOF
创建一个拦截所有流量的ingress指向虚拟服务:
cat <<EOF | kubectl create -f -apiVersion: extensions/v1beta1kind: Ingressmetadata:name: all-istio-ingressannotations:kubernetes.io/ingress.class: istiospec:rules:- http:paths:- backend:serviceName: ingress-dummy-serviceservicePort: grpcEOF
给每个服务创建一个RouteRule ,将流量从虚拟服务重定向到正确的gRPC服务:
cat <<EOF | istioctl create -f -apiVersion: config.istio.io/v1alpha2kind: RouteRulemetadata:name: foo-service-routespec:destination:name: ingress-dummy-servicematch:request:headers:uri:prefix: "/foo.FooService"precedence: 1route:- weight: 100destination:name: foo-service---apiVersion: config.istio.io/v1alpha2kind: RouteRulemetadata:name: bar-service-routespec:destination:name: ingress-dummy-servicematch:request:headers:uri:prefix: "/bar.BarService"precedence: 1route:- weight: 100destination:name: bar-serviceEOF
理解ingress原理
Ingress为外部流量进入Istio service mesh提供一个网关,并使Istio的流量管理和策略功能可用于边缘服务。
在前面的步骤中,我们在Istio service mesh中创建了一个服务,并展示了如何将服务的HTTP和HTTPS公开给外部流量,同时还展示了如何使用Istio路由规则来控制入口流量。
清理
删除密钥,Ingress Resource定义以及Istio规则。
istioctl delete routerule deny-route status-routekubectl delete ingress simple-ingress secure-ingresskubectl delete -n istio-system secret istio-ingress-certs
删除httpbin服务。
kubectl delete -f samples/httpbin/httpbin.yaml
进阶阅读
- 进一步了解和学习Ingress Resources.
- 进一步了解和学习routing rules.
