在Elasticbeanstalk Docker环境中提供Django静态文件

7

当使用docker环境将Django应用程序部署到EB时,静态文件返回404。

我在docker容器中使用gunicorn,由于不建议/不可能通过gunicorn提供静态文件服务,因此我想配置EB nginx使用主机文件系统来提供它们。

Dockerfile

FROM python:3
....
....
# Expose listen ports
EXPOSE 8002

RUN chmod +x ./docker/container_start.sh

CMD ["sh", "./docker/container_start.sh"]

Dockerrun.aws.json

{
  "AWSEBDockerrunVersion": "1",
  "Ports": [
    {
      "ContainerPort": "8002"
    }
  ],
  "Volumes": [
    {
      "ContainerDirectory": "/app/assets",
      "HostDirectory": "/var/app/current/assets"
    }
  ]
}

我该如何告诉 EB nginx 从 /var/app/current/assets 提供/assets/*,并将其余内容代理到Docker容器?以下配置不起作用,因为它是在Docker环境中。
option_settings:
  "aws:elasticbeanstalk:container:python:staticfiles":
    "/static/": "www/static/"

你找到解决方案了吗? - MikeMarsian
3个回答

2

为了总结我们的解决方案,即在运行在弹性Beanstalk Docker容器中的Django中提供静态文件,使用 SolutionStackName:64位Amazon Linux 2 v3.2.0运行Docker

  1. 我们不想在容器真正准备好之前运行collectstatic。为此,我们在entrypoint.sh中启动它,并在短时间内启动gunicorn。
  2. 我们让collectstatic将静态文件放置在“static”中。从我们的设置中:
STATIC_ROOT = "static"
STATIC_URL = "/static/"

我们在 .platform/hooks/postdeploy 中配置了一个部署后脚本,它会将静态文件从容器中复制到 ec2 虚拟机的 /var/app/current 目录下(脚本运行的位置)。
#! /bin/bash
docker cp $(docker ps --no-trunc -q | head -n 1):/home/app/static .

我们通过将自定义配置文件放在.platform/nginx/conf.d/elasticbeanstalk/custom.conf中来告诉nginx在哪里找到静态文件:
location /static/ {
    root /var/app/current/;
}

就这样。对我们来说很有效。


只需要更改/home/app/static,其他都像魔法一样运行良好。 - Abishek Kumar

0

我有完全相同的问题!解决方法是在服务器上自定义 /etc/sites-enabled/elasticbeanstalk-nginx-docker-proxy.conf 中的 nginx 配置。

基本上,我将该文件内容复制到 .ebextension 配置文件中,并添加了静态文件夹的位置指令。

因此,您可以使用 Dockerrun.aws.json。

{
  "AWSEBDockerrunVersion": "1",
  "Ports": [
    {
      "ContainerPort": "8002"
    }
  ],
  "Volumes": [
    {
      "ContainerDirectory": "/app/assets",
      "HostDirectory": "/var/app/current/assets"
    }
  ]
}

您可以创建.ebextension/01_nginx.config文件

files:
  "/etc/nginx/sites-enabled/elasticbeanstalk-nginx-docker-proxy.conf":
  mode: 000644
  owner: root
  group: root
  content: |
    map $http_upgrade $connection_upgrade {
        default        "upgrade";
        ""            "";
    }

    server {
        listen 80;

        gzip on;
        gzip_comp_level 4;
        gzip_types text/html text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;

        if ($time_iso8601 ~ "^(\d{4})-(\d{2})-(\d{2})T(\d{2})") {
            set $year $1;
            set $month $2;
            set $day $3;
            set $hour $4;
        }
        access_log /var/log/nginx/healthd/application.log.$year-$month-$day-$hour healthd;

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

        location /assets/ {
          root /var/app/current;
        }

        location / {
            proxy_pass            http://docker;
            proxy_http_version    1.1;

            proxy_set_header    Connection          $connection_upgrade;
            proxy_set_header    Upgrade             $http_upgrade;
            proxy_set_header    Host                $host;
            proxy_set_header    X-Real-IP           $remote_addr;
            proxy_set_header    X-Forwarded-For     $proxy_add_x_forwarded_for;
        }
    }

对我来说没问题!


这个答案是不正确的!当主机卷被挂载时,它将在容器中指定的目录上方进行挂载。该目录的内容将无法在主机上使用。请参考此问题:https://dev59.com/L1gQ5IYBdhLWcg3wYy_y?rq=1 - Chris W.
嗯...你知道它适用于我,这不仅是我的说法。你试过了吗? - Sune Kjærgård
是的,我自己尝试过,并且在它不起作用时需要重新设计。您确定系统的行为方式与您描述的方式相同吗?例如,我在您的EB Dockerrun配置中看到主机上的静态目录为/var/app/current/assets,但在您的nginx配置中,静态目录为/var/current - Chris W.
也许你在 Docker 中运行的 Web 应用程序实际上正在自己提供静态资源? - Chris W.
关于路径你是正确的。那是一个错误,我已经将实际路径更改为通用路径,但显然弄错了。应该是/var/app/current/。我会立即进行修正。 - Sune Kjærgård
显示剩余2条评论

-1

你想做的事情是不可能的。

你不能将 /host-dir 挂载到 /container-dir 上,并期望主机读取挂载前存在于 /container-dir 中的内容。(/container-dir 的内容是隐藏的。)请参见 this question/answer

你可能希望将静态资源包含在 Elastic Beanstalk 包中,而不是 Docker 镜像中。如果你这样做,这些资源将出现在 /var/app/current 中,然后你可以告诉 Elastic Beanstalk 内置的 nginx 如何按照 本线程中的其他答案 提供服务。


可以使用现有容器内容填充卷:https://docs.docker.com/storage/volumes/#populate-a-volume-using-a-container 如果您启动一个创建新卷的容器(如上所述),并且容器在要挂载的目录中具有文件或目录(例如上面的/app/),则该目录的内容将被复制到卷中。 - Sune Kjærgård
@SuneKjærgård 在您提供的文档中,它解释说容器将使用目录内容填充“新卷”,可以在其他容器之间共享。但是,它不会替换您已将其作为“共享”挂载到容器上的主机目录的内容。 - Chris W.
@SuneKjærgård 这是我终端的输出,我试图明确地证明我的观点:https://gist.github.com/topher515/e56430e7e0c12c2aa8b5aa30eb24bc97 - Chris W.

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