1. 程式人生 > >第五部分:DogFood環境,Ingress和Edge路由_Kubernetes中文社群

第五部分:DogFood環境,Ingress和Edge路由_Kubernetes中文社群

概述

在這篇文章中,我們將向您展示如何使用Linkerd實現的Service Mesh來處理Kubernetes上的入口流量,在Service Mesh中的每個例項上分發流量。我們還將通過一個完整的例子來介紹Linkerd的高階路由功能:如何將特定的請求路由到較新版本的應用例項上,比如用於內部測試的、預釋出的應用版本。

這篇文章是關於使用Linkerd作為到Kubernetes網路流量的入口點。 從0.9.1開始,Linkerd直接支援Kubernetes的Ingress資源,這對於本文中的一些用例來說是一個可替代的,也是更簡單的起點。

注意: 這是關於Linkerd、Kubernetes和service mesh的系列文章其中一篇,其餘部分包括:

在本系列的前幾個部分,我們向您展示瞭如何使用Linkerd來捕獲top-line的服務指標,在服務中透明地新增TLS以及執行藍綠髮布。這些文章展示瞭如Kubernetes這樣的環境中如何使用Linkerd作為Service Mesh的元件,為內部服務到服務呼叫中添加了一層彈性和效能的保障,在本篇文章中,我們將這個模型擴充套件到入口路由。

雖然這篇文章以Kubernetes為例,但我們不會使用Kubernetes內建的Ingress資源物件。雖然Ingress提供了一種便捷的基於宿主機和基本路徑的路由方法,但在本文撰寫時,Kubernetes Ingress的功能是相當有限的。在下面的例子中,我們將遠遠超出Ingress提供的範圍。

一、釋出Linkerd Service Mesh

從以前文章中基本的Linkerd Service Mesh配置開始,我們進行兩個更改來支援Ingress:我們將修改Linkerd的配置用以新增一個額外的邏輯路由器,我們在Kubernetes Service資源物件中調整VIP在Linkerd中的範圍。

在Linkerd的例項提供了一個新的邏輯路由器,用於處理入口流量並將其路由到相應的服務:

yaml
routers:
- protocol: http
  label: ingress
  dtab: |
    /srv                    => /#/io.l5d.k8s/default/http ;
    /domain/world/hello/www => /srv/hello ;
    /domain/world/hello/api => /srv/api ;
    /host                  => /$/io.buoyant.http.domainToPathPfx/domain ;
    /svc                    => /host ;
  interpreter:
    kind: default
    transformers:
    - kind: io.l5d.k8s.daemonset
      namespace: default
      port: incoming
      service: l5d
  servers:
  - port: 4142
    ip: 0.0.0.0

在這個配置中,我們使用Linkerd的路由語法,dtabs將請求從域名傳遞到服務——在這種情況下從api.hello.world傳遞到api服務,從www.hello.world到hello服務。為了簡單起見,我們已經為每個域添加了一個規則,但是對於更復雜的設定,也可以輕鬆地生成對映規則。

我們已經將這個入口路由器新增到每個Linkerd例項中 – 以真正Service Mesh的方式,我們將在這些例項中完全分配入口流量,使得應用不存在單點故障。

我們還需要修改Kubernetes Service物件,以在埠80上用非入口VIP替換出口的VIP——這將允許我們直接將出口流量傳送到Linkerd的Service Mesh中,主要是用於除錯的目的,因為這個流量在到達Linkerd之前不會被審查(在下一步,我們將解決這個問題)。

對Kubernetes Service修改如下:

apiVersion: v1
kind: Service
metadata:
  name: l5d
spec:
  selector:
    app: l5d
  type: LoadBalancer
  ports:
  - name: ingress
    port: 80
    targetPort: 4142
  - name: incoming
    port: 4141
  - name: admin
    port: 9990

以上所有的修改都可以通過簡單執行一個命令就能生效,細節請檢視:

$ kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/linkerd-ingress.yml

二、部署服務

對於此例中的Service,我們將使用早先發布的部落格使用到的例子hello and world configs,並且我們會新增兩個新的service:一個api service,其用來呼叫hello和world,還有world service的新版本:world-v2,其將會返回一個“earth”而非“world”——我們擴大黑客團隊已經向我們保證,他們的A/B測試顯示這一變化將使參與度提高10倍。

下面的命令將會把hello world services部署在default名稱空間下。這些應用依賴於Kubernetes downward API提供的節點名來發現Linkerd。為了檢查你的叢集是否支援節點名,你可以執行該測試任務:

kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/node-name-test.yml

然後看它的日誌資訊:

kubectl logs node-name-test

如果你看到了IP,那就非常棒,接著使用如下命令部署hello world應用:

$ kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/hello-world.yml
$ kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/api.yml
$ kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/world-v2.yml

如果你看到的是“server can’t find…”這樣的報錯資訊,請部署hello-world遺留版本,該版本依賴於hostIP而不是節點名:

$ kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/hello-world-legacy.yml
$ kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/api-legacy.yml
$ kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/world-v2.yml

這時我們應該能夠通過入口Kubernetes VIP傳送流量來測試裝置,在沒有使用DNS的情況下,我們將在請求中手動設定一個Host Header:

$ INGRESS_LB=$(kubectl get svc l5d -o jsonpath="{.status.loadBalancer.ingress[0].*}")
$ curl -s -H "Host: www.hello.world" $INGRESS_LB
Hello (10.0.5.7) world (10.0.4.7)!!
$ curl -s -H "Host: api.hello.world" $INGRESS_LB
{"api_result":"api (10.0.3.6) Hello (10.0.5.4) world (10.0.1.5)!!"}

或者如果叢集不支援外部負載均衡器,請使用hostIP:

$ INGRESS_LB=$(kubectl get po -l app=l5d -o jsonpath="{.items[0].status.hostIP}"):$(kubectl get svc l5d -o 'jsonpath={.spec.ports[0].nodePort}')

成功了!我們已經將Linkerd設定為入口控制器,並且我們已經使用它將不同域中收到的請求路由到不同的服務。正如您所見,生產流量正衝擊world-v1服務——我們還沒準備要將world-v2推出。

三、Nginx層

至此ingress已經可以使用了。但還不能用於生產環境中。因為我們的ingress路由器不能將header從請求中提取出來。這就意味著我們不能接收包含header的外部請求。例如,Linkerd允許設定15d-dtab頭部以按請求應用路由規則,這對於新服務的臨時分級是一個有用的功能,但這可能不適合於來自外部的請求。

例如,我們可以使用15d-dtab請求頭覆蓋路由邏輯來使用world-v2而不是world-v1來服務外部請求:

$ curl -H "Host: www.hello.world" -H "l5d-dtab: /host/world => /srv/world-v2;" $INGRESS_LB
Hello (10.100.4.3) earth (10.100.5.5)!!

當earth作為響應,意味著這是world-v2服務的結果。

我們通過新增nginx來解決這個問題(或者其他問題如服務靜態檔案)。如果我們在代理請求到linkerd ingress路由之前配置nginx來提取輸入的header,我們將會兩全其美:有能力安全處理外部流量的ingress層並且Linkerd做動態的、基於服務的路由。

讓我們新增nginx到叢集中。使用this nginx conf來配置它。我們將在www.hello.world和api.hello.world虛擬伺服器下使用proxy_pass命令來發送請求給Linkerd例項,並且我們將使用Headers More模組提供的more_clear_input_headers命令來提取linkerd’s context headers。

對於linkerd 0.9.0,我們可以通過在ingress路由器伺服器上設定clearContext:true來清除輸入的15d-*請求頭。然而,nginx有許多我們可以使用到的特性,所以使用nginx連線Linkerd很有價值。

我們已經發布了一個安裝了Headers More模組的Docker映象:buoyantio/nginx:1.11.5。我們用該配置部署這個映象:

$ kubectl apply -f https://raw.githubusercontent.com/linkerd/linkerd-examples/master/k8s-daemonset/k8s/nginx.yml

在等待外部IP出現後,我們可以通過點選nginx.conf中的簡單測試端點來測試nginx是否啟動:

$ INGRESS_LB=$(kubectl get svc nginx -o jsonpath="{.status.loadBalancer.ingress[0].*}")
$ curl $INGRESS_LB
200 OK

或者如果叢集的外部負載均衡器不可用,使用hostIP:

$ INGRESS_LB=$(kubectl get po -l app=nginx -o jsonpath="{.items[0].status.hostIP}"):$(kubectl get svc nginx -o 'jsonpath={.spec.ports[0].nodePort}')

我們現在應用已經可以通過nginx傳送流量給我們的服務了:

$ curl -s -H "Host: www.hello.world" $INGRESS_LB
Hello (10.0.5.7) world (10.0.4.7)!!
$ curl -s -H "Host: api.hello.world" $INGRESS_LB
{"api_result":"api (10.0.3.6) Hello (10.0.5.4) world (10.0.1.5)!!"}

最後,讓我們嘗試直接與world-v2服務通訊:

$ curl -H "Host: www.hello.world" -H "l5d-dtab: /host/world => /srv/world-v2;" $INGRESS_LB
Hello (10.196.1.8) world (10.196.2.13)!!

沒有earth,Nginx正在淨化外部流量。

四、簡述Dogfood

好了,到了重點部分:讓我們使用world-v1服務來配置dogfood的環境,不過這僅針對一些流量。

為簡化問題,我們只關注設定了特殊cookiespecial_employee_cookie的流量。在實踐中,你可能想要比這更復雜的情況如驗證它,要求它來自公司網路IP範圍等。

用nginx和Linkerd安裝,完成這個相當簡單。我們將會使用nginx來檢查該cookie是否存在,為linkerd設定一個dtab覆蓋頭來調整其路由。有關的nginx配置如下:

if ($cookie_special_employee_cookie ~* "dogfood") {
  set $xheader "/host/world => /srv/world-v2;";
}

proxy_set_header 'l5d-dtab' $xheader;

如果你已經按以上步驟做了,被部署的nginx已經包含了這個配置。我們可以用如下來進行測試:

$ curl -H "Host: www.hello.world" --cookie "special_employee_cookie=dogfood" $INGRESS_LB
Hello (10.196.1.8) earth (10.196.2.13)!!

系統已經工作了。當這個cookie被設定了,你將置於dogfood模式下。如果沒有它,你將置於常規生產流量模式。最重要的是,dogfood模式可以包含在service stack到處出現的service的新版本,甚至很多層——只要服務程式碼轉發Linkerd的上下文頭,Linkerd服務網格將負責其餘部分。

結束語

在本文中,我們看到了如何使用Linkerd給Kubernetes叢集提供有力而又靈活的入口。我們已經演示瞭如何部署名義上的生產就緒設定,使用Linkerd進行服務路由。我們已經演示瞭如何使用Linkerd的一些高階路由功能來將流量服務拓撲從部署拓撲結構中分離出來,從而允許建立dogfood環境而不需要單獨的叢集或部署時間複雜性。

譯者:容器時代 大偉

歡迎關注微信公眾號