掘金 后端 ( ) • 2021-06-22 14:05
.markdown-body{word-break:break-word;line-height:1.75;font-weight:400;font-size:15px;overflow-x:hidden;color:#333}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5,.markdown-body h6{line-height:1.5;margin-top:35px;margin-bottom:10px;padding-bottom:5px}.markdown-body h1{font-size:30px;margin-bottom:5px}.markdown-body h2{padding-bottom:12px;font-size:24px;border-bottom:1px solid #ececec}.markdown-body h3{font-size:18px;padding-bottom:0}.markdown-body h4{font-size:16px}.markdown-body h5{font-size:15px}.markdown-body h6{margin-top:5px}.markdown-body p{line-height:inherit;margin-top:22px;margin-bottom:22px}.markdown-body img{max-width:100%}.markdown-body hr{border:none;border-top:1px solid #ddd;margin-top:32px;margin-bottom:32px}.markdown-body code{word-break:break-word;border-radius:2px;overflow-x:auto;background-color:#fff5f5;color:#ff502c;font-size:.87em;padding:.065em .4em}.markdown-body code,.markdown-body pre{font-family:Menlo,Monaco,Consolas,Courier New,monospace}.markdown-body pre{overflow:auto;position:relative;line-height:1.75}.markdown-body pre>code{font-size:12px;padding:15px 12px;margin:0;word-break:normal;display:block;overflow-x:auto;color:#333;background:#f8f8f8}.markdown-body a{text-decoration:none;color:#0269c8;border-bottom:1px solid #d1e9ff}.markdown-body a:active,.markdown-body a:hover{color:#275b8c}.markdown-body table{display:inline-block!important;font-size:12px;width:auto;max-width:100%;overflow:auto;border:1px solid #f6f6f6}.markdown-body thead{background:#f6f6f6;color:#000;text-align:left}.markdown-body tr:nth-child(2n){background-color:#fcfcfc}.markdown-body td,.markdown-body th{padding:12px 7px;line-height:24px}.markdown-body td{min-width:120px}.markdown-body blockquote{color:#666;padding:1px 23px;margin:22px 0;border-left:4px solid #cbcbcb;background-color:#f8f8f8}.markdown-body blockquote:after{display:block;content:""}.markdown-body blockquote>p{margin:10px 0}.markdown-body ol,.markdown-body ul{padding-left:28px}.markdown-body ol li,.markdown-body ul li{margin-bottom:0;list-style:inherit}.markdown-body ol li .task-list-item,.markdown-body ul li .task-list-item{list-style:none}.markdown-body ol li .task-list-item ol,.markdown-body ol li .task-list-item ul,.markdown-body ul li .task-list-item ol,.markdown-body ul li .task-list-item ul{margin-top:0}.markdown-body ol ol,.markdown-body ol ul,.markdown-body ul ol,.markdown-body ul ul{margin-top:3px}.markdown-body ol li{padding-left:6px}.markdown-body .contains-task-list{padding-left:0}.markdown-body .task-list-item{list-style:none}@media (max-width:720px){.markdown-body h1{font-size:24px}.markdown-body h2{font-size:20px}.markdown-body h3{font-size:18px}}

这是我参与更文挑战的第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
复制代码