我有一个使用以下堆栈的单页Web应用程序:
使用docker-compose
对Web应用程序进行了docker化。我的React应用程序从Django服务器获取数据(django使用Django Rest Framework作为api端点构建)。
我在部署时遇到问题,无法通过Nginx提供媒体文件。
我最初的想法是按照以下stackoverflow post所示提供媒体文件,这很简单。但是,由于Nginx在自己的docker中运行(我的django服务器也是如此),我无法指向django媒体文件,因为它们位于不同的容器中。
理想情况下,我不想使用Webpack,而是让Nginx负责提供媒体文件。
如果您查看下面的nginx Dockerfile,您将看到我将静态文件复制到/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 settings.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)
当我安装共享卷并在我的nginx.conf
中引用它时,尝试访问在django后端中上传的图像时会得到一个404 page not found
。
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;
}
}
}
答案 0 :(得分:0)
问题出在我将卷安装到docker-compose.yml
的方式上(对我而言这是一种理解上的缺失)。
首先,我们参考django服务中存在的./backend/
文件夹创建一个主机装载的卷(/app/
)。我们创建了此文件夹,并将所有相关文件添加到了后端文件夹中的Dockerfile
中。基本上,这会将/app/
Docker映像上的django
文件夹链接到主机上的./backend
文件夹-从OP中引用文件结构。
一旦有了该卷,只要对我们的/app/
文件夹进行了更新(即上传新图像),它就会反映在我们的主机安装的卷中(即./backend/
)-反之亦然反之亦然。
我们最终创建了两套主机安装的卷集(./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;
}
}
}