如何使用Django、Docker、Nginx和PostgreSQL使静态文件正常工作,因为它们没有被正确地提供。

17

当我尝试访问 http://127.0.0.1:8000/admin 时,我收到了以下提示。

enter image description here

我的文件夹结构如下:

django-react-nginx
|
|_ _ docker-compose.yml
|
  > backend
        |
        |_ Dockerfile
        |
        |_ entrypoint.sh

     > languages
          |
          |_ settings.py
     > media
     > static # This folder appears after running docker-compose -d --build
  > nginx
      |
      |_ default.conf
      |
      |_ Dockerfile

现在

这里是文件

Django

settings.py

DEBUG = True

ALLOWED_HOSTS = ['*']

STATIC_URL = '/static/'

STATIC_ROOT = os.path.join(BASE_DIR, 'static')

MEDIA_ROOT = os.path.join(BASE_DIR, 'media')        

MEDIA_URL = '/media/'

Docker文件

FROM python:3.8

ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

WORKDIR /backend

COPY  requirements.txt /backend/

RUN pip install -r requirements.txt && \
    pip install --upgrade pip

COPY ./entrypoint.sh /

ENTRYPOINT ["sh", "/entrypoint.sh"]

entrypoint.sh

#!/bin/sh

python manage.py migrate --no-input

python manage.py collectstatic --no-input

gunicorn languages.wsgi:application --bind 0.0.0.0:8000

Nginx

default.conf

upstream django {
    server backend:8000;
}

server {
    listen 80;

    location / {
        proxy_pass http://django;
    }

    location /static/ {
        autoindex on;
        alias /backend/static;
    }

    location /media/ {
        autoindex on;
        alias /backend/static;
    }

}

Dockerfile

FROM nginx:1.19.8-alpine

COPY ./default.conf  /etc/nginx/conf.d/default.conf

根目录

Docker-compose

version: "3.7"

services:
  backend:
    build: ./backend/languages
    stdin_open: true # interactive
    tty: true        # interactive
    restart: "on-failure"
    env_file:
      .env
    volumes:
      - ./backend/languages:/backend
      - ./backend/languages/static:/backend/static
    ports:
      - 8000:8000
    networks:
      - nginx_network
      - db_network
    depends_on:
      - db
  db:
    image: postgres:11
    restart: "on-failure"
    environment:
      - POSTGRES_DB=postgres
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=postgres
    volumes:
      - postgres_data:/var/lib/postgresql/data/
    networks:
      - db_network
  
  nginx:
    build: ./nginx
    restart: always
    volumes:
      - ./backend/languages:/backend
      - ./backend/languages/static:/static
    ports:
      - 80:80
    networks:
      - nginx_network
    depends_on:
      - backend

networks:
  nginx_network:
    driver: bridge
  db_network:
    driver: bridge

volumes:
  postgres_data:

如上所述,我不确定如何使静态文件工作,它们已被复制到上面提到的文件夹中,因为当我查看时可以看到已创建该文件夹,当我检查日志时,我得到了以下信息:165 static files copied to '/backend/static'。


这个回答解决了你的问题吗?使用Docker、nginx和gunicorn提供Django静态文件 - addu390
2个回答

12

Nginx配置

Nginx配置看起来很好。容器映射到/backend/languages/static,使用/static进行访问,而别名指向容器内相同的文件夹 - /static

nginx.conf

location /static/ {
        autoindex on;
        alias /static;
    }

更新问题已检测到:别名必须具有相同的结束斜杠才能正常工作。因此,它必须是alias /static/

使用Docker Compose中的Nginx

  nginx:
    ...
    volumes:
      - ./backend/languages:/backend
      - ./backend/languages/static:/static

Django配置

但是Django的配置看起来有些问题。你已经配置好了将静态文件收集到BASE_DIR内的static文件夹中。

settings.py

STATIC_ROOT = os.path.join(BASE_DIR, 'static')
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')        

这正是collectstatic向您报告的内容:

已复制165个静态文件到'/backend/static'

文件在/backend/static中,而不是/static。然而容器被配置为根目录/static

Django在Compose中

  backend
    ...
    volumes:
      - ./backend/languages:/backend
      - ./backend/languages/static:/static

看起来该问题可以通过指向解决。

    volumes:
      - ./backend/languages/static:/backend/static

然而仍需完成一些工作:Django不应该用于提供媒体文件,因此建议配置Nginx来提供媒体文件。

Django Dockerfile

我认为映射./backend/languages:/backend是有效的,但那么做容器化有何意义呢?这个 Docker 镜像中没有应用程序,只有依赖项。最好将源代码包含在镜像中,以便最终部署只需要更新镜像并重新启动容器。

因此,附注一下,我建议至少尝试:

  • 使用 Nginx 更新配置以提供媒体文件
  • 在 Docker 镜像中包含 Django 应用程序源代码
  • 在构建过程中收集静态文件,而不是将其包含在 Docker 镜像中
  • entrypoint 中删除 collectstatic
  • 提供静态文件并将其视为单独的产品,如果您要将它们交付给 CDN,单独托管它们-这是非常常见的解决方案
  • 虽然它们仍然在同一个主机上,但将它们映射到容器中的方式与现在所做的相反:将静态文件交付到主机文件夹中,在容器中以 ro 模式访问它们

非常感谢你详细的回复,Ivan。我对Docker非常新手,因此即使阅读了所有关于Docker的书籍,也不完全明白自己在做什么。你介意向我展示一下上面最后两个要点的含义吗?我现在不确定如何自己完成它。我已经更新了上面的代码以在nginx中提供媒体文件。再次非常感谢你。 - cu__007
目前您在容器内执行collectstatic并从容器内部生成静态文件到主机。我的建议是在构建阶段收集静态文件,并将静态文件视为构建产物之一。然后将它们部署到目标文件夹(可能远离项目源),并将Docker容器卷映射到该文件夹。ro是只读的。有一天,您可能会考虑将静态文件存储在CDN服务/不同的托管上,并且每次启动容器时运行collectstatic将变得奇怪和无用。 - Ivan Starostin
然而,这仍然只是一个建议,其中一种可能的方法,并非必须遵循。 - Ivan Starostin
2
并不是这样的。在生产环境中,或者在Debug=False的情况下,Django不应该提供静态文件或媒体文件。这些URL模式仅在Debug=True时有效,并且对于生产环境来说并不好。 - Ivan Starostin
我不确定我理解了nginx +文件和debug=true的Django的组合。 Django不应该提供这些文件。而且,如果这些urlpatterns有助于nginx运行,那么nginx似乎根本没有参与,也许配置存在更大的问题。还要注意答案中nginx conf的upd。检测到小错误。当然,nginx、django和其他组件的日志应该能够更多地告诉我们有关错误的信息。 - Ivan Starostin
显示剩余4条评论

1

1
“链接回答”被认为是非常低质量的,可能会被删除,请将链接资源中的重要部分放入答案正文中。 - helvete
1
如果您能解释一下在这种情况下whitenoise如何帮助,那会更好。复制链接太过模糊。 - roshandeep singh

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接