Docker Swarm 中用于 Django 容器的反向代理和 SSL 证书的 Nginx 容器的实现

Implementation of Nginx Container for Reverse Proxying and SSL certificates for Django Containers inside Docker Swarm

我想用 Docker Swarm 部署 Django 应用程序。 我一直在关注 this guide,它不使用 docker swarm 也不使用 docker-compose,并且专门为 SSL 证书创建了两个 Django 容器、一个 Nginx 容器和一个 Certbot 容器。 Nginx 容器反向代理和负载平衡在两个服务器中的两个 Django 容器之间使用它们的 IP

upstream django {
    server APP_SERVER_1_IP;
    server APP_SERVER_2_IP;
}

server {
    listen 80 default_server;
    return 444;
}

server {
    listen 80;
    listen [::]:80;
    server_name your_domain.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name your_domain.com;

    # SSL
    ssl_certificate /etc/letsencrypt/live/your_domain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/your_domain.com/privkey.pem;

    ssl_session_cache shared:le_nginx_SSL:10m;
    ssl_session_timeout 1440m;
    ssl_session_tickets off;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers off;

    ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384";

    client_max_body_size 4G;
    keepalive_timeout 5;

        location / {
          proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
          proxy_set_header X-Forwarded-Proto $scheme;
          proxy_set_header Host $http_host;
          proxy_redirect off;
          proxy_pass http://django;
        }

    location ^~ /.well-known/acme-challenge/ {
        root /var/www/html;
    }



}

我想实现所有这些相同的功能,但使用 Docker Swarm 以便我可以使用一个命令扩展容器 docker service update --replicas 3 <servicename>

问题是我无法理解如何在这种情况下使用 Nginx 容器,Docker Swarm 提供了它的负载平衡,所以我不需要 Nginx,但 SSL 仍然需要 Nginx证书。那么我如何在 Swarm 中实现 Nginx,以便它为所有节点提供 SSL 证书并为 Django 容器提供反向代理? 我之前只使用 Nginx 进行反向代理,所以我不知道如何编写 Nginx conf 并使 Nginx 容器与 Django 容器一起工作,SSL 包含在 Docker Swarm 中。

####################
# docker-stack.yml #
####################
version: '3.7'
services:
    web:
      image: 127.0.0.1:5000/django-image
      deploy:
        replicas: 3
      command: gunicorn mydjangoapp.wsgi:application --bind 0.0.0.0:8000
      expose:
        - 8000
      depends_on:
        - nginx
    nginx:
      image: 127.0.0.1:5000/nginx-image
      deploy:
        replicas: 2
      ports:
        - 80:80
      depends_on:
        - web

nginx.conf,我用于编写指向一个 Django 容器的文件

upstream django {
    server web:8000; #web is name of django service
}

server {
    #SSL STUFF        
    listen 80;

    location / {
        proxy_pass http://django;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_redirect off;
    }

}

因此,在 nginx 和世界之间,您可以选择让 dockers 入口负载平衡到您的 nginx 实例,或使用外部负载平衡器。如果您有一组固定的外部负载均衡器指向的节点,那么

 nginx:
   image: 127.0.0.1:5000/nginx-image
   ports:
   - 443:443
   networks:
   - proxy
   deploy:
     mode: global
     placement:
       constraints:
       - node.labels.myorg.lb==true

并用myorg.lb=true

标记相应的节点

接下来,关于您的服务,docker 基本上有两种宣传复制服务的方式:vip 和 dnsrr。使用 vip 模式 - 默认 - docker 将为名称“web”分配一个 ip 地址 - 这是你给 nginx 副本的内容,然后它会在它们之间负载平衡流量。您可以将服务切换到 dnsrr 模式,在这种情况下,网络上的 dns 查询将是所有服务副本的当前 ips 的动态变化列表。或者,您可以使用显式名称 tasks.<service> 来获取相同的 dnsrr 条目。

现在。我不知道 nginx 是否支持开箱即用的 dnsrr 负载平衡。但我知道它会缓存条目很长时间,因此您需要使用具有较短刷新间隔的显式解析器 (127.0.0.11) 来设置 nginx。

  web:
    image: 127.0.0.1:5000/django-image
    command: gunicorn mydjangoapp.wsgi:application --bind 0.0.0.0:8000
    networks:
    - proxy
    deploy:
      replicas: 3
      endpoint_mode: dnsrr