在微服務中另外一個重點就是網關,網關理論包含入口網關和出口網關,傳統意義上的網關很難做到出口網絡控制,但是對于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就可以沒有任何訪問限制了
作者:文振熙
鏈接:http://www.lxweimin.com/p/03bf0f54b301
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。