HAProxy 容器化實踐

您可以將 HAProxy 作爲 Docker 容器運行嗎?是的!這還需要問嗎?如今 Docker 無處不在,您會發現許多應用程序都已被 Docker 化;HAProxy 負載均衡器也不例外,但 HAProxy 就是爲此而生的。作爲在 Linux 上運行的獨立服務,將其移植到 Docker 似乎很自然。

爲什麼要在 Docker 容器內運行負載均衡器?這樣做性能會有折扣麼?它會引入任何安全問題嗎?

在這篇博文中,您將瞭解爲什麼要考慮在容器內運行 HAProxy 以及可能產生的後果。然後你會看到如何去做。請注意,我們介紹的是如何運行 HAProxy,而不是 HAProxy Kubernetes Ingress Controller。

HAProxy Technologies 在其命名空間 haproxytech 下構建自己的一組 Docker 鏡像。這些會定期更新最新的補丁和安全更新。我將在這篇博文中使用這些鏡像。你會在這裏找到它們:

我演示的命令是在 Linux 工作站上執行的,如果您在使用 Docker Desktop for Windows 或 Docker Desktop for Mac 時也能正常工作。

使用 Docker 的好處

您是否希望能夠運行 HAProxy 而無需編譯、安裝依賴項或以其他方式更改您的系統?

Docker 容器帶來了可觀的好處,其中最主要的是安裝和執行的操作較少。Docker 允許您將容器放到主機系統上並立即獲得正在運行的服務——無需安裝腳本,無需安裝 C 庫。該服務完全包含在容器中,您需要做的就是啓動它,然後將 TCP 端口映射到它。當您部署一個容器時,您可以獲得運行完整的應用程序及其運行時環境的能力,而無需將其實際安裝到主機系統上。

生命週期管理也變得標準化。啓動、停止和刪除容器就像調用一行 docker 命令一樣簡單。這反過來又使部署成爲一個可重複和可測試的過程。它還有助於更輕鬆地進行軟件升級。

使用 Docker 的性能影響

您希望您的負載均衡器運行速度快,且不會增加環境延遲。那麼,問題是,在容器內運行 HAProxy 有什麼影響?

在 CPU 開銷方面,記住,與虛擬機不同,Docker 不需要在主機操作系統之上的虛擬化層。容器在主機的內核上運行,基本上只是另一個進程,儘管它與主機上運行的其他進程具有更好的隔離性(它使用命名空間來實現這一點)。IBM 研究人員的一項研究發現,使用 Docker 的 CPU 開銷可以忽略不計,這應該不足爲奇。

網絡是另一回事。默認情況下,Docker 允許您通過創建到主機的橋接網絡來訪問在容器內運行的服務。由於必須在容器的本地網絡和主機的橋接網絡之間發生的網絡地址轉換 (NAT),這確實會導致延遲。在之前引用的同一 IBM 研究中,研究人員發現 Docker 的 NAT 將來自客戶端的 100 字節請求和來自應用程序的 200 字節響應的延遲從大約 35 微秒增加到 70 微秒。

另一方面,橋接網絡很有用,因爲它們允許您將容器組隔離到容器網絡中,並且僅將其中一些容器暴露給主機,這對於減少主機網絡所需的 IP 地址數量非常方便(想想運行數百甚至數千個容器所需的 IP 數量)。如果您有興趣瞭解有關 Docker 中網絡如何工作的更多信息,可以在 YouTube 上觀看 Docker 團隊提供的深入探討。

如果您需要非常低的延遲,您可以切換到使用 Docker 的主機網絡功能,它允許您的容器與主機共享相同的網絡,從而無需 NAT。再說一次,如果你想運行 Docker Swarm 或 Kubernetes,它們使用覆蓋網絡,對於不同的網絡驅動程序,如 Project Calico 和 Cilium 有解決方案,本篇文章文章並不涉及該怎麼做。

簡而言之,除非您需要非常低的延遲,否則您應該堅持使用默認的橋接網絡選項。請務必對其進行測試,看看您是否達到了所需的吞吐量。

使用 Docker 的安全考慮

您可能會擔心許多 Docker 容器以 root 身份運行他們的服務,而這個 root 用戶與主機系統上的 root 用戶相同。對容器突破的擔憂是合理的。HAProxy 也以 root 身份運行。但是,讓您放心:HAProxy 需要 root 訪問權限,因爲它需要綁定到受限制的 TCP 端口,如 80 和 443。但是,一旦完成啓動,它就會放棄其 root 權限並以非特權用戶身份運行。

人們還會權衡容器可能是惡意的風險。這是堅持使用由 HAProxy Technologies 製作的 haproxytech Docker 鏡像的一個很好的理由。

使用 Docker 運行 HAProxy

我們將創建一個 Web 應用程序的三個實例、一個 HAProxy 實例和一個將它們連接在一起的橋接網絡。因此,一旦您安裝了 Docker,請使用以下命令在 Docker 中創建一個新的橋接網絡:

$ sudo docker network create --driver=bridge mynetwork

然後使用該 docker run 命令創建並運行 Web 應用程序的三個實例。在此示例中,我使用 Docker 鏡像 jmalloc/echo-server https://hub.docker.com/r/jmalloc/echo-server。這是一個簡單的 Web 應用程序,可返回您發送給它的 HTTP 請求的詳細信息。

$ sudo docker run -d \
   --name web1 --net mynetwork jmalloc/echo-server:latest

$ sudo docker run -d \
   --name web2 --net mynetwork jmalloc/echo-server:latest

$ sudo docker run -d \
   --name web3 --net mynetwork jmalloc/echo-server:latest

請注意,我們爲每個服務分配了一個唯一名稱並將其附加到我們創建的橋接網絡。您現在應該運行了三個 Web 應用程序,您可以通過調用以下 docker ps 命令進行驗證:

$ sudo docker ps

CONTAINER ID   IMAGE                        COMMAND              CREATED              STATUS              PORTS      NAMES
98216bb8c5ff   jmalloc/echo-server:latest   "/bin/echo-server"   About a minute ago   Up About a minute   8080/tcp   web3
ae6accc111d9   jmalloc/echo-server:latest   "/bin/echo-server"   About a minute ago   Up About a minute   8080/tcp   web2
554fafbc2b3b   jmalloc/echo-server:latest   "/bin/echo-server"   About a minute ago   Up About a minute   8080/tcp   web1

這些容器監聽自己的端口 8080,但我們沒有將這些端口映射到主機,因此它們不可路由。我們將通過 HAProxy 負載均衡器將流量中繼到這些容器。接下來,讓我們在它們前面添加 HAProxy。在當前目錄中創建一個名爲 haproxy.cfg 的文件,並在其中添加以下內容:

global
  stats socket /var/run/api.sock user haproxy group haproxy mode 660 level admin expose-fd listeners
  log stdout format raw local0 info

defaults
  mode http
  timeout client 10s
  timeout connect 5s
  timeout server 10s
  timeout http-request 10s
  log global

frontend stats
  bind *:8404
  stats enable
  stats uri /
  stats refresh 10s

frontend myfrontend
  bind :80
  default_backend webservers

backend webservers
  server s1 web1:8080 check
  server s2 web2:8080 check
  server s3 web3:8080 check

需要注意的幾點:

接下來,創建並運行一個 HAProxy 容器,並通過包含 - p 參數將其端口 80 映射到主機上的相同端口。還要爲 HAProxy Stats 頁面映射端口 8404:

$ sudo docker run -d \
   --name haproxy \
   --net mynetwork \
   -v $(pwd):/usr/local/etc/haproxy:ro \
   -p 80:80 \
   -p 8404:8404 \
   haproxytech/haproxy-alpine:2.4

docker ps 之後調用顯示 HAProxy 正在運行:

$ sudo docker ps

CONTAINER ID   IMAGE                            COMMAND                  CREATED          STATUS          PORTS                                        NAMES
d734d0ef2635   haproxytech/haproxy-alpine:2.4   "/docker-entrypoint.…"   3 seconds ago    Up 2 seconds    0.0.0.0:80->80/tcp, 0.0.0.0:8404->8404/tcp   haproxy

您可以通過 http://localhost 訪問 echo-server Web 應用程序。每個對它的請求都將由 HAProxy 進行負載平衡。此外,您可以在 http://localhost:8404 看到 HAProxy Stats 頁面。

如果您對 haproxy.cfg 文件進行了更改,則可以通過調用以下 docker kill 命令重新加載負載均衡器,而不會損失流量:

$ sudo docker kill -s HUP haproxy

要刪除容器和網絡,運行 docker stop,docker rm 和 docker network rm 命令:

$ sudo docker stop web1 && sudo docker rm web1
$ sudo docker stop web2 && sudo docker rm web2
$ sudo docker stop web3 && sudo docker rm web3
$ sudo docker stop haproxy && sudo docker rm haproxy
$ sudo docker network rm mynetwork

總結

在這篇博文中,您瞭解瞭如何在 Docker 容器內運行 HAProxy 簡化其部署和生命週期管理。Docker 提供了一種用於部署應用程序的標準化方法,使該過程具有可重複性和可測試性。雖然運行 Docker 的 CPU 開銷可以忽略不計,但它可能會導致額外的網絡延遲,但其影響取決於您的場景和吞吐量需求。

要運行 HAProxy,只需創建一個 HAProxy 配置文件,然後使用 docker run 命令調用 HAProxy Docker 鏡像的名稱。HAProxy Technologies 在 Docker Hub 上提供最新的 Docker 鏡像。


本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/PVlSuNxPz0wrI6XXSVMnCQ