1. 程式人生 > >用DCOS和marathon-lb實現服務發現和負載均衡:第一部分

用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的情況,還沒有成功。等試驗成功,再補充進來。