docker compose没有在共享卷中拾取文件系统更改



大家好。

我在这里的任务是使用一些将在几个服务之间共享的卷。此卷将由特定服务Dockerfile中的ADDCOPY命令填充。我遇到的问题是,当通过docker-compose up启动服务时,卷没有得到更新。

考虑以下设置:

# docker-compose.yml
version: "3"
services:
service-a:
build:
context: service-a
dockerfile: Dockerfile
volumes:
- shared:/test/dir
service-b:
build:
context: service-b
dockerfile: Dockerfile
volumes:
- shared:/another-test/dir
volumes:
shared:
# ./service-a/Dockerfile
FROM alpine:3.8
COPY test-dir /test/dir
CMD [ "tail", "-f", "/dev/null" ]
# ./service-b/Dockerfile
FROM alpine:3.8
CMD [ "tail", "-f", "/dev/null" ]

我们将创建./service-a/test-dir文件夹。现在让我们构建它:

> docker-compose build
Building service-a
Step 1/3 : FROM alpine:3.8
---> 196d12cf6ab1
Step 2/3 : COPY test-dir /test/dir
---> ac66ed92b442
Step 3/3 : CMD [ "tail", "-f", "/dev/null" ]
---> Running in 932eb32b6184
Removing intermediate container 932eb32b6184
---> 7e0385d17f96
Successfully built 7e0385d17f96
Successfully tagged docker-compose-test_service-a:latest
Building service-b
Step 1/2 : FROM alpine:3.8
---> 196d12cf6ab1
Step 2/2 : CMD [ "tail", "-f", "/dev/null" ]
---> Running in 59a8b91c6b2d
Removing intermediate container 59a8b91c6b2d
---> 4e2c16ea5a80
Successfully built 4e2c16ea5a80
Successfully tagged docker-compose-test_service-b:latest

并启动服务:

> docker-compose up --no-build -d
Creating network "docker-compose-test_default" with the default driver
Creating volume "docker-compose-test_shared" with default driver
Creating docker-compose-test_service-a_1 ... done
Creating docker-compose-test_service-b_1 ... done

让我们检查映射的目录:

> docker-compose exec service-a ls -lah /test/dir
total 8
drwxr-xr-x    2 root     root        4.0K Dec 12 06:14 .
drwxr-xr-x    3 root     root        4.0K Dec 12 06:14 ..
> docker-compose exec service-b ls -lah /another-test/dir
total 8
drwxr-xr-x    2 root     root        4.0K Dec 12 06:14 .
drwxr-xr-x    3 root     root        4.0K Dec 12 06:14 ..

现在,让我们在主机上的./service-a/test-dir中放入一些文本文件,然后重新构建:

> docker-compose build
Building service-a
Step 1/3 : FROM alpine:3.8
---> 196d12cf6ab1
Step 2/3 : COPY test-dir /test/dir
---> bd168b0fc8cc
Step 3/3 : CMD [ "tail", "-f", "/dev/null" ]
---> Running in 6e81b32243e1
Removing intermediate container 6e81b32243e1
---> cc28fc6de9ac
Successfully built cc28fc6de9ac
Successfully tagged docker-compose-test_service-a:latest
Building service-b
Step 1/2 : FROM alpine:3.8
---> 196d12cf6ab1
Step 2/2 : CMD [ "tail", "-f", "/dev/null" ]
---> Using cache
---> 4e2c16ea5a80
Successfully built 4e2c16ea5a80
Successfully tagged docker-compose-test_service-b:latest

正如您所看到的,service-a中的COPY步骤没有使用缓存,这意味着更改将烘焙到图像中。现在让我们开始服务:

> docker-compose up --no-build -d
Recreating docker-compose-test_service-a_1 ...
Recreating docker-compose-test_service-a_1 ... done

service-b再次保持不变,只有service-a被重新创建。让我们检查实际的服务(这就是问题发生的地方(:

> docker-compose exec service-a ls -lah /test/dir
total 8
drwxr-xr-x    2 root     root        4.0K Dec 12 06:17 .
drwxr-xr-x    3 root     root        4.0K Dec 12 06:20 ..
> docker-compose exec service-b ls -lah /another-test/dir
total 8
drwxr-xr-x    2 root     root        4.0K Dec 12 06:17 .
drwxr-xr-x    3 root     root        4.0K Dec 12 06:14 ..

所以文件没有反映。。。然而,如果我们基于service-a图像启动临时容器,它将显示正确的列表:

> docker run --rm docker-compose-test_service-a ls -lah /test/dir
total 8
drwxr-xr-x    2 root     root        4.0K Dec 12 06:20 .
drwxr-xr-x    3 root     root        4.0K Dec 12 06:20 ..
-rwxr-xr-x    1 root     root           0 Dec 12 06:20 rrrrrr.txt
-rwxr-xr-x    1 root     root           0 Dec 12 06:16 test.txt

有什么解决办法吗?到目前为止,似乎只有通过带有卷销毁的docker-compose down完全关闭才有帮助。虽然不是最好的解决方案,但与实际项目一样,它会导致严重的停机时间。

我希望配置是可读的,但如果需要的话,我可以把它放进小的git repo中。

提前谢谢。

Docker只有在第一次创建时才会自动填充卷。在您描述的工作流程中,当您删除并重新创建具有新映像的"第一个"容器时,您还需要删除并重新生成卷,这可能意味着删除并重新构建整个堆栈。

有几种方法可以解决这个问题:

  1. 重新配置应用程序,使其不需要共享文件。(显然是最有效的。(如果有某种半静态内容,您可能需要将它们"烘焙"到消费图像中,或者将系统的两个部分设置为通过HTTP进行通信。(这种跨容器的数据共享不是Docker擅长的,当你开始考虑Swarm或Kubernetes等多主机解决方案时,情况会变得更糟。(

  2. 如果只涉及两个部分,那么构建一个运行这两个过程的映像。我看到了其他SO问题,它们针对一个提供动态内容的PHP-FPM组件和一个提供静态内容并向PHP-FPM转发一些请求的nginx服务器,但其中所有静态和动态内容都是"应用程序的一部分",而通过nginx的HTTP入口点是"容器的单个入口点"。supervisord是在必要时的默认控制过程。

  3. 在"生产"容器中,编写一些启动时间代码,将图像中的数据复制到共享数据位置中

    #!/bin/sh
    # Run me as the image's ENTRYPOINT.
    if [ -d /data ]; then
    cp -r /app/static /data
    done
    exec "$@"
    

    这将在每次启动时重新填充上的数据卷。

相关内容

最新更新