在微服务中另外一个重点就是网关,网关理论包含入口网关和出口网关,传统意义上的网关很难做到出口网络控制,但是对于Istio是一件非常轻松的事情(因为所有的出口流量都会经过Istio),入口网关控制解析路由数据流向,出口网关控制对外访问的限制,在Istio中使用了 Ingress和Egress 来实现网关的功能.
附上:
喵了个咪的博客:w-blog.cn
Istio官方地址:https://preliminary.istio.io/zh
Istio中文文档:https://preliminary.istio.io/zh/docs/
PS : 此处基于当前最新istio版本1.0.3版本进行搭建和演示
一. Ingress(入口网关)
Istio的网关运行配置路由规则以及流量如何进入到集群中,我们使用httpbin来作为实验项目
>kubectl apply -n istio-test -f istio-1.0.3/samples/httpbin/httpbin.yaml
- 确定入口 IP 和端口
执行以下命令以确定您的 Kubernetes 集群是否在支持外部负载均衡器的环境中运行。
> kubectl get svc istio-ingressgateway -n istio-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
istio-ingressgateway LoadBalancer 10.43.92.244 172.16.0.203 80:31380/TCP,443:31390/TCP,31400:31400/TCP,15011:30921/TCP,8060:30126/TCP,853:30117/TCP,15030:31865/TCP,15031:30683/TCP 22h
如果环境不再一套内网中使用了负载均衡,需要使用映射的对应的IP和端口,笔者是内网所以对应的访问可以通过其中的任意一个节点即可
- 使用 Istio 网关配置 Ingress
Ingress Gateway描述了在网格边缘操作的负载平衡器,用于接收传入的 HTTP/TCP 连接。它配置暴露的端口,协议等,但与 Kubernetes Ingress Resources 不同,它不包括任何流量路由配置。流入流量的流量路由使用 Istio 路由规则进行配置,与内部服务请求完全相同。
让我们看看如何为 Gateway 在 HTTP 80 端口上配置流量。
kubectl apply -n istio-test -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 -n istio-test -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。
该网关列表指定,只有通过我们的要求 httpbin-gateway 是允许的。所有其他外部请求将被拒绝,并返回 404 响应。
请注意,在此配置中,来自网格中其他服务的内部请求不受这些规则约束,而是简单地默认为循环路由。要将这些(或其他规则)应用于内部调用,我们可以将特殊值 mesh 添加到 gateways 的列表中。
- 使用 curl 访问 httpbin 服务:
curl -I -HHost:httpbin.example.com http://172.16.0.203:31380/status/200
HTTP/1.1 200 OK
server: envoy
date: Thu, 08 Nov 2018 02:35:52 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: 46
请注意,这里使用该 -H 标志将 Host HTTP Header 设置为 “httpbin.example.com”。这以操作是必需的,因为上面的 Ingress Gateway 被配置为处理 “httpbin.example.com”,但在测试环境中没有该主机的 DNS 绑定,只是将请求发送到 Ingress IP。
- 访问任何未明确公开的其他 URL,应该会看到一个 HTTP 404 错误:
curl -I -HHost:httpbin.example.com http://172.16.0.203:31380/headers
HTTP/1.1 404 Not Found
date: Thu, 08 Nov 2018 02:36:32 GMT
server: envoy
transfer-encoding: chunked
二. Egress(出口网关)
入口网关大家都很好理解不就是一个NGINX域名解析路由控制嘛,你这个出口网关有啥用啊? 在日益精细化运维管理的今天对于出口流量的控制越来越重要, 可以访问什么不可以访问什么对每一个程序来说应该都是确定的,这样的限制可以避免异常流量外部攻击等.
缺省情况下,Istio 服务网格内的 Pod,由于其 iptables 将所有外发流量都透明的转发给了 Sidecar,所以这些集群内的服务无法访问集群之外的 URL,而只能处理集群内部的目标。
这就导致了文章开头所说的问题Istio无法外网访问,如果大家的数据库不在集群内就会发现根本连不上
我们还是使用sleep来作为我们的例子
> kubectl apply -n istio-test -f istio-1.0.3/samples/sleep/sleep.yaml
> export SOURCE_POD=$(kubectl get -n istio-test pod -l app=sleep -o jsonpath={.items..metadata.name})
# 尝试访问(访问任何外部地址都会出现404)
> kubectl exec -n istio-test -it $SOURCE_POD -c sleep bash
crul -I baidu.com
bash: crul: command not found
root@sleep-76df4f989c-9hvvd:/# curl -I baidu.com
HTTP/1.1 404 Not Found
date: Thu, 08 Nov 2018 03:37:16 GMT
server: envoy
transfer-encoding: chunked
- 配置外部服务
kubectl apply -n istio-test -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: baidu-ext
spec:
hosts:
- baidu.com
ports:
- number: 80
name: http
protocol: HTTP
resolution: DNS
location: MESH_EXTERNAL
EOF
创建一个 ServiceEntry 以及 VirtualService,允许访问外部 HTTPS 服务。注意:包括 HTTPS 在内的 TLS 协议,在 ServiceEntry 之外,还需要创建 TLS VirtualService
> kubectl exec -n istio-test -it $SOURCE_POD -c sleep bash
> curl -I baidu.com
HTTP/1.1 200 OK
date: Thu, 08 Nov 2018 03:37:57 GMT
server: envoy
last-modified: Tue, 12 Jan 2010 13:48:00 GMT
etag: "51-47cf7e6ee8400"
accept-ranges: bytes
content-length: 81
cache-control: max-age=86400
expires: Fri, 09 Nov 2018 03:37:57 GMT
content-type: text/html
x-envoy-upstream-service-time: 67
- 配置外部 HTTPS 服务
上面只配置了http可以访问,如果使用https会出现以下情况
> curl -I https://baidu.com
curl: (35) Unknown SSL protocol error in connection to baidu.com:443
创建一个 ServiceEntry 和一个 VirtualService 以允许访问外部 HTTPS 服务。请注意, 对于 TLS 协议(包括 HTTPS),除了 ServiceEntry 之外,还需要 VirtualService。 VirtualService 必须在 match 子句中包含 tls 规则和 sni_hosts 以启用 SNI 路由。
kubectl apply -n istio-test -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: baidu
spec:
hosts:
- baidu.com
ports:
- number: 443
name: https
protocol: HTTPS
resolution: DNS
location: MESH_EXTERNAL
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: baidu
spec:
hosts:
- baidu.com
tls:
- match:
- port: 443
sni_hosts:
- baidu.com
route:
- destination:
host: baidu.com
port:
number: 443
weight: 100
EOF
> curl -I https://baidu.com
HTTP/1.1 302 Moved Temporarily
Server: bfe/1.0.8.18
Date: Thu, 08 Nov 2018 03:41:05 GMT
Content-Type: text/html
Content-Length: 161
Connection: keep-alive
Location: http://www.baidu.com/
- 为外部服务设置路由规则
通过 ServiceEntry 访问外部服务的流量,和网格内流量类似,都可以进行 Istio 路由规则 的配置。下面我们使用 istioctl 为 httpbin.org 服务设置一个超时规则。
在测试 Pod 内部,使用 curl 调用 httpbin.org 这一外部服务的 /delay 端点:
> kubectl apply -n istio-test -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: ServiceEntry
metadata:
name: httpbin-ext
spec:
hosts:
- httpbin.org
ports:
- number: 80
name: http
protocol: HTTP
resolution: DNS
location: MESH_EXTERNAL
EOF
> time curl -o /dev/null -s -w "%{http_code}\n" http://httpbin.org/delay/5
200
real 0m5.752s
user 0m0.013s
sys 0m0.022s
使用 kubectl 为 httpbin.org 外部服务的访问设置一个 3 秒钟的超时
kubectl apply -n istio-test -f - <<EOF
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: httpbin-ext
spec:
hosts:
- httpbin.org
http:
- timeout: 3s
route:
- destination:
host: httpbin.org
weight: 100
EOF
这一次会在 3 秒钟之后收到一个内容为 504 (Gateway Timeout) 的响应。虽然 httpbin.org 还在等待他的 5 秒钟,Istio 却在 3 秒钟的时候切断了请求。
time curl -o /dev/null -s -w "%{http_code}\n" http
504
real 0m3.046s
user 0m0.010s
sys 0m0.010s
- 直接调用外部服务
确认限制可以带来更多的控制避免出错,但是很多时候还是会带来很多麻烦,那么如果不希望Istio进行限制可以随意的访问需要怎么办呢?当然是可以的,可以配置Istio对于哪些范围,首先我们需要确定内部集群IP范围:
- 使用minikube 范围是 10.0.0.1/24
- 使用rancher 范围是 10.43.0.1/24
方案一(HELM):
注意这里应该使用和之前部署 Istio 的时候同样的 Helm 命令,尤其是 --namespace 参数。在安装 Istio 原有命令的基础之上,加入 --set global.proxy.includeIPRanges="10.0.0.1/24" -x templates/sidecar-injector-configmap.yaml 即可。
helm template install/kubernetes/helm/istio <安装 Istio 时所使用的参数> --set global.proxy.includeIPRanges="10.0.0.1/24" -x templates/sidecar-injector-configmap.yaml | kubectl apply -f -
然后重新部署sleep就可以了
方案二(改编排):
应为笔者不是使用helm进行的istio安装,直接使用的官方demo来安装的,我们可以先找到includeOutboundIPRanges然后修改后面的*改成对应的IP段
PS : 不同版本生成的yaml是不一样的需要注意
istio-1.0.1版本
- "[[ index .ObjectMeta.Annotations "traffic.sidecar.istio.io/includeOutboundIPRanges" ]]"
[[ else -]]
- "10.43.0.1/24"
[[ end -]]
istio1.0.3版本
- "[[ annotation .ObjectMeta `traffic.sidecar.istio.io/includeOutboundIPRanges` "10.43.0.1/24" ]]"
然后重新部署Istio就可以没有任何访问限制了
作者:文振熙
链接:https://www.jianshu.com/p/03bf0f54b301
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。