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

How to properly configure HAProxy in Docker Swarm to automatically route traffic to replicated services (via SSL)?

我正在尝试部署一个 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

我的haproxy.cfg(基于official example):

# 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

我的主机是 Lightsail VPS Ubuntu 个实例并且共享同一个私有网络。


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

我现在尝试使这项工作的方式是 ssh 进入 manager 节点(它也有一个静态和 public IP),从上面复制我的配置文件,然后 运行:

docker stack deploy --compose-file=docker-compose.yml hackathon-2021

但是没用。

嗯,首先关于 SSL(因为这是你提到的第一件事)你需要使用证书配置它并监听端口 443, 不是端口 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

这将是允许 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

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

如果您检查我们在做什么,我们正在 node-server 服务中为 Swarm 中的每个发现的容器创建一个服务器(因此是副本),我们将创建那些添加前缀 node-给他们每个人。

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


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

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

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

记得在部署 Stack 之前将您的 haproxy.cfg 和应用程序的自签名(或真实)证书复制到实例。

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