為Docker建立自動化nginx反向代理

davidchang365發表於2016-04-05

翻譯。原文見: http://jasonwilder.com/blog/2014/03/25/automated-nginx-reverse-proxy-for-docker/

反向代理伺服器是一種通常位於web伺服器之前的伺服器,它可以提供web伺服器本身沒有的附件功能。

例如,反向代理可以提供SSL終結、負載均衡、請求路由、快取、壓縮,甚至A/B測試。

當用docker容器執行web服務時,執行一個反向代理可以簡化部署。

**

為什麼為docker使用反向代理?

**
docker容器被分配隨機的IP和埠,這使得從客戶端的角度來定位這些容器比較困難。預設地,這些IP和埠是私有的,不能從外部訪問,除非它們和宿主機繫結。

把容器和宿主機繫結,會阻止執行在同一個埠上的容器。例如,每次都只能有一個docker繫結到埠80。另外,這也使得部署新版本的容器變得複雜。因為新版本只有在舊版本停止服務後,才能啟動服務。

反向代理可以解決上面的這些問題,同時通過提供0當機時間來改進可靠性。

**

產生反向代理配置

**

當容器啟動和停止時,設定反向代理的配置是一件負責的事情。通常配置需要手動更新,這需要大量的時間,而且容易出錯。

幸運的是,docker提供了一個遠端呼叫API,可以觀察容易,並訪問容器的IP和埠,已經配置後設資料。另外,docker也提供了一個實時事件API,當容器啟動和停止時,可以用來傳送通知。這些API可以用來自動生成反向代理配置。

docker-gen是一個小應用。它使用docker的API,把容器的後設資料匯入模板。生成模板後,可以用它重啟服務。

使用docker-gen,可以自動生成nginx配置,並當配置發生改變時,重新載入nginx。同樣的方法可以用在docker log管理上。

**

針對docker的nginx反向代理

**
下面的nginx模板例子可以用來生成docker容器的反向代理配置。這個模板使用golang。groupby模板函式被用來給執行中的容器分組,分組是基於VIRTUAL_HOST環境變數做的。這個方式簡化了遍歷容器,以便生成負載均衡的後臺,同時也支援了0當機的部署。

{{ range host,

host,
containers := groupBy “Env.VIRTUAL_HOST” }}  
upstream {{
“Env.VIRTUAL_HOST” }} upstream {{
host }} {

{{ range index,

index,
value := containers }}  
    {{ with
containers }} {{ with
address := index value.Addresses 0 }}  
    server {{
value.Addresses 0 }} server {{
address.IP }}:{{ $address.Port }};
{{ end }}
{{ end }}

}

server {
#ssl_certificate /etc/nginx/certs/demo.pem;
#ssl_certificate_key /etc/nginx/certs/demo.key;

gzip_types text/plain text/css application/json application/x-javascript
           text/xml application/xml application/xml+rss text/javascript;

server_name {{ $host }};

location / {
    proxy_pass http://{{ $host }};
    include /etc/nginx/proxy_params;
}

}
{{ end }}

這個模板使用下面的命令執行:
docker-gen -only-exposed -watch -notify “/etc/init.d/nginx reload” templates/nginx.tmpl /etc/nginx/sites-enabled/default

-only-exposed - 僅使用暴露出埠的容器.
-watch - 執行後,觀察容器的事件,並重新生成模板.
-notify "/etc/init.d/nginx reload" - 重新載入nginx.
templates/nginx.tmpl - nginx模板.
/etc/nginx/sites-enabled/default - 目標檔案.

下面是配置了兩個容器demo1和demo2的模板

upstream demo1.localhost {
server 172.17.0.4:5000;
server 172.17.0.3:5000;
}

server {
#ssl_certificate /etc/nginx/certs/demo.pem;
#ssl_certificate_key /etc/nginx/certs/demo.key;

gzip_types text/plain text/css application/json application/x-javascript
           text/xml application/xml application/xml+rss text/javascript;

server_name demo1.localhost;

location / {
    proxy_pass http://demo.localhost;
    include /etc/nginx/proxy_params;
}

}

upstream demo2.localhost {
server 172.17.0.5:5000;
}

server {
#ssl_certificate /etc/nginx/certs/demo.pem;
#ssl_certificate_key /etc/nginx/certs/demo.key;

gzip_types text/plain text/css application/json application/x-javascript
           text/xml application/xml application/xml+rss text/javascript;

server_name demo2.localhost;

location / {
    proxy_pass http://demo2.localhost;
    include /etc/nginx/proxy_params;
}

}

**

嘗試一下

**

可以嘗試一下我做好的build。 https://index.docker.io/u/jwilder/nginx-proxy/
執行nginx代理容器:
dockerrundp80:80v/var/run/docker.sock:/tmp/docker.socktjwilder/nginxproxyVIRUTALHOST

如果你使用HTTPS,想執行其他的容器,可以看看github上的專案,以得到更多的資訊。

**

結論

**
為docker容器生成nginx反向代理配置,可以通過使用docker API自動的完成。這個方式可以簡化部署,提供可用性。

這個方案對執行在單個host上的容器很方便。為分散式主機提供配置依賴服務發現。可以看看docker服務發現的內容,然後找到解決方案。

相關文章