【问题标题】:Django serve multiple domains with a single instanceDjango 使用单个实例服务多个域
【发布时间】:2016-08-26 19:53:48
【问题描述】:

为了节省成本并充分利用我所购买的硬件,我想使用单个 Django 实例在多个域/子域上提供我的企业应用程序。用于给定请求的数据库取决于发出请求的域。否则,提供给每个域/子域的唯一区别可以通过 Django 配置文件轻松控制。

如何使用单个 Django 实例执行此操作?

附加信息:我计划使用带有 gunicorn 的 nginx 进行部署。

编辑:“单个 Django 实例”是指只有一个实例化的 Django 实例。我想避免在同一台机器上运行相同的 Django 代码五次,以便为五个主机提供服务。

【问题讨论】:

  • 您应该查看网站文档; docs.djangoproject.com/en/1.9/ref/contrib/sites
  • 我已经检查过了,但它似乎使用单个数据库实例。我可以看到这在某些情况下很有用,但在我的情况下,出于多种原因,我需要将每个主机的数据保存在单独的数据库中,其中最重要的是我需要独立的数据库备份。
  • 出于兴趣,您最终采用了哪种方法?我正在考虑做一些非常相似的事情,但我不确定自己该走哪条路。

标签: django nginx web-hosting gunicorn


【解决方案1】:

请弄清楚你是否可以试试这个。

在中间件模块中,检查主机名是什么。根据主机名设置数据库。

import socket

try:
    hostname = socket.gethostname()
except:
    hostname = 'default'

if hostname == 'site1.com':

  DATABASES = {
      'default': {
          'ENGINE': 'django.db.backends.mysql',
          'NAME': 'site1DB',
          'USER': 'root',
          'PASSWORD': '*****',
          'HOST': 'localhost',   
          'PORT': '3306',
      }
  }


elif hostname == 'site2.com':

  DATABASES = {
      'default': {
          'ENGINE': 'django.db.backends.mysql',
          'NAME': 'site2DB',
          'USER': 'root',
          'PASSWORD': '*****',
          'HOST': 'localhost',   
          'PORT': '3306',
      }
  }

如果 Django 路由器 (https://docs.djangoproject.com/ja/1.9/topics/db/multi-db/) 有帮助,也请。

【讨论】:

  • 这看起来很有趣。我将不得不对其进行深入研究,以查看基于主机名的设置是否存在任何性能问题,但这绝对看起来很有希望。
  • 这会扼杀数据库连接池的好处吗?
  • @adam,多个 DB(路由器)是 Django 本身的一部分(所以我假设连接池问题已经解决)。但路由器略有不同。但我总是推荐使用 Django 路由器。我相信我们可以在 current_url 站点上切换基于数据库(在中间件中)。
【解决方案2】:

您有几个选择,这实际上取决于您要实现的目标。

有这个 Django 应用程序https://github.com/bernardopires/django-tenant-schemas,您可以在其中设置多个数据库模式并根据子域处理请求。不过我没试过。


实际上我曾经遇到过类似的问题。我需要我的应用程序的 7 个独立实例,用于可用性实验,我不想添加任何额外的依赖项,因为它是临时的。

我在 Ubuntu 服务器中克隆了我的存储库,并在那里创建了 7 个不同的数据库(db_1、db_2、...、db_7)并创建了 7 个设置文件:

settings_1.py

from django_app.settings import *

ENVIRONMENT_NAME = 'Test Environment 1'

DATABASES = {
    'default': dj_database_url.config(
        default = 'postgres://u_db:123@localhost:5432/db_1' 
    )
}

MEDIA_ROOT = PROJECT_DIR.parent.parent.child('media').child('_1')

settings_2.py

from django_app.settings import *

ENVIRONMENT_NAME = 'Test Environment 2'

DATABASES = {
    'default': dj_database_url.config(
        default = 'postgres://u_db:123@localhost:5432/db_2' 
    )
}

MEDIA_ROOT = PROJECT_DIR.parent.parent.child('media').child('_2')

等等...基本上我是在导入我的项目设置并覆盖我需要的参数,即数据库

然后,我为我的每个环境创建了一个 gunicorn_start 脚本:

gunicorn_start_1

#!/bin/bash

NAME="django_app_1"
DJANGODIR=/opt/django_app/django_app
SOCKFILE=/opt/django_app/run/gunicorn_1.sock
USER=app_user
GROUP=django_apps
NUM_WORKERS=3
DJANGO_SETTINGS_MODULE=django_app.settings_1
DJANGO_WSGI_MODULE=django_app.wsgi

cd $DJANGODIR
source ../bin/activate
export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE
export PYTHONPATH=$DJANGODIR:$PYTHONPATH

RUNDIR=$(dirname $SOCKFILE)
test -d $RUNDIR || mkdir -p $RUNDIR

exec ../bin/gunicorn ${DJANGO_WSGI_MODULE}:application \
  --name $NAME \
  --workers $NUM_WORKERS \
  --user=$USER --group=$GROUP \
  --bind=unix:$SOCKFILE \
  --log-level=error \
  --log-file=-

gunicorn_start_2

#!/bin/bash

NAME="django_app_2"
DJANGODIR=/opt/django_app/django_app
SOCKFILE=/opt/django_app/run/gunicorn_2.sock
USER=app_user
GROUP=django_apps
NUM_WORKERS=3
DJANGO_SETTINGS_MODULE=django_app.settings_2
DJANGO_WSGI_MODULE=django_app.wsgi

cd $DJANGODIR
source ../bin/activate
export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE
export PYTHONPATH=$DJANGODIR:$PYTHONPATH

RUNDIR=$(dirname $SOCKFILE)
test -d $RUNDIR || mkdir -p $RUNDIR

exec ../bin/gunicorn ${DJANGO_WSGI_MODULE}:application \
  --name $NAME \
  --workers $NUM_WORKERS \
  --user=$USER --group=$GROUP \
  --bind=unix:$SOCKFILE \
  --log-level=error \
  --log-file=-

其余的都做了同样的事情。

每个实例都有自己的 nginx 配置文件:

app_1(nginx 配置)

upstream app_server_1 {
  server unix:/opt/django_app/run/gunicorn_1.sock fail_timeout=0;
}

server {
    listen   80;
    server_name env1.mydomain.com;
    client_max_body_size 4G;

    access_log /opt/django_app/logs/nginx-access_1.log;
    error_log /opt/django_app/logs/nginx-error_1.log;

    location /static/ {
        alias   /opt/django_app/static/;
    }

    location /media/ {
        alias   /opt/django_app/media/_1/;
    }

    location / {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        if (!-f $request_filename) {
            proxy_pass http://app_server_1;
            break;
        }
    }

}

app_2(nginx 配置)

upstream app_server_2 {
  server unix:/opt/django_app/run/gunicorn_2.sock fail_timeout=0;
}

server {
    listen   80;
    server_name env2.mydomain.com;
    client_max_body_size 4G;

    access_log /opt/django_app/logs/nginx-access_2.log;
    error_log /opt/django_app/logs/nginx-error_2.log;

    location /static/ {
        alias   /opt/django_app/static/;
    }

    location /media/ {
        alias   /opt/django_app/media/_2/;
    }

    location / {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_redirect off;
        if (!-f $request_filename) {
            proxy_pass http://app_server_2;
            break;
        }
    }

}

之后,我为每个实例配置了一个主管,并配置了我的域的 DNS。

所以基本上我有一个共享的 Django 源代码和静态文件,以及独立的媒体文件夹、日志文件和数据库。


可能这不是最好的方法,但我设法实现了我当时需要的东西

【讨论】:

  • 当您有多个 gunicorn 配置、nginx 配置等时,您最终会遇到多个运行相同代码的进程。如果这是最好的方法,我会使用它,但我更愿意将所有主机指向同一个运行实例以节省服务器容量。
猜你喜欢
  • 2011-03-15
  • 1970-01-01
  • 2013-04-07
  • 2013-01-09
  • 2023-03-07
  • 1970-01-01
  • 1970-01-01
  • 2017-03-12
  • 2012-12-02
相关资源
最近更新 更多