【问题标题】:Docker configuration for Django+Vuejs+Gunicorn+Nginx lead to 502 Bad GatewayDjango+Vuejs+Gunicorn+Nginx 的 Docker 配置导致 502 Bad Gateway
【发布时间】:2021-10-22 19:10:19
【问题描述】:

上下文

我正在开发一个必须为每个客户部署一次的应用程序(它不是我的所有客户都会使用的多租户应用程序)。

最终,它将部署在 AWS 上,提供 RDS(数据库)、S3(存储)和 ECS(容器服务)等服务。

如果可以帮助回答我,您可以通过下图看到我的想象:

我的应用程序在没有 Docker 的情况下在本地运行良好。

但我想在尝试在 AWS 上部署它之前在本地使用它的 dockerized 版本,因为我希望能够在尝试在 AWS 上执行它之前使用 Docker 在本地运行它(...)。

由于我所有的客户都有自己的实例(有时 customer1 可能有与 customer2 不同的版本),所以我想到了一个包含所有需要的容器,如图所示:Django 应用程序、 Vue 构建的文件、gunicorn 和 nginx。

问题 1:这样做是个好主意吗?或者我应该使用具有多个服务(后端(django)和 nginx)的 docker-compose 东西。会导致多个容器吗?

问题

为此,我做了以下配置:

Dockerfile:

FROM node:lts-alpine as build-frontend-stage
WORKDIR /frontend
COPY ./frontend/package*.json /frontend/
RUN npm install
COPY ./frontend .
RUN npm run build

FROM python:3.8.10-slim as build-backend-stage
RUN apt-get update
RUN apt-get install --yes --no-install-recommends \
    g++ \
    libpq-dev \
    nginx
WORKDIR /backend
RUN pip install --upgrade pip
COPY ./backend/requirements.txt /backend
RUN pip install -r requirements.txt
COPY ./backend .
COPY --from=build-frontend-stage /frontend/dist/static /backend/static
COPY --from=build-frontend-stage /frontend/dist/index.html /backend/static
COPY ./docker-entrypoint.sh /backend
RUN ["chmod", "+x", "/backend/docker-entrypoint.sh"]
RUN rm -rf /etc/nginx/sites-available/default
RUN rm -rf /etc/nginx/sites-enabled/default
COPY ./nginx/nginx.config /etc/nginx/sites-available/
RUN ln -s /etc/nginx/sites-available/nginx.config /etc/nginx/sites-enabled

ENTRYPOINT ["bash", "/backend/docker-entrypoint.sh"]

这导致一个具有以下结构的容器:

ls -al

drwxr-xr-x 1 root root 4096 Oct 21 14:21 .
drwxr-xr-x 1 root root 4096 Oct 22 08:56 ..
drwxrwxr-x 1 root root 4096 Oct 22 08:56 backend
-rwxrwxr-x 1 root root  552 Oct 21 14:20 docker-entrypoint.sh
-rwxrwxr-x 1 root root  638 Oct  5 12:37 manage.py
-rw-rw-r-- 1 root root  115 Oct  5 10:05 requirements.txt
drwxr-xr-x 1 root root 4096 Oct 21 14:09 static

静态文件夹所在的位置:

ls -al static

drwxr-xr-x 1 root root 4096 Oct 21 14:09 .
drwxr-xr-x 1 root root 4096 Oct 21 14:21 ..
drwxr-xr-x 2 root root 4096 Oct 18 14:47 css
drwxr-xr-x 2 root root 4096 Oct 18 14:47 fonts
-rw-r--r-- 1 root root  773 Oct 18 14:47 index.html
drwxr-xr-x 2 root root 4096 Oct 18 14:47 js

我有一个这样的 nginx 配置:

upstream app_server {
    server unix:gunicorn.sock fail_timeout=0;
}

server {
    listen 80;

    root /backend/static;
    index index.html;
    include /etc/nginx/mime.types;

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

问题 2:我使用 gunicorn.sock 的东西。当我不这样做时,使用 0.0.0.0:8000 之类的东西,我通常甚至无法到达 nginx,它直接到达 gunicorn,不知道为什么......

我的 Docker-compose 是这样的:

version: "3.8"
services:
  web:
    network_mode: host
    env_file:
      - local.env
    build: .
    ports:
      - "8000:8000"

我的 local.env 文件有 env 变量,例如:

DB_HOST=127.0.0.1
DB_NAME=db_name
DB_PASSWORD=db_password
DB_PORT=5432
DB_USER=db_user
SECRET_KEY=some_django_secret_key

最后我的入口点是:

#!/bin/bash

DJANGO_SETTINGS_MODULE=backend.settings.production
DJANGO_WSGI_MODULE=backend.wsgi
SOCK_FILE=gunicorn.sock

export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE

echo Migrating...
python manage.py migrate --no-input


service nginx start
service nginx status
echo Sarting gunicorn...
gunicorn ${DJANGO_WSGI_MODULE}:application \
    --workers 3 \
    --bind=unix:$SOCK_FILE \
    --log-file=-

要开始这一切,我会这样做:

docker-compose -f ./docker-compose-dev.yml up

正确构建一切,gunicorn 启动:

web_1  | [2021-10-22 09:06:50 +0000] [53] [INFO] Starting gunicorn 20.0.4
web_1  | [2021-10-22 09:06:50 +0000] [53] [INFO] Listening at: unix:gunicorn.sock (53)
web_1  | [2021-10-22 09:06:50 +0000] [53] [INFO] Using worker: sync
web_1  | [2021-10-22 09:06:50 +0000] [55] [INFO] Booting worker with pid: 55
web_1  | [2021-10-22 09:06:50 +0000] [56] [INFO] Booting worker with pid: 56
web_1  | [2021-10-22 09:06:50 +0000] [57] [INFO] Booting worker with pid: 57

但是,当我尝试在浏览器中访问 127.0.0.1 时,除了来自 nginx 的 502 Bad Gateway 之外,我什么也得不到:

我不知道为什么。我想这一定是我的某种困惑..

问题 3:您能帮我弄清楚我的配置中的错误是什么,或者给我一些关于如何配置这种部署的指导(这里是本地的,而不是 AWS),或者关于如何找到源的一些指导错误?

提前感谢您的阅读。我在这些 devOps 方面真的很糟糕,任何帮助都将不胜感激。

【问题讨论】:

    标签: django amazon-web-services docker vue.js amazon-ecs


    【解决方案1】:

    您不想将所有内容都运行到单个容器中。一个容器应该只做一件事。你有几个选择。每个模块(nginx、app 等)运行一个容器,并将它们分组到一个 ECS 任务中。该任务是 ECS 中的一个部署和扩展单元,您可以使用 ECS 服务对其进行控制。因此,您可以为每位客户提供 1 个 ECS 服务,并从支持它的 1 个任务开始。如果您需要更多“功能”,ECS 会将您的单个任务扩展到 2 个任务(将所有容器加倍)。以此类推。

    第二种方法(架构更好,但可能更昂贵)是每个容器都有一个任务,因此总共有 3 个独立的任务包含在 3 个独立的服务中。然后,每个服务都可以自行扩展(例如,如果您需要更多 NGINX 容量,则只有 NGINX 任务将在 NGINX ECS 服务中扩展。如果采用这种方法,则每个客户需要 3 个服务(加上 db)。

    This is a demo application 我正在使用这些实验来模拟您的应用程序。我的docker-compose file for this application 看起来像这样:

    version: "3.0"
    services:
      yelb-ui:
        image: mreferre/yelb-ui:0.7
        depends_on:
          - yelb-appserver
        ports:
          - 80:80
        networks:
          - yelb-network
    
      yelb-appserver:
        image: mreferre/yelb-appserver:0.5
        depends_on:
          - redis-server
          - yelb-db
        networks:
          - yelb-network
    
      redis-server:
        image: redis:4.0.2
        networks:
          - yelb-network
        # uncomment the following lines if you want to persist redis data across deployments
        #volumes:
        # - redisdata:/data
    
      yelb-db:
        image: mreferre/yelb-db:0.5
        networks:
          - yelb-network
        # uncomment the following lines if you want to persist postgres data across deployments
        #volumes:
        #  - postgresqldata:/var/lib/postgresql/data
    
    networks:
      yelb-network:
        driver: bridge # a user defined bridge is required; the default bridge network doesn't support name resolution
    

    这就是您的应用程序在本地运行的方式。如果您想在 ECS 上运行它,您可以使用 Copilot 之类的工具,或者,如果您想继续使用 docker compose,您可以直接将新的 docker compose integration with ECSdocker compose up 应用到 ECS 中。

    这两种解决方案都将实现我所描述的第二种模式(每个任务 1 个容器)。如果您想要“任务中的所有容器”模式,您应该制作一个原生 CloudFormation 模板。

    【讨论】:

    • 感谢您的回答。好的,如果我理解正确,这意味着每个服务 1 个 dockerfile。在这里,我将拥有后端服务,使用我的 wsgi 应用程序运行 gunicorn。以及 nginx 服务,它将充当为我构建的 Vuejs 文件提供服务的反向代理。我想我在这里不需要 Vuejs 服务,因为它只是构建静态文件?同样在本地我不需要数据库服务,因为我可以将数据库设为本地?!我也不需要它用于 ECS,因为我会使用 AWS RDS 数据库。对吗?
    • 为了确保数据库会住在外面。是的,我的错,我不熟悉您使用的技术,但无论如何,请根据您需要运行的“进程”数量考虑一个单独的 dockerfile。我知道您至少需要 1 个用于 nginx 和 1 个用于 gunicorn/app。那将制作2个容器。更深入地看,部署此类应用程序的最常见模式似乎是使用单个任务,主 gunicorn 应用程序和 nginx 作为 sidecar(辅助容器)。例如,请参阅this
    • 好吧,我做得更好了。但我还有一个问题。由于我的 django 应用程序是 MVC,而我的 vuejs 应用程序是 SPA,所有 django 所要做的就是为每个 URL 提供构建的 vuejs index.html。但是既然 nginx 应该服务 de 静态文件,而不是 django (?),我应该如何组织呢?
    • 我猜 Django 不再需要提供 vuejs 文件,而只充当后端 api。虽然 nginx 不惜一切代价提供 vue 文件。
    • 这对 Django/Vue 的工作方式来说太过分了(我不熟悉)。
    猜你喜欢
    • 2016-04-20
    • 2014-04-30
    • 2023-03-20
    • 2016-01-04
    • 2016-03-26
    • 2019-01-22
    • 1970-01-01
    • 2020-09-01
    • 2020-06-12
    相关资源
    最近更新 更多