如何在 Docker Swarm 中正确配置 HAProxy 以自动将流量路由到复制服务(通过 SSL)?

Jan*_*har 0 haproxy docker docker-compose docker-swarm

我正在尝试部署具有单个复制服务的三个主机节点的 Docker Swarm,并在其前面放置一个 HAProxy。我希望客户端能够通过 SSL 进行连接。

我的docker-compose.yml

version: '3.9'

services:
  proxy:
    image: haproxy
    ports:
      - 443:8080
    volumes:
      - haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg
    deploy:
      placement:
        constraints: [node.role == manager]
    networks:
      - servers-network
  node-server:
    image: glusk/hackathon-2021:latest
    ports:
      - 8080:8080
    command: npm run server
    deploy:
      mode: replicated
      replicas: 2
    networks:
      - servers-network
networks:
  servers-network:
    driver: overlay
Run Code Online (Sandbox Code Playgroud)

我的haproxy.cfg(基于官方示例):

# Simple configuration for an HTTP proxy listening on port 80 on all
# interfaces and forwarding requests to a single backend "servers" with a
# single server "server1" listening on 127.0.0.1:8000
global
    daemon
    maxconn 256

defaults
    mode http
    timeout connect 5000ms
    timeout client 50000ms
    timeout server 50000ms

frontend http-in
    bind *:80
    default_backend servers

backend servers
    server server1 127.0.0.1:8000 maxconn 32
Run Code Online (Sandbox Code Playgroud)

我的主机是 Lightsail VPS Ubuntu 实例并共享相同的专用网络。


node-service在其自己的容器内运行每个 https 服务器任务:0.0.0.0:8080

我目前尝试执行此操作的方法是ssh进入管理器节点(它也有一个静态和公共 IP),从上面复制我的配置文件,然后运行:

docker stack deploy --compose-file=docker-compose.yml hackathon-2021
Run Code Online (Sandbox Code Playgroud)

但它不起作用。

Dan*_*res 5

好吧,首先,关于SSL(因为这是您提到的第一件事),您需要使用证书配置它并侦听 port 443,而不是 port 80

通过该修改,您的代理配置已更改为:

global
    daemon
    maxconn 256

defaults
    mode http
    timeout connect 5000ms
    timeout client 50000ms
    timeout server 50000ms

frontend http-in
    bind *:80
    default_backend servers

frontend https-in
    bind *:443 ssl crt /etc/ssl/certs/hackaton2021.pem
    default_backend servers
Run Code Online (Sandbox Code Playgroud)

这将是允许SSL连接的真正简化的配置。


现在,让我们来访问不同的服务。

首先,您无法访问 上的服务localhost,实际上您甚至不应该向主机公开您拥有的服务的端口。原因?您已经在与 相同的网络中拥有这些应用程序haproxy,因此理想的情况是利用 Docker DNS 直接访问它们

为此,首先我们需要能够解析服务名称。为此,您需要将以下部分添加到您的配置中:

resolvers docker
    nameserver dns1 127.0.0.11:53
    resolve_retries 3
    timeout resolve 1s
    timeout retry   1s
    hold other      10s
    hold refused    10s
    hold nx         10s
    hold timeout    10s
    hold valid      10s
    hold obsolete   10s
Run Code Online (Sandbox Code Playgroud)

Docker Swarm DNS 服务始终可用127.0.0.11

现在,对于您之前的现有配置,我们必须添加服务器,但使用服务名称发现:

backend servers
    balance roundrobin
    server-template node- 2 node-server:8080 check resolvers docker init-addr libc,none
Run Code Online (Sandbox Code Playgroud)

如果你检查一下我们正在做的事情,就会发现我们正在为服务中 Swarm 中发现的每个容器(即副本)创建一个服务器,并且我们将创建那些为每个容器node-server添加前缀的服务器。node-

基本上,这相当于获取每个副本的实际 IP 并将它们添加为基本server配置。


对于部署,您还会遇到一些错误,因为我们不感兴趣实际将端口公开node-server给主机,而是创建两个副本并使用 HAProxy 进行网络。

为此,我们应该使用以下 Docker Compose:

version: '3.9'

services:
  proxy:
    image: haproxy
    ports:
      - 80:80
      - 443:443
    volumes:
      - hackaton2021.pem:/etc/ssl/certs/hackaton2021.pem
      - haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg
    deploy:
      placement:
        constraints: [node.role == manager]

  node-server:
    image: glusk/hackathon-2021:latest
    command: npm run server
    deploy:
      mode: replicated
      replicas: 2
Run Code Online (Sandbox Code Playgroud)

haproxy.cfg请记住在部署堆栈之前将应用程序的自签名(或真实)证书复制到实例。

此外,当您创建该堆栈时,它会自动创建一个名为 的网络<STACK_NAME>-default,因此您不需要仅为连接这两个服务而定义网络。