Mesos+Zookeeper+Marathon的Docker管理平臺部署記錄(2)- 負載均衡marathon-lb

散盡浮華發表於2017-05-12

 

之前介紹了Mesos+Zookeeper+Marathon的Docker管理平臺部署記錄(1)的操作,多餘的廢話不說了,下面接著說下在該叢集環境下的負載均衡marathon-lb的部署過程:

預設情況下,mesos marathon會把app釋出到隨機節點的隨機埠上,當mesos slaves和app越來越多的時候,想查詢某組app就變得困難。
mesos提供了兩個工具:mesos-dns和marathon-lb,他們倆是mesosphere 官網提供的兩種服務發現和負載均衡工具,其中:
mesos-dns是一個服務發現工具,marathon-lb不僅是服務發現工具,還是負載均衡工具。

鑑於Mesos-DNS有如下諸多缺陷:
1)DNS無法識別服務埠,除非使用SRV查詢(SRV記錄它是DNS伺服器的資料庫中支援的一種資源記錄的型別,它記錄了哪臺計算機提供了哪個服務這麼一個簡單的資訊);大多數應用程式都無法使用SRV記錄“開箱即用”。
2)DNS不具有快速故障轉移能力,沒有快速容錯功能。
3) DNS記錄有一個TTL(生存時間:time to live),同時Mesos-DNS使用輪詢來建立DNS記錄; 這可能會導致過時的記錄。
4)DNS記錄不提供任何服務的健康資料。
5)一些應用程式和庫不正確地處理多個A記錄(handle multiple A records);在某些情況下,查詢可能被快取,並根據需要不正確地重新載入。

所以現在一般不推薦使用Mesos-DNS作為服務發現工具,而是推薦使用marathon-lb,marathon-lb是可以起到與Mesos-DNS同樣作用。
Marathon-lb既是一個服務發現工具,也是負載均衡工具,它整合了haproxy,自動獲取各個app的資訊,為每一組app生成haproxy配置,通過servicePort或者web虛擬主機提供服務。
1)要使用marathonn-lb,每組app必須設定HAPROXY_GROUP標籤。
2)Marathon-lb執行時繫結在各組app定義的服務埠(servicePort,如果app不定義servicePort,marathon會隨機分配埠號)上,可以通過marathon-lb所在節點的相關服務埠訪問各組app。
比如說:marathon-lb部署在slave2,test-app 部署在slave1,test-app 的servicePort是10004,那麼可以在slave2的10004埠訪問到test-app提供的服務。
 
3)由於servicePort非80、443埠(80、443埠已被marathon-lb中的 haproxy獨佔),對於web服務來說不太方便,可以使用 haproxy虛擬主機解決這個問題:
在提供web服務的app配置裡增加HAPROXY_{n}_VHOST(WEB虛擬主機)標籤,marathon-lb會自動把這組app的WEB叢集服務釋出在marathon-lb所在節點的80和443埠上,使用者設定DNS後通過虛擬主機名來訪問。

Marathon-lb基於HAProxy,給基於TCP和HTTP協議的應用提供代理和負載均衡功能,此外還提供諸如SSL支援,HTTP壓縮,健康檢查,Lua指令碼等。Marathon-lb訂閱Marathon的事件匯流排,實時更新HAProxy的配置,並過載應用。

配置過程如下:
1)首先分別在slave-1、slave-2、slave-3節點機器上拉取marathon-lb映象

[root@slave-1 ~]# docker pull mesosphere/marathon-lb
[root@slave-1 ~]# docker images
REPOSITORY                         TAG                 IMAGE ID            CREATED             SIZE
docker.io/tomcat                   latest              08f8166740f8        6 days ago          366.7 MB
docker.io/nginx                    latest              46102226f2fd        2 weeks ago         109.4 MB
docker.io/mesosphere/marathon-lb   latest              08e0c402b5c2        3 weeks ago         229.3 MB

2)編寫marathon-lb的json檔案

[root@master-1 ~]# vim marathon-lb.json
{
"id": "marathon-lb",
"instances": 1,
"constraints": [["hostname", "UNIQUE"]],
"container": {
"type": "DOCKER",
"docker": {
"image": "docker.io/mesosphere/marathon-lb",
"privileged": true,
"network": "HOST"
}
},
"args": ["sse", "-m","http://182.48.115.233:8080","--group", "external"]
}

特別注意下:

1)network採用的是"HOST"
2)args後面http配置的ip是marathon的ip;也可以將多個master的ip都配置上
   "args": ["sse", "-m","http://master1_ip:8080", "-m","http://master2_ip:8080", "-m","http://master3_ip:8080","--group", "external"]
3)注意group後面的external引數

3)部署marathon-lb應用
第一種方法:在marathon機器上通過curl的方式呼叫

[root@master-1 ~]# curl -i -H 'Content-Type: application/json' 182.48.115.233:8080/v2/apps -d@marathon-lb.json

第二種方式:在marathon訪問介面裡點選"Create Application",在"JSON Mode"模式下,將上面marathon-lb.json檔案內容貼上進去

4)接著編寫應用的json,然後構建應用。這裡以建立docker的nginx容器應用為例

[root@master-1 ~]# vim docker_nginx.json
{
  "id":"nginx",
  "labels": {
     "HAPROXY_GROUP":"external",
     "HAPROXY_0_VHOST":"nginx.marathon.mesos"
  },
  "cpus":0.2,
  "mem":20.0,
  "instances": 2,
  "healthChecks": [{ "path": "/" }],
  "container": {
    "type":"DOCKER",
    "docker": {
     "image": "docker.io/nginx",
     "network": "BRIDGE",
     "portMappings":[{"containerPort":80,"hostPort":0,"servicePort":80,"protocol":"tcp"}]
    }
  }
}

注意幾點:

1)一定要加上HAPROXY_GROUP標籤,它填寫的是marathon-lb建立時定義的組名(如上) 
2)HAPROXY_0_VHOST是標籤名,對於web服務可以加上VHOST標籤,讓marathon-lb設定WEB虛擬主機;
   這個標籤名字可以隨便定義,目的是為了便於區別應用容器。一般可以用業務域名來描述標籤。
3)"instances"表示應用的例項數,一般預設是1,如果寫成n,說明建立n個應用。
4)containerPort為80,是指容器內的埠。
5)hostPort是當前主機對映到contenterPort的埠,如果hostPort為0的話,則說明是隨機的。
6)serverPort是marathon-lb需要配置的haproxy代理暴露的埠,這裡設定為80,說明訪問marathon-lb機器的80埠就可為訪問這個應用容器的80埠。

需要記住:
對於web服務,servicePort設定為0即可,marathon-lb會自動把web服務叢集釋出到80、443上;
所以上面docker_nginx_json檔案裡的"servicePort"後面的埠可以寫成0,這樣後端若是有443埠開啟,marathon-lb會自動分發到上面。
最後把域名解析到marathon-lb所在的機器ip上,訪問域名時就會自動釋出到後端的容器應用上。

部署docker的nginx容器應用,方式也有兩種:
第一種方法:在marathon機器上通過curl的方式呼叫

[root@master-1 ~]# curl -i -H 'Content-Type: application/json' 182.48.115.233:8080/v2/apps -d@docker_nginx.json

第二種方式:在marathon訪問介面裡點選"Create Application",在"JSON Mode"模式下,將上面marathon-lb.json檔案內容貼上進去

應用容器建立好之後,如下,可以看到應用容器建立後的"Labels"標籤資訊,這個在應用容器繁多的情況下很有用,便於識別。

還可以再建立一組繫結marathon-lb的nginx應用容器(只需將docker_nginx.json檔案裡的id改變一下,比如改成"nginx2",然後建立這個應用)

為了試驗效果,分別將下面繫結了marathon-lb的四個ngixn容器的訪問內容修改下,簡單做法是:

在182.48.115.237本機編寫index.html檔案,使用"docker cp"將檔案覆蓋到對映埠分別為31277、31022、31667的nginx容器的80埠預設站點目錄/usr/share/nginx/html下的index.html。
同理,在182.48.115.239本機也編寫index.html檔案,然後將其覆蓋到對映埠為31380的nginx容器的80埠預設站點目錄/usr/share/nginx/html下的index.html。

四個nginx容器訪問頁面為:

5)登陸marathon-lb的容器裡面,檢視生成的haproxy.cfg檔案

如上可知,marathon-lb容器建立在slave3節點機器上(182.48.115.239),登陸該容器,檢視haproxy.cfg檔案,可以發現已經生成了負載配置:

[root@slave-3 ~]# docker ps
CONTAINER ID        IMAGE                              COMMAND                  CREATED             STATUS              PORTS                   NAMES
5acf0e5390dc        docker.io/nginx                    "nginx -g 'daemon off"   About an hour ago   Up About an hour    0.0.0.0:31380->80/tcp   mesos-92c601e1-3522-49f3-b030-9e0456aa19b9-S2.4ffe15aa-d840-443b-af6d-963a1680b792
39a89fe14869        docker.io/mesosphere/marathon-lb   "tini -g -- /marathon"   About an hour ago   Up About an hour                            mesos-92c601e1-3522-49f3-b030-9e0456aa19b9-S2.3bdc6abc-0eaa-47a6-b562-cfe436168b78

[root@slave-3 ~]# docker exec -ti 39a89fe14869 /bin/bash
root@slave-3:/marathon-lb# cat haproxy.cfg   
........
........
frontend nginx_80
  bind *:80
  mode http
  use_backend nginx_80

frontend nginx2_80
  bind *:80
  mode http
  use_backend nginx2_80

backend nginx_80
  balance roundrobin
  mode http
  option forwardfor
  http-request set-header X-Forwarded-Port %[dst_port]
  http-request add-header X-Forwarded-Proto https if { ssl_fc }
  option  httpchk GET /
  timeout check 20s
  server 182_48_115_237_31022 182.48.115.237:31022 check inter 60s fall 4
  server 182_48_115_237_31277 182.48.115.237:31277 check inter 60s fall 4

backend nginx2_80
  balance roundrobin
  mode http
  option forwardfor
  http-request set-header X-Forwarded-Port %[dst_port]
  http-request add-header X-Forwarded-Proto https if { ssl_fc }
  option  httpchk GET /
  timeout check 20s
  server 182_48_115_237_31667 182.48.115.237:31667 check inter 60s fall 4
  server 182_48_115_239_31380 182.48.115.239:31380 check inter 60s fall 4

 這時候訪問marathon-lb容器所在機的80埠(即訪問http://182.48.115.239),則請求就會負載到後端的nginx機器上(即上面那4個ngixn容器所在機器)。如下,不斷重新整理,就會負載到後端不同的頁面上。

 

可以在三個slave節點上做keepalived心跳測試,繫結一個VIP,三個節點做成一主兩從,keepalived.conf裡監控80埠的marathon-lb程式。當marathon-lb在哪個節點上,VIP就漂移到那個節點上,業務域名解析到VIP上,這樣也就完成了一個高可用方案。

6)檢視haproxy的監控頁面

即可以分別方面下面url以檢視健康狀態(182.48.115.239是marathon-lb所在機器的ip)

http://182.48.115.239:9090/haproxy?stats
http://182.48.115.239:9090/haproxy?stats;csv
http://182.48.115.239:9090/_haproxy_health_check
http://182.48.115.239:9090/_haproxy_getconfig
http://182.48.115.239:9090/_haproxy_getpids

總結幾點

1)docker應用容器建立時的servicePort埠設定,這個關係到使用haproxy負載後,最終的訪問埠。
2)可以建立不同的marathon-lb容器(可以定義不同的group),然後依據這些marathon-lb建立不同業務的應用容器,以實現負載均衡。
3)marathon-lb容器預設會在三個slave節點中的某一個節點上建立,當所在節點出現故障或重啟marathon-lb容器時,才會漂移到其他節點上
   這樣即實現了高可用(相當於"一主兩從"),將業務玉域名解析到marathon-lb所在的節點ip上。
4)如果之前建立的應用容器繫結了marathon-lb,後續這個應用容器刪除了,那麼要記得重啟marathon-lb,否則LB訪問會出現故障。
   因為haproxy.cfg檔案裡還保留這個已刪的應用容器的負載配置,重啟marathon-lb後,haproxy.cfg檔案才會更新。
5)為了安全考慮,最好不要將Marathon暴漏到公網上,要不定時監控Docker執行情況。
   此外,Mesos和Marathon啟動的時候最好加認證,具體操作是:
   Marathon啟動的時候加上--http_credentials即可,然後Mesos啟動時候加上--authenticate --credentials引數,讓Mesos slave 連線到Master的時候加上認證。

相關文章