我正在学习Docker website上的官方教程
Docker文件是
FROM python:3
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
WORKDIR /code
COPY requirements.txt /code/
RUN pip install -r requirements.txt
COPY . /code/
对接合成为:
web:
build: .
command: python manage.py runserver 0.0.0.0:8000
volumes:
- .:/code
我不明白为什么他们在Dockerfile中复制代码COPY . /code/
,然后又在docker-compose - .:/code
中挂载它?如果我复制或挂载,这还不够吗?
3条答案
按热度按时间shyt4zoc1#
docker-compose.yml
文件中的volumes:
和command:
都是不必要的,应该删除。要运行的代码和默认CMD
应该包含在Dockerfile中。当您设置Docker环境时,假设您被授予了对一个全新虚拟机的root访问权限,该虚拟机上除了Docker之外什么都没有安装。理想的情况是能够将
docker run your-image
作为单个命令从某个注册表中提取出来,并使用尽可能少的附加选项。当您运行映像时,您不需要单独提供其源代码或要运行的命令。这些通常应该被构建到映像中。在大多数情况下,您应该能够使用相当少的选项构建Compose设置。(如果计划推送映像,则两者都有),通常为
environment:
、ports:
和depends_on:
(注意后一种选择的局限性),并且您的数据库容器需要volumes:
作为其持久化状态。如果你需要在同一个图像和代码库上运行一个单独的命令,那么你需要在Compose中覆盖
command:
。在Python上下文中,这通常会出现在Django应用程序旁边运行一个Celery worker。下面是一个完整的例子,它是一个数据库支持的Web应用程序,有一个异步工作线程。Redis缓存层没有持久性,除了数据库存储,没有任何文件存储在本地的任何容器中。缺少的一点是数据库凭证的设置,它需要额外的
environment:
变量。注意代码缺少volumes:
。单个command:
覆盖(如果需要),environment:
变量提供主机名。当你看到
volumes:
像这样覆盖图像的代码时,这通常是为了避免在代码改变时需要重新构建图像。但是,在你展示的Docker文件中,如果requirements.txt
文件没有改变,那么重新构建几乎是免费的。你也几乎总是可以在Docker之外进行日常开发--对于Python来说,在虚拟环境中-并使用容器设置进行集成测试和部署,这通常比让IDE相信它所需的语言解释器在容器中更容易。有时候Dockerfile会做一些额外的设置(改变行尾或权限,重新排列文件),而
volumes:
挂载会隐藏这些设置。这意味着你从来没有真正运行过在开发中内置到映像中的代码,所以如果映像设置在某些方面有错误,你不会看到它。简而言之,它重新引入了“在我的机器上工作”的问题,而这正是Docker通常试图避免的。8ehkhllq2#
它用于保存图像后的代码。
使用COPY时,它会将其保存为图像的一部分。
而装裱则只是在显影的时候。
mnowg1ta3#
理想情况下,我们使用一个
Dockerfile
来创建用于生产和开发的映像,这增加了应用运行时环境的相似性,这是一件好事。与@大卫所写的相反:使用Docker容器进行日常开发是非常方便的。您的代码在生产和开发中运行在相同的环境中。如果您在开发中使用
virtualenv
,您就没有利用Docker的这个非常实用的属性。环境可能会在您不知道的情况下发生变化,并且在dev继续工作的同时prod可能会中断。那么,我们如何让一个
Dockerfile
生成一个可以在生产环境中运行并在开发过程中使用的映像呢?首先,我们应该讨论我们想要运行的代码。(很可能是仓库中某个特定提交的代码)但是在开发过程中我们不断地改变我们想要运行的代码,通过 checkout 不同的分支或编辑文件。那么我们如何同时满足这两个需求呢?我们指示
Dockerfile
将代码目录(在您的示例.
中)复制到映像中,在您的示例/code
中。这将是运行的代码。这发生在生产中。但在开发中,我们可以使用卷将/code
目录 * 覆盖 * 为主机上的目录。在示例中,Docker Compose文件设置了卷。然后,我们可以轻松更改dev容器中运行的代码,而无需重建映像。另外:即使重建很快,让Python进程用新文件重新启动也要快得多。