6

我正在使用 docker compose 构建一个以 django、nginx 作为服务的项目。当我启动 daphne 服务器并且客户端尝试连接到 websocket 服务器时,我收到此错误:

*1 recv() failed (104: Connection reset by peer) while reading response header from upstream

客户端显示这个

failed: Error during WebSocket handshake: Unexpected response code: 502

这是我的 docker-compose.yml

version: '3'
services:
  nginx:
    image: nginx
    command: nginx -g 'daemon off;'
    ports:
      - "1010:80"
    volumes:
      - ./config/nginx/nginx.conf:/etc/nginx/nginx.conf
      - .:/makeup
    links:
      - web
  web:
    build: .
    command: /usr/local/bin/circusd /makeup/config/circus/web.ini
    environment:
      DJANGO_SETTINGS_MODULE: MakeUp.settings
      DEBUG_MODE: 1
    volumes:
      - .:/makeup
    expose:
      - '8000'
      - '8001'
    links:
      - cache
    extra_hosts:
      "postgre": 100.73.138.65

Nginx:

server {
        listen 80;
        server_name thelab518.cloudapp.net;

        keepalive_timeout 15;
        root /makeup/;

        access_log /dev/stdout;
        error_log /dev/stderr;

        location /api/stream {
            proxy_pass http://web:8001;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";

            proxy_redirect     off;
            proxy_set_header   Host $host;
            proxy_set_header   X-Real-IP $remote_addr;
            proxy_set_header   X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_set_header   X-Forwarded-Host $server_name;
        }


location / {
        try_files $uri @proxy_to_app;
    }

    location @proxy_to_app {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Host $server_name;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        proxy_pass http://web:8000;
    }

马戏团的 web.ini 文件:

[watcher:web]
cmd = /usr/local/bin/gunicorn MakeUp.wsgi:application -c config/gunicorn.py
working_dir = /makeup/
copy_env = True
user = www-data

[watcher:daphne]
cmd = /usr/local/bin/daphne -b 0.0.0.0 -p 8001 MakeUp.asgi:channel_layer
working_dir = /makeup/
copy_env = True
user = root

[watcher:worker]
cmd = /usr/bin/python3 manage.py runworker
working_dir = /makeup/
copy_env = True
user = www-data
4

2 回答 2

1

看起来你盯着daphne端口 8001,并试图在 docker-compose 中暴露端口 8000 和 8001。端口 8000 未指向任何服务器(daphne位于 8001 上)。在您的 nginx 中,请将代理设置为 8001 端口,并在 docker-compose 中仅公开端口 8001。

我创建了一个简单的示例,如何在github上设置它,我有代理到 asgi 和 wsgi 服务器,但你只能使用 asgi 服务器:

nginx:

upstream app {
    server wsgiserver:8000;
}

upstream ws_server {
    server asgiserver:9000;
}


server {
    listen 8000 default_server;
    listen [::]:8000;

    client_max_body_size 20M;

    location / {
        try_files $uri @proxy_to_app;
    }

    location /tasks {
        try_files $uri @proxy_to_ws;
    }

    location @proxy_to_ws {
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_redirect off;

        proxy_pass   http://ws_server;
    }

    location @proxy_to_app {
        proxy_set_header X-Forwarded-Proto https;
        proxy_set_header X-Url-Scheme $scheme;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;

        proxy_pass   http://app;
    }

}

docker-compose.yml:

version: '2'

services:
    nginx:
        extends:
            file: docker-common.yml
            service: nginx
        ports:
            - 8000:8000
        volumes:
            - ./docker/nginx/default.conf:/etc/nginx/conf.d/default.conf
        volumes_from:
            - asgiserver
   asgiserver:
        extends:
            file: docker-common.yml
            service: backend
        entrypoint: /app/docker/backend/asgi-entrypoint.sh
        links:
            - postgres
            - redis
            - rabbitmq
        expose:
            - 9000
    wsgiserver:
        extends:
            file: docker-common.yml
            service: backend
        entrypoint: /app/docker/backend/wsgi-entrypoint.sh
        links:
            - postgres
            - redis
            - rabbitmq
        expose:
            - 8000        
于 2018-10-25T10:50:01.620 回答
1

正如精美手册中明确指出的那样,要成功运行 Channels,您需要有一个实现 ASGI 协议的专用应用程序服务器,例如提供的daphne

整个 Django 执行模型已经通过 Channels 进行了更改,因此有单独的“接口服务器”负责接收和发送消息,例如,WebSockets 或 HTTP 或 SMS,以及运行实际代码的“工作服务器”(可能在不同的服务器或虚拟机或容器上或...)。两者通过一个“通道层”连接,该通道层来回传递消息和回复。

当前的实现提供了 3 个通道层,它们在接口服务器和工作服务器之间讨论 ASGI:

  • 内存通道层,主要用于运行测试服务器(它是单进程)
  • 基于 IPC 的通道层,可用于在同一台服务器上运行不同的工作人员
  • 一个基于 redis 的通道层,应该用于重型生产站点,能够将接口服务器连接到多个工作服务器。

您可以像对 DATABASES:: 一样配置它们

CHANNEL_LAYERS = {
    "default": {
        "BACKEND": "asgi_redis.RedisChannelLayer",
        "ROUTING": "my_project.routing.channel_routing",
        "CONFIG": {
            "hosts": [("redis-channel-1", 6379), ("redis-channel-2", 6379)],
        },
    },
}

当然,这意味着您的 docker 配置必须更改并添加一个或多个接口服务器,而不是或除此之外nginx(即使在这种情况下,您需要在不同端口上接受所有已连接的 websocket 连接)可能的问题),并且很可能是一个 redis 实例连接所有这些。

这反过来意味着在 circus 和 nginx 可以支持 ASGI 之前,不可能将它们与 django-channels 一起使用,或者这种支持仅适用于系统的常规 http 部分。

您可以在官方文档的部署部分找到更多信息。

于 2017-04-12T05:30:57.517 回答