这是我参与更文挑战的第14天,活动详情查看: 更文挑战
操作环境
- Centos 7.9.2009
- Docker version 20.10.2, build 2291f61
原始镜像
直接下载最新的redis镜像
docker pull redis
复制代码
[root@testmachine fuhanxiao]# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
redis latest 621ceef7494a 13 days ago 104MB
[root@testmachine fuhanxiao]# docker run -p 6379:6379 -d redis
1ab8246b84bc23afbd8348deecd74e4260d457e6dd987917bec8b1ddb3f1afdf
复制代码
需要注意的是因为做了端口映射,必须要满足下面两个
必须要有firewalld或者是iptables服务在跑,默认centos7使用的是firewalld,systemctl status firewalld
必须要打开ip forward,echo 1 > /proc/sys/net/ipv4/ip_forward
查看下容器信息
[root@testmachine fuhanxiao]# docker inspect 1ab
...
...
"Mounts": [
{
"Type": "volume",
"Name": "d31bb6212a374dd34a93a992274f3a522cd1555c554ccf497277c3c89a668f5b",
"Source": "/var/lib/docker/volumes/d31bb6212a374dd34a93a992274f3a522cd1555c554ccf497277c3c89a668f5b/_data",
"Destination": "/data",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
...
...
复制代码
可以看到原始镜像配置了一个volume,Destination对应的是容器内的目录/data,Source对应的是宿主机的目录,这里的目录名是一个随机数。
这其实是镜像内暴露了一个volume出来,但是起容器的时候没有声明本地对应的目录,所以docker就自己新建了一个目录作为对应的volume,下面我还会用自己新建的volume对这一理论进行验证。
声明volume
下面我们在原始镜像的基础上开始自己的实验。
创建Dockerfile内容如下
FROM redis
COPY ./redis.conf /usr/local/etc/redis/redis.conf
VOLUME /usr/local/etc/redis
CMD [ "redis-server", "/usr/local/etc/redis/redis.conf" ]
复制代码
主要是这里的第三行,通过VOLUME关键字将容器内部的一个目录声明成一个volume。需要注意的是Dockfile里面只能声明容器内部的目录,因为生成的镜像可能会被运行在各种设备上,所以宿主机的目录一定是在起容器的时候指定和生成的。
同时这里还拷贝了一份本地的配置文件到容器内,作为新镜像的启动配置,下面我们就用这个文件来进行测试。
生成新的镜像
[root@testmachine myredis]# docker build -t redis:v2 .
Sending build context to Docker daemon 190.5kB
Step 1/4 : FROM redis
---> 621ceef7494a
Step 2/4 : COPY ./redis.conf /usr/local/etc/redis/redis.conf
---> fdd3cb20855c
Step 3/4 : VOLUME /usr/local/etc/redis
---> Running in a95a0f7fad1c
Removing intermediate container a95a0f7fad1c
---> 884d688cb230
Step 4/4 : CMD [ "redis-server", "/usr/local/etc/redis/redis.conf" ]
---> Running in 9badfe62c79d
Removing intermediate container 9badfe62c79d
---> ca75e474ccf3
Successfully built ca75e474ccf3
Successfully tagged redis:v2
[root@testmachine myredis]# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
redis v2 ca75e474ccf3 10 minutes ago 104MB
redis latest 621ceef7494a 2 weeks ago 104MB
复制代码
下面我们用这个新的v2镜像来测试。
创建volume
指定容器目录不指定宿主机目录
如上面看到的那样,指定了容器的目录但是不指定宿主机目录的话,docker会自动在宿主机上创建对应的目录。
其中指定容器目录的方式有两种:
通过命令行
[root@testmachine myredis]# docker run -p 6379:6379 -v /usr/local/etc/redis -d redis
af3aeeb1071d3fd2470fa3174803fc73c0872033f5e2e44c25144368f0281aa3
复制代码
注意这里用的镜像是默认镜像redis,并不是redis:v2,然后通过-v
参数声明了容器内的一个目录作为volume。
注意,为了避免错误,volume的目录路径最好是完整路径
下面查看下容器绑定的volume
[root@testmachine myredis]# docker inspect af3
...
...
"Mounts": [
{
"Type": "volume",
"Name": "b7b0151ded2be4f71dab89ef1ce5289be2785917106d71efe35a0ca2e07aadf8",
"Source": "/var/lib/docker/volumes/b7b0151ded2be4f71dab89ef1ce5289be2785917106d71efe35a0ca2e07aadf8/_data",
"Destination": "/usr/local/etc/redis",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
},
{
"Type": "volume",
"Name": "d9b95843b00e4f4861668b79dcd8261b78a233c2c5ee4a588a664e4950730361",
"Source": "/var/lib/docker/volumes/d9b95843b00e4f4861668b79dcd8261b78a233c2c5ee4a588a664e4950730361/_data",
"Destination": "/data",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
...
...
复制代码
可以看到docker同样创建了一个随机目录,进入这个目录,新建一个文件写点内容
[root@testmachine myredis]# cd /var/lib/docker/volumes/b7b0151ded2be4f71dab89ef1ce5289be2785917106d71efe35a0ca2e07aadf8/_data
[root@testmachine _data]# echo 123 > test.txt
复制代码
然后去容器内就马上能看到了
[root@testmachine fuhanxiao]# docker exec -it af3 /bin/bash
root@af3aeeb1071d:/data# cd /usr/local/etc/redis/
root@af3aeeb1071d:/usr/local/etc/redis# cat test.txt
123
复制代码