首页 > 解决方案 > Django+Vuejs+Gunicorn+Nginx 的 Docker 配置导致 502 Bad Gateway

问题描述

语境

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

最终,它将通过 RDS(DB)、S3(存储)和 ECS(容器服务)等服务部署在 AWS 上。

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

在此处输入图像描述

我的应用程序在没有 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

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

在此处输入图像描述

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

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

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

标签: djangoamazon-web-servicesdockervue.jsamazon-ecs

解决方案


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

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

这是我用于这些实验的演示应用程序,它模仿了您的应用程序。docker-compose 的这个应用程序的文件如下所示:

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 与 ECS 的集成以及docker compose up您的应用程序直接进入 ECS。

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


推荐阅读