六, 跨語言微服務框架 - Istio Ingress和Egress詳解(解決Istio無法外網訪問問題)

在微服務中另外一個重點就是網關,網關理論包含入口網關和出口網關,傳統意義上的網關很難做到出口網絡控制,但是對於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
  1. 確定入口 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和端口,筆者是內網所以對應的訪問可以通過其中的任意一個節點即可

  1. 使用 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 的列表中。

  1. 使用 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。

  1. 訪問任何未明確公開的其他 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
  1. 配置外部服務
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
  1. 配置外部 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/
  1. 爲外部服務設置路由規則

通過 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
  1. 直接調用外部服務

確認限制可以帶來更多的控制避免出錯,但是很多時候還是會帶來很多麻煩,那麼如果不希望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就可以沒有任何訪問限制了

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章