Обслуживание файлов мультимедиа Django через Nginx (Django / React / Nginx / Docker-Compose) - PullRequest
0 голосов
/ 27 февраля 2019

Context

У меня есть одностраничное веб-приложение, использующее следующий стек:

  • Реагирование для внешнего интерфейса
  • Django для внутреннего интерфейса
  • Nginx для веб-сервера

Веб-приложение докеризуется с использованием docker-compose.Мое приложение React, получает данные с сервера Django (django создается как конечная точка API с использованием Django Rest Framework).

Вопрос / проблема

У меня возникла проблема при развертывании, когда я не могучтобы обслуживать мои медиафайлы через Nginx.

Что я до сих пор пробовал

Сначала я думал об обслуживании медиа-файлов, как показано в этом стеке post -довольно прямо.Тем не менее, поскольку Nginx работает в своем собственном докере (как и мой сервер django), я не смог указать свои медиафайлы django, поскольку они находятся в разных контейнерах.

В идеале я бы не хотел использовать webpack,и пусть Nginx позаботится о том, чтобы обслуживать мультимедийные файлы.

Если вы посмотрите на файл Docker nginx ниже, вы увидите, что я копирую свои статические файлы в /usr/share/nginx/html/static/staticfiles, чтобы затем обслуживать их с помощью nginx (см. location ^~ /static/в nginx.conf).Я попытался сделать то же самое для своего медиа-файла (в качестве теста), и он работает - хотя все файлы, которые я загружаю после запуска сайта, недоступны, поскольку копирование происходит, когда я собираю свой контейнер.

Структура файла

Root Dirc  
 |__ docker-compose.yml  
 |__ backend  
      |__ root  
           |__ Project
                |__ api
                     |__ models.py
                     |__ ...
                |__ media
           |__ teddycrepineau
                |__ settings.py
                |__ ...
           |__ production
                |__ Dockerfile
 |__ nginx
      |__ Dockerfile
      |__ nginx.conf
 |__ frontend
      |__ ...

Соответствующий код

docker-compose.yml

version: '3'

volumes:
  postgres_data: {}
  postgres_backup: {}

services:
  postgres:
    image: postgres
    volumes: 
      - postgres_data:/var/lib/postgresql/data
      - postgres_backup:/backups
    env_file: .env

  nginx:
    container_name: nginx
    build:
      context: .
      dockerfile: ./nginx/Dockerfile
    image: nginx
    restart: always
    depends_on: 
      - django
    ports:
      - "80:80"

  django:
    container_name: django
    build:
      context: backend
      dockerfile: ./root/production/Dockerfile
    hostname: django
    ports:
      - 8000:8000
    volumes:
      - ./backend:/app/
    depends_on: 
      - postgres
    command: >
      bash -c '
      python3 ./root/manage.py makemigrations &&
      python3 ./root/manage.py migrate &&
      python3 ./root/manage.py initadmin &&
      gunicorn teddycrepineau.wsgi -b 0.0.0.0:8000 --chdir=./root/'

    env_file: .env

nginx.conf

user nginx;
worker_processes 1;

error_log   /var/log/nginx/error.log warn;
pid         /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include         /etc/nginx/mime.types;
    default_type    application/octet-stream;

    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
    '$status $body_bytes_sent "$http_referer" '
    '"$http_user_agent" "$http_x_forwarded_for"';

    access_log      /var/log/nginx/access.log main;

    upstream app {
        server django:8000;
    }

    server {
        listen  80 default_server;
        listen  [::]:80 default_server;
        server_name 0.0.0.0;
        charset utf-80;

        root /usr/share/nginx/html;
        index index.html;

        location / {
            try_files $uri $uri/ @proxy_to_app;
        }

        location @proxy_to_app {
            rewrite ^(.+)$ /index.html last;
        }

        location ^~ /static/ {
            autoindex on;
            alias /usr/share/nginx/html/static/;
        }

        location ~ ^/api {
            proxy_pass http://django:8000;
        }
        location ~ ^/admin {
            proxy_pass http://django:8000;
        }
    }
}

nginx Dockerfile

FROM nginx:latest
ADD ./nginx/nginx.conf /etc/nginx/nginx.conf
COPY ./frontend/build /usr/share/nginx/html
COPY ./backend/root/staticfiles /usr/share/nginx/html/static/staticfiles

Django Dockerfile

FROM python:3.7

ENV PYTHONUNBUFFERED 1

RUN export DEBIAN_FRONTEND=noninteractive

RUN mkdir /app

RUN pip install --upgrade pip
ADD /root/requirements.txt /app/

WORKDIR /app/
ADD . /app/

RUN pip install -r requirements.txt

EXPOSE 8000

Настройки Django.py

BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
APPS_DIR = os.path.join(BASE_DIR, 'project')
....
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(APPS_DIR, 'media/')

Django urls.py

urlpatterns = [
    path('admin/', admin.site.urls),
    re_path(r'^api/', include('project.api.urls')),
    path('summernote/', include('django_summernote.urls')),
] 
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)


Обновление

Когда я подключаю общийvolum и ссылаться на него в моем nginx.conf Я получаю 404 page not found при попытке получить доступ к изображению, загруженному в бэкэнд django.

docker-compose.yml

version: '3'

volumes:
  postgres_data: {}
  postgres_backup: {}

services:
  postgres:
    image: postgres
    volumes: 
      - postgres_data:/var/lib/postgresql/data
      - postgres_backup:/backups
    env_file: .env

  nginx:
    container_name: nginx
    build:
      context: .
      dockerfile: ./nginx/Dockerfile
    image: nginx
    restart: always
    depends_on: 
      - django
    ports:
      - "80:80"
    volumes:
      - ./static:/app/backend/root/staticfiles
      - ./media:/app/backend/root/project/media

  django:
    container_name: django
    build:
      context: backend
      dockerfile: ./root/production/Dockerfile
    hostname: django
    ports:
      - 8000:8000
    volumes:
      - ./backend:/app/
      - ./static:/app/backend/root/staticfiles
      - ./media:/app/backend/root/project/media
    depends_on: 
      - postgres
    command: >
      bash -c '
      python3 ./root/manage.py collectstatic --no-input &&
      python3 ./root/manage.py makemigrations &&
      python3 ./root/manage.py migrate &&
      python3 ./root/manage.py initadmin &&
      gunicorn teddycrepineau.wsgi -b 0.0.0.0:8000 --chdir=./root/'

    env_file: .env 

nginx.conf

user nginx;
worker_processes 1;

error_log   /var/log/nginx/error.log warn;
pid         /var/run/nginx.pid;

events {
    worker_connections  1024;
}

http {
    include         /etc/nginx/mime.types;
    default_type    application/octet-stream;

    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
    '$status $body_bytes_sent "$http_referer" '
    '"$http_user_agent" "$http_x_forwarded_for"';

    access_log      /var/log/nginx/access.log main;

    upstream app {
        server django:8000;
    }

    server {
        listen  80 default_server;
        listen  [::]:80 default_server;
        server_name localhost;
        charset utf-80;

        root /usr/share/nginx/html;
        index index.html;

        location / {
            try_files $uri $uri/ @proxy_to_app;
        }

        location @proxy_to_app {
            rewrite ^(.+)$ /index.html last;
        }

        location ^~ /static/ {
            autoindex on;
            alias /usr/share/nginx/html/static/;
        }

        location ^~ /media/ {
            autoindex on;
            alias /app/backend/root/project/media/;
        }

        location ~ ^/api {
            proxy_pass http://django:8000;
        }
        location ~ ^/admin {
            proxy_pass http://django:8000;
        }
    }
}

1 Ответ

0 голосов
/ 01 марта 2019

Проблема возникла из-за того, что я смонтировал свои тома в docker-compose.yml (это было неправильное понимание с моей стороны).

Сначала мы создаем смонтированный на хосте том (./backend/), ссылающийся на наш/app/ папка, которая существует в нашем сервисе django.Мы создали эту папку и добавили все соответствующие файлы в наш Dockerfile, расположенный в бэкэнд-папке.Это в основном свяжет нашу папку /app/, которая существует на образе django Docker, с папкой ./backend, которая существует на хосте - обратитесь к файловой структуре из OP.

Как только мы получим этот том, при каждом обновлениисоздается в нашей папке /app/ (т. е. загружается новый образ), она будет отражена в томах, смонтированных на нашем хосте (т. е. ./backend/) - и наоборот.

Наконец, мы создаем еще 2 набора томов, смонтированных на хосте (./backend/root/staticfiles/... и ./backend/root/project/media/), которые мы будем использовать для обслуживания наших носителей и статических файлов через Nginx.Мы разделяем эти тома, смонтированные на хосте, между службами nginx и django.Начиная с версии 2 docker-compose автоматически создает сеть между образами Docker, которая позволяет вам разделять тома между службами.

Наконец, в нашем файле nginx.conf мы ссылаемся на тома, смонтированные на хосте, в файле docker-compose.yml дляstatic и media url.

docker-compose.yml

version: '3'

volumes:
  postgres_data: {}
  postgres_backup: {}

services:
  postgres:
    image: postgres
    volumes: 
      - postgres_data:/var/lib/postgresql/data
      - postgres_backup:/backups
    env_file: .env

  django:
    container_name: django
    build:
      context: backend
      dockerfile: ./root/production/Dockerfile
    hostname: django
    ports:
      - 8000:8000
    volumes:
      - ./backend:/app/
      - ./backend/root/staticfiles/admin:/usr/share/nginx/html/static/admin
      - ./backend/root/staticfiles/rest_framework:/usr/share/nginx/html/static/rest_framework
      - ./backend/root/staticfiles/summernote:/usr/share/nginx/html/static/summernote
      - ./backend/root/project/media/:/usr/share/nginx/html/media/
    depends_on: 
      - postgres
    command: >
      bash -c '
      python3 ./root/manage.py collectstatic --no-input &&
      python3 ./root/manage.py makemigrations &&
      python3 ./root/manage.py migrate &&
      python3 ./root/manage.py initadmin &&
      gunicorn teddycrepineau.wsgi -b 0.0.0.0:8000 --chdir=./root/'
    env_file: .env

  nginx:
    container_name: nginx
    build:
      context: .
      dockerfile: ./nginx/Dockerfile
    image: nginx
    restart: always
    depends_on: 
      - django
    ports:
      - "80:80"
    volumes:
      - ./backend/root/staticfiles/admin:/usr/share/nginx/html/static/admin
      - ./backend/root/staticfiles/rest_framework:/usr/share/nginx/html/static/rest_framework
      - ./backend/root/staticfiles/summernote:/usr/share/nginx/html/static/summernote
      - ./backend/root/project/media/:/usr/share/nginx/html/media/

nginx.conf

....

    server {
        listen  80 default_server;
        listen  [::]:80 default_server;
        server_name localhost;
        charset utf-80;

        root /usr/share/nginx/html;
        index index.html;

        location / {
            try_files $uri $uri/ @proxy_to_app;
        }

        location @proxy_to_app {
            rewrite ^(.+)$ /index.html last;
        }

        location ^~ /static/ {
            autoindex on;
            alias /usr/share/nginx/html/static/;
        }

        location ^~ /media/ {
            autoindex on;
            alias /usr/share/nginx/html/media/;
        }

        location ~ ^/api {
            proxy_pass http://django:8000;
        }
        location ~ ^/admin {
            proxy_pass http://django:8000;
        }
    }
}
...