一. 架構設計
在現實中,我們一直渴望着追求提供高質量、高可用的服務架構體系,同時減少不必要的部署和維護代價,減少容錯率。面對如此高的要求,可以有兩種架構方案:
Docker+Etcd+Confd+Nginx
Docker+Consul+Nginx
本文中我們主要來介紹 Docker+Etcd+Confd+Nginx方案,此方案更加高效、快捷,並且維護代價和容錯率更低,分佈式支持力度更強,如下圖所示:
上面示意圖的大概流程如下:
1、docker01主機上以二進制包的方式部署consul服務並後臺運行,其身份爲leader;
2、docker02、docker03以容器的方式運行consul服務,並加入到docker01的consul羣集中;
3、在主機docker02、docker03上後臺運行registrator容器,使其自動發現docker容器提供的服務;
4、在docker01上部署Nginx,提供反向代理服務,docker02、docker03主機上基於Nginx鏡像,各運行兩個web容器,提供不同的網頁文件,以便測試效果;
5、在docker01上安裝consul-template命令,將收集到的信息(registrator收集到容器的信息)寫入template模板中,並且最終寫入Nginx的配置文件中。
6、至此,實現客戶端通過訪問Nginx反向代理服務器(docker01),獲得docker02、docker03服務器上運行的Nginx容器提供的網頁文件。
注:registrator是一個自動發現docker container提供的服務,並且在後端服務註冊中心(數據中心)註冊服務。主要用來收集容器運行服務的信息,並且發送給consul。數據中心除了consul外,還有etcd、zookeeper等。
二. 架構優勢
Docker+Consul+Nginx雖然看起來是三個組件的運用,但卻證明是一個有機的整體。它們互相聯繫、互相作用,完全滿足我們對高可用、高效服務架構方案的需求,是Docker生態圈中最理想的組合之一,具有以下優勢:
1.發現與註冊組件consul使用 Raft 算法來保證一致性,比複雜的Paxos 算法更直接。相比較而言,zookeeper 採用的是 Paxos,而 etcd 使用的則是 Raft;
2.多數據中心,多數據中心集羣可以避免單數據中心的單點故障,zookeeper 和 etcd 均不提供多數據中心功能的支持;
3.、實時發現及無感知服務刷新,具備資源彈性,伸縮自如;
4.健康檢查,負載能動態在可用的服務實例上進行均衡,etcd 不提供此功能;
5.足夠多臺Docker容器(前提架構資源足以保證性能支撐);
6.http 和dns 協議接口,zookeeper 的集成較爲複雜,etcd 只支持 http 協議;
7.規模方便進行快速調整,官方提供web管理界面,etcd 無此功能;
8.nsul template 搭配consul使用,支持多種接入層,如Nginx、Haproxy。
三. 實驗環境
主機 | iP地址 | 服務 |
---|---|---|
docker01 | 192.168.1.11 | consul+consul-template+nginx |
docker02 | 192.168.1.13 | consul+registrator |
docker03 | 192.168.1.20 | consul+registrator |
三臺主機關閉防火牆,禁用selinux,更改主機名如上所述。
四. 部署consul服務
(1)docker01去官網https://www.consul.io/downloads.html下載consul服務
[root@docker01 ~]# unzip consul_1.5.1_linux_amd64.zip
//現在是本地導入壓縮包,需要解壓
[root@docker01 ~]# mv consul /usr/local/bin/
//移動服務到bin目錄
[root@docker01 ~]# chmod +x /usr/local/bin/consul
//給予一個可執行權限
(2)啓動consul
[root@docker01 ~]# consul agent -server -bootstrap -ui -data-dir=/var/lib/consul-data -bind=192.168.1.11 -client=0.0.0.0 -node=master
PS: //-bootstrap: 加入這個選項時,一般都在server單節點的時候用,自選舉爲leader。
參數解釋:
-server:添加一個服務
-bootstrap:一般在server單節點的時候使用,自選舉爲leader。
-data-dir:key/volume指定數據存放的目錄
-ui:開啓內部的web界面
-bind:指定開啓服務的ip
-client:指定訪問的客戶端
-node:在集羣內部通信使用的名稱,默認是主機名。
現在這個ip是外部使用
PS:開啓的端口
8300 集羣節點
8301 集羣內部的訪問
8302 跨數據中心的通信
8500 web ui界面
8600 使用dns協議查看節點信息的端口
可參考下圖查看端口的意思:
這時,這條啓動consul的命令會佔用終端,可以使用nohup命令讓它保持後臺運行。
[root@docker01 ~]# nohup consul agent -server -bootstrap -ui -data-dir=/var/lib/consule-data -bind=192.168.1.11 -client=0.0.0.0 -node=master &
(3)查看consul端口的信息**
[root@docker01 ~]# consul info
五. docker01下載部署consul-template
在 https://github.com/hashicorp/consul-template 上,下載consul-template
[root@docker01 ~]# unzip consul-template_0.19.5_linux_amd64.zip
//解壓安裝好的consul-template包
[root@docker01 ~]# mv consul-template /usr/local/bin/
//移動到命令目錄
[root@docker01 ~]# chmod +x /usr/local/bin/consul-template
//給予一個可執行權限
六和七步驟簡要說明
在docker01和docker02上操作
先來說一下在docker服務器上操作的大概思路:
分別在兩臺docker服務器上都創建registrator容器,注意到consul服務中心;
在docker01上運行兩臺nginx容器(端口隨機生成),在docker02上運行兩臺nginx容器(端口隨機生成);
修改這4臺nginx容器中的index.html頁面內容爲(xgp-web01、xgp-web02、xgp-web03、xgp-web04)
訪問consul web界面驗證
訪問nginx服務器地址 http://192.168.1.11:8000 進行驗證;
六. docker02,docker03,加入consul集羣
這裏我們採用容器的方式去運行consul服務。
(1)下載consu所需的l鏡像
[root@docker02 ~]# docker pull consul
(2)基於consul鏡像開啓一臺容器
[root@docker02 ~]# docker run -d --name consul -p 8301:8301 -p 8301:8301/udp -p 8500:8500 -p 8600:8600 -p 8600:8600/udp --restart always progrium/consul -join 192.168.1.11 -advertise 192.168.1.13 -client 0.0.0.0 -node=node01
參數解釋:
-d:守護進程
--name:容器名稱
--restart:容器隨着docker服務一直運行
-advertise:聲明本機地址
-join:聲明服務端地址
-node:consul集羣中的名稱
(3)docker查看consul集羣成員的信息
[root@docker01 ~]# consul members
(4)兩臺docker開啓容器後,docker01查看
(5)瀏覽器訪問http://192.168.1.11:8500
七. docker02、docker03 上部署registrator服務
registrator是一個能自動發現docker container提供的服務,並在後端服務註冊中心註冊服務或取消服務的工具,後端註冊中心支持conusl、etcd、 skydns2、zookeeper等。
(1)下載registrator鏡像
[root@docker02 ~]# docker pull registrator
//下載registrator鏡像
(2)基於registrator鏡像,開啓一臺容器
[root@docker02 ~]# docker run -d --name registrator -v /var/run/docker.sock:/tmp/docker.sock --restart always gliderlabs/registrator consul://192.168.1.13:8500
參數說明:
--network:把運行的docker容器設定爲host網絡模式;
-v /var/run/docker.sock:把宿主機的Docker守護進程(Docker daemon)默認監聽的Unix域套接字掛載到容器中;
--ip : 剛纔把network指定了host模式,所以我們指定下IP爲宿主機的IP;
consul:j最後這個選項是配置consul服務器的IP和端口。(3)開啓一臺nginx容器
[root@docker02 ~]# docker run -d —P --name nginx nginx:latest
(4)瀏覽器查看一下http://192.168.1.11:8500/ui/dc1/nodes
八.docker01部署一個nginx服務
配置nginx,大概配置的思路爲:
在/usr/local/nginx/conf中創建目錄consul,目錄名自定義;
在consul目錄中創建nginx.ctmpl模板;
在nginx.conf配置中添加include項並指向consul目錄 ;
重啓nginx服務;
(1)安裝開啓nginx服務
安裝nginx依賴包
[root@docker01 ~]# yum -y install pcre pcre-devel openssl openssl-devel zlib zlib-devel
編譯安裝nginx
[root@docker01 ~]# cd nginx-1.14.0/
[root@docker01 nginx-1.14.0]# ./configure --user=nginx --group=nginx --with-http_stub_status_module --with-http_realip_module --with-pcre --with-http_ssl_module && make && make install
創建所需用戶和鏈接命令目錄
[root@docker01 nginx-1.14.0]# useradd -M -s /sbin/nologin nginx
[root@docker01 nginx-1.14.0]# ln -s /usr/local/nginx/sbin/* /usr/local/bin/
檢查nginx是否有問題,並開啓nginx
[root@docker01 nginx-1.14.0]# 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@docker01 nginx-1.14.0]# nginx
PS:這裏nginx作爲反向代理,代理後端docker02、 docker03 上nginx的容器服務,所以我們先去docker02、docker03. 上部署一些服務, 爲了方便等會看到負載的效果,所以,我們運行完成容器之後,做一個主界面內容的區分。
(2)安裝完成之後,本機測試訪問
[root@docker01 nginx-1.14.0]# curl 127.0.0.1
(3)部署環境
主機 | 服務 | |
---|---|---|
docker02 | nginx | web01,web02 |
docker03 | nginx | web03,web04 |
<1>下載nginx鏡像(docker02,docker03都要)
[root@docker02 ~]# docker pull nginx
//下載nginx鏡像
<2>docker01操作
基於nginx鏡像運行上述所說的容器並設置測試頁面
web01
[root@docker02 ~]# docker run -itd --name web01 -P nginx:latest
[root@docker02 ~]# docker exec -it web01 /bin/bash
root@44b59d07202f:/# cd /usr/share/nginx/html/
root@44b59d07202f:/usr/share/nginx/html# echo web01 > index.html
web02
[root@docker02 ~]# docker run -itd --name web02 -P nginx:latest
[root@docker02 ~]# docker exec -it web02 /bin/bash
root@44b59d07202f:/# cd /usr/share/nginx/html/
root@44b59d07202f:/usr/share/nginx/html# echo web02 > index.html
<3>docker02操作
基於nginx鏡像運行上述所說的容器並設置測試頁面
web03
[root@docker03 ~]# docker run -itd --name web03 -P nginx:latest
[root@docker03 ~]# docker exec -it web03 /bin/bash
root@fd8e8b2df136:/# cd /usr/share/nginx/html/
root@fd8e8b2df136:/usr/share/nginx/html# echo web03 > index.html
root@fd8e8b2df136:/usr/share/nginx/html# exit
web04
[root@docker03 ~]# docker run -itd --name web04 -P nginx:latest
[root@docker03 ~]# docker exec -it web04 /bin/bash
root@fd8e8b2df136:/# cd /usr/share/nginx/html/
root@fd8e8b2df136:/usr/share/nginx/html# echo web04 > index.html
root@fd8e8b2df136:/usr/share/nginx/html# exit
(4)docker01更改nginx配置文件
[root@docker01 ~]# cd /usr/local/nginx/
//進入nginx配置文件目錄
[root@docker01 nginx]# mkdir consul
//創建consul目錄
[root@docker01 nginx]# cd consul/
//進入consul目錄
<1>創建nginx.ctmpl模板
[root@docker01 consul]# vim nginx.ctmpl
upstream http_backend {
{{range service "nginx"}}
server {{ .Address }}:{{ .Port }};
{{ end }}
}
server {
listen 8000;
server_name localhost;
location / {
proxy_pass http://http_backend;
}
}
nginx.ctmpl模板中的內容就是兩段意思,熟悉nginx的朋友一看也能明白:第1 定義nginx upstream一個簡單模板,第2 定義一個server,監聽8000端口,反向代理到upstream。
<2>修改nginx配置文件,通過 include 參數包含剛剛創建的文件
[root@docker01 consul]# cd /usr/local/nginx/conf/
[root@docker01 conf]# vim nginx.conf
include /usr/local/nginx/consul/*.conf; #文件最後添加(要在大括號裏面)
<3> 生成一個vhost.conf配置文件,並重啓nginx(會佔用終端)
使用consul-template命令,根據模板生產新的配置文件,並重新加載nginx的配置文件。
[root@docker01 conf]# consul-template -consul-addr 192.168.1.11:8500 -template "/usr/local/nginx/consul/nginx.ctmpl:/usr/local/nginx/consul/vhost.conf:/usr/local/bin/nginx -s reload"
參數說明:
--consul-addr:指定consul服務的ip和端口;
./nginx.ctmpl:這是用nginx.ctmpl這個模板來啓動進程,這是寫的相對路徑,也可以寫絕對路徑;
vhost.conf:nginx.ctmpl模板生成後的文件名,這也可以寫絕對路徑,如果不寫絕對路徑,這個文件就在當前目錄生成(/usr/local/nginx/consul/)
這時,這條命令會佔用終端,可以使用nohup命令讓它保持後臺運行,並重啓nginx服務。
[root@docker01 conf]# nohup consul-template -consul-addr 192.168.1.11:8500 -template "/usr/local/nginx/consul/nginx.ctmpl:/usr/local/nginx/consul/vhost.conf:/usr/local/sbin/nginx -s reload" &
查看一下文件是否生成,裏面是否有內容
[root@docker01 ~]# cd /usr/local/nginx/consul/
[root@docker01 consul]# ls
nginx.ctmpl vhost.conf
[root@docker01 consul]# cat vhost.conf
此時,應該能夠看到,新生產的vhost.conf配置文件已經生效,訪問本機8000端口可以得到不同容器提供的服務。
<4>測試訪問
[root@docker01 consul]# curl 127.0.0.1:8000
web01
此時可以看到負載均衡的效果!
<5>如果訪問不成功
查看端口8000是否開啓
[root@docker01 consul]# ss -lnt
檢查nginx配置文件
[root@docker01 consul]# 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
檢查自己編寫的nginx配置文件
[root@docker01 consul]# cd /usr/local/nginx/consul/
[root@docker01 consul]# cat nginx.ctmpl
upstream http_backend {
{{range service "nginx"}}
server {{ .Address }}:{{ .Port }};
{{ end }}
}
server {
listen 8000;
server_name localhost;
location / {
proxy_pass http://http_backend;
}
}
如果nginx配置文件沒問題,重啓nginx
[root@docker01 consul]# nginx -s reload
<6>測試自動發現
docker02 創建測試容器
[root@docker02 ~]# docker run -itd --name web05 -P nginx:latest
[root@docker02 ~]# docker exec -it web05 /bin/bash
root@44b59d07202f:/# cd /usr/share/nginx/html/
root@44b59d07202f:/usr/share/nginx/html# echo web02 > index.html
[root@docker02 ~]# docker ps
docker01查看
[root@docker01 consul]# cd /usr/local/nginx/consul/
[root@docker01 consul]# cat vhost.conf
docker01測試訪問
[root@docker01 consul]# curl 127.0.0.1:8000
//同上
此時可以看到負載均衡的效果!
這時不需要考慮後端的web服務器添加還是刪除都會自動更新的,這是因爲在運行consul-template這條命令後添加的/usr/local/sbin/nginx -s reload的作用!