【Docker】容器挂载文件修改后 Commit 新镜像,挂载文件不会更新
【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"]
步骤说明
- 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
3. 构建自定义镜像
在 Dockerfile 所在目录中运行以下命令来构建镜像:
docker build -t my_custom_busybox .
[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]#
可以看到,构建了一个新的镜像,并且在镜像里面预置了自定义了一个文件;
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/
第一次运行,查看预置文件内容时,先不挂载目录,直接运行:
[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 test_busybox]# docker exec -it my-custom-busybox sh
/ #
/ #
/ # ls /data/
/ #
/ # ls /data/
hello.txt
/ #
/ # cat /data/hello.txt
Hello from custom busybox image
/ #
可以看到,当前镜像运行的容器,确实是我们之前构建镜像时的文件内容;
5. 新增挂载目录,并修改,验证 Commit 的新镜像
在当前目录下新建文件夹,并新增一个同名文件,来覆盖容器内的文件:
mkdir data
echo "Updated content from host" > ./data/hello.txt
打开上面 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/
保存后,再次启动:
[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
为了保险起见,我这里先删除了旧的容器,然后启动新的容器;
再次进入容器内查看 /data/hello.txt
文件内容:
[root@VM-0-5-centos data]# docker exec -it my-custom-busybox sh
/ #
/ # cat /data/hello.txt
Updated content from host
/ #
可以看到,在挂载目录之后,容器内的同名文件确实被覆盖了,并且在宿主机上修改,容器内也是实时生效的。
接着验证 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]#
这里将当前已经挂载了的容器 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. docker commit 时不会抓取容器挂载的文件系统;
在 Docker
中,容器挂载的文件系统变化不会影响到通过 docker commit
创建的新镜像,因为 docker commit
只会保存容器的层,而不会保存挂载点的内容。
2. 解决办法
2.1 直接在 Dockerfile 中更新文件:
FROM busybox:latest
COPY path/to/your/files /path/in/container
修改 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
/ #
/ #