当前位置: 首页 > 科技观察

如何在Docker中优雅地运行高性能负载均衡器HAProxy

时间:2023-03-21 15:03:21 科技观察

可以将HAProxy作为Docker容器运行吗?是的!我还需要问吗?随着Docker无处不在,你会发现许多应用程序都被Dockerized;HAProxy负载均衡器也不例外,但这正是HAProxy的诞生目的。作为在Linux上运行的独立服务,将其移植到Docker似乎很自然。为什么要在Docker容器内运行负载均衡器?这样做会有性能折扣吗?它会引入任何安全问题吗?在这篇博文中,您将了解为什么应该考虑在容器内运行HAProxy以及可能的后果。然后你会看到如何去做。请注意,我们描述的是如何运行HAProxy,而不是HAProxyKubernetesIngressController。HAProxyTechnologies在其命名空间haproxytech下构建了自己的Docker镜像集。这些会定期更新最新的补丁和安全更新。我将在这篇博文中使用这些图片。您可以在这里找到它们:HAProxy(AlpineLinux基础)-https://hub.docker.com/r/haproxytech/haproxy-alpineHAProxy(Ubuntu基础)-https://hub.docker.com/r/haproxytech/haproxy-ubuntuHAProxy(Debianbase)-https://hub.docker.com/r/haproxytech/haproxy-debian我演示的命令是在Linux工作站上执行的,如果你使用的是DockerDesktopforWindows或DockerDesktop它也适用于Mac。1使用Docker的好处您是否希望能够在不编译、安装依赖项或以其他方式更改系统的情况下运行HAProxy?Docker容器带来了相当大的好处,其中最主要的是安装和执行的操作更少。Docker允许您将容器放到主机系统上并立即获得正在运行的服务——无需安装脚本,无需安装C库。该服务完全包含在容器中,您需要做的就是启动它,然后将TCP端口映射到它。部署容器时,您无需在主机系统上实际安装即可运行完整的应用程序及其运行时环境。生命周期管理也已标准化。启动、停止和删除容器就像调用单行docker命令一样简单。这反过来又使部署成为一个可重复和可测试的过程。它还有助于更轻松地进行软件升级。2使用Docker的性能影响您希望负载均衡器快速运行而不增加环境延迟。那么,问题是,在容器内运行HAProxy意味着什么?在CPU开销方面,请记住,与虚拟机不同,Docker不需要在主机操作系统之上的虚拟化层。容器在主机的内核上运行,基本上只是另一个进程,尽管它与主机上运行的其他进程有更好的隔离(它使用命名空间来实现这一点)。IBM研究人员的一项研究发现使用Docker的CPU开销可以忽略不计也就不足为奇了。网络是另一回事。默认情况下,Docker允许您通过创建到主机的桥接网络来访问容器内运行的服务。由于必须在容器的本地网络和主机的桥接网络之间发生网络地址转换(NAT),这确实会引入延迟。在前面引用的同一项IBM研究中,研究人员发现Docker的NAT将来自客户端的100字节请求和来自应用程序的200字节响应的延迟从大约35微秒增加到70微秒。另一方面,桥接网络很有用,因为它们允许您将容器组隔离到容器网络中,并仅将其中的一部分暴露给主机,这对于减少主机网络所需的IP地址数量很方便(想想数字数百甚至数千个容器所需的IP)。如果您有兴趣详细了解Docker中网络的工作原理,可以在YouTube上观看Docker团队的深入讨论。如果您需要非常低的延迟,您可以切换到使用Docker的主机网络功能,它允许您的容器与主机共享同一网络,而无需NAT。同样,如果你想运行使用覆盖网络的DockerSwarm或Kubernetes,有针对不同网络驱动程序的解决方案,如ProjectCalico和Cilium,本文不是关于如何做到这一点的。简而言之,除非您需要非常低的延迟,否则您应该坚持使用默认的桥接网络选项。请务必对其进行测试以查看是否达到了所需的吞吐量。3使用Docker的安全注意事项您可能担心许多Docker容器以root身份运行其服务,即与主机系统上的root用户相同的root用户。对容器破裂的担忧是有道理的。HAProxy也以root身份运行。但是,请放心:HAProxy需要root访问权限,因为它需要绑定到受限的TCP端口,例如80和443。但是,一旦完成启动,它就会放弃其root权限并以非特权用户身份运行。人们还权衡了容器可能是恶意的风险。这是坚持使用HAProxyTechnologies制作的haproxytechDocker镜像的一个很好的理由。4.使用Docker运行HAProxy我们将创建一个Web应用程序的三个实例,一个HAProxy实例,以及将它们连接在一起的桥接网络。因此,安装Docker后,使用以下命令在Docker中创建一个新的桥接网络:$sudodockernetworkcreate--driver=bridgemyne??twork然后使用dockerrun命令创建并运行web应用程序的三个实例。在此示例中,我使用Docker映像jmalloc/echo-serverhttps://hub.docker.com/r/jmalloc/echo-server。这是一个简单的Web应用程序,可返回您发送给它的HTTP请求的详细信息。$sudodockerrun-d\--nameweb1--netmynetworkjmalloc/echo-server:latest$sudodockerrun-d\--nameweb2--netmynetworkjmalloc/echo-server:latest$sudodockerrun-d\--nameweb3--netmynetworkjmalloc/echo-server:latest请注意,我们为每个服务分配了一个唯一的名称并将其附加到我们创建的桥接网络。您现在应该有三个正在运行的Web应用程序,您可以通过调用以下dockerps命令来验证它们:echo-server"AboutamuteagoUpAboutaminute8080/tcpweb2554fafbc2b3bjmalloc/echo-server:latest"/bin/echo-server"AboutamuteagoUpAboutaminute8080/tcpweb1这些容器监听自己的8080端口,但是我们没有把这些端口映射到主机,所以它们是不可路由的。我们会通过HAProxy负载均衡器将流量中继到这些容器,接下来我们在它们前面添加HAProxy。在当前目录中创建一个名为haproxy.cfg的文件,并在其中添加以下内容:globalstatssocket/var/run/api.sockuserhaproxygrouphaproxymode660leveladminexpose-fdlistenerslogstdoutformatrawlocal0infodefaultsmodehttptimeoutclient10stimeoutconnect5stimeoutserver10stimeouthttp-request10slogglobalfrontendstatsbind*:8404statsenablestatsuri/statsrefresh10sfrontendmyfrontendbind:80default_backendwebserversbackendwebserversservers1web1:8080checkservers2web2:8080checkservers3web3:8080check需要注意的几点:在global部分,statssocket这一行启用了HAProxyruntimeAPI,同时也启用了HAProxy的seamlessreload。第一个前端侦听端口8404并启用HAProxyStats仪表板,该仪表板显示有关负载均衡器的实时统计信息。另一个前端侦听端口80并将请求分派到Web服务器后端中列出的三个Web应用程序之一。我们不使用每个Web应用程序的IP地址,而是使用它们的主机名web1、web2和web3。当您像我们一样创建Docker桥接网络时,您也可以使用这种基于DNS的路由。接下来,创建并运行一个HAProxy容器,并通过包含-p参数将其端口80映射到主机上的同一端口。还要为HAProxy统计页面映射端口8404:$sudodockerrun-d\--namehaproxy\--netmynetwork\-v$(pwd):/usr/local/etc/haproxy:ro\-p80:80\-p8404:8404\haproxytech/haproxy-alpine:2.4在dockerps调用后显示HAProxy正在运行:$sudodockerpsCONTAINERIDIMAGECOMMANDCREATEDSTATUSPORTSNAMESd734d0ef2635haproxytech/haproxy-alpine:2.4"/docker-entrypoint.…"3secondsagoUp2seconds0.0.0.0:80->80/t8404->8404/tcphaproxy您可以通过http://localhost访问echo-serverWeb应用程序。对它的每个请求都将由HAProxy进行负载平衡。此外,您还可以在http://localhost:8404查看HAProxyStats页面。如果您对haproxy.cfg文件进行了更改,则可以通过调用以下dockerkill命令重新加载负载均衡器而不会丢失流量:$sudodockerkill-sHUPhaproxy要删除容器和网络,请运行dockerstop、dockerrm和dockernetworkrm命令:$sudodockerstopweb1&&sudodockerrmweb1$sudodockerstopweb2&&sudodockerrmweb2$sudodockerstopweb3&&sudodockerrmweb3$sudodockerstophaproxy&&sudodockerrmhaproxy$sudodockernetworkrmmynetwork5在这篇博文中,您了解了如何在Docker容器中运行HAProxy来简化其部署和生命周期管理。Docker提供了一种用于部署应用程序的标准化方法,使该过程可重复和可测试。虽然运行Docker的CPU开销可以忽略不计,但它可能会导致额外的网络延迟,但其影响取决于您的场景和吞吐量需求。要运行HAProxy,只需创建一个HAProxy配置文件,然后使用dockerrun命令调用HAProxyDocker镜像的名称。HAProxyTechnologies在DockerHub上提供最新的Docker镜像。