為“多變”的Docker容器構建自動化的Nginx反向代理

nwbg 9年前發布 | 61K 次閱讀 Docker

【編者的話】Docker容器是無狀態的,它們會隨機分配IP和端口號。而在Web服務器中,我們經常需要適用Nginx來做負載均衡。眾所周知,Nginx的配置需要制定主機IP和端口,那容器的IP、端口是變化的,這個時候我們應該如何配置了?作者給出了自己的解決方案,讀者可以參考。需要注意的是,這種方案只適用于所有容器都在一臺服務器上。

反向代理服務器通常是位于Web服務器的前端,它會提供一些Web服務器無法提供的附加功能。例如,一個反向代理服務器可以提供SSL、負載均衡、路由請求、緩存、壓縮甚至A/B測試。

當在Docker容器中運行Web服務的時候,如果能在容器前運行一個反向代理服務器,那將會極大的簡化部署流程。

-------------------------------------------------------------------------------------------------------------------------

為什么Docker要使用反向代理?

Docker容器會隨機分配IP和端口號,所以從客戶端尋找它們會變得異常復雜(譯者注:比如你部署了一個Web服務,但每次重啟后容器地址都會發生改變,這個時候你怎么去訪問你的服務了?)。默認情況下,IP和端口號是專用于容器的,不能被外部訪問,除非它們被綁定到主機上。

綁定容器到主機端口上的思路并不可行,它不便于在同一臺主機運行多個容器。例如,在同一個時間內只能有一個容器可以綁定到80端口。同時這種方案也不利于擴展,因為在新容器開始之前,老容器必須停止。

反向代理可以幫助解決這些問題,也可以通過加快零死機時間部署來提高可用性。

-------------------------------------------------------------------------------------------------------------------------

生成反向代理配置

當容器開始和停止時,設置一個反向代理配置是非常復雜的。典型的配置都需要手動升級,但這個方式不僅容易出錯,而且還很浪費時間。

幸運的是Docker提供了一個遠程應用程序接口(API)來檢查容器和它們的IP、端口和其它配置元數據。除此之外,也提供了一個實時事件API,當容器開始和停止的時候,可以發出實時通知。這些API都可以被用于自動生成一個反向代理配置。

docker-gen 是一個小程序,它可以使用這些API將容器元數據傳遞給模板,隨之模板就可以重新生成,并通過一個可選擇的通知指令來重啟服務。

通過使用docker-gen,我們可以在重啟改變的時候自動生成Nginx配置文件并重啟。當然這些方法也可以用來管理Docker日志

-------------------------------------------------------------------------------------------------------------------------

用Docker建Nginx反向代理

下面例子中的這個Nginx模板可以為Docker容器生成一個反向代理配置,這個模板是使用golangtext/template package來實現的。它使用一個自定義的groupBy模板函數來對運行的容器進行分組(通過VIRTUAL_HOST環境變量)。這簡化了遍歷容器來生成一個負載均衡后端以及使得零停機部署變得可行。

{{ range $host, $containers := groupBy $ "Env.VIRTUAL_HOST" }}
upstream {{ $host }} {

{{ range $index, $value := $containers }} {{ with $address := index $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 }}</pre>
這個模板可以使用docker-gen來運行:

docker-gen -only-exposed -watch -notify &quot;/etc/init.d/nginx reload&quot; templates/nginx.tmpl /etc/nginx/sites-enabled/default

  • -only-exposed- 僅使用已經暴露的端口。
  • -watch- 啟動之后,監控docker容器事件和生成模板。
  • -notify &quot;/etc/init.d/nginx reload&quot;- 在生成模板之后重載Nginx配置。
  • templates/nginx.tmpl- Nginx模板。
  • /etc/nginx/sites-enabled/default- 目標文件。
  • </ul>
    這是一個容器配置了VIRTUAL_HOST=demo1.localhost,另一個配置VIRTUAL_HOST=demo2.localhost的容器的模板。

    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; } }

    }}}

     試一試 

    我創建了一個可信任的Docker鏡像來做試驗。 運行Nginx-proxy容器: {{{$ docker run -d -p 80:80 -v /var/run/docker.sock:/tmp/docker.sock -t jwilder/nginx-proxy</pre>
    使用VIRTUAL_HOST環境變量來啟動你的容器:

    docker run -e VIRTUAL_HOST=foo.bar.com -t ...

    如果你需要HTTPS,可能會喜歡在一個Nginx分組容器里運行docker-gen,需要Websocket支持或者其它特性,請在GitHub項目網站查看以獲取更多信息。

    -------------------------------------------------------------------------------------------------------------------------

    結論

    我們可以通過自動地使用Docker API和一些基本的模板來為Docker容器生成Nginx反向代理配置,這可以簡化部署也可以提高可用性。

    需要注意的是這種方案僅適用于單臺機器,如果有多臺機器可能就得考慮服務發現來生成配置了。如果你有興趣,請查看Docker服務發現尋找解決問題的方法。

    另外,這里有一些類似的觀點值得你閱讀:

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