之前介紹了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的時候加上認證。