如何優(yōu)雅的在 Docker 中運行高性能負載均衡器 HAProxy
您可以將 HAProxy 作為 Docker 容器運行嗎?是的!這還需要問嗎?如今 Docker 無處不在,您會發(fā)現(xiàn)許多應(yīng)用程序都已被 Docker 化;HAProxy 負載均衡器也不例外,但 HAProxy 就是為此而生的。作為在 Linux 上運行的獨立服務(wù),將其移植到 Docker 似乎很自然。
為什么要在 Docker 容器內(nèi)運行負載均衡器?這樣做性能會有折扣么?它會引入任何安全問題嗎?
在這篇博文中,您將了解為什么要考慮在容器內(nèi)運行 HAProxy 以及可能產(chǎn)生的后果。然后你會看到如何去做。請注意,我們介紹的是如何運行 HAProxy,而不是 HAProxy Kubernetes Ingress Controller。
HAProxy Technologies 在其命名空間 haproxytech 下構(gòu)建自己的一組 Docker 鏡像。這些會定期更新最新的補丁和安全更新。我將在這篇博文中使用這些鏡像。你會在這里找到它們:
- HAProxy(Alpine Linux 基礎(chǔ))- https://hub.docker.com/r/haproxytech/haproxy-alpine
- HAProxy (Ubuntu 基礎(chǔ)) – https://hub.docker.com/r/haproxytech/haproxy-ubuntu
- HAProxy (Debian 基礎(chǔ)) – https://hub.docker.com/r/haproxytech/haproxy-debian
我演示的命令是在 Linux 工作站上執(zhí)行的,如果您在使用 Docker Desktop for Windows 或 Docker Desktop for Mac 時也能正常工作。
1使用 Docker 的好處
您是否希望能夠運行 HAProxy 而無需編譯、安裝依賴項或以其他方式更改您的系統(tǒng)?
Docker 容器帶來了可觀的好處,其中最主要的是安裝和執(zhí)行的操作較少。Docker 允許您將容器放到主機系統(tǒng)上并立即獲得正在運行的服務(wù)——無需安裝腳本,無需安裝 C 庫。該服務(wù)完全包含在容器中,您需要做的就是啟動它,然后將 TCP 端口映射到它。當您部署一個容器時,您可以獲得運行完整的應(yīng)用程序及其運行時環(huán)境的能力,而無需將其實際安裝到主機系統(tǒng)上。
生命周期管理也變得標準化。啟動、停止和刪除容器就像調(diào)用一行 docker 命令一樣簡單。這反過來又使部署成為一個可重復(fù)和可測試的過程。它還有助于更輕松地進行軟件升級。
2使用 Docker 的性能影響
您希望您的負載均衡器運行速度快,且不會增加環(huán)境延遲。那么,問題是,在容器內(nèi)運行 HAProxy 有什么影響?
在 CPU 開銷方面,記住,與虛擬機不同,Docker 不需要在主機操作系統(tǒng)之上的虛擬化層。容器在主機的內(nèi)核上運行,基本上只是另一個進程,盡管它與主機上運行的其他進程具有更好的隔離性(它使用命名空間來實現(xiàn)這一點)。IBM 研究人員的一項研究發(fā)現(xiàn),使用 Docker 的 CPU 開銷可以忽略不計,這應(yīng)該不足為奇。
網(wǎng)絡(luò)是另一回事。默認情況下,Docker 允許您通過創(chuàng)建到主機的橋接網(wǎng)絡(luò)來訪問在容器內(nèi)運行的服務(wù)。由于必須在容器的本地網(wǎng)絡(luò)和主機的橋接網(wǎng)絡(luò)之間發(fā)生的網(wǎng)絡(luò)地址轉(zhuǎn)換 (NAT),這確實會導(dǎo)致延遲。在之前引用的同一 IBM 研究中,研究人員發(fā)現(xiàn) Docker 的 NAT 將來自客戶端的 100 字節(jié)請求和來自應(yīng)用程序的 200 字節(jié)響應(yīng)的延遲從大約 35 微秒增加到 70 微秒。
另一方面,橋接網(wǎng)絡(luò)很有用,因為它們允許您將容器組隔離到容器網(wǎng)絡(luò)中,并且僅將其中一些容器暴露給主機,這對于減少主機網(wǎng)絡(luò)所需的 IP 地址數(shù)量非常方便(想想運行數(shù)百甚至數(shù)千個容器所需的 IP 數(shù)量)。如果您有興趣了解有關(guān) Docker 中網(wǎng)絡(luò)如何工作的更多信息,可以在 YouTube 上觀看 Docker 團隊提供的深入探討。
如果您需要非常低的延遲,您可以切換到使用 Docker 的主機網(wǎng)絡(luò)功能,它允許您的容器與主機共享相同的網(wǎng)絡(luò),從而無需 NAT。再說一次,如果你想運行 Docker Swarm 或 Kubernetes,它們使用覆蓋網(wǎng)絡(luò),對于不同的網(wǎng)絡(luò)驅(qū)動程序,如 Project Calico 和 Cilium 有解決方案,本篇文章文章并不涉及該怎么做。
簡而言之,除非您需要非常低的延遲,否則您應(yīng)該堅持使用默認的橋接網(wǎng)絡(luò)選項。請務(wù)必對其進行測試,看看您是否達到了所需的吞吐量。
3使用 Docker 的安全考慮
您可能會擔心許多 Docker 容器以 root 身份運行他們的服務(wù),而這個 root 用戶與主機系統(tǒng)上的 root 用戶相同。對容器突破的擔憂是合理的。HAProxy 也以 root 身份運行。但是,讓您放心:HAProxy 需要 root 訪問權(quán)限,因為它需要綁定到受限制的 TCP 端口,如 80 和 443。但是,一旦完成啟動,它就會放棄其 root 權(quán)限并以非特權(quán)用戶身份運行。
人們還會權(quán)衡容器可能是惡意的風險。這是堅持使用由 HAProxy Technologies 制作的 haproxytech Docker 鏡像的一個很好的理由。
4使用 Docker 運行 HAProxy
我們將創(chuàng)建一個 Web 應(yīng)用程序的三個實例、一個 HAProxy 實例和一個將它們連接在一起的橋接網(wǎng)絡(luò)。因此,一旦您安裝了 Docker,請使用以下命令在 Docker 中創(chuàng)建一個新的橋接網(wǎng)絡(luò):
- $ sudo docker network create --driver=bridge mynetwork
然后使用該 docker run 命令創(chuàng)建并運行 Web 應(yīng)用程序的三個實例。在此示例中,我使用 Docker 鏡像 jmalloc/echo-server https://hub.docker.com/r/jmalloc/echo-server。這是一個簡單的 Web 應(yīng)用程序,可返回您發(fā)送給它的 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
請注意,我們?yōu)槊總€服務(wù)分配了一個唯一名稱并將其附加到我們創(chuàng)建的橋接網(wǎng)絡(luò)。您現(xiàn)在應(yīng)該運行了三個 Web 應(yīng)用程序,您可以通過調(diào)用以下 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
這些容器監(jiān)聽自己的端口 8080,但我們沒有將這些端口映射到主機,因此它們不可路由。我們將通過 HAProxy 負載均衡器將流量中繼到這些容器。接下來,讓我們在它們前面添加 HAProxy。在當前目錄中創(chuàng)建一個名為 haproxy.cfg 的文件,并在其中添加以下內(nèi)容:
- 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
需要注意的幾點:
- 在該 global 部分中,該 stats socket 行啟用了 HAProxy 運行時 API,還啟用了 HAProxy 的無縫重新加載。
- 第一個前端監(jiān)聽端口 8404 并啟用 HAProxy Stats 儀表板,該儀表板顯示有關(guān)您的負載均衡器的實時統(tǒng)計信息。
- 另一個前端監(jiān)聽端口 80,并將請求分派到 Web 服務(wù)器后端中列出的三個 Web 應(yīng)用程序之一。
- 我們沒有使用每個 Web 應(yīng)用程序的 IP 地址,而是使用它們的主機名 web1、web2 和 web3。當您像我們一樣創(chuàng)建 Docker 橋接網(wǎng)絡(luò)時,您也可以使用這種基于 DNS 的路由。
接下來,創(chuàng)建并運行一個 HAProxy 容器,并通過包含-p 參數(shù)將其端口 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 之后調(diào)用顯示 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 應(yīng)用程序。每個對它的請求都將由 HAProxy 進行負載平衡。此外,您可以在http://localhost:8404看到 HAProxy Stats 頁面。
如果您對 haproxy.cfg 文件進行了更改,則可以通過調(diào)用以下 docker kill 命令重新加載負載均衡器,而不會損失流量:
- $ sudo docker kill -s HUP haproxy
要刪除容器和網(wǎng)絡(luò),運行 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
5總結(jié)
在這篇博文中,您了解了如何在 Docker 容器內(nèi)運行 HAProxy 簡化其部署和生命周期管理。Docker 提供了一種用于部署應(yīng)用程序的標準化方法,使該過程具有可重復(fù)性和可測試性。雖然運行 Docker 的 CPU 開銷可以忽略不計,但它可能會導(dǎo)致額外的網(wǎng)絡(luò)延遲,但其影響取決于您的場景和吞吐量需求。
要運行 HAProxy,只需創(chuàng)建一個 HAProxy 配置文件,然后使用 docker run 命令調(diào)用 HAProxy Docker 鏡像的名稱。HAProxy Technologies 在 Docker Hub 上提供最新的 Docker 鏡像。


























