Docker是一种操作系统级别的虚拟化方案,它依赖于Linux的两个内核特性:Namespaces 和 Cgroups(Control Groups),因此Docker容器内只能运行与主机host相同或相似内核的操作系统。所以最常见/适合运行在Linux Host上。尽管Docker也可以安装在Windows和Mac OS等host上,但那都是Docker在OS上先运行了一层虚拟层,用Hype-V技术虚拟出Linux环境后再在其上运行Docker的Linux image。
容器Container和镜像image的区别
镜像(Image)是docker的核心,它是只读的,由多层结构组成,用户可以方便进行后续开发。Docker Hub上有很多官方的镜像,可以使用该Docker的pull命令从网络上下载下来。
容器(Container)则是由Docker程序从镜像Image创建,并在该image上再增加一层可写层,这样用户就可以往容器里面写入/删除数据了,比如安装自己的程序,保存自己的应用数据。每次运行docker run 同一个image都会创建一个不同的container。
同时,用户可以把当前正在使用的Container制作成自己定制的image。例如运行官方的Ubuntu镜像后,在该容器里安装好LAMP框架,然后把此Container保存成新的image。则后续每次都只要用docker运行此image,就可以得到装好LAMP的Ubuntu,非常方便。
使用Docker帮助文件
这个单独拿出来,是想让自己增强对程序内帮助文件的使用。Linux系统本身就有了man帮助系统,内容非常强大,只是比较枯燥,而且排版比较简陋,和常规的网页相差很远,但毕竟是系统的官方帮助,权威性高,因此要养成使用man系统的习惯。
Docker 主要用于Linux系统,因此帮助文件也采用man指令。比如man docker-run, man docker-logs, man docker-top, man docker-exec 等,基本上就是把docker的命令的前两个词用-连起来(也可以不连接,直接用man docker run等)。不过我在Mac上找不到此帮助,只有Ubuntu host才能看到。
镜像的一些基本操作
1. 获取镜像
docker pull [OPTIONS] NAME[:TAG|@DIGEST]
可能用到的选项是 -a 或 --all-tags,即下载该repo下的所有tag的镜像。如果没有:tag,则使用默认的:latest。这个操作经常可以省略,因为一般都是直接用docker run 命令。该run命令如果在本地没有找到镜像,就会自动去pull新的镜像。
2. 查看镜像
docker images [OPTIONS] [REPOSITORY[:TAG]]
最常用的格式就是什么参数没有,直接用docker images 就会输出当前本地的所有images,不包括interme images。列出的信息包括repo,tag,id等。
![](https://zangchuantao.com/wp-content/uploads/2018/12/image.png)
可选的几个参数是:
-a 显示全部image,包括intermediate images
--no-trunc 对image的id不进行截取,即显示id的完整字符。默认的是没有这个参数,只取id的12位
![](https://zangchuantao.com/wp-content/uploads/2018/12/image-1.png)
后续的REPO和TAG是用来过滤的,如果要用,必须严格match,不支持模糊查询。比如上面例子,docker images php 将返回php镜像信息,但docker images ph就返回空。
3. 删除镜像
docker rmi [OPTIONS] IMAGE [IMAGE...]
这个命令用来删除镜像,前提是目前没有用它生成的container。如果有container,则会报错而无法删除。此时需要先用docker rm container命令删除依赖于它的container,然后才可以删除此镜像。
另外,对于同一个image有好几个tag的情况,比如下图,就会报错,
![](https://zangchuantao.com/wp-content/uploads/2018/12/image-2.png)
因此可以手动利用REPO:TAG的方式依此删除,注意前几个都是untag,最后才是删除镜像
![](https://zangchuantao.com/wp-content/uploads/2018/12/image-3.png)
或者建议加上-f参数强制删除
![](https://zangchuantao.com/wp-content/uploads/2018/12/image-4.png)
推送镜像到dockerhub
docker push container
推荐先用--name使容器有个合理的name和tag,然后以name:TAG的方式来推送镜像到自己dockerhub的repo下面。默认是公有,别人也可以看到,可以转为私有,只供自己使用。
容器的基本操作
1. 启动新容器
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
每次运行此命令,即使是同一个image,也会生成多个不同id的容器。另外,多数docker命令都是把options选项放在镜像/容器前面的,这个就是。IMAGE都是采用REPO:TAG的形式,:TAG省略时就是默认的:latest。后面的command和参数是启动容器后运行命令的参数(如果有)。例如,启动后运行bash,就可以在镜像后加/bin/bash,或者直接bash。
常用的选项有如下几个:
什么参数都不加,例如 docker run hello-world就是直接从镜像hello-world创建1个新的容器。此容器内置一个程序打印输出一些信息,运行完毕则此容器就停止了,不再运行。
![](https://zangchuantao.com/wp-content/uploads/2018/12/image-5.png)
-d,容器在后台运行(守护模式),host上看不到上面的打印消息。此时可以通过 docker logs container 来查看它的输出,就可以看到信息了。此后台模式适合运行LAMP服务器等不需要用户进行交互干涉的容器。需要指出,如果容器内没有在一直执行的程序,则虽然是后台运行,但是执行完毕后仍然会退出容器。因此该容器一般是运行LAMP,这样Apache程序就一直在运行,监听端口。
![](https://zangchuantao.com/wp-content/uploads/2018/12/image-6.png)
-i,交互式操作,常和-t一起使用,这样容器的输入输出就被映射到了host的bash命令行,就可以在host的bash里直接操作容器内的命令。例如下面的命令就是用交互方式运行ubutnu容器,执行后就进入了容器的bash,输入命令后容器的输出会直接返回给host,就仿佛用户登陆进了容器进行直接操作,按exit退出。
![](https://zangchuantao.com/wp-content/uploads/2018/12/image-7.png)
一点补充,上面截图中的ubuntu容器,此时会一直运行等待用户输入,用户并无法执行host的任何命令。如果用户输入exit,则会退出并结束此容器运行,因为此ubuntu并没有执行任何命令。此时我们可以用组合键Ctrl+p,Ctrl+q键来退出,此时ubuntu仍然在后台运行,但是我们可以在host里执行别的命令了。如果想重新连接上此容器,需用docker attache container命令就可以了。
![](https://zangchuantao.com/wp-content/uploads/2018/12/image-8.png)
-p hostPort:containerPort 注意这个是小写字母p,将容器的某个端口映射到host的某个端口。用于容器是网络服务器的情况,如下面例子,假设ubutnu容器内运行Apache并监听80端口,则因为此端口已经映射到host的83, 则用户可以在host的浏览器内输入192.168.1.98:83就可以访问了。
![](https://zangchuantao.com/wp-content/uploads/2018/12/image-9.png)
-P 这个是大写字母,则将容器的所有端口或某个范围内的端口映射到host。
多说几句,容器到host的端口映射有四种方式:
a) -p containerPort, 只指定容器端口,此时host端口随机映射
b) -p hostPort : containerPort 同时指定容器和主机端口。最常用
c) -p ip::containerPort
d)-p ip:hostPort : containerPort
仔细看了下Docker的官方文档,这里还涉及到一个--expose 参数,它的意思是把容器的某些端口expose暴露出来,比如允许容器内Apache监听某个端口,但是并不会接着把这些端口暴露给host。而-p和-P命令则是把已经expose的容器端口接着expose给主机,例如,-p 8080:80就是把容器内的80端口映射到host的8080。
-v hostPath:containerPath 将容器的某个路径映射到host的某个路径。这个是文件挂载,常用来保存容器内的运行数据,因为容器一旦被关闭,则它内部的所有数据就丢失了,比如新建的数据表或新加安装的程序等,此时就可以用挂载的方式指定host的一个路径。例如下面例子就是将host的docker-demo路径映射到容器内的/tmp,则用户在容器内访问它的/tmp时,实际访问的是host的docker-demo。只要docker-demo文件夹内容不变,则每次运行该docker命令,都会执行上述挂载。
![](https://zangchuantao.com/wp-content/uploads/2018/12/image-10.png)
--name NAME 是给容器设置一个容易区分的名字,这样后续对容器的操作就可以不再使用12位的字符,而是使用此名字。
-w path 是指定登陆进容器后容器的当前工作目录。
2. 容器列表
docker ps [OPTIONS]
默认没有参数时只显示当前仍在运行的镜像。其他常用参数:
-a 显示全部容器,包括已经停止的。
3. 删除容器
docker rm [OPTIONS] CONTAINER [CONTAINER...]
可以同时删掉多个容器,只要把名字或id依此写好就可以了。默认是只能删除已经停止的容器,加参数-f 则可以删除正在运行中的容器(先给容器发一个kill信号)
4. 停止/启动守护式容器
普通的容器执行完程序后就自动结束并退出了,而守护式容器(run -d),比如LAMP容器,则会一直在后台运行,此时可以使用stop或kill命令停止一个容器。然后start命令再重新运行此容器,此时不会创建新的容器。注意start命令不不能启动一个不存在的container。
![](https://zangchuantao.com/wp-content/uploads/2018/12/image-12.png)
stop和kill的差别: stop命令执行时,容器会收到stop信号然后执行清理并过一段时间才退出,而kill命令是容器收到KILL信号而立即退出。
5. 保存容器到新镜像
保存容器有两种方式,一个是commit,另一个是用Dockerfile使用docker build命令来创建。
docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
此命令可用于保存修改过的容器,通过生成新的image,新生成的容器会保持相同设置。下图里的例子,我在当前Ubuntu容器的/tmp路径下创建个文本文件zang.txt,然后保存此容器到新的image ubuntu:chuantao。再运行此image生成新的容器里就带着这个文本文件了。
![](https://zangchuantao.com/wp-content/uploads/2018/12/image-13.png)
6. 查看容器日志
docker logs [-f][-t] --tail container
查看容器日志,这个对于守护模式运行的比较有用,因为无法从host的bash里直接看到输出。参数-f是follow,一直跟踪日志变化并返回结果。-t是加上时间戳,非常有用。 --tail n是类似tail命令,显示最新的几条,如果不加,就会显示所有log。n=0 则显示最新日志。
7. 查看容器内正在运行进程
docker top container
Linux显示当前所有进程的命令是top。这个docker top命令就可以不用attach上容器而可以直接查看容器内正在运行的进程。就相当于先attache上给容器,然后在容器内运行top命令。
8. 在运行中容器启动新进程
如果user想在一个已经运行的容器内执行别的命令,比如ls,copy等等。一种方式是先attach上给容器,然后在容器内部bash里执行相应命令。还有一种方式就是不attach,直接用exec命令来执行。具体命令如下
docker exec [-d -i -t -w等] container command arg
这个命令和docker run命令非常相似,也是支持类似的函数参数