docker-compose:不同的运行、执行和层会发生什么
据我了解docker,docker-compose流程是这样的:
Dockerfile --build--> Docker Image --create--> Docker Container #1
--create--> Docker Container #2
--create--> ...
--create--> Docker Container #n
所以Image是由 中的命令制作的,Dockerfile但纯粹是某种“离线”版本。您可以将其“联机”,然后作为容器使用。
我的理解docker-compose up是通过service里面的定义为我们做这个两步过程docker-compose.yml,除了一些其他的东西,比如安装卷,暴露端口等等。
我的第一个问题是:
如果我运行docker-compose exec some_command,那么我正在操纵 docker 容器 - 对吗?
据我了解的文档,docker-compose run some_command几乎是一样的,但是,它事先创建了一个新的“层”,所以…… 像这样:
Docker Container #n (layer 0) ----> Docker Container #n (layer 1)
而some_command正确的-然后对层1中执行?此外,它似乎run正在传递some_command到入口点,而exec确实覆盖了定义的入口点。
我的第二个问题是:
run之后创建的新层会发生什么?有没有办法在不创建新层的情况下执行命令?我想知道,因为我添加了一个这样的入口点脚本:
#!/bin/sh
case "$@" in
"update")
pip3 install -r requirements.txt
;;
"start")
python manage.py runserver
;;
*)
echo "executing $@"
exec "$@"
;;
esac
我这样做是为了能够通过运行像docker-compose run backend update. 问题是run如果我up之后运行,则不会使用创建的图层。
回答
首先让我们澄清这里的基本术语。引用官方文档:
一个图像是用于创建一个码头工人容器指令的只读模板。
基本上,映像只是一个文件系统存档,其中包含文件和目录结构以及容器的一些附加元数据(如ENV或CMD)。因此,您也可以将其视为一个tar或zip存档。
甲容器是图像的可运行实例。
要从镜像启动一个新容器,需要解压镜像docker,设置各自的命名空间,并使用解压后的镜像作为文件系统根启动一个进程。
该层通常所说的层通过在生成过程中创建的图像中,并且被用于高速缓存和重用在多个图像中的公共文件/层。因此,您只需要在Dockerfile.
而不是为每个新容器提取/复制图像内容,docker只会在存储该容器更改的图像顶部添加一个薄的可写层。这的确切机制是一个实现细节,取决于使用的存储驱动程序!在大多数情况下,使用时docker您不需要关心这一点。
现在使用docker-compose:它在后台所做的基本上是构建和执行相应的docker命令*,以根据您的docker-compose.yml配置文件运行和管理您的服务所需的容器。因此,让我们看看docker-compose与相应docker命令的关系:
docker-compose build: 将docker build使用指定build选项为每个服务执行相应的命令docker-compose pull:docker pulls 所有服务的图像,带有image来自相应存储库的选项docker-compose up:- 如有必要:将首先
docker-compose build/docker-compose pull所有您的服务 - 通过构建和执行相应的
docker run命令来启动服务容器
- 如有必要:将首先
docker-compose exec: 将运行docker exec以在现有的运行容器中启动新进程/命令docker-compose run: 启动一个新的容器来交互执行指定的命令,即执行docker run
* 请注意,docker-compose它实际上并没有调用docker命令,而是docker直接使用 API与守护程序对话。但为了更容易理解,你可以假装它确实如此。
现在回答你的问题:
如果我运行
docker-compose exec some_command,那么我正在操纵 docker 容器 - 对吗?据我了解的文档,
docker-compose run some_command几乎是一样的,但是,它事先创建了一个新的“层”,所以…… 像这样:
docker-compose exec将在您现有的、正在运行的服务容器中运行,同时docker-compose run将启动一个新的、独立的容器。
此外,它似乎
run正在传递some_command到入口点,而exec确实覆盖了定义的入口点。
正确,exec不使用入口点。
run之后创建的新层会发生什么?有没有办法在不创建新层的情况下执行命令?
这些更改是由其启动的容器的一部分,run并将持续到您删除该容器为止。但是,如果要将更改应用于服务容器(由 使用docker-compose up),则需要运行docker-compose exec!
我想知道,因为我添加了一个这样的入口点脚本:
我这样做是为了能够通过运行像
docker-compose run backend update.
由于docker-compose run将在新容器中执行该命令,因此您需要运行docker-compose exec而不是手动调用入口点:
docker-compose exec app /entrypoint.sh update
# and if you need to restart your app restart the service containers
docker-compose restart
然而,这是错误的使用方式docker!因为容器是短暂的,在容器中执行的命令只会影响该特定容器。当您必须在该映像上运行新的容器实例(您停止容器、电源故障等)时,所有更改都将丢失。
相反,您应该将update命令作为(最后一个)命令添加到您Dockerfile的图像中并重建(最后一层)图像:
docker-compose up --build
或者,如果您必须跳过构建缓存以强制进行新构建:
docker-compose build --no-cache
docker-compose up