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/v1beta1
kind: Ingress
metadata:
name: simple-ingress
annotations:
kubernetes.io/ingress.class: istio
spec:
rules:
- http:
paths:
- path: /.*
backend:
serviceName: httpbin
servicePort: 8000
EOF
/. 是一个 Istio 特殊表示法,以前缀 / 开始的配置,都表示前缀匹配。上面的配置允许访问 httpbin 服务中的所有 URI。然而,实际上我们只想开放一部分特殊的 URI。我们可以先定义一个默认的 deny all* 路由规则,将所有的请求都拒绝:
cat <<EOF | istioctl create -f -
## Deny all access from istio-ingress
apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
name: deny-route
spec:
destination:
name: httpbin
match:
# Limit this rule to istio ingress pods only
source:
name: istio-ingress
labels:
istio: ingress
precedence: 1
route:
- weight: 100
httpFault:
abort:
percent: 100
httpStatus: 403 #Forbidden for all URLs
EOF
然后,再定义一个高优先级的路由,允许访问
/status/
前缀的 URI。cat <<EOF | istioctl create -f -
## Allow requests to /status prefix
apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
name: status-route
spec:
destination:
name: httpbin
match:
# Limit this rule to istio ingress pods only
source:
name: istio-ingress
labels:
istio: ingress
request:
headers:
uri:
prefix: /status
precedence: 2 #must be higher precedence than the deny-route
route:
- weight: 100
EOF
这里也可以用其他的路由功能,比如重定向,重写,正则表达式匹配 HTTP headers,websocket upgrades,超时,重试等。详情请参看 routing rules 。
验证 ingress
确定 ingress URL:
如果你的集群运行的环境支持外部的负载均衡器,请使用 ingress 的外部地址:
kubectl get ingress simple-ingress -o wide
NAME HOSTS ADDRESS PORTS AGE
simple-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) AGE
istio-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 OK
Server: meinheld/0.6.1
Date: Thu, 05 Oct 2017 21:23:17 GMT
Content-Type: text/html; charset=utf-8
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
X-Powered-By: Flask
X-Processed-Time: 0.00105214118958
Content-Length: 0
Via: 1.1 vegur
Connection: Keep-Alive
如果访问其他的没有明确公开的 URL,应该收到 HTTP 403 错误
curl -I http://$INGRESS_HOST/headers
HTTP/1.1 403 FORBIDDEN
Server: meinheld/0.6.1
Date: Thu, 05 Oct 2017 21:24:47 GMT
Content-Type: text/html; charset=utf-8
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
X-Powered-By: Flask
X-Processed-Time: 0.000759840011597
Content-Length: 0
Via: 1.1 vegur
Connection: 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/v1beta1
kind: Ingress
metadata:
name: secure-ingress
annotations:
kubernetes.io/ingress.class: istio
spec:
tls:
- secretName: istio-ingress-certs # currently ignored
rules:
- http:
paths:
- path: /.*
backend:
serviceName: httpbin
servicePort: 8000
EOF
创建 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: v1
kind: Service
metadata:
name: ingress-dummy-service
spec:
ports:
- name: grpc
port: 1337
EOF
创建一个拦截所有流量的ingress指向虚拟服务:
cat <<EOF | kubectl create -f -
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: all-istio-ingress
annotations:
kubernetes.io/ingress.class: istio
spec:
rules:
- http:
paths:
- backend:
serviceName: ingress-dummy-service
servicePort: grpc
EOF
给每个服务创建一个RouteRule ,将流量从虚拟服务重定向到正确的gRPC服务:
cat <<EOF | istioctl create -f -
apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
name: foo-service-route
spec:
destination:
name: ingress-dummy-service
match:
request:
headers:
uri:
prefix: "/foo.FooService"
precedence: 1
route:
- weight: 100
destination:
name: foo-service
---
apiVersion: config.istio.io/v1alpha2
kind: RouteRule
metadata:
name: bar-service-route
spec:
destination:
name: ingress-dummy-service
match:
request:
headers:
uri:
prefix: "/bar.BarService"
precedence: 1
route:
- weight: 100
destination:
name: bar-service
EOF
理解ingress原理
Ingress为外部流量进入Istio service mesh提供一个网关,并使Istio的流量管理和策略功能可用于边缘服务。
在前面的步骤中,我们在Istio service mesh中创建了一个服务,并展示了如何将服务的HTTP和HTTPS公开给外部流量,同时还展示了如何使用Istio路由规则来控制入口流量。
清理
删除密钥,Ingress Resource定义以及Istio规则。
istioctl delete routerule deny-route status-route
kubectl delete ingress simple-ingress secure-ingress
kubectl delete -n istio-system secret istio-ingress-certs
删除httpbin服务。
kubectl delete -f samples/httpbin/httpbin.yaml
进阶阅读
- 进一步了解和学习Ingress Resources.
- 进一步了解和学习routing rules.