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

在微服務中另一個重點就是網關,網關理論包含入口網關和出口網關,傳統意義上的網關很難作到出口網絡控制,可是對於Istio是一件很是輕鬆的事情(由於全部的出口流量都會通過Istio),入口網關控制解析路由數據流向,出口網關控制對外訪問的限制,在Istio中使用了 Ingress和Egress 來實現網關的功能.html

附上:數據庫

喵了個咪的博客:w-blog.cnjson

Istio官方地址:https://preliminary.istio.io/zhapi

Istio中文文檔:https://preliminary.istio.io/zh/docs/bash

PS : 此處基於當前最新istio版本1.0.3版本進行搭建和演示網絡

一. Ingress(入口網關)

Istio的網關運行配置路由規則以及流量如何進入到集羣中,咱們使用httpbin來做爲實驗項目app

>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 路由規則進行配置,與內部服務請求徹底相同。curl

讓咱們看看如何爲 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就能夠沒有任何訪問限制了

相關文章
相關標籤/搜索