基於consul的docker容器服務發現及自動更新(原理+部署)
前言
之前的文章大致上將docker入門級別的一些內容進行了講述。本文開始深入講解docker的其他內容,首先就來講一講docker容器服務發現和自動更新部分的原理和實際操作。
先嘮嘮嗑兒——講一講概念和優勢(瞅兩眼就行)
consul的介紹
由HashiCorp公司使用go語言開發的一個支持多數據中心分佈式高可用的服務發現和配置共享的服務軟件(開源)。
主要特點:
服務發現及配置;
支持健康檢查,並且運行HTTP、GTPC和DNS協議調用API存儲鍵值對;
採用Raft算法,保證服務的高可用
支持安全服務通信;
支持多數據中心;
consul agent
consul通過agent來運行的,agent分爲server 和client兩種類型,這兩種類型基本上沒有什麼區別,server agent是將服務的消息存儲,一般來說爲了防止單點故障推薦使用3到5個來構建集羣架構。
而client agent主要用於註銷服務、健康檢查及轉發server agent的查詢等,相當於一個代理,因此它必須要在集羣的每臺主機上運行。
一種服務或軟件工具的產生必然有其使用場景和其優勢,否則哪有其立足之地?
consul使用的場景
- Docker 容器的註冊與配置共享
- Coreos 實例的註冊與配置共享
- SaaS 應用的配置共享、服務發現和健康檢查。
- vitess 集羣
- 與 confd 服務集成,動態生成 nginx 和 haproxy 配置文件
consul優勢(與其他服務工具對比)
通過對比你就可以發現consul對比其他軟件工具有自己的優勢,而本文將使用其的場景是在docker中進行搭建。
再來看看consul發現和更新機制原理(可以結合實踐部署理解)
通過一幅圖就能夠了解consul的特點和內部角色的工作機制,包括支持多數據中心,端口號,服務發現、配置和更新功能等等
相關說明:
1. Consul Cluster由部署和運行了Consul Agent的節點組成。 在Cluster中有兩種角色:Server和 Client。
2. Server和Client的角色和Consul Cluster上運行的應用服務無關, 是基於Consul層面的一種角色劃分.
3. Consul Server: 用於維護Consul Cluster的狀態信息, 實現數據一致性, 響應RPC請求。官方建議是: 至少要運行3個或者3個以上的Consul Server。 多個server之中需要選舉一個leader, 這個選舉過程Consul基於Raft協議實現. 多個Server節點上的Consul數據信息保持強一致性。 在局域網內與本地客戶端通訊,通過廣域網與其他數據中心通訊。Consul Client: 只維護自身的狀態, 並將HTTP和DNS接口請求轉發給服務端。
4. Consul 支持多數據中心, 多個數據中心要求每個數據中心都要安裝一組Consul cluster,多個數據中心間基於gossip protocol協議來通訊, 使用Raft算法實現一致性
下面開始部署實踐過程演示了
實踐演示
兩臺服務器
ip | hostname | tools |
---|---|---|
192.168.10.128/24 | consul-server | docker-ce(安裝和啓動docker服務)、consul、consul-template、nginx軟件 |
192.168.10.129/24 | docker-service | docker-ce、registrator |
實現流程簡述
第一項:部署操作驗證consul的服務自動發現機制
第二項:部署操作驗證consul的服務配置更新機制
下面開始進行第一項的驗證部署流程
1、在consul-server節點上配置
#設置主機名、解壓相關工具、優化工具使用
[root@localhost ~]# hostnamectl set-hostname consul-server
[root@localhost ~]# su
[root@consul-server ~]# cd /opt/
[root@consul-server opt]# ls
consul_0.9.2_linux_amd64.zip consul-template_0.19.3_linux_amd64.zip containerd docker.sh rh
[root@consul-server opt]# unzip consul_0.9.2_linux_amd64.zip
Archive: consul_0.9.2_linux_amd64.zip
inflating: consul
[root@consul-server opt]# unzip consul-template_0.19.3_linux_amd64.zip
Archive: consul-template_0.19.3_linux_amd64.zip
inflating: consul-template
[root@consul-server opt]# ls
consul consul_0.9.2_linux_amd64.zip consul-template consul-template_0.19.3_linux_amd64.zip containerd docker.sh rh
[root@consul-server opt]# mv consul /usr/bin
[root@consul-server opt]# mv consul-template /usr/bin
#創建工作目錄
[root@consul-server opt]# mkdir /root/consul
[root@consul-server opt]# cd /root/consul/
[root@consul-server consul]# ls
2、在consul-server節點上部署consul
[root@consul-server consul]# consul agent \
> -server \
> -bootstrap \
> -ui \
> -data-dir=/var/lib/consul-data \
> -bind=192.168.10.128 \
> -client=0.0.0.0 \
> -node=consul-server01 &> /var/log/consul.log &
[1] 6489
[root@consul-server consul]# jobs
[1]+ 運行中 consul agent -server -bootstrap -ui -data-dir=/var/lib/consul-data -bind=192.168.10.128 -client=0.0.0.0 -node=consul-server01 &>/var/log/consul.log &
3、查看運行agent的日誌:
注意紅色部分,在日誌中體現了算法、代理功能開啓、相關的端口協議等特點和信息,其中有一個ERR,此處暫時忽略(其實之後的信息可以發現已經解決了,會自動成爲leader,因爲這裏是單節點,生產環境中推薦3或5個)
4、在docker-service節點上配置
[root@localhost ~]# hostnamectl set-hostname docker-service
[root@localhost ~]# su
#安裝配置 gliderlabs/registrator
[root@docker-service ~]# docker run -d \
> --name=registrator \
> --net=host \
> -v /var/run/docker.sock:/tmp/docker.sock \
> --restart=always \
> gliderlabs/registrator:latest \
> -ip=192.168.10.129 \
> consul://192.168.10.128:8500
Unable to find image 'gliderlabs/registrator:latest' locally
latest: Pulling from gliderlabs/registrator
Image docker.io/gliderlabs/registrator:latest uses outdated schema1 manifest format. Please upgrade to a schema2 image for better future compatibility. More information at https://docs.docker.com/registry/spec/deprecated-schema-v1/
c87f684ee1c2: Pull complete
a0559c0b3676: Pull complete
a28552c49839: Pull complete
Digest: sha256:6e708681dd52e28f4f39d048ac75376c9a762c44b3d75b2824173f8364e52c10
Status: Downloaded newer image for gliderlabs/registrator:latest
befb4e5e2b4239a48bb85cedbdd061ef27996b31e3f323a4ba35d66b68286691
5、查看當前服務器節點上下載的鏡像以及運行的容器
在當前服務器節點上運行兩個nginx容器服務來測試consul服務的發現機制
[root@docker-service ~]# docker run -itd -p 88:80 --name nginx01 -h nginx-01 nginx:latest
Unable to find image 'nginx:latest' locally
latest: Pulling from library/nginx
54fec2fa59d0: Pull complete
4ede6f09aefe: Pull complete
f9dc69acb465: Pull complete
Digest: sha256:86ae264c3f4acb99b2dee4d0098c40cb8c46dcf9e1148f05d3a51c4df6758c12
Status: Downloaded newer image for nginx:latest
441d11db3bcf4bb47d758967661e27df2e9d5855ab540e01766236e8587fd1ae2
[root@docker-service ~]# docker run -itd -p 89:80 --name nginx02 -h nginx-02 nginx:latest
18508414acc2327d0df9aa570575a2369a239dd408a075eaa23fdfccfd14660f
[root@docker-service ~]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
18508414acc2 nginx:latest "nginx -g 'daemon of…" 5 seconds ago Up 4 seconds 0.0.0.0:89->80/tcp nginx02
441d11db3bcf nginx:latest "nginx -g 'daemon of…" 41 seconds ago Up 40 seconds 0.0.0.0:88->80/tcp nginx01
befb4e5e2b42 gliderlabs/registrator:latest "/bin/registrator -i…" 4 minutes ago Up 4 minutes registrator
測試運行的容器是否可以在瀏覽器中打開
我們訪問consul服務器節點ip地址及8500端口來查看驗證consul的自動發現、註冊機制
第一項驗證完畢
當然,此時還不能通過直接訪問consul服務器來訪問後端的web服務頁面
所以,接下來我們就需要來驗證consul自動更新機制
第二項驗證配置流程
1、在consul-server節點上編寫模板文件
[root@consul-server consul]# vim nginx.ctmpl
[root@consul-server consul]# cat nginx.ctmpl
upstream backend-server {
{{range service "nginx"}}
server {{.Address}}:{{.Port}};
{{end}}
}
server {
listen 8023;
server_name localhost 192.168.10.128;
access_log /var/log/nginx/lokott-access.log;
location / {
proxy_set_header HOST $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Client-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarder_for;
#以上四行可以不設置,如果設置中出錯,之後執行consul-template啓動時會發生幾種情況下的error
#尤其是X-Forwarded-For配置項
proxy_pass http://backend-server;
}
}
圖解上述文件相關說明:
2、這裏我們需要手工編譯安裝nginx服務(這裏就省略了吧!)直接給出啓動的結果吧
[root@consul-server nginx-1.12.2]# ln -s /usr/local/nginx/sbin/nginx /usr/bin/
[root@consul-server nginx-1.12.2]# nginx -t
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
[root@consul-server nginx-1.12.2]# nginx
[root@consul-server nginx-1.12.2]# netstat -natp | grep 80
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 44370/nginx: master
3、此時consul節點服務器上的nginx服務正常啓動,我們此時需要配置nginx的配置文件
其實只要進入配置目錄中創建一個vhost目錄用來存放你的其他配置文件(解耦性高、容易維護更改擴展)以及創建日誌目錄(根據你的模板),隨後在執行consul-template命令後以及訪問web後會在對應的目錄下生成配置文件和日誌文件
對於主配置文件中只要添加一行代碼即可,就是包含後面vhost目錄下的所有配置文件
[root@consul-server nginx-1.12.2]# cd /usr/local/nginx/conf/
[root@consul-server conf]# mkdir /var/log/nginx
[root@consul-server conf]# mkdir vhost
[root@consul-server conf]# vim nginx.conf
#根據下圖進行配置即可
4、此時需要使用我們的consul-template工具來啓動服務了
[root@consul-server consul]# consul-template -consul-addr 192.168.10.128:8500 -template "/root/consul/nginx.ctmpl:/usr/local/nginx/conf/vhost/lokott.conf:/usr/local/nginx/sbin/nginx -s reload" --log-level=info
2020/04/24 02:15:57.369809 [INFO] consul-template v0.19.3 (ebf2d3d)
2020/04/24 02:15:57.369819 [INFO] (runner) creating new runner (dry: false, once: false)
2020/04/24 02:15:57.370054 [INFO] (runner) creating watcher
2020/04/24 02:15:57.370345 [INFO] (runner) starting
2020/04/24 02:15:57.370352 [INFO] (runner) initiating run
2020/04/24 02:15:57.371539 [INFO] (runner) initiating run
2020/04/24 02:15:57.372779 [INFO] (runner) rendered "/root/consul/nginx.ctmpl" => "/usr/local/nginx/conf/vhost/lokott.conf"
2020/04/24 02:15:57.372800 [INFO] (runner) executing command "/usr/local/nginx/sbin/nginx -s reload" from "/root/consul/nginx.ctmpl" => "/usr/local/nginx/conf/vhost/lokott.conf"
2020/04/24 02:15:57.372843 [INFO] (child) spawning: /usr/local/nginx/sbin/nginx -s reload
此時我們開啓另一個終端(terminal)來查看vhost中的文件
[root@consul-server ~]# cd /usr/local/nginx/conf/vhost/
[root@consul-server vhost]# cat lokott.conf
upstream backend-server {
server 192.168.10.129:88;
server 192.168.10.129:89;
}
server {
listen 8023;
server_name localhost 192.168.10.128;
access_log /var/log/nginx/lokott-access.log;
location / {
proxy_set_header HOST $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Client-IP $remote_addr;
proxy_pass http://backend-server;
}
}
此時會發現我們設置的docker容器服務(nginx應用服務)已經提供出來,並且是以輪循方式進行負載均衡,注意這裏使用的是容器所提供的服務是由宿主機的ip地址,因爲先前我們設置的網絡模式(docker的網絡模式可以參考我的另一篇博客:透過現象看本質——docker的網絡模式、一邊排障一邊配置docker自定義網絡(bridge模式))爲host,因此這裏容器是使用宿主機ip地址的。
此時我們可以通過瀏覽器直接訪問consul服務器地址和你配置的端口號,驗證是否可以訪問nginx服務提供的web頁面
可以通過日誌文件進行查看
然後我們在docker-service節點上再添加一個nginx服務,隨後進行自動添加和更新配置的驗證
[root@docker-service ~]# docker run -itd -p 90:80 --name nginx03 -h nginx-03 nginx:latest
144df900d69e682bf356c3b32d9aa043106327964c700cc99850ae2c1e7a5f3c
運行完該指令後,我們可以在consul-server的原始終端查看到信息,因爲此時該服務一直在監控着
會發現多了一下幾行
2020/04/24 02:27:46.318181 [INFO] (runner) initiating run
2020/04/24 02:27:46.319400 [INFO] (runner) rendered "/root/consul/nginx.ctmpl" => "/usr/local/nginx/conf/vhost/lokott.conf"
2020/04/24 02:27:46.319434 [INFO] (runner) executing command "/usr/local/nginx/sbin/nginx -s reload" from "/root/consul/nginx.ctmpl" => "/usr/local/nginx/conf/vhost/lokott.conf"
2020/04/24 02:27:46.319467 [INFO] (child) spawning: /usr/local/nginx/sbin/nginx -s reload
與此同時,lokott.conf文件也會隨之變化
[root@consul-server vhost]# cat lokott.conf
upstream backend-server {
server 192.168.10.129:88;
server 192.168.10.129:89;
server 192.168.10.129:90;
}
server {
listen 8023;
server_name localhost 192.168.10.128;
access_log /var/log/nginx/lokott-access.log;
location / {
proxy_set_header HOST $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Client-IP $remote_addr;
proxy_pass http://backend-server;
}
}
一些總結
首先,需要明白基於consul構建docker容器提供服務的目的,就本文的nginx而言,可以靈活而快速地擴展配置更新服務,方便彈性伸縮;
其次,需要理清楚相關工具的使用以及其目的;
再者,搞清楚內部的一些端口服務以及對應協議,本文就不做羅列了。
後續的思考和驗證
目前有三個nginx容器服務,如果此時有一個服務故障了會有什麼現象,對運行命令終端和配置文件以及web ui界面內容(ip:8500)有什麼影響呢?
模擬測試一下,可以停掉一個nginx容器服務
[root@docker-sevice ~]# docker stop test03
test03
結果是:
終端會同時相關信息,而配置文件將會隨之動態變化,踢出故障服務,那麼可想而知,web UI界面也會動態變化,回到最初的兩個nginx服務狀態。可以自己驗證查看了哈!
謝謝閱讀!