Swarm mode 上線 5 - load balancer | proxy gateway 代理伺服器
前面的例子,我們已經成功設定 ingress Network,也加了 virtual ip 。如果大家的目標是單一 web 應用,應該就已經很足夠。但作為一個足夠節儉的老闆,怎會讓一個 Swarm 只跑一個 Web 應用?但問題來了,一個 docker swarm service 就已經佔用一個公開端口 例如上述的8888,或是更常見的443。怎麼可以做到多個 service 分享同一個端口?答案就是回到傳統的 Web Server 當中,使用它們的 virtual host 及 proxy 功能,以達到這一效果。我們就以 Nginx 為例,去建立一個守門口的網關 gateway 。 以下就是一個最簡單的例子,最前端的 httpgateway nginx 對外公開端口 8080 ,它根據 virtual host,去分派對應的請求去 dmzhttp bretfisherhttpenv 及 managerhttp bretfisherhttpenv 。構架圖就是以下這樣。 ┌───────────┐ ┌──────────────►│ dmzhttp │ │ └───────────┘ │ ┌───────────────┐ │ httpgateway │ ────────►│ nginx8080 │ └──┬────────────┘ │ │ ┌─────────────┐ └─────────────►│ managerhttp │ └─────────────┘ 換成 docker stack ,就大概如下 services httpgateway image httpgateway ports 80808080 deploy replicas 1 update_config delay 10s restart_policy condition onfailure dmzhttp image bretfisherhttpenv deploy replicas 2 update_config delay 10s restart_policy condition onfailure managerhttp image bretfisherhttpenv deploy replicas 3 update_config delay 10s restart_policy condition onfailure docker stack有一個很好的功能,就是 service 名會自動成為同一段網絡中的 hostname 。即是httpgateway中,它可以經DNS,找到 dmzhttp 、 managerhttp,也就是它的 nginx 可以設定成如下的樣子。 # default.conf server listen 8080; listen 8080; server_name managerhttp; resolver 127.0.0.11 valid=30s; location set $upstream_manager managerhttp; proxy_cache off; proxy_pass http$upstream_manager8888$request_uri; server listen 8080; listen 8080; server_name dmzhttp; resolver 127.0.0.11 valid=30s; location set $upstream_dmz dmzhttp; proxy_cache off; proxy_pass http$upstream_dmz8888$request_uri; 上面的例子中,就是一般的 virtual host nginx proxy 設定。特別要說明的是 resolver 那一行,它指向 docker DNS 127.0.0.11, 而且還可以讓nginx在找不到上游時,不要馬上死亡。這樣 docker swarm 中各個 service 隨時加加減減,有保命的作用。 最後我們的 httpgateway 就是 nginx image default.conf 上述的 docker 就可以用以下方式打包。 # Dockerfile # docker image build t httpgateway . FROM nginxlatest COPY default.conf etcnginxconf.ddefault.conf 上面的 docker stack 和 nginx config,只要同步增加 service 及對應的 proxy pass,就可以o讓同一個端口,根據不同hostname做分流。當然,如果大家可以共用端口及 hostname 也可以,分流就改用 nginx location 來設定,不過這是更加偏向 nginx 的內容,日後有機會再介紹。本篇就先集中於 docker 相關的議題。 在安全性的角度, docker 還有一些配置可以做,就是讓 dmzhttp 和 managerhttp 在不同的機器上發佈。假設我們的網絡分開兩段,一段是 manager 專用,一段是 dmz 專用。在建立 docker swarm 後,我們可以為不同的節點加入對應的標簽。 docker node update labeladd zone=manager YOUR_MANAGER_NODE docker node update labeladd zone=dmz YOUR_DMZ_NODE 然後我們通過修改 docker stakc 中的 placement gt; constraints ,限制不同的 service 在不同的節點上運行。 services httpgateway image httpgateway ports 80808080 deploy replicas 1 update_config delay 10s restart_policy condition onfailure dmzhttp image bretfisherhttpenv deploy replicas 2 update_config delay 10s restart_policy condition onfailure placement constraints node.labels.zone==dmz managerhttp image bretfisherhttpenv deploy replicas 3 update_config delay 10s restart_policy condition onfailure placement constraints node.labels.zone==manager 使用上面的例子,我們就可以達到簡單分離的效果。但大家緊記,這個分離效果始終是一個規則式功能,它與防火牆的隔離還是有本質上的區別。除了利用傳統的防火牆技術外,我們的docker swarm network,其實也可以做更多隔離,我們日後再慢慢加強這個例子。