二、docker的简单示例
运行第一个镜像 尝试执行下述命令,测试 Docker 的安装是否正确。 $ docker run deb
运行第一个镜像
尝试执行下述命令,测试 Docker 的安装是否正确。
$ docker run debian echo "Hello World"
运行这个命令需要花点时间,实际所需时间依网络速度而定,但最终你应看到类似下面的 结果。
Unable to find image 'debian' locally
debian:latest: The image you are pulling has been verified
511136ea3c5a: Pull complete
638fd9704285: Pull complete
61f7f4f722fb: Pull complete
Status: Downloaded newer image for debian:latest
Hello World
究竟发生了什么?刚才我们调用了 docker run 命令,它的功能是负责启动容器。
其中的 debian 参数是我们打算使用的镜像名称,这里所指的是一个被精简过的 Debian Linux2 发行版。
输出结果的第一行告诉我们本地没有 Debian 镜像。Docker 便会在 Docker Hub 进行 在线搜索,并下载 Debian 最新版本的镜像。
镜像下载后,Docker 会将它转成容器并运行, 然后在容器中执行我们指定的命令 echo "Hello World" 。命令的结果则显示在输出内容的最后一行。
如果再次执行同一命令,那就无需再下载镜像了,容器会立即启动。
而整个命令的运行 时间大概只需一秒,要是想象一下它背后所做的一切事情,就会觉得这个速度十分惊人:
Docker 部署并启动了我们的容器,执行我们指定的 echo 命令,最后把容器关掉。
类似的 工作如果用传统的虚拟机执行,所需时间将会是好几秒,甚至是好几分钟。
用以下命令,请求 Docker 提供一个容器中的 shell:
$ docker run -i -t debian /bin/bash
root@622ac5689680:/# echo "Hello from Container-land!"
Hello from Container-land!
root@622ac5689680:/# exit
exit
这样就可以进入容器中的命令行了,和使用 ssh 进入远程机器很相似。
当中的 -i 和 -t 参数表示我们想要一个附有 tty 的交互会话(interactive session).
/bin/bash 参数表示想获得一个 bash shell。
当退出 shell 时,容器就会停止 ( 主进程运行多久,容器就运行多久 )。
基本命令
- 启动容器
启动一个新的容器,不过这次用 -h 参数来设定一个新的主机名 (hostname)。
$ docker run -h CONTAINER -i -t debian /bin/bash
root@CONTAINER:/#
如果故意把容器弄坏会怎样呢?
root@CONTAINER:/# mv /bin /basket
root@CONTAINER:/# ls
bash: ls: command not found
我们移动了 /bin 目录的位置,现在这个容器已经没用了,至少暂时是这样的。
在删掉这个 容器之前,先来看看 ps、inspect 和 diff 会显示什么结果。 现在,打开一个新的终端(同时保持原来的容器运行),并在主机执行 docker ps。 运行结果如下:
CONTAINER ID IMAGE COMMAND ... NAMES
00723499fdbf debian "/bin/bash" ... stupefied_turing
上面的内容告诉目前运行中的容器的一些详细信息。其中大部分信息应无需多作解释。
不过,有一点要特别注意,那就是 Docker 为容器起了一个容易看懂的名称,这里叫 作“stupefied_turing”,在本机上可以用它来识别这个容器。
- 查看容器信息
我们可以把容器的名称或 ID 作为 docker inspect 命令的参数,来获取更多有关某个容器的信息:
$ docker inspect stupefied_turing
[
{
"Id":"00723499fdbfe55c14565dc53d61452519deac72e18a8a6fd7b371ccb75f1d91", "Created": "2015-09-14T09:47:20.2064793Z",
"Path": "/bin/bash",
"Args": [],
"State": {
"Running": true,
...
这里有很多有用的信息,但却不太容易读懂。我们可以用 grep 或 --format 参数(需要一 个 Go 模板)来过滤感兴趣的信息。例如:
$ docker inspect stupefied_turing | grep IPAddress
"IPAddress": "172.17.0.4",
"SecondaryIPAddresses": null,
$ docker inspect ––format {{.NetworkSettings.IPAddress}} stupefied_turing 172.17.0.4
这两行命令都能找出容器的 IP 地址。
- 查看容器哪些内容更改过
现在来看看另一个命令,docker diff:
$ docker diff stupefied_turing
C /.wh..wh.plnk
A /.wh..wh.plnk/101.715484
D /bin
A /basket
A /basket/bash
A /basket/cat
A /basket/chacl
A /basket/chgrp
A /basket/chmod
...
可以看到,在这个运行中的容器内,有哪些文件被改动过;
而这个例子中,被删除的文件 有 /bin,有新增的 /basket 以及它底下的文件,还有一些存储驱动的相关文件。
Docker 容 器使用联合文件系统(ofilee,UFS),它允许多个文件系统以层级方式挂载,并 表现为一个单一的文件系统。镜像的文件系统以只读方式挂载,任何对运行中容器的改变 则只会发生在它之上的可读写层。因此,Docker 只需查看最上面的可读写层,便可找出曾 对运行系统所作的所有改变。
- 查看容器操作记录
docker logs 以容器名称作为它的参数,就能得知这个容器里曾经发生过的一切事情:
$ docker logs stupefied_turing
root@CONTRAINER:/# mv /bin /basket
root@CONTRAINER:/# ls
bash: ls: command not found
- 删除容器 首先,从 shell 退出:
root@CONTRAINER:/# exit
exit
由于 shell 是唯一一个在容器中运行的进程,容器也会同时停止。
这时候如果执行docker ps,会发现已经没有任何正在运行的容器了。
如果键入 docker ps -a,它会列出所有容器,包括已经停止的 容器(官方说法是“已退出容器”,exited container)。已退出的容器可以用 docker start 重启
要把容器删掉, 需要使用 docker rm 命令:
$ docker rm stupefied_turing
stupefied_turing
- 清理已停止的容器
如果想删除所有已停止的容器,可以利用
docker ps -aq -f status=exited的结果,结果中包含所有已停止容器的ID。
$ docker rm -v $(docker ps -aq -f status=exited)
这个命令很常用,因此你可以考虑把它写成一个shell 脚本或定义为alias。
请注意 -v 参数在这里的作用,它意味着当所有由 Docker 管理的数据卷已经没有和任何容器关联时,都会一律删除。
为了避免已停止的容器的数量不断增加,可以在执行 docker run 的时候加上 --rm 参数,它的作用是当容器退出时,容器和相关的文件系统会被一并删掉。
- 删除所有没有关联容器的镜像:
docker rmi $(docker images -q)
- 退出容器不关闭容器:
ctrl + p + q
将 cowsay 的应用“ Docker 化”。
- 首先启动一个容器,并安装一些包:
$ docker run -it --name cowsay --hostname cowsay debian bash
root@cowsay:/# apt-get update ... Reading package lists... Done
root@cowsay:/# apt-get install -y cowsay fortune
现在就来试一试吧!
root@cowsay:/# /usr/games/fortune | /usr/games/cowsay
_____________________________________
/ Writing is easy; all you do is sit
| staring at the blank sheet of paper |
| until drops of blood form on your |
| forehead. |
| |
-- Gene Fowler /
-------------------------------------
^__^
(oo)_______
(__) )/
||----w |
|| ||
要把它转成镜像的话,执行 docker commit 即可,无论容器是在运行中还是在停止状态都可以。
执行 docker commit 时,需要提供的参数包括容器的名称(“cowsay”)、新镜像的名称(“cowsayimage”),以及用来存放镜像的仓库 名称(“test”):
root@cowsay:/# exit
exit
$ docker commit cowsay test/cowsayimage d1795abbc71e14db39d24628ab335c58b0b45458060d1973af7acf113a0ce61d
命令的返回值是这个镜像的唯一识别码(unique ID)。
现在创建了一个能随时使用, 并且已安装 cowsay 的镜像:
$ docker run test/cowsayimage /usr/games/cowsay "Moo"
______
< Moo >
------
^__^
(oo)_______
(__) )/
||----w |
|| ||
但是如果需要更改一些东西,那么还得手动重复刚才的步骤。假设希望基于另一个镜像来创建容器的话,也必须从头开始。
更重要的是,这样做的可重复性(repeatable)很差;创建镜像的步骤很难与他人分享,把 步骤重做也不是件易事,而且容易出错。解决这些问题的方法就是利用 Dockerfile,使创 建镜像的过程全部自动化。
通过Dockerfile创建镜像
Dockerfile 是一个描述如何创建 Docker 镜像所需步骤的文本文件。 先创建一个文件夹和文件:
$ mkdir cowsay
$ cd cowsay
$ touch Dockerfile
然后把下面的内容放入 Dockerfile:
FROM debian:wheezy
RUN apt-get update && apt-get install -y cowsay fortune
FROM 指令指定初始镜像(和之前一样,这里使用debian,这次还指定使用“wheezy”版本)。所有 Dockerfile 一定要有 FROM 指令作为第一个非注释指令。
RUN 指令指 定的 shell 命令,是将要在镜像里执行的。 这个例子中,它所做的事情其实和之前一样,就 是安装 cowsay 和 fortune。
现在已准备好生成镜像了,在同一目录下执行 docker build 命令:
$ ls Dockerfile
$ docker build -t test/cowsay-dockerfile .
Sending build context to Docker daemon 2.048 kB
Step 0 : FROM debian:wheezy ---> f6fab3b798be
Step 1 : RUN apt-get update && apt-get install -y cowsay fortune
---> Running in 29c7bd4b0adc
...
Setting up cowsay (3.03+dfsg1-4) ...
---> dd66dc5a99bd Removing intermediate container 29c7bd4b0adc
Successfully built dd66dc5a99bd
创建成功后,就可以与之前一样运行镜像了:
$ docker run test/cowsay-dockerfile /usr/games/cowsay "Moo"