天天看點

Consul實踐之Consul結合nginx建構高可用可擴充的Web服務方案概述配置概述操作步驟

nginx提供的負載均衡服務同樣支援高可用、可擴充的web服務,但缺點是較依賴于人工。例如傳統的nginx負載均衡的配置方式是,在nginx某個include的某個配置檔案中配置一個upstream,upstream中配置多個服務節點,每一個服務節點就是一個web應用服務。nginx雖然可以做到對服務節點的健康檢查,但是當服務節點增加、減少或者發生狀态改變(如負載較大、網絡故障、其他故障)時,nginx配置檔案是固定寫死的,不能動态的感覺後端服務節點的服務狀态資訊,是以需要有一種解決方案能夠幫助ngnix動态的感覺後端服務節點的服務資訊。要想實作這種需求,絕不僅consul一家,但此例中使用consul來實作,關于consul其他的使用案例可以繼續學習和研究。

部署環境:本例子用阿裡雲的虛拟主機作為測試主機,該測試主機内建有docker環境,consul cluster用docker搭建而成,nginx搭建在測試主機上,consul-template安裝在測試主機上,服務應用以容器的形式運作在docker中。注釋:consul支援多種部署環境,具體的如何部署可以參考已有的知識庫、經驗,也可以參考文本自己構思。

下圖是整理過的consul應用場景模拟圖。使用者通路前端的application也就是ui,前端application通過app configuration file從後端application上擷取提供的服務,再傳回給使用者。後端application上均安裝consul,并以agent的形式運作在伺服器上,并将consul agent加入到consul cluster中。consul-template與consul cluster的server連接配接,動态的從consul的服務資訊庫彙中拉取後端application的服務資訊,這些服務資訊寫入到前端application的配置檔案中,在完成一次寫入後(即背景服務發生變更時),consul-template将自動通過指令告知前端應用重新加載,實作前端application動态發現後端服務以及應用新配置檔案的目的。

Consul實踐之Consul結合nginx建構高可用可擴充的Web服務方案概述配置概述操作步驟

下圖是根據上圖延伸來的一個實際的方案,利用consul結合nginx建構高可用可擴充的web服務。nginx前端作為負載均衡器使用,它代理了三台能提供web服務的伺服器,每一台伺服器上均安裝consul,并以agent的形式運作在伺服器上,并将consul agent加入到consul cluster中。consul-template與consul cluster的server連接配接,動态的從consul的服務資訊庫彙中拉取nginx代理的三台伺服器的ip、端口号等資訊,并将ip位址以及端口号寫入到nginx的配置檔案中,在完成一次寫入後(即背景服務發生變更時),consul-template将自動将nginx重新開機加載,實作nginx應用新配置檔案的目的。

Consul實踐之Consul結合nginx建構高可用可擴充的Web服務方案概述配置概述操作步驟

本文假設系統中已經安裝好nginx和docker engine以及docker-enter以及git等工具。其操作步驟概括如下:

建構consul cluster(consul 叢集)

建構web應用服務

每一個服務應用安裝和配置consul agent

安裝并配置consul-template使consul-template與nginx關聯

驗證與測試

具體地操作步驟如下文所示。

建構consul cluster(consul 叢集)可以部署在docker中,也可以部署在多個實體機中,也可以部署在多個虛拟機中,也可以部署在這些混合環境中。此例最初是為了快速學習consul而用docker搭建的consul叢集,用其他方式部署也大同小異,可以根據docker的部署步驟反推,具體的可以參考下文分割線中間的部分。

關于docker images的選用。可以通過搜尋docker hub,輸入consul關鍵詞,搜尋所有與consul有關的關鍵詞,根據使用人數(pull次數)或星數(stars)以及點開details(細節)按鈕檢視repo info頁籤中關于該image的較長的描述以及使用方法,再根據已有的知識庫、經驗判斷使用哪一個image。此方案中使用progrium/consul作為docker images。

選用理由如下:

已有方案中有使用progrium/consul的案例,可以供參考;

此鏡像的星數和pull次數是最多的,pull次數高達9百萬次;

在它的repo info中詳細的介紹了該鏡像如何使用以及如何部署consul叢集;

此外,該image大小合适,僅有五六十mb,雖然基于busybox,但同樣适用于有linux經驗的技術人員。

在progrium提供的方案中提供了三種部署方式:1,試用consul;2.單機環境部署;3.生産環境部署。

下表中列出了不同叢集規模下的群體大小以及容錯率,推薦使用3-5台伺服器用于部署consul。為防止在故障發生時造成必不可免的資料損失,單個伺服器的部署方案是極不推薦的。

servers

quorum size

failure tolerance

1

2

3

4

5

6

7

由于環境有限,可用測試的主機的數量低于3,是以隻能解決單機環境用docker滿足consul的配置要求(盡管此要求并不是強制的,也就是說可以使用一個伺服器、兩個伺服器)。

8

9

<code># refer: </code>

<code>https:</code><code>//hub</code><code>.docker.com</code><code>/r/progrium/consul/</code>

<code>    </code> 

<code>docker pull progrium</code><code>/consul</code>    

<code>docker run -d --name node1 -h node1 progrium</code><code>/consul</code> <code>-server -bootstrap-expect 3    </code>

<code>join_ip=</code><code>"$(docker inspect -f '{{.networksettings.ipaddress}}' node1)"</code>    

<code>docker run -d --name node2 -h node2 progrium</code><code>/consul</code> <code>-server -</code><code>join</code> <code>$join_ip    </code>

<code>docker run -d --name node3 -h node3 progrium</code><code>/consul</code> <code>-server -</code><code>join</code> <code>$join_ip    </code>

<code>docker run -d -p 8400:8400 -p 8500:8500 -p 8600:53</code><code>/udp</code> <code>--name node4 -h node4 progrium</code><code>/consul</code> <code>-</code><code>join</code> <code>$join_ip</code>

經過上述指令,測試主機上的8400、8500以及8600端口就可以使用了,端口作用分别是8400 (rpc), 8500 (http), and 8600 (dns) ,後面會用到8500。注意,此處的rpc與dubbo定義的rpc有所不同,在dubbo中rpc用于“遠端通訊: 提供對多種基于長連接配接的nio架構抽象封裝,包括多種線程模型,序列化,以及“請求-響應”模式的資訊交換方式。”,而在這裡的rpc是是consul agent與consul server通信用的端口。除了以上端口還有其他一些端口,比如8300、8301、8302,這三個是用于consul内部通信使用的,單個主機環境中這三個端口用不到,是以不需要将這幾個端口暴露給測試主機。

以上指令會在docker環境中建立4個容器(node1、node2、node3和node4),其中node1因為-server參數被顯式的設定為server,其他的容器被設定成client,并加入到以node1為server的叢集中,他們每個節點都回監聽接口,但隻有node4将其端口與測試主機連接配接到了一起,這樣可以通過通路測試主機上的端口就能擷取到consul中存儲的已注冊服務的服務資訊。

=========================分割線======================================

非docker環境如何搭建consul?

根據docker容器中運作的指令以及配置檔案能夠輕松的發現在非docker環境中運作consul的方法,摘錄如下:

# node1   

<code>/bin/consul</code> <code>agent -config-</code><code>dir</code><code>=</code><code>/config</code> <code>-server -bootstrap-expect 3</code>

#192.168.0.7是node1的内網ip   

# node2    

<code>/bin/consul</code> <code>agent -config-</code><code>dir</code><code>=</code><code>/config</code> <code>-server -</code><code>join</code> <code>192.168.0.7</code>

# node3    

# node4    

<code>/bin/consul</code> <code>agent -config-</code><code>dir</code><code>=</code><code>/config</code> <code>-</code><code>join</code> <code>192.168.0.7</code>

# cat /config/consul.json     

{    

"data_dir": "/data",    

"ui_dir": "/ui",    

"client_addr": "0.0.0.0",    

"ports": {    

  "dns": 53    

},    

"recursor": "8.8.8.8",    

"disable_update_check": true    

}

根據上面的consul的json資料,根目錄下還有個ui目錄,其内容可以通過如下獲得:

<code># for consul web ui   </code>

<code>wget -c </code>

<code>https:</code><code>//releases</code><code>.hashicorp.com</code><code>/consul/0</code><code>.6.0</code><code>/consul_0</code><code>.6.0_web_ui.zip</code>

<code>mkdir</code> <code>consul_web_ui    </code>

<code>unzip -d consul_web_ui consul_0.6.0_web_ui.zip</code>

除了ui以外還有一個/data目錄,此目錄可以自己建,根據consul指令的提示自己建立。

建構web應用服務可以通過多種方式,根據自己的實際情況搭建。比如可以用java語言寫一個簡單的serverlet也可以nginx做一個web測試頁出來,還可以直接用docker hub上現有的web程式做測試。

此處可以使用如下的方法快速建構一個web應用。

<code>#docker commit jdk8-firstvert jdk8-firstvert_with_consul   </code>

<code>#docker images    </code>

<code>docker run -idt --name firstvertnode1 -h firstvertnode1 jdk8-firstvert_with_consul </code><code>/bin/bash</code>     

<code>docker run -idt --name firstvertnode2 -h firstvertnode2 jdk8-firstvert_with_consul </code><code>/bin/bash</code>

<code>docker run -idt --name firstvertnode3 -h firstvertnode2 jdk8-firstvert_with_consul </code><code>/bin/bash</code>

經過上述指令後,就會生成3個新的容器,每個容器運作着一個java serverlet,可以監聽某個端口來提供web服務。   

通過docker-enter指令進入每一個容器下載下傳并配置consul

10

<code># for test    </code>

<code>[ -x </code><code>/bin/consul</code> <code>] || ( wget -c </code>

<code>https:</code><code>//releases</code><code>.hashicorp.com</code><code>/consul/0</code><code>.6.0</code><code>/consul_0</code><code>.6.0_linux_amd64.zip</code>

<code> </code><code>&amp;&amp; unzip -d </code><code>/bin</code> <code>consul_0.6.0_linux_amd64.zip )    </code>

<code>[ -d </code><code>/config</code> <code>] || </code><code>mkdir</code> <code>/config</code>    

<code>[ -d </code><code>/data</code> <code>] || </code><code>mkdir</code> <code>/data</code>    

<code># join_ip is 192.168.0.7    </code>

<code>nohup</code> <code>/bin/consul</code> <code>agent -config-</code><code>dir</code><code>=</code><code>/config</code> <code>-</code><code>join</code> <code>192.168.0.7 -data-</code><code>dir</code> <code>/data</code> <code>2&gt;&amp;1 &gt;</code><code>/tmp/consul</code><code>.log &amp;    </code>

<code>nohup</code> <code>java -dfile.encoding=utf-8 -jar firstvert.x3-1.0-snapshot-fat.jar 2&gt;&amp;1 &gt;</code><code>/dev/null</code> <code>&amp;    </code>

<code># echo '{"service": {"name": "web", "tags": ["firstvert"], "port": 8081}}' &gt; /config/firstvert.json</code>

#下面這個指令是可以通過ping檢查與百度網站連接配接的網絡狀态,可以加也可以不加   

<code>echo</code> <code>'{</code><code>"check"</code><code>: {</code><code>"name"</code><code>: </code><code>"ping"</code><code>, </code><code>"script"</code><code>: "</code><code>ping</code> <code>-c1 </code>

<code>www.baidu.com</code>

<code> </code><code>2&gt;&amp;1 &gt;</code><code>/dev/null</code><code>", "</code><code>interval</code><code>": "</code><code>30s"}}' &gt;</code><code>/config/ping</code><code>.json</code>

# 下面的service中name為web是自定義的,可以自己取名字,tags後的firstvert也是自己取的,腳本是用來檢測此服務是否正常的,根據語義應該是根據函數傳回值判斷的   

<code>echo</code> <code>'{"service": {"name": "web", "tags": ["firstvert"], "port": 8081, "check": {"script": "curl localhost:8081 &gt;/dev/null 2&gt;&amp;1", "interval": "10s"}}}'</code> <code>&gt;</code><code>/config/firstvert</code><code>.json</code>

#更新consul資料檔案(相當于向consul注冊服務)後,需要重新運作consul agent

<code>killall consul   </code>

<code>nohup</code> <code>/bin/consul</code> <code>agent -config-</code><code>dir</code><code>=</code><code>/config</code> <code>-</code><code>join</code> <code>192.168.0.7 -data-</code><code>dir</code> <code>/data</code> <code>2&gt;&amp;1 &gt;</code><code>/tmp/consul</code><code>.log &amp;</code>

如果想簡單的測試一下是否好用,可以用以下指令進行測試,

<code>while</code> <code>: ; </code><code>do</code> <code>curl http:</code><code>//ipaddress</code><code>:port -w %{http_code} -s -o </code><code>/dev/null</code><code>; </code><code>sleep</code> <code>1; </code><code>done</code>

<code>https:</code><code>//releases</code><code>.hashicorp.com</code><code>/consul-template/0</code><code>.12.0</code><code>/consul-template_0</code><code>.12.0_linux_amd64.zip</code>

<code>unzip -d . consul-template_0.12.0_linux_amd64.zip    </code>

<code>cp</code> <code>consul-template </code><code>'/bin'</code>    

<code>rm</code> <code>-rf consul*</code>

# ready for test

# 把下面的{{range service "web"}}改成上面修改的service的名稱,把server_name改成要監聽的主機名或ip位址

# 負載均衡算法由nginx控制,具體的可以查閱nginx相關手冊和網上的其他資料   

# refer: nohup /bin/consul agent -config-dir=/config -join 192.168.0.7 -data-dir /data 2&gt;&amp;1 &gt;/tmp/consul.log &amp;    

<code>vim </code><code>/root/nginx_web</code><code>.ctmpl</code>

編輯内容如下

upstream web {    

    ip_hash;    

    # least_conn;    

    # least_time;    

{{range service "web"}}    

    server {{.address}}:{{.port}} fail_timeout=0;    

{{end}}    

    keepalive 64;    

server {   

    listen 80;    

    server_name ipaddress;

    location / {   

        client_max_body_size    0;    

        proxy_connect_timeout 300s;    

        proxy_send_timeout   900;    

        proxy_read_timeout   900;    

        proxy_buffer_size    32k;    

        proxy_buffers      4 32k;    

        proxy_busy_buffers_size 64k;    

        proxy_redirect     off;    

        proxy_hide_header  vary;    

        proxy_set_header   accept-encoding '';    

        proxy_set_header   host   $host;    

        proxy_set_header   referer $http_referer;    

        proxy_set_header   cookie $http_cookie;    

        proxy_set_header   x-real-ip  $remote_addr;    

        proxy_set_header   x-forwarded-for $proxy_add_x_forwarded_for;    

        proxy_set_header   host $host;    

        proxy_set_header   x-forwarded-for $proxy_add_x_forwarded_for;           

        proxy_headers_hash_max_size 51200;    

        proxy_headers_hash_bucket_size 6400;    

    }    

# -dry表示僅運作此指令,但不實際執行寫入檔案的指令,此處是指不根據模版修改檔案,不執行nginx -s reload指令

<code>consul-template -consul 127.0.0.1:8500 -template </code><code>/root/nginx_web</code><code>.ctmpl:</code><code>/usr/local/nginx/conf/vhost/http_temp_port_80</code><code>.conf:</code><code>"/usr/local/nginx/sbin/nginx -s reload"</code> <code>-dry</code>

#通過此指令可以将consul-template 放到背景執行

<code>nohup</code> <code>consul-template -consul 127.0.0.1:8500 -template nginx_web.ctmpl:</code><code>/usr/local/nginx/conf/vhost/http_temp_port_80</code><code>.conf:</code><code>"/usr/local/nginx/sbin/nginx -s reload"</code> <code>2&gt;&amp;1 &gt;</code><code>/tmp/consul-template</code><code>.log &amp;</code>

上述指令執行後可以通過ps -ef | grep consul和檢視/tmp/consul-template.log日志檔案,檢視consul-template的運作情況,也可以直接通過測試的手段來檢測consul-template的運作情況。    

可以嘗試分别測試如下内容:

容器停止後,nginx的配置檔案的内容,nginx的通路情況;

容器建立并啟動consul agent後,nginx的配置檔案的内容,nginx的通路情況;

發現容器出現任何非passing的情況,都會導緻從nginx配置檔案中移除;容器啟動并配置正常後,nginx配置檔案更新,容器可以被通路。這說明是非常符合預期需求的。

在初讀consul的文檔和查閱相關資料後,還尚未發現依賴于consul自身就能實作,提供根據服務節點的負載或健康狀況而增加、移除服務節點的功能。這個有待于進一步檢視和研究。

tag:consul測試方案,consul配置,consul rpc,consul搭建,consul執行個體

--end--

繼續閱讀