【Docker】容器挂载文件修改后 Commit 新镜像,挂载文件不会更新
  • 问题描述:
  • 场景验证
  • 1. 自定义镜像 Dockerfile
  • 2. 创建 hello.txt 文件:
  • 3. 构建自定义镜像
  • 4. 运行镜像,并检查容器内部文件内容
  • 5. 新增挂载目录,并修改,验证 Commit 的新镜像
  • 总结
  • 1. docker commit 时不会抓取容器挂载的文件系统;
  • 2. 解决办法
  • 2.1 直接在 Dockerfile 中更新文件:
  • 2.2 将文件复制到容器并重新构建


问题描述:

在使用某个镜像的时候,由于需要频繁修改镜像中的某些文件,于是就将这些文件所在的文件夹挂载到宿主机上了,在需要更新的时候,直接更新宿主机上挂载的目录下的文件来达到更新容器中的文件。

上面的骚操作,看似没什么问题,实际也是正常可用的。

最多是修改完挂载路径下面的文件,然后重启一下容器,修改就生效了,省时省力,不用重新构建镜像了。

但是在需要打版本,更新成新的镜像时,问题就暴露出来了,Commit 的新镜像发现某个路径下面的文件竟然不是最新的。

如果不是特意瞅一眼新镜像内挂载目录下的文件的时间,这打着新版本旗号的镜像,里子却是旧的文件,如果没有发现,那么可能在某个阳光明媚的午后,一回头,一颗子弹正中眉心。。。。。

场景验证

1. 自定义镜像 Dockerfile

创建一个自定义镜像,并让它持续运行,Dockerfile 内容如下:

# 使用 busybox 作为基础镜像
FROM busybox:latest

# 在容器中创建一个目录
RUN mkdir -p /data

# 将宿主机的文件复制到容器中的 /data 目录
COPY hello.txt /data/hello.txt

# 设置容器启动后执行的命令
CMD ["sh", "-c", "while true; do sleep 3600; done"]
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

步骤说明

  • FROM busybox:latest: 使用 busybox:latest 作为基础镜像。
  • RUN mkdir -p /data: 在容器内创建 /data 目录。
  • COPY hello.txt /data/hello.txt: 将宿主机上的 hello.txt 文件复制到容器的 /data 目录。请确保在构建镜像的目录中存在 hello.txt 文件。
  • CMD [“sh”, “-c”, “while true; do sleep 3600; done”]: 设置容器启动后执行的命令,使容器持续运行,每小时休眠一次。

2. 创建 hello.txt 文件:

在与 Dockerfile 相同的目录中,创建一个 hello.txt 文件,添加一些内容:

echo "Hello from custom busybox image" > hello.txt
  • 1.

3. 构建自定义镜像

在 Dockerfile 所在目录中运行以下命令来构建镜像:

docker build -t my_custom_busybox .
  • 1.
[root@VM-0-5-centos test_busybox]# docker build -t my_custom_busybox .
Sending build context to Docker daemon  3.072kB
Step 1/4 : FROM busybox:latest
latest: Pulling from library/busybox
ec562eabd705: Pull complete 
Digest: sha256:9ae97d36d26566ff84e8893c64a6dc4fe8ca6d1144bf5b87b2b85a32def253c7
Status: Downloaded newer image for busybox:latest
 ---> 65ad0d468eb1
Step 2/4 : RUN mkdir -p /data
 ---> Running in 8f33e3fc38e5
Removing intermediate container 8f33e3fc38e5
 ---> 05e6ea4bdc10
Step 3/4 : COPY hello.txt /data/hello.txt
 ---> 3f4301a9012e
Step 4/4 : CMD ["sh", "-c", "while true; do sleep 36000; done"]
 ---> Running in cf5704c53a4c
Removing intermediate container cf5704c53a4c
 ---> 2d188d99b7f8
Successfully built 2d188d99b7f8
Successfully tagged my_custom_busybox:latest
[root@VM-0-5-centos test_busybox]#
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.

可以看到,构建了一个新的镜像,并且在镜像里面预置了自定义了一个文件;

4. 运行镜像,并检查容器内部文件内容

新建 docker-compose.yaml 文件,内容如下:

version: "3.1"
services:

  # my-custom-busybox
  my-custom-busybox:
    image: my_custom_busybox:1.0.1
    container_name: my-custom-busybox
    hostname: my-custom-busybox
    restart: always
    deploy:
      resources:
        limits:
          cpus: '1'
          memory: 1G
    # volumes:
    #   - ./data:/data/
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.

第一次运行,查看预置文件内容时,先不挂载目录,直接运行:

[root@VM-0-5-centos test_busybox]# docker-compose up -d 
[+] Running 1/1
 ⠿ Container my-custom-busybox  Started                                                                                                                                                                                                                   10.9s
[root@VM-0-5-centos test_busybox]#
  • 1.
  • 2.
  • 3.
  • 4.

进入容器内部,查看预置文件内容:

[root@VM-0-5-centos test_busybox]# docker exec -it my-custom-busybox sh
/ # 
/ # 
/ # ls /data/
/ # 
/ # ls /data/
hello.txt
/ # 
/ # cat /data/hello.txt 
Hello from custom busybox image
/ #
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.

可以看到,当前镜像运行的容器,确实是我们之前构建镜像时的文件内容;

5. 新增挂载目录,并修改,验证 Commit 的新镜像

在当前目录下新建文件夹,并新增一个同名文件,来覆盖容器内的文件:

mkdir data
echo "Updated content from host" > ./data/hello.txt
  • 1.
  • 2.

打开上面 docker-compose.yaml 文件中的注释,新的内容如下:

version: "3.1"
services:

  # my-custom-busybox
  my-custom-busybox:
    image: my_custom_busybox:latest
    container_name: my-custom-busybox
    hostname: my-custom-busybox
    restart: always
    deploy:
      resources:
        limits:
          cpus: '1'
          memory: 1G
    volumes:
      - ./data:/data/
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.

保存后,再次启动:

[root@VM-0-5-centos test_busybox]# docker rm -f my-custom-busybox 
my-custom-busybox
[root@VM-0-5-centos test_busybox]# 
[root@VM-0-5-centos test_busybox]# docker-compose up -d           
[+] Running 1/1
 ⠿ Container my-custom-busybox  Started
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

为了保险起见,我这里先删除了旧的容器,然后启动新的容器;

再次进入容器内查看 /data/hello.txt 文件内容:

[root@VM-0-5-centos data]# docker exec -it my-custom-busybox sh
/ # 
/ # cat /data/hello.txt 
Updated content from host
/ #
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

可以看到,在挂载目录之后,容器内的同名文件确实被覆盖了,并且在宿主机上修改,容器内也是实时生效的。

接着验证 Commit 新镜像:

[root@VM-0-5-centos data]# docker ps | grep busybox
861e5b55ea63   my_custom_busybox:latest                                             "sh -c 'while true; …"   2 minutes ago    Up 2 minutes                                                                                                  my-custom-busybox
[root@VM-0-5-centos data]# 
[root@VM-0-5-centos data]# docker commit -m "update volume file content" 861e5b55ea63 my_custom_busybox:1.0.1
sha256:d8986fb86d74b0d5eae145a89780fad62b6335502ad9013bf17f169f0edee1fa
[root@VM-0-5-centos data]#
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

这里将当前已经挂载了的容器 Commit 成一个新的镜像,镜像为:my_custom_busybox:1.0.1

修改 docker-compose.yaml 文件中的镜像版本为my_custom_busybox:1.0.1,然后重新启动容器,再次进入容器内查看文件内容:

[root@VM-0-5-centos test_busybox]# docker-compose up -d 
[+] Running 1/1
 ⠿ Container my-custom-busybox  Started                                                                                                                                                                                                                   10.9s
[root@VM-0-5-centos test_busybox]# 
/ # [root@VM-0-5-centos data]# docker exec -it my-custom-busybox sh
/ # 
/ # 
/ # cat /data/hello.txt 
Hello from custom busybox image
/ #
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.

发现文件内容还是原来构建镜像时的内容;

总结

1. docker commit 时不会抓取容器挂载的文件系统;

Docker 中,容器挂载的文件系统变化不会影响到通过 docker commit 创建的新镜像,因为 docker commit 只会保存容器的层,而不会保存挂载点的内容。

2. 解决办法

2.1 直接在 Dockerfile 中更新文件:
FROM busybox:latest
COPY path/to/your/files /path/in/container
  • 1.
  • 2.

修改 Dockerfile,然后重新构建镜像。这种方式最直接,可以确保所有更改都被纳入到新的镜像中。

使用 docker build 构建镜像:docker build -t my_updated_image .

2.2 将文件复制到容器并重新构建

通过 docker cp 将文件从宿主机复制到运行中的容器中,然后使用 docker commit 创建新镜像。这种方法会包含手动修改后的文件。

[root@VM-0-5-centos test_busybox]# cat data/hello.txt 
Updated content from host
[root@VM-0-5-centos test_busybox]# 
[root@VM-0-5-centos test_busybox]# docker cp  data/hello.txt my-custom-busybox:/data/
[root@VM-0-5-centos test_busybox]# docker ps  | grep busy
aeab9533145f   my_custom_busybox:1.0.1                                              "sh -c 'while true; …"   3 hours ago     Up 3 hours                                                                                                    my-custom-busybox
[root@VM-0-5-centos test_busybox]# 
[root@VM-0-5-centos test_busybox]# docker commit -m "docker cp and commit new images " aeab9533145f my_custom_busybox:1.0.2
sha256:0212216bf47dcdd9dfbf3184bdbdf9e44ce1d86238a0ca4290079a54f7104ee0
[root@VM-0-5-centos test_busybox]# 
[root@VM-0-5-centos test_busybox]# docker-compose up -d 
[+] Running 1/1
 ⠿ Container my-custom-busybox  Started                                                                                                                                                                                                                   10.9s
[root@VM-0-5-centos test_busybox]# docker exec -it my-custom-busybox sh
/ # 
/ # cat /data/hello.txt 
Updated content from host
/ # 
/ #
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.