【问题标题】:docker-compoes.yml settings with Django + Gunicorn + NGINX does not work on `docker-compose up`Django + Gunicorn + NGINX 的 docker-compose.yml 设置不适用于 `docker-compose up`
【发布时间】:2018-03-09 07:13:14
【问题描述】:

这是我的文件夹结构。

./awesome_app
├── awesome_app
│   ├── celery.py
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── awesome_app_to_do_list
├── db.sqlite3
├── docker-compose.yml
├── Dockerfile
├── logs
│   ├── nginx-access.log
│   └── nginx-error.log
├── manage.py
├── nginx
│   └── nginx.conf
├── requirements.txt
├── run
└── start.sh

这是我的 nginx.conf。

upstream awesome_app {
    server unix:/home/notalentgeek/Downloads/awesome_app/run/gunicorn.sock fail_timeout=10s;
}

server {
    client_max_body_size 4G;
    listen 8080;

    access_log /home/notalentgeek/Downloads/awesome_app/logs/nginx-access.log;
    error_log /home/notalentgeek/Downloads/awesome_app/logs/nginx-error.log warn;

    location /static/ {
        autoindex on;
        alias   /home/notalentgeek/Downloads/awesome_app/static/;
    }

    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://awesome_app;
            break;
        }
    }
}

这是我的 docker-compose.yml。

version: "3"  
services:  
  nginx:
    image: nginx:latest
    container_name: nginx_awesome_app
    ports:
      - "8080:8080"
    volumes:
      - ./:/src
      - ./nginx:/etc/nginx/conf.d
    depends_on:
      - web
  web:
    build: ./
    container_name: django_awesome_app
    volumes:
      - ./:/src
    expose:
      - "8080"

这是我的 start.sh。

#!/bin/bash

# PENDING: From the source here,
# http://tutos.readthedocs.io/en/latest/source/ndg.html it says that it is a
# common practice to have a specific user to handle the webserver.

SCRIPT=$(readlink -f "$0")
BASEDIR=$(dirname "$SCRIPT")
DJANGO_SETTINGS_MODULE=awesome_app.settings
DJANGO_WSGI_MODULE=awesome_app.wsgi
NAME="awesome_app"
NUM_WORKERS=3

VENV_BIN=${BASEDIR}"/venv/bin"
SOCKFILE=${BASEDIR}"/run/gunicorn.sock"

echo $SOCKFILE

SOCKFILEDIR="$(dirname "$SOCKFILE")"
VENV_ACTIVATE=${VENV_BIN}"/activate"
VENV_GUNICORN=${VENV_BIN}"/gunicorn"

# Activate the virtual environment.
cd $BASEDIR
source $VENV_ACTIVATE
export DJANGO_SETTINGS_MODULE=$DJANGO_SETTINGS_MODULE
export PYTHONPATH=$PYTHONPATH:$BASEDIR

# Create run directory if they does not exists.
test -d $SOCKFILEDIR || mkdir -p $SOCKFILEDIR

# Start Gunicorn!
# Programs meant to be run under supervisor should not daemonize themselves
# (do not use --daemon).
exec ${VENV_GUNICORN} ${DJANGO_WSGI_MODULE}:application \
    --bind=unix:$SOCKFILE \
    --name $NAME \
    --workers $NUM_WORKERS

运行这些命令。

  • docker-compose build
  • docker-compose up -d
  • docker-compose up

给我这些错误。

Starting django_awesome_app ... 
Starting django_awesome_app ... done
Starting nginx_awesome_app ... 
Starting nginx_awesome_app ... done
Attaching to django_awesome_app, nginx_awesome_app
django_awesome_app | //run/gunicorn.sock
django_awesome_app | /start.sh: line 25: //venv/bin/activate: No such file or directory
django_awesome_app | /start.sh: line 35: //venv/bin/gunicorn: No such file or directory
nginx_awesome_app | 2017/09/27 17:21:31 [emerg] 1#1: open() "/home/notalentgeek/Downloads/awesome_app/logs/nginx-access.log" failed (2: No such file or directory)
nginx_awesome_app | nginx: [emerg] open() "/home/notalentgeek/Downloads/awesome_app/logs/nginx-access.log" failed (2: No such file or directory)
django_awesome_app exited with code 127
nginx_awesome_app exited with code 1

我想有什么问题:

  • virtualenv 如何激活(或根本没有激活)。
  • volumes 如何在 docker-compose.yml 中传输。

此外,当它进入容器时没有检测到消息日志,因为我的 nginx.conf 中仍然有access_log /home/notalentgeek/Downloads/awesome_app/logs/nginx-access.log;

我该如何解决这些问题?

【问题讨论】:

    标签: django docker nginx docker-compose


    【解决方案1】:

    首先,您的nginx.conf 引用的是您的主机路径,而不是容器路径。 nginx 服务将没有 /home/notalentgeek/

    您没有包含您的 Dockerfile,但我想问题在于 Dockerfile 中没有安装 virtualenv。这就是您收到错误 /start.sh: line 25: //venv/bin/activate: No such file or directory 的原因。

    您可能会发现处理一个示例将有助于更多地了解 Docker 具体是如何工作的,以及容器在一般情况下是如何工作的。不幸的是,在过去的几年里,Docker 的工作方式和最佳实践发生了很多变化,所以很多示例都包含过时的信息。最好通读几篇以及 Docker 官方文档来拼凑一个工作系统。查看活跃的 Github 项目有助于了解开源系统如何处理 Docker。

    我发现nginx-proxy 项目有助于将 nginx 放在 Docker 容器前面。该项目的自述文件有很好的说明,可以将其用作docker-compose.yml 的插件。使用该容器将处理 nginx 端,您只需要修复 Django 应用程序 Dockerfile。

    【讨论】:

    • 我会尝试一一解决问题。尽管我还没有在容器中安装虚拟环境,但我已经在我的主机中准备了 venv 文件夹。这不是已经解决了我的问题吗?
    • 不,容器有自己的独立文件系统。您需要将venv 文件夹作为卷复制,在容器映像中安装virtualenv 包。否则,没有什么可运行的。要了解发生了什么,请尝试在您的web 服务中设置entrypoint: sleep 9999,然后运行docker-compose exec web /bin/bash 并四处寻找。您应该确切地看到安装了哪些命令、存在哪些文件等。
    • 我只是尝试从我的 start.sh 中echo 来查看容器中有哪些文件。它返回我拥有启动脚本所需的所有文件。例如,当我从 start.sh 运行 ls 时存在 /venv/bin/activate。那么我可以将整个项目复制到容器中吗?这是否是最佳做法?
    • 我认为你的问题是VENV_BIN=${BASEDIR}"/venv/bin",其中BASEDIR=/。所以最终结果是//venv/bin,而不是/venv/bin。不过,我认为您仍然需要在容器内安装 virtualenv 才能使其正常工作。我认为更改文件路径也存在问题,其中环境将假设 /home/notalentgeek 存在。