使用Docker、Registrator、Consul、Consul Template和Nginx實現高可擴展的Web框架

yne7 9年前發布 | 210K 次閱讀 Docker

Consul是一個支持多數據中心分布式高可用的服務發現和配置共享的服務軟件,由 HashiCorp 公司用Go語言開發,基于 Mozilla Public License 2.0 的協議開源。本文介紹了如何使用Consul將多個Docker容器組合起來,以提供一個高可擴展的Web服務。

使用Docker、Registrator、Consul、Consul Template和Nginx實現高可擴展的Web框架

當你開始將容器拼裝起來構建你的系統的時候,你會發現Docker非常有趣。最近,我在玩 Consul,并嘗試用它來構建一個高可擴展的Web應用框架。Consul是 HashiCorpVagrant的創建者)開發的一個 服務發現與配置項目。

我之前嘗試借助SRV的記錄使用Consul來創建一個可擴展的框架(詳情請見: here),但我發現這種方式有點復雜。而我追求簡單,所以我又發現了 Consul Template,當添加或者移除服務時,Consul Template可以通過連接Consul更新配置并重啟應用。

在這篇文章中,我將會講述如何使用Docker將Consul、Consul Template、Registrator和Nginx組裝成一個值得信任且可擴展的框架——DR CoN。一旦組裝完成,DR CoN就可以讓你在這個框架中添加和移除服務,關鍵是你不需要重寫任何配置,也不需要重啟任何服務,一切都能正常運行!

Docker

Docker在LXC的基礎上(Linux Containers)上包裝了一些API,所以它只能運行在Linux上(注[1])。由于我使用的是OS X操作系統(讀者中可能大部分人都是),為此我寫了 “ 通過Boot2Docker在OSX上運行Docker”這篇文章,以下是簡要介紹:

brew install boot2docker
boot2docker init  
boot2docker up

執行之后,將在Ubuntu上啟一個虛擬機來運行Docker daemon。為了連上daemon,執行以下命令:

export DOCKER_IP=`boot2docker ip`  
export DOCKER_HOST=`boot2docker socket`

你可以通過執行下述命令來驗證Docker是否成功安裝:

docker ps

通過Docker構建一個簡單的Web服務

我們需要一個服務來測試Dr Con這個框架。為此,讓我們開始構建一個我了解的簡單服務(詳情請見 此文)。創建一個Dockerfile文件,將以下內容寫入其中:

FROM  python:3  
EXPOSE  80  
CMD ["python", "-m", "http.server"]

在Dockerfile文件所在目錄下執行以下命令:

docker build -t python/server .

執行后,將創建一個名為python/server的鏡像,通過執行以下命令運行一個容器:

docker run -it \
-p 8000:80 python/server

我們可以通過curl命令調用這個簡單服務來測試它是否能夠正常運行:

curl $DOCKER_IP:8000

Consul

Consul是一個擁有DNS和HTTP API的服務。它還有很多其它功能,例如服務健康檢測、跨主機集群構建和“鍵-值”對存儲庫。執行以下命令在Docker container中運行Consul:

docker run -it -h node \
 -p 8500:8500 \
 -p 8600:53/udp \
 progrium/consul \
 -server \
 -bootstrap \
 -advertise $DOCKER_IP \
 -log-level debug

如果你通過瀏覽器能夠訪問$DOCKER_IP:8500,你將在控制面板上看到Consul中已經注冊的所有服務。

我們能夠通過curl向Consul的Web API注冊一個服務:

curl -XPUT \
$DOCKER_IP:8500/v1/agent/service/register \
-d '{
 "ID": "simple_instance_1",
 "Name":"simple",
 "Port": 8000, 
 "tags": ["tag"]
}'

然后,我們可以通過dig命令查詢Consul為這個提供的DNS API:

dig @$DOCKER_IP -p 8600 simple.service.consul

執行后,結果如下:

; <<>> DiG 9.8.3-P1 <<>> simple.service.consul
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 39614
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION: ;simple.service.consul.        IN    A

;; ANSWER SECTION: simple.service.consul.    0    IN    A    192.168.59.103

;; Query time: 1 msec ;; SERVER: 192.168.59.103#53(192.168.59.103) ;; WHEN: Mon Jan 12 15:35:01 2015 ;; MSG SIZE  rcvd: 76</pre>
等等,這有個問題,服務的端口號在哪?很遺憾,DNS的記錄中并沒有返回服務的端口號。為了獲取端口號,我們必須檢查SRV記錄:

dig @$DOCKER_IP -p 8600 SRV simple.service.consul

執行后,結果如下:

; <<>> DiG 9.8.3-P1 <<>> SRV simple.service.consul
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 3613
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; QUESTION SECTION: ;simple.service.consul.        IN    SRV

;; ANSWER SECTION: simple.service.consul.    0    IN    SRV    1 1 8000 node.node.dc1.consul.

;; ADDITIONAL SECTION: node.node.dc1.consul.    0    IN    A    192.168.59.103

;; Query time: 1 msec ;; SERVER: 192.168.59.103#53(192.168.59.103) ;; WHEN: Mon Jan 12 15:36:54 2015 ;; MSG SIZE  rcvd: 136</pre>
SRV記錄很難用,因為很多技術不支持它們。

srv-router這個容器被Consul和Nginx用來路由訪問請求到相應服務(詳情請見: here)。但是,下面我們將介紹一種更簡單的方式讓Nginx路由這些請求到相應服務。

Registrator

在Docker容器啟動后,Registrator配置好相應的環境變量并將這個容器注冊到Consul上,示例如下:

docker run -it \
-v /var/run/docker.sock:/tmp/docker.sock \
-h $DOCKER_IP progrium/registrator \
consul://$DOCKER_IP:8500

Registrator啟動后,我們運行一個服務:

docker run -it \
-e "SERVICE_NAME=simple" \
-p 8000:80 python/server

命令執行后,這個服務被自動添加到Consul,同理,如果我們關閉這個服務,它在Consul上會被自動移除。由于Registrator不需要我們手動將服務注冊到Consul,因此它是DR CoN需要組裝的第一部分。

Consul Template

Consul Template的作用是,當它發現Consul上的服務有變化時,它會利用Consul更新文件并執行相應的命令。

比如說,它能夠重寫nginx.conf這個文件,將所有服務的路由信息列入其中,然后重新加載Nginx的配置,使得多個相似服務達到負載均衡,或者給多種服務提供一個單一的終端。

我對這個Docker容器做了如下修改(詳情請見這里):

FROM nginx:1.7

Install Curl

RUN apt-get update -qq && apt-get -y install curl

Download and Install Consul Template

ENV CT_URL http://bit.ly/15uhv24 RUN curl -L $CT_URL | \ tar -C /usr/local/bin --strip-components 1 -zxf -

Setup Consul Template Files

RUN mkdir /etc/consul-templates ENV CT_FILE /etc/consul-templates/nginx.conf

Setup Nginx File

ENV NX_FILE /etc/nginx/conf.d/app.conf

Default Variables

ENV CONSUL consul:8500 ENV SERVICE consul-8500

 Command will

 1. Write Consul Template File

 2. Start Nginx

 3. Start Consul Template

CMD echo "upstream app {                 \n\   least_conn;                            \n\   {{range service \"$SERVICE\"}}         \n\   server  {{.Address}}:{{.Port}};        \n\   {{else}}server 127.0.0.1:65535;{{end}} \n\ }                                        \n\ server {                                 \n\   listen 80 default_server;              \n\   location / {                           \n\     proxy_pass http://app;               \n\   }                                      \n\ }" > $CT_FILE; \ /usr/sbin/nginx -c /etc/nginx/nginx.conf \ & CONSUL_TEMPLATE_LOG=debug consul-template \   -consul=$CONSUL \   -template "$CT_FILE:$NX_FILE:/usr/sbin/nginx -s reload";</pre>
下載這個Dockerfile,請點擊這里

注意: 上面的\n\表示另起一行,并且為Docker的多行命令去除換行。

這個Docker容器將會運行Consul Template和Nginx,當服務有變化時,它將重寫Nginx的app.conf文件并且重新加載Nginx。

通過以下命令構建這個容器:

docker build -t drcon .

然后,啟動容器:

docker run -it \
-e "CONSUL=$DOCKER_IP:8500" \
-e "SERVICE=simple" \
-p 80:80 drcon

SERVICE選項用來指定Consul上的服務。因此,上面這個DR CoN 容器將會通過所有命名為simple的服務來達到負載均衡。

組裝到一起

現在讓我們把一切都組裝起來。

運行Consul:

docker run -it -h node \
 -p 8500:8500 \
 -p 53:53/udp \
 progrium/consul \
 -server \
 -bootstrap \
 -advertise $DOCKER_IP

運行Registrator:

docker run -it \
-v /var/run/docker.sock:/tmp/docker.sock \
-h $DOCKER_IP progrium/registrator \
consul://$DOCKER_IP:8500

運行DR CoN:

docker run -it \
-e "CONSUL=$DOCKER_IP:8500" \
-e "SERVICE=simple" \
-p 80:80 drcon

執行curl $DOCKER_IP:80命令,結果如下:

curl: (52) Empty reply from server

現在開啟simple的服務:

docker run -it \
-e "SERVICE_NAME=simple" \
-p 8000:80 python/server

執行后,將發生:

  1. Registrator將這個服務注冊到Consul;
  2. Consul Template重寫nginx.conf,然后重新加載配置。

現在執行curl $DOCKER_IP:80將成功路由到這個服務。

如果我們在其他端口上啟動另一個simple服務:

docker run -it \
-e "SERVICE_NAME=simple" \
-p 8001:80 python/server

請求將通過這兩個simple服務進行負載均衡。

有趣的是,我們可以執行while true; do curl $DOCKER_IP:80; sleep 1; done這個腳本,當關閉或者啟動simple服務時,腳本仍在快速運行且所有請求都能正常進行。

總結

借助Docker,描述、分布和實現DR CoN這類框架變得更加容易,當然也少不了Consul這么好用的工具。使用Docker更加強大的工具來組裝服務是非常有趣和有用的,現在我就能創建一種橫向可擴展的框架,并且一切都能正常運行。

注[1]: Docker在1.2版本之后就默認使用libcontainer,而不是LXC,雖然Docker支持LXC。由于不論libcontainer和LXC都是基于Linux Kernel中的namespace和Cgroup,所以現在只能運行在Linux上。

原文鏈接:Scalable Architecture DR CoN: Docker, Registrator, Consul, Consul Template and Nginx (翻譯: 肖遠昊 校對:李穎杰)

來自:http://dockerone.com/article/272

 本文由用戶 yne7 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!