一、 目的
在服務在容器中部署時,外部調用服務需要知道服務接口ip及端口號,這樣導致部署時需要配置,從而增加部署的困難。本文檔主要介紹如何使用ningx反向代理和consul進行自動化服務發現與部署,從而使外部訪問服務只需要訪問nginx代理即可解決,同時也可以解決分布式服務及大訪問量負載問題。
場景說明:如有一個數據服務data-service,如果在docker集群中部署的話,ip和port都可能變化,這時線上服務必須更改配置,才能訪問到data-service服務。而采用本方案的話,只需要配置好ningx負載均衡的ip與地址,數據服務可隨時重新部署調整,不需要重新配置。
二、 概述
Nginx是常用的輕量級反向代理插件,使用Ningx可以讓服務統一入口,通過Ningx配置服務路徑請求轉發路徑,將對應的請求路由到對應的服務中處理。使用Ningx可以使后端服務部署更加靈活。
Consul包含多個組件,但是作為一個整體,為你的基礎設施提供服務發現和服務配置的工具.他提供以下關鍵特性:
服務發現 Consul的客戶端可用提供一個服務,比如 api 或者mysql ,另外一些客戶端可用使用Consul去發現一個指定服務的提供者.通過DNS或者HTTP應用程序可用很容易的找到他所依賴的服務.
健康檢查 Consul客戶端可用提供任意數量的健康檢查,指定一個服務(比如:webserver是否返回了200 OK 狀態碼)或者使用本地節點(比如:內存使用是否大於90%). 這個信息可由operator用來監視集群的健康.被服務發現組件用來避免將流量發送到不健康的主機.
Key/Value存儲 應用程序可用根據自己的需要使用Consul的層級的Key/Value存儲.比如動態配置,功能標記,協調,領袖選舉等等,簡單的HTTP API讓他更易於使用.
多數據中心 Consul支持開箱即用的多數據中心.這意味着用戶不需要擔心需要建立額外的抽象層讓業務擴展到多個區域.
Consul面向DevOps和應用開發者友好.是他適合現代的彈性的基礎設施.
三、 部署方案
i. 部署圖

圖1 部署圖
ii. 部署過程
- 部署consul server
docker run -d --name=consul_server -p 8400:8400 -p 8500:8500 -p 8600:53/udp -h docker_server progrium/consul -server -bootstrap
- 部署consul registrator
docker run -d --name=consul_registrator --net=host --volume=/var/run/docker.sock:/tmp/docker.sock gliderlabs/registrator:latest -ip="192.168.1.60" consul://192.168.1.60:8500
-ip:使用主機ip,因為nginx轉發可能涉及到跨主機的服務請求轉發,所以需要綁定主機ip;
consul://192.168.1.60:8500:為consul server的ip和端口。
- 部署consul template&nginx
- 部署容器
docker -d run liberalman/nginx-consul-template:latest
- 配置Nginx
Nginx配置存儲路徑為:/etc/nginx/conf.d,使用的是分文件,該文件是由consul template自動更新的,不需要進行配置。
- 配置Consul template
配置文件存儲的路徑為:/etc/consul-templates/nginx.conf.ctmpl,該文件為consul template在監控consul server服務有改動時,進行配置修改,並存儲到/etc/nginx/conf.d/app.conf當中。
示例配置:
upstream solr {
least_conn;
{{range service "solr"}}server {{.Address}}:{{.Port}} max_fails=3 fail_timeout=60 weight=1;
{{else}}server 127.0.0.1:65535; # force a 502{{end}}
}
upstream data_service {
least_conn;
{{range service "data_service"}}server {{.Address}}:{{.Port}} max_fails=3 fail_timeout=60 weight=1;
{{else}}server 127.0.0.1:65535; # force a 502{{end}}
}
server {
listen 80 default_server;
location /solr {
proxy_pass http://solr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
location /data {
proxy_pass http://data_service;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
配置一個服務需要倆個地方進行配置修改。
upstream solr {
least_conn;
{{range service "solr"}}server {{.Address}}:{{.Port}} max_fails=3 fail_timeout=60 weight=1;
{{else}}server 127.0.0.1:65535; # force a 502{{end}}
}
1) upstream配置
-
- upstream solr:該solr為定義的服務別名,在后面server節點中需要用到;
- {{range service "solr"}}:其中solr為該服務在注冊時到服務時的服務名稱,該名稱在容器啟動時設置環境變量SERVICE_NAME得到,如果需指定某端口對應某服務,使用SERVICE_80_NAME,80替換為端口號即可,下圖是配置了80端口的服務名為data_service
2) server配置
location /solr:配置路由進行轉發
proxy_pass http://data_service:配置對應的路由轉發到哪個upstream上。
location /solr {
proxy_pass http://solr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
該段代碼表示將請求路徑/solr的請求轉發到服務名為solr的地址上。
以app.conf為例:
upstream solr {
least_conn;
server 192.168.1.60:8080 max_fails=3 fail_timeout=60 weight=1;
}
upstream data_service {
least_conn;
server 192.168.1.60:5000 max_fails=3 fail_timeout=60 weight=1;
}
server {
listen 80 default_server;
location /solr {
proxy_pass http://solr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
location /data {
proxy_pass http://data_service;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
}
}
假設nginx部署在192.168.1.112服務器上,那么訪問 http://192.168.1.112/solr,該請求會被轉發到http://192.168.1.60:8080/solr
4. 啟動服務
1) 如果需要忽略不注冊到consul上,則在創建容器時添加環境變量SERVICE_IGNORE=true
2) 如果需要注冊到consul上,則需要設置服務名,使用SERVICE_NAME=[服務名]進行設置,也可將容器對應的不同端口設置為不同的服務名,例如需要將容器暴露的端口8088設置為bussiness服務名,則使用SERVICE_8088_NAME=[服務名],即在中間加上端口號即可
3) 如果需要對服務加上標簽,可使用環境變量SERVICE_TAGS進行設置,多個標簽以英文逗號隔開
iii. 采用docker compose部署
Docker compose部署可以解決容器先后啟動順序問題
version: '2'
services:
load_balancer:
image: nginx-consul-template:latest
hostname: lb
container_name: consul-nginx-template
links:
- consul_server
depends_on:
- consul_server
ports:
- "80:80"
environment:
- SERVICE_IGNORE=true
consul_server:
image: progrium/consul
hostname: consul_server
container_name: consul_server
ports:
- "8300:8300"
- "8301:8301"
- "8302:8302"
- "8400:8400"
- "8500:8500"
- "8600:8600"
environment:
- SERVICE_IGNORE=true
command: -server -bootstrap
registrator:
image: gliderlabs/registrator:latest
hostname: registrator
container_name: consul_registrator
links:
- consul_server
depends_on:
- consul_server
volumes:
- "/var/run/docker.sock:/tmp/docker.sock"
environment:
- SERVICE_IGNORE=true
command: -ip 192.168.1.60 consul://192.168.1.60:8500
四、 常見問題
待補充...
