使用 Gunicorn 在 Docker 中使用 Django 开发自动重新加载代码更改
Auto-reloading of code changes with Django development in Docker with Gunicorn
我正在使用 Docker 容器进行 Django 开发,该容器运行带有 Nginx 的 Gunicorn。我希望代码更改能够自动加载,但让它们加载的唯一方法是使用 docker-compose (docker-compose build
) 进行重建。 "build" 的问题在于它会重新运行我所有的 pip 安装。
我正在使用 Gunicorn --reload
标志,这显然应该做我想做的事。这是我的 Docker 配置文件:
## Dockerfile:
FROM python:3.4.3
RUN mkdir /code
WORKDIR /code
ADD . /code/
RUN pip install -r /code/requirements/docker.txt
## docker-compose.yml:
web:
restart: always
build: .
expose:
- "8000"
links:
- postgres:postgres
volumes:
- /usr/src/app/static
env_file: .env
command: /usr/local/bin/gunicorn myapp.wsgi:application -w 2 -b :8000 --reload
nginx:
restart: always
build: ./config/nginx
ports:
- "80:80"
volumes:
- /www/static
volumes_from:
- web
links:
- web:web
postgres:
restart: always
image: postgres:latest
volumes:
- /var/lib/postgresql
ports:
- "5432:5432"
我已经尝试了其他一些 Docker 命令(docker-compose restart
、docker-compose up
),但代码不会刷新。
我错过了什么?
感谢 kikicarbonell,我研究了我的代码的卷,在查看 Docker Compose recommended Django setup 之后,我将 volumes: - .:/code
添加到 docker-[= 中的 Web 容器中34=],现在我所做的任何代码更改都会自动应用。
## docker-compose.yml:
web:
restart: always
build: .
expose:
- "8000"
links:
- postgres:postgres
volumes:
- /usr/src/app/static
- .:/code
env_file: .env
command: /usr/local/bin/gunicorn myapp.wsgi:application -w 2 -b :8000 --reload
更新: 了解将 Gunicorn 和 Django 与 Docker 一起使用的完整示例,请查看此 example project from Rackspace,其中还展示了如何使用 [=35] =]-machine 在 Rackspace Cloud 等远程服务器上启动设置。
警告: 目前,当您的代码存储在本地并且 docker 主机位于远程(例如,在像 Digital Ocean 这样的云提供商上)时,此方法不起作用或机架空间)。如果您的本地文件系统未安装在 VM 上,这也适用于虚拟机。请注意,有单独的卷驱动程序(例如,flocker),并且 可能 可以满足此需求。 目前,“修复”是 rsync/scp 您的文件到远程 docker 主机上的一个目录。然后,--reload
标志将在任何 scp/rsync. 更新后自动重新加载 gunicorn: 如果将代码推送到远程 docker 主机,我发现只重建 docker 容器(例如 docker-compose build web && docker-compose up -d
)要容易得多。如果您的 src 文件夹很大,这可能比 rsync 方法慢。
您还有另一个问题 - Docker 缓存它构建的每一层。你不应该每次都重新运行 pip install!
ADD . /code/
RUN pip install -r /code/requirements/docker.txt
这是您的问题 - Docker 检查每个 ADD 语句以查看是否有任何文件已更改并使它的缓存无效,如果有则在每个后续步骤中使缓存无效。正确的做法是...
ADD ./requirements/docker.txt /code/requirements/
RUN pip install -r /code/requirements/docker.txt
ADD ./code/
如果您的需求文件发生变化,这只会使您的 pip 安装行无效!
由于我从未找到理想的解决方案,请考虑这个有趣的 hack。在这里发帖我想看看是否有人 similar/good/bad 有这方面的经验 "work around".
为了在本地重新加载代码以进行开发,我只是创建了一个立即调用 exit()
的视图。退出将使 Django 崩溃,并且在代码更改可用的地方将发生重新加载。重启只需几分之一秒,可以通过浏览器中的选项卡、requests.get
调用或任何其他类似调用来完成。重新加载不是自动的,但它会跳过任何 Docker 延迟,例如重新启动。
调用退出时,您将看到 PID 增量(如果拖尾日志):
web | [2019-07-15 18:29:52 +0000] [22] [INFO] Worker exiting (pid: 22)
web | [2019-07-15 18:29:52 +0000] [24] [INFO] Booting worker with pid: 24
我希望这对其他人有帮助 and/or 得到对这种方法的反馈。
我在尝试使用稍微不同的设置配置项目的自动重新加载时遇到了非常相似的问题。我设置了音量,但无论如何它都不起作用。经过一个小时的谷歌搜索和彻底检查我的代码后,我发现 Dockerfile 中的卷 路径和 docker-compose.yml 根本不匹配 。确保它们相同。
我的 Dockerfile
FROM python:3.6.9-alpine3.10
COPY ./requirements/local.txt /app/requirements/local.txt
RUN set -ex \
&& apk add --no-cache --virtual .build-deps postgresql-dev git gcc libgcc musl-dev jpeg-dev zlib-dev build-base \
&& python -m venv /env \
&& /env/bin/pip install --upgrade pip \
&& /env/bin/pip install --no-cache-dir -r /app/requirements/local.txt \
&& runDeps="$(scanelf --needed --nobanner --recursive /env \
| awk '{ gsub(/,/, "\nso:", ); print "so:" }' \
| sort -u \
| xargs -r apk info --installed \
| sort -u)" \
&& apk add --virtual rundeps $runDeps \
&& apk del .build-deps
### Here is the path to the project
COPY . /app
WORKDIR /app/project
ENV VIRTUAL_ENV /env
ENV PATH /env/bin:$PATH
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
EXPOSE 8088
我的docker-compose.yml
version: '3'
services:
web:
build:
context: ../..
dockerfile: compose/local/Dockerfile
restart: on-failure
command: python manage.py runserver 0.0.0.0:8088 --settings=project.settings.local
volumes:
# - .:/var/www/app # messed up path
- .:/app # correct path
env_file:
- ../../.env.local
depends_on:
- db
ports:
- "8000:8000"
我你用docker-compose:
Docker文件:当你从Docker文件构建图像时,你需要添加一些目录来保存你的代码(在我的案例 /api/):
WORKDIR /api/
-> 重要
COPY . .
-> 重要
- Docker-compose:您的 docker-compose 文件为您提供应用程序服务,其中 django 中的图像刚刚从 Docker 文件构建,现在您需要添加与在 Dockerfile:
中使用的 WORKDIR 相同的卷
volumes:
- .:/app
-> 重要
这就是全部。
创建卷时,您似乎需要在 docker-compose.yml 中匹配 Dockerfile 中的 WORKDIR/COPY 命令。这是一个例子:
Docker 文件
WORKDIR /app
COPY . /app
docker-compose.yml
app:
/ other commands /
volumes:
- ./app:/app
我正在使用 Docker 容器进行 Django 开发,该容器运行带有 Nginx 的 Gunicorn。我希望代码更改能够自动加载,但让它们加载的唯一方法是使用 docker-compose (docker-compose build
) 进行重建。 "build" 的问题在于它会重新运行我所有的 pip 安装。
我正在使用 Gunicorn --reload
标志,这显然应该做我想做的事。这是我的 Docker 配置文件:
## Dockerfile:
FROM python:3.4.3
RUN mkdir /code
WORKDIR /code
ADD . /code/
RUN pip install -r /code/requirements/docker.txt
## docker-compose.yml:
web:
restart: always
build: .
expose:
- "8000"
links:
- postgres:postgres
volumes:
- /usr/src/app/static
env_file: .env
command: /usr/local/bin/gunicorn myapp.wsgi:application -w 2 -b :8000 --reload
nginx:
restart: always
build: ./config/nginx
ports:
- "80:80"
volumes:
- /www/static
volumes_from:
- web
links:
- web:web
postgres:
restart: always
image: postgres:latest
volumes:
- /var/lib/postgresql
ports:
- "5432:5432"
我已经尝试了其他一些 Docker 命令(docker-compose restart
、docker-compose up
),但代码不会刷新。
我错过了什么?
感谢 kikicarbonell,我研究了我的代码的卷,在查看 Docker Compose recommended Django setup 之后,我将 volumes: - .:/code
添加到 docker-[= 中的 Web 容器中34=],现在我所做的任何代码更改都会自动应用。
## docker-compose.yml:
web:
restart: always
build: .
expose:
- "8000"
links:
- postgres:postgres
volumes:
- /usr/src/app/static
- .:/code
env_file: .env
command: /usr/local/bin/gunicorn myapp.wsgi:application -w 2 -b :8000 --reload
更新: 了解将 Gunicorn 和 Django 与 Docker 一起使用的完整示例,请查看此 example project from Rackspace,其中还展示了如何使用 [=35] =]-machine 在 Rackspace Cloud 等远程服务器上启动设置。
警告: 目前,当您的代码存储在本地并且 docker 主机位于远程(例如,在像 Digital Ocean 这样的云提供商上)时,此方法不起作用或机架空间)。如果您的本地文件系统未安装在 VM 上,这也适用于虚拟机。请注意,有单独的卷驱动程序(例如,flocker),并且 可能 可以满足此需求。 目前,“修复”是 rsync/scp 您的文件到远程 docker 主机上的一个目录。然后, 更新后自动重新加载 gunicorn: 如果将代码推送到远程 docker 主机,我发现只重建 docker 容器(例如 --reload
标志将在任何 scp/rsync.docker-compose build web && docker-compose up -d
)要容易得多。如果您的 src 文件夹很大,这可能比 rsync 方法慢。
您还有另一个问题 - Docker 缓存它构建的每一层。你不应该每次都重新运行 pip install!
ADD . /code/
RUN pip install -r /code/requirements/docker.txt
这是您的问题 - Docker 检查每个 ADD 语句以查看是否有任何文件已更改并使它的缓存无效,如果有则在每个后续步骤中使缓存无效。正确的做法是...
ADD ./requirements/docker.txt /code/requirements/
RUN pip install -r /code/requirements/docker.txt
ADD ./code/
如果您的需求文件发生变化,这只会使您的 pip 安装行无效!
由于我从未找到理想的解决方案,请考虑这个有趣的 hack。在这里发帖我想看看是否有人 similar/good/bad 有这方面的经验 "work around".
为了在本地重新加载代码以进行开发,我只是创建了一个立即调用 exit()
的视图。退出将使 Django 崩溃,并且在代码更改可用的地方将发生重新加载。重启只需几分之一秒,可以通过浏览器中的选项卡、requests.get
调用或任何其他类似调用来完成。重新加载不是自动的,但它会跳过任何 Docker 延迟,例如重新启动。
调用退出时,您将看到 PID 增量(如果拖尾日志):
web | [2019-07-15 18:29:52 +0000] [22] [INFO] Worker exiting (pid: 22)
web | [2019-07-15 18:29:52 +0000] [24] [INFO] Booting worker with pid: 24
我希望这对其他人有帮助 and/or 得到对这种方法的反馈。
我在尝试使用稍微不同的设置配置项目的自动重新加载时遇到了非常相似的问题。我设置了音量,但无论如何它都不起作用。经过一个小时的谷歌搜索和彻底检查我的代码后,我发现 Dockerfile 中的卷 路径和 docker-compose.yml 根本不匹配 。确保它们相同。
我的 Dockerfile
FROM python:3.6.9-alpine3.10
COPY ./requirements/local.txt /app/requirements/local.txt
RUN set -ex \
&& apk add --no-cache --virtual .build-deps postgresql-dev git gcc libgcc musl-dev jpeg-dev zlib-dev build-base \
&& python -m venv /env \
&& /env/bin/pip install --upgrade pip \
&& /env/bin/pip install --no-cache-dir -r /app/requirements/local.txt \
&& runDeps="$(scanelf --needed --nobanner --recursive /env \
| awk '{ gsub(/,/, "\nso:", ); print "so:" }' \
| sort -u \
| xargs -r apk info --installed \
| sort -u)" \
&& apk add --virtual rundeps $runDeps \
&& apk del .build-deps
### Here is the path to the project
COPY . /app
WORKDIR /app/project
ENV VIRTUAL_ENV /env
ENV PATH /env/bin:$PATH
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1
EXPOSE 8088
我的docker-compose.yml
version: '3'
services:
web:
build:
context: ../..
dockerfile: compose/local/Dockerfile
restart: on-failure
command: python manage.py runserver 0.0.0.0:8088 --settings=project.settings.local
volumes:
# - .:/var/www/app # messed up path
- .:/app # correct path
env_file:
- ../../.env.local
depends_on:
- db
ports:
- "8000:8000"
我你用docker-compose:
Docker文件:当你从Docker文件构建图像时,你需要添加一些目录来保存你的代码(在我的案例 /api/):
WORKDIR /api/
-> 重要COPY . .
-> 重要
- Docker-compose:您的 docker-compose 文件为您提供应用程序服务,其中 django 中的图像刚刚从 Docker 文件构建,现在您需要添加与在 Dockerfile: 中使用的 WORKDIR 相同的卷
volumes:
- .:/app
-> 重要
这就是全部。
创建卷时,您似乎需要在 docker-compose.yml 中匹配 Dockerfile 中的 WORKDIR/COPY 命令。这是一个例子:
Docker 文件
WORKDIR /app
COPY . /app
docker-compose.yml
app:
/ other commands /
volumes:
- ./app:/app