http://seanlook.com/2014/10/31/docker-command-best-use-1/
docker run -it --name mytest centos:centos6 /bin/bash 会启一个伪终端
在伪终端执行top,可发现只有top和bash两个进程
因为容器的核心是所执行的应用程序,所需要的资源都是应用程序运行所必需的,除此之外,并没有其它的资源,可见Docker对资源的利用率极高。
exit退出伪终端
docker ps 看不到刚刚的container应用了
但docker ps -a,可以看到
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
851a967f07e9 centos:centos6 "/bin/bash" 2 minutes ago Exited (0) About a minute ago mytest
再次执行docker run -it --name mytest centos:centos6 /bin/bash,会启动失败
/usr/bin/docker-current: Error response from daemon: Conflict. The name "/mytest" is already in use by container 851a967f07e9555edb2a548f37628844543a75eff15bf920d03d4808ebf43313. You have to remove (or rename) that container to be able to reuse that name..
See '/usr/bin/docker-current run --help'.
如果第一次,docker run -it --rm=true --name mytest centos:centos6 /bin/bash的话,就不会报这错。执行完就删除container
============
数据卷
数据卷 是一个可供一个或多个容器使用的特殊目录,它绕过 UFS,可以提供很多有用的特性:
-
数据卷可以在容器之间共享和重用 -
对
数据卷的修改会立马生效 -
对
数据卷的更新,不会影响镜像 -
数据卷默认会一直存在,即使容器被删除
创建一个数据卷
docker volume create --name my-vol
docker volume ls
docker volume inspect my-vol
[
{
"Name": "my-vol",
"Driver": "local",
"Mountpoint": "/var/lib/docker/volumes/my-vol/_data", #在本地主机下的目录
"Labels": {},
"Scope": "local"
}
]
启动一个挂载数据卷的容器
在用 docker run 命令的时候,使用 --mount 标记来将 数据卷 挂载到容器里。在一次 docker run 中可以挂载多个 数据卷。
下面创建一个名为 web 的容器,并加载一个 数据卷 到容器的 /webapp 目录。
$ docker run -d -P \
--name web \
# -v my-vol:/wepapp \
--mount source=my-vol,target=/webapp \
training/webapp \
python app.py
使用名字进行挂载
目录映射其实是“绑定挂载”host的路径到container的目录,这对于内外传送文件比较方便,使用比较简单,-v <host_path:container_path>,绑定多个目录时再加-v。
-v /tmp/docker:/tmp/docker
另外在两个container之间建立联系可用--link,详见高级部分或官方文档。
下面是一个例子:
docker run --name nginx_test -v /tmp/docker:/usr/share/nginx/html:ro -p 90:80 -d nginx
在主机的/tmp/docker下建立index.html,就可以通过http://localhost:80/或http://host-ip:80访问了。
#例子 生成ffmpeg镜像 #Dockerfile FROM centos:centos6 WORKDIR /data/ COPY ./ffmpeg ./ffserver ./ffprobe ./ ENTRYPOINT [ "./ffmpeg" ]
#生成镜像
docker build -t ffmpeg_in_centos:v1 .
#测试
# docker run ffmpeg_in_centos:v1
./ffmpeg: error while loading shared libraries: libasound.so.2: cannot open shared object file: No such file or directory
#docker run ffmpeg_in_centos:v1 -v /lib64/:/lib64 错误,选项应该在image前面, docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
docker run -v /lib64/:/lib64 ffmpeg_in_centos:v1
https://www.binss.me/blog/learn-docker-with-me-about-volume/
https://www.binss.me/blog/learn-docker-with-me-about-volume/
在使用Docker的过程中,常常需要通过Volume来挂载目录。可以通过以下两种方式创建Volume:
-
在Dockerfile中指定VOLUME /some/dir
-
生成容器时执行docker run -v /some/dir命令来指定
有个问题我纠结了很久:Dockerfile中使用VOLUME指令挂载目录和docker run时通过-v参数指定挂载目录有什么区别?
区别
根据官方文档,Dockerfile生成目标镜像的过程就是不断docker run + docker commit的过程,当Dockerfile执行到VOLUME /some/dir(这里为/var/lib/mysql)这一行时,输出:
| Step 6 : VOLUME /var/lib/mysql | |
| ---> Running in 0c842ec90849 | |
| ---> 214e3dccd0f2 |
在这一步,docker生成了临时容器0c842ec90849,然后commit容器得到镜像214e3dccd0f2。因此VOLUME /var/lib/mysql是通过docker run -v /var/lib/mysql,即第二种方式来实现的,随后由于容器的提交,该配置被保存到了镜像214e3dccd0f2中,通过inspcet可以查看到:
| "Volumes": { | |
| "/var/lib/mysql": {}, | |
| } |
通过inspect该镜像生成的容器可以发现挂载配置:
| "Mounts": [ | |
| { | |
| "Name": "8827c361d103c1272907da0b82268310415f8b075b67854f27dbca0b59a31a1a", | |
| "Source": "/mnt/sda1/var/lib/docker/volumes/8827c361d103c1272907da0b82268310415f8b075b67854f27dbca0b59a31a1a/_data", | |
| "Destination": "/var/lib/mysql", | |
| "Driver": "local", | |
| "Mode": "", | |
| "RW": true, | |
| "Propagation": "" | |
| } | |
| ] |
由于没有指定挂载到的宿主机目录,因此会默认挂载到宿主机的/var/lib/docker/volumes下的一个随机名称的目录下,在这里为/mnt/sda1/var/lib/docker/volumes/8827c361d103c1272907da0b82268310415f8b075b67854f27dbca0b59a31a1a/_data。
Source:宿主机的目录
Destination: 容器内的目录
因此Dockerfile中使用VOLUME指令挂载目录和docker run时通过-v参数指定挂载目录的区别在于,run的-v可以指定挂载到宿主机的哪个目录,而Dockerfile的VOLUME不能,其挂载目录由docker随机生成。
若指定了宿主机目录,比如:
| docker run --name mysql -v ~/volume/mysql/data:/var/lib/mysql -d mysql:5.7 |
那么inspect如下:
| "Mounts": [ | |
| { | |
| "Source": "/Users/binss/volume/mysql/data", | |
| "Destination": "/var/lib/mysql", | |
| "Mode": "", | |
| "RW": true, | |
| "Propagation": "rprivate" | |
| } | |
| ] |
这里将/var/lib/mysql挂载到宿主机的/Users/binss/volume/mysql/data目录下,而不再是默认的/var/lib/docker/volumes目录。
这样做有什么好处呢?我们知道,/var/lib/mysql是mysql在linux下默认的数据存储目录。将该目录挂载到宿主机,可以使数据在容器被移除时得以保留,而不会随着容器go die。
VOLUME /path_of_container #容器的path_of_container将会被挂在到宿主机上的一个目录
VOLUME /path_of_host /path_of_container #容器的path_of_container将会被挂在到宿主机上的path_of_host目录
下次新建mysql容器,只需同样挂载到/Users/binss/volume/mysql/data,即可复用原有数据。
有童鞋可能会问,那VOLUME /some/dir和不指定宿主机目录的docker run -v /some/dir有什么用?我们不可能为了复用该目录的数据,先inspect找到目录在哪,然后将新容器挂载上去,多麻烦呀。
查阅官方文档,发现还有另外一种挂载方式:
| docker run --name mysql2 --volumes-from mysql -d mysql:5.7 |
docker inspect mysql2发现,mysql2的/var/lib/mysql和mysql的/var/lib/mysql都挂载到了相同的目录下,因此在mysql2中可以复用mysql的数据:
| "Mounts": [ | |
| { | |
| "Name": "8827c361d103c1272907da0b82268310415f8b075b67854f27dbca0b59a31a1a", | |
| "Source": "/mnt/sda1/var/lib/docker/volumes/8827c361d103c1272907da0b82268310415f8b075b67854f27dbca0b59a31a1a/_data", | |
| "Destination": "/var/lib/mysql", | |
| "Driver": "local", | |
| "Mode": "", | |
| "RW": true, | |
| "Propagation": "" | |
| } | |
| ] |
值得注意的是,虽然/var/lib/mysql没有在run的指令中出现,但其出现在了生成mysql:5.7镜像的Dockerfile中,所以即使在run时忘记使用volume,该目录依然能够从宿主机直接访问,官方真是用心良苦啊。另外,由于复用了mysql的所有数据,因此连接数据库用户名密码也和mysql一样,而不会是run时传入的参数,一切都和原来mysql中的一样。
备份与恢复
既然有了--volumes-from,那么备份也不成问题。
| docker run --rm --volumes-from mysql -v $(pwd):/backup mysql:5.7 tar cvf /backup/backup.tar /var/lib/mysql |
该指令将mysql容器的/var/lib/mysql目录打包成backup.tar,存放在宿主机的当前目录下。实现方法很简单,创建一个新容器,通过--volumes-from将新容器的/var/lib/mysql挂载到mysql的相同目录下,同时又将宿主机的当前目录挂载到容器的/backup目录下,然后通过tar将/var/lib/mysql打包存放到容器的/backup目录下,这样宿主机的当前目录就得到了打包文件backup.tar。以上流程完成后,容器由于设置了--rm而被删除,只留下backup.tar,毫无痕迹地备份了容器mysql的数据文件。
恢复时,只需执行以下命令:
| docker run --rm --volumes-from mysql -v $(pwd):/backup mysql:5.7 bash -c "cd /var/lib/mysql && tar xvf /backup.tar --strip 1" |
同样是创建了一个临时容器,将刚才打包backup.tar解压到mysql容器的/var/lib/mysql中。因为backup.tar解压出来是backup文件夹,所以通过--strip 1跳过这一级目录。
移除无用的挂载目录
由于poll下来的镜像常常都设置了VOLUME指令,所以如果我们创建容器时没有为其指定宿主机挂载目录,如前文所述,会在/var/lib/docker/volumes目录下生成挂载目录。而在删除容器时,如果忘记使用-v,则该挂载目录会残留在宿主机中,占用硬盘空间。例如/var/lib/mysql文件夹,一个就好几百M。
通过以下指令可以移除这些残余的无用挂载目录:
| docker volume rm $(docker volume ls -qf dangling=true) |
总结
通过VOLUME,我们得以绕过docker的Union File System,从而直接对宿主机的目录进行直接读写,实现了容器内数据的持久化和共享化。
[root@ffmpeg]# docker run -it centos:v1 [root@c2f0ba7b0c35 data]# ls /lib64/ | wc -l 144 [root@c2f0ba7b0c35 data]# exit exit [root@10.20.170.131 ffmpeg]# docker run -it -v /lib64:/lib64/ ffmpeg_in_centos:v1 [root@38dc7bfebfe5 LCMS]# ls /lib64/ | wc -l 1178
浙公网安备 33010602011771号