用DCOS和marathon-lb實現服務發現和負載均衡:第一部分

最近在研究使用Mesos,對marathon-lb和mesos-dns等諸多工具,只是停留在知道和會用的階段,特別是對於基於marathon-lb的HAProxy的應用分組和使用更是一頭霧水。現在資料也少,看了官網上的這篇文章覺得講得還算是全面。兄弟英文水平差,先用Google翻譯了一下,然後再梳理整理,同時,加上了一些自己的理解的說明。因爲每個人的經歷和經驗都不同,以下這些東西對於有些人可能很難對於有些人可能很簡單,所以不當之處還請大家多多見諒。歡迎討論和拍磚。


這是服務發現和負載均衡系列的第一部分,共兩部分。

Mesosphere Datacenter Operating System (DCOS) 爲服務發現和負載均衡提供了有用的工具。其中一個主要的工具就是marathon-lb,這將是本文的重點。

在啓動了DCOS集羣以後,通過使用Mesos-DNS可以發現所有的task。發現是通過DNS實現的,但是有一些限制,其中包括:
- DNS無法識別服務端口,除非使用SRV查詢(SRV記錄它是DNS服務器的數據庫中支持的一種資源記錄的類型,它記錄了哪臺計算機提供了哪個服務這麼一個簡單的信息);大多數應用程序都無法使用SRV記錄“開箱即用”。
- DNS不具有快速故障轉移能力。
- DNS記錄有一個TTL(生存時間:time to live),同時Mesos-DNS使用輪詢來創建DNS記錄; 這可能會導致過時的記錄。
- DNS記錄不提供任何服務的健康數據。
- 一些應用程序和庫不正確地處理多個A記錄(handle multiple A records);在某些情況下,查詢可能被緩存,並根據需要不正確地重新加載。

注:A記錄也稱爲主機記錄,是使用最廣泛的DNS記錄,A記錄的基本作用就是說明一個域名對應的IP是多少,它是域名和IP地址的對應關係,表現形式爲:www.xxx.com 192.168.1.1這就是一個A記錄!A記錄除了進行域名IP對應以外,還有一個高級用法,可以作爲低成本的負載均衡的解決方案,比如說:www.xxx.com 可以創建多個A記錄,對應多臺物理服務器的IP地址,可以實現基本的流量均衡!

爲了解決這個問題,我們爲Marahon提供一個叫做Marathon Load Balancer的工具,簡稱marathon-lb.

注:這句話是否意味着:使用Mesos-DNS是有侷限,而marathon-lb是可以起到與Mesos-DNS同樣作用的,這樣的話就不需要使用Mesos-DNS?

marathon-lb是基於HAProxy(一個快速的代理服務器和負載均衡器)的。HAProxy可以爲基於TCP和HTTP協議的應用提供代理和負載均衡。支持如SSL,HTTP壓縮,健康檢查,Lua腳本等功能。marathon-lb會將事件提交至marathon事件總線,同時實時的對HAProxy的配置進行更新和修改。

你可以可以用多種拓撲結構配置marathon-lb。以下是如何使用的marathon-lb的一些例子:

  • 使用marathon-lb做爲的邊緣負載均衡器(edge load balancer
    LB)和服務發現機制。你可以運行在面向公衆的節點marathon-lb路由入口流量。你可以使用的A記錄面向公衆的節點的IP地址,以供內部或外部DNS記錄(根據您的使用情況)。

注:”edge load balancer”,我理解應該是頂級或者入口級的負載均

  • 使用marathon-lb作爲內部(internal)LB和服務發現機制,有一個單獨的HA負載均衡器作爲公共的路由處理。例如,你可以使用預置的外部F5負載均衡器,或者在Amazon
    Web Services的彈性負載均衡。
  • 將marathon-lb嚴格的作爲內部(internal)LB和服務發現機制。
  • 可能還需要使用內(internal)部和外部(external )的LB的組合,爲不同的服務提供不同的負載均衡。

在本文中,我們將討論上述第四個選項,以突出說明marathon-lb的特點。

這裏寫圖片描述

爲了演示marathon-lb,我們將啓動一個部署在AWS上的DCOS集羣,並運行一個內部和外部負載均衡器。外部負載均衡將用於分發由外部HTTP請求到集羣,並且內部的LB將用於內部服務發現和負載平衡。由於我們是在AWS上實現,對外通訊將先做一個ELB配置用來對外暴露“public”代理節點。

如果想跟着一起操作,你可以在AWS上創建自己的集羣。合在AWS上使用DCOS社區版Mesosphere不會收取任何費用,但你仍然必須支付的基本情況和相關的AWS費用。

marathon-lb提供可直接安裝的包。要安裝marathon-lb:

$ dcos package install marathon-lb

注:我是使用mesosphere提供的安裝包,在centos7上搭建的mesos環境,然後使用marathon-lb的docker鏡像。我覺得閱讀本文主要是要了解marathon-lb的使用以及如何規劃負載均衡,dcos的安裝模式可以忽略。

要驗證marathon-lb是否正常工作,根據你搭建的Mesos環境,用Mesos-slave主機的IP,訪問http://:9090/haproxy?stats。你會看到這樣的統計報表頁面:

這裏寫圖片描述

接下來,我們將建立我們的內部LB。要做到這一點,我們必須先指定marathon-lb中的一些配置選項。創建一個名爲options.json包含以下內容:

{
  "marathon-lb":{
    "name":"marathon-lb-internal",
    "haproxy-group":"internal",
    "bind-http-https":false,
    "role":""
  }
}

在這個選項文件,我們需要修改 a)的應用實例的名稱,b)HAProxy的組名,同時,我們停用HAProxy端口80和443的HTTP和HTTPS轉發(因爲它不需要)。

接下來,運行與我們的新選項安裝命令:

$ dcos package install --options=options.json marathon-lb

注:在Mesos環境中,可以直接用命令執行,例如:curl -X POST http://mesos-master:8080/v2/apps -d @options.json -H “Content-type: application/json”

現在,我們將有2個負載均衡:一個外部LB和一個內部LB.讓我們運行一個示例應用程序來演示功能。下面是我們的nginx的外部實例:

注:
1)以上內容中共安裝了兩個marathon-lb。第一個是上文中最早安裝的,默認安裝的marathon-lb,HAPROXY_GROUP值是external的,默認是綁定了80和443端口的。用上面的帶options.json參數的命令,又安裝了一個marathon-lb,這裏面指定HAPROXY_GROUP爲internal,同時取消對80和443的綁定。
2)這裏的Nginx不是用於負載均衡,這裏把Nginx當作一個服務或者一個微服務就行。可能是考慮nginx相對比較小,好配置,所以很多mesos的文章中都是用nginx做示例。

{
  "id": "nginx-external",
  "container": {
    "type": "DOCKER",
    "docker": {
      "image": "nginx:1.7.7",
      "network": "BRIDGE",
      "portMappings": [
        { "hostPort": 0, "containerPort": 80, "servicePort": 10000 }
      ],
      "forcePullImage":true
    }
  },
  "instances": 1,
  "cpus": 0.1,
  "mem": 65,
  "healthChecks": [{
      "protocol": "HTTP",
      "path": "/",
      "portIndex": 0,
      "timeoutSeconds": 10,
      "gracePeriodSeconds": 10,
      "intervalSeconds": 2,
      "maxConsecutiveFailures": 10
  }],
  "labels":{
    "HAPROXY_GROUP":"external"
  }
}

您可以通過粘貼上面的JSON到一個文件中(稱爲發動DCOS這個程序nginx-external.json),並運行:

$ dcos marathon app add nginx-external.json

注:與第一個json說明的運行方式相同,直接用curl來執行。

Application(執行json就會在marathon創建一個application)的定義中,包含了用HAPROXY_GROUP作爲Key的特殊標籤。這個標籤告訴marathon-lb是否對外暴露該應用程序。外部marathon-lb運行時設置–group參數的值爲external,這是默認值。你可以在這裏檢查代碼,如果你願意的話。

下面是我們的內部nginx的:

{
  "id": "nginx-internal",
  "container": {
    "type": "DOCKER",
    "docker": {
      "image": "nginx:1.7.7",
      "network": "BRIDGE",
      "portMappings": [
        { "hostPort": 0, "containerPort": 80, "servicePort": 10001 }
      ],
      "forcePullImage":true
    }
  },
  "instances": 1,
  "cpus": 0.1,
  "mem": 65,
  "healthChecks": [{
      "protocol": "HTTP",
      "path": "/",
      "portIndex": 0,
      "timeoutSeconds": 10,
      "gracePeriodSeconds": 10,
      "intervalSeconds": 2,
      "maxConsecutiveFailures": 10
  }],
  "labels":{
    "HAPROXY_GROUP":"internal"
  }
}

請注意,我們指定一個servicePort參數。servicePort端口是該服務(本例中的Ninx)在marathon-lb中的端口。默認情況下,marathon-lb保留從10000至10100的端口,用於對外的服務使用,所以你應該從10000開始使用(如果你數一下,共計101服務端口可以使用)。您可能需要使用電子表格,來跟蹤記錄這些端口在marathon-lb中的分配和使用情況,以及每個端口是與哪組LB的服務對應。

讓我們再添加一個Nginx實例:

{
  "id": "nginx-everywhere",
  "container": {
    "type": "DOCKER",
    "docker": {
      "image": "nginx:1.7.7",
      "network": "BRIDGE",
      "portMappings": [
        { "hostPort": 0, "containerPort": 80, "servicePort": 10002 }
      ],
      "forcePullImage":true
    }
  },
  "instances": 1,
  "cpus": 0.1,
  "mem": 65,
  "healthChecks": [{
      "protocol": "HTTP",
      "path": "/",
      "portIndex": 0,
      "timeoutSeconds": 10,
      "gracePeriodSeconds": 10,
      "intervalSeconds": 2,
      "maxConsecutiveFailures": 10
  }],
  "labels":{
    "HAPROXY_GROUP":"external,internal"
  }
}

內外部都可以方案該Nginx實例。請注意,我們已經改變了servicePort端口,因此不會與其他Nginx的情況下重疊。

可以通過使用端口映射來定義服務端口(如在上面的例子),或者在marathon application的定義中增加ports參數。

爲了測試我們的配置,用SSH登錄到集羣中的實例(如主機)之一,並嘗試curl-ing端點:

$ curl http://marathon-lb.marathon.mesos:10000/

$ curl http://marathon-lb-internal.marathon.mesos:10001/

$ curl http://marathon-lb.marathon.mesos:10002/

$ curl http://marathon-lb-internal.marathon.mesos:10002/

每一個地址都應該返回Nginx的“歡迎”頁面,如下所示:

這裏寫圖片描述

虛擬主機

marathon-lb的一個重要特點是支持虛擬主機。這可以使您將HTTP通路分發到多個主機(FQDN的),並且將請求路由到正確的endpoint。例如,你可以有兩個不同的網絡地址,ilovesteak.com和steaknow.com,同時這兩個地址的DNS都通過相同的端口指向同一個LB,並且將HAProxy基於域名將通信路由到正確的endpoint。

要測試虛擬主機功能,切換到AWS控制檯,查看您的punblic ELB。爲了進行測試,我們將對public ELB進行兩處修改。

首先,我們將修改健康檢查,使用HAProxy的內置的健康檢查:

這裏寫圖片描述

其次,修改健康檢查的路徑/_haproxy_health_check,讓它去ping主機的9090端口。現在,如果你瀏覽到實例選項卡,您應該看到界面列出狀態爲InService的實例,就像這樣:

這裏寫圖片描述

現在,我們的ELB能夠將流量路由到HAProxy的。接下來,讓我們修改nginx的應用程序來暴露我們的服務。要做到這一點,你需要從Description tab頁面中找到ELB public DNS的名稱。在這個例子中,我的public DNS名字是brenden-j-PublicSl-1LTLKZEH6B2G6-1145355943.us-west-2.elb.amazonaws.com。

現在我將修改外部nginx的應用是這樣的:

{
  "id": "nginx-external",
  "container": {
    "type": "DOCKER",
    "docker": {
      "image": "nginx:1.7.7",
      "network": "BRIDGE",
      "portMappings": [
        { "hostPort": 0, "containerPort": 80, "servicePort": 10000 }
      ],
      "forcePullImage":true
    }
  },
  "instances": 1,
  "cpus": 0.1,
  "mem": 65,
  "healthChecks": [{
      "protocol": "HTTP",
      "path": "/",
      "portIndex": 0,
      "timeoutSeconds": 10,
      "gracePeriodSeconds": 10,
      "intervalSeconds": 2,
      "maxConsecutiveFailures": 10
  }],
  "labels":{
    "HAPROXY_GROUP":"external",
    "HAPROXY_0_VHOST":"brenden-j-PublicSl-1LTLKZEH6B2G6-1145355943.us-west-2.elb.amazonaws.com"
  }
}

我們已經添加了標籤HAPROXY_0_VHOST,它告訴marathon-lb就用虛擬主機的外部負載均衡來暴露Nginx的訪問。在labels中,包含0的Key與servicePort定義對應 ,從0開始。如果你有多個servicePort定義,你會遍歷它們作爲0,1,2,依此類推。

現在,如果你瀏覽到在瀏覽器中ELB的公共DNS地址,您應該看到以下內容:

這裏寫圖片描述

噹噹!

注:原文是“Ta-da!”,語氣詞而已,不是噹噹網

在第二部分中,在這裏我們談論更多marathon-lb的高級功能,以及如何使用HAProxy的實現應用程序autoscaling。

總結

本文更多的是在講解如何來使用marathon-lb,以及在marathon-lb中,如何對HAProxy進行分組。講得還是比較淺,特別是沒有說明marathon-lb自動增加節點進行負載均衡沒有說明。我本人搭的環境中,marathon-lb是可以進行自動負載均衡的,例如:關閉一個Nginx容器,marathon-lb會根據scaling(就是下一部分要說的)的值,自動創建一個Nginx鏡像。但是,組合internal和external的情況,還沒有成功。等試驗成功,再補充進來。


參考資料:
[1]: https://mesosphere.com/blog/2015/12/04/dcos-marathon-lb/
[2]: http://blog.chinaunix.net/uid-23241716-id-134106.html
[3]: http://bbs.51cto.com/thread-909189-1.html

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