一、前言
- 本文所涉及的操作均在良好、无访问限制的网络环境下进行的。
- 本文纯属个人学习经验分享,出错再所难免,尤其是概念理解部分。另外我的语言表达能力也非常有限,有些地方也写得比较乱。故本文仅供参考!如果发现错误的地方,可以的话麻烦指点下,特别感谢!
二、Docker 简介
Docker 是一个开源项目。
可以把它理解为是一种新兴的超轻量级虚拟化技术。
传统虚拟化技术需要模拟计算机的一整套硬件出来,而且还要有自己的一套操作系统。
而 Docker 却不需要,它只需要与主机共享同一个内核,并充分利用 Linux 上内核的“环境隔离方案”来实现轻量级的虚拟化。
它在一些特定场景下与传统虚拟化技术相比,效率大幅提高,而资源开销却大幅降低。
Docker 的迁移也是十分方便的,基本上只需要把整个 Docker 目录搬过去即可。
Docker 使用 服务器-客户端 架构。
如果想在 Docker 上运行 exe 软件的话,那不用看下去了,左转找 KVM 去吧。
三、理解 Docker 的结构
四个基本结构:容器(Container
)、镜像(Image
)、仓库(Repository
)、注册点(Registry
)。
看着一脸懵逼对吧!是的,这几个概念确实比较难理解。但是我用类比法还是把它搞明白了。
先想象一个无盘系统是怎么样的,下面我们用一般的无盘系统来类比。
3.1 镜像
无盘服务器硬盘内有各种软件。比如说有 Win 7
,还有各类应用软件
。
而这些软件是相互依赖的。比如微信
需要装 Win 7
系统才能运行。
各个无盘计算机(容器)想要运行什么软件可以直接告诉无盘服务器。
无盘服务器会准备好一切所需软件,打成一个包(镜像),然后推送给无盘计算机。
假设整个无盘系统中只有两种包。一种包是 Win 7 & QQ
,另一种包是 Win 7 & 微信
。
但是无论这两种包有多少个,都不会占用额外的硬盘空间(利用 Union mount 实现镜像分层)。只有 Win 7
(某个镜像层) 、QQ
、微信
这三个软件会占用硬盘空间。
一个镜像通常是这样被标识的:<仓库名>:<标签名(版本号)>
(或者 <仓库名>:<@sha256:<校验值>>
) ,例如 nginx:latest
。如果不指定标签,默认为 latest
。
3.2 容器
相当于无盘计算机。
无盘计算机启动(容器启动)时,要从无盘服务器上拉取所需文件。如果无盘计算机对硬盘有写入操作的话,写入的数据将保存到无盘服务器的缓存区(容器存储层)。
无盘计算机关机(容器停止)时,如果没有额外设置,所有保存到无盘服务器的缓存区的文件(容器存储层)都将丢失。除非另外保存在 U 盘等外接设备(数据卷)中。
各个无盘计算机之间的运行互不干扰。(利用 cgroups 、namespace 实现隔离)
3.3 仓库
相当于同一个软件所有版本的集合。
3.4 注册点
相当于一个应用商店。
无盘服务器会来这里查找并下载软件。
3.5 与传统虚拟机类比
四、操作环境
- 操作系统:CentOS 7.3.1611(已关闭 SELinux)
- Linux 内核版本:3.10.0-514.26.2.el7.x86_64
- Docker 版本:17.06.2-ce
五、Docker 的安装
5.1 安装一些组件
yum -y install yum-utils device-mapper-persistent-data lvm2
5.2 添加 Docker 源
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
5.3 建立 yum 缓存
yum makecache fast
5.4 安装新版本的 Docker
yum -y install docker-ce
若出现密钥警告,按 y
回车即可。
5.5 启动 Docker 服务
systemctl start docker
如需开机自启动,请执行:
systemctl enable docker
六、运行个容器
6.1 运行 hello-world 容器
docker run hello-world
若出现以下执行结果,说明运行成功!
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
b04784fba78d: Pull complete
Digest: sha256:f3b3b28a45160805bb16542c9531888519430e9e6d6ffc09d72261b0d26ff74f
Status: Downloaded newer image for hello-world:latest
Hello from Docker!
#以下内容省略
6.2 过程解析
- Docker 客户端向 Docker 守护进程发出运行命令。
- Docker 守护进程发现没有
hello-world
这个镜像,于是从仓库中寻找并下载它。 - 下载完毕之后,Docker 守护进程以
hello-world
这个镜像创建一个新的容器。 - 容器向 Docker 守护进程输出内容之后,容器停止。Docker 守护进程把输出的内容传递给 Docker 客户端。
七、Docker 的基本操作
下面以创建一个 Ubuntu 系统的容器为例来了解一下 Docker 的基本操作。
为了方便理解,我把命令完整地写出来。
本节的命令参数只有基本的参数,需要其他设置(如数据卷)的话会在后面讲到。
docker
命令支持自动补全,这点必须赞!
7.1 获取一个镜像
常用格式
docker image pull [<注册点名>/]<仓库名>[:<标签名(版本号)>]
例如
docker image pull ubuntu
执行结果
Using default tag: latest
latest: Pulling from library/ubuntu
d5c6f90da05d: Pull complete
1300883d87d5: Pull complete
c220aa3cfc1b: Pull complete
2e9398f099dc: Pull complete
dc27a084064f: Pull complete
Digest: sha256:34471448724419596ca4e890496d375801de21b0e67b81a77fd6155ce001edad
Status: Downloaded newer image for ubuntu:latest
可以明显地看出,镜像被分为了多个块。
7.2 以某个镜像建立一个容器
常用格式
docker container create --interactive --tty [--name=<容器名>] [<--env <变量名>=<变量值>> [--env <变量名>=<变量值>] ... ] [--privileged] <镜像名> [要运行的程序和参数]
例如
以 ubuntu
为镜像,建立一个名为 ubuntu_test
的容器。
docker container create --interactive --tty --name=ubuntu_test ubuntu
执行结果
46cc818c92f0780ccd89811c12906c4527b554d18a61e72b0b2337b663ebab5f
这是自动生成的容器长 ID。
7.3 启动一个容器
常用格式
docker container start <容器名> [容器名] [容器名] ...
可同时启动多个容器。
例如
启动刚才创建的 ubuntu_test
容器。
docker container start ubuntu_test
执行结果
ubuntu_test
返回容器名称,说明启动成功。
7.4 查看容器信息
常用格式
docker container ls [--all] [--no-trunc]
或
docker container ps [--all] [--no-trunc]
例如
查看本机所有容器的状态。
docker container ls --all
执行结果
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
#<容器ID> <镜像名> <命令参数> <创建时间> <状态> <打开的端口> <容器名称>
d4bc3be9148d hello-world "/hello" 5 hours ago Exited (0) 5 hours ago practical_rosalind
46cc818c92f0 ubuntu "/bin/bash" 3 hours ago Up 2 minutes ubuntu_test
可以看到,除了刚创建的 ubuntu_test
容器之外,还有一个名为 practical_rosalind
容器。practical_rosalind
这个容器正是刚才运行 docker run hello-world
时生成的。
7.5 操作一个容器 & 容器内外进程简析
7.5.1 操作一个容器
常用格式
docker container attach <容器名>
例如
docker container attach ubuntu_test
执行之后按几下回车,如果出现类似 root@46cc818c92f0:/#
的提示符,那说明您已经在容器内操作了。
我们来查看下系统的版本。
uname -a
Linux 46cc818c92f0 3.10.0-514.26.2.el7.x86_64 #1 SMP Tue Jul 4 15:04:05 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
好像看不出是 Ubuntu 系统,没关系,我们再执行下以下命令。
cat /etc/os-release
NAME="Ubuntu"
VERSION="16.04.3 LTS (Xenial Xerus)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 16.04.3 LTS"
VERSION_ID="16.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
VERSION_CODENAME=xenial
UBUNTU_CODENAME=xenial
好,已经确定了是在虚拟的 Ubuntu 系统中操作了!我们再来看一下容器内都有什么进程吧。
7.5.2 容器内进程简析
在容器内执行以下命令:
ps aux
执行结果
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 18304 2072 pts/0 Ss 05:19 0:00 /bin/bash
root 229 0.0 0.0 34416 1436 pts/0 R+ 07:27 0:00 ps aux
可以看到,容器中目前只存在 bash
和刚开启的 ps
这两个进程,而且 bash
的 PID
为 1
!
这说明了容器处在与实体机不同的 namespace
中,容器看不到实体机的进程。
容器进程数目与传统虚拟机的进程数目相比大幅减少了,所以说容器的效率非常高,启动基本上是毫秒级的!
7.5.3 容器外进程简析
实体机可以看到容器内的进程吗?答案是可以的。
我们来看下实体机上的进程树。
systemd─┬─ModemManager───2*[{ModemManager}
├─dockerd─┬─docker-containe─┬─docker-containe─┬─bash
│ │ │ └─8*[{docker-containe}]
│ │ └─12*[{docker-containe}]
│ └─11*[{dockerd}]
#无关部分已省略
可以看出,bash
属于 dockerd
的子进程。
这说明了容器处在实体机的子 namespace
中,同时需要依赖实体机中的进程才可以运行。
所以,容器并不是完全的“虚拟化”。
7.6 从容器中脱开
前面 7.2
我们已经说过了:容器启动时会运行镜像里指定的应用程序,而这个程序运行结束后,容器也会停止。
现在这个容器启动时运行了镜像默认设定的的 /bin/bash
,所以当 /bin/bash
关闭时,容器就会跟着关闭。
如果直接按 Ctrl + D
退出容器操作的话,bash
就会退出而使整个容器停止运行,我们显然不希望这样。
正确的脱开方法是 先按 Ctrl+P
再按 Ctrl+Q
(跟 Screen
的操作方法非常相似)。
执行完该操作之后,如果出现 read escape sequence
,就说明已经从容器中脱开了。
7.7 停止一个容器
常用格式
docker container stop <容器名>
执行完以上命令之后,实体机将向容器内所有的进程发送 SIGTERM
信号,然后给 10 秒的时间,让容器内的进程可以“优雅地”结束。
如果容器内的进程在 10 秒内没有结束,则实体机向未结束的进程发送 SIGKILL
信号来强制结束。
如果想立即强制结束容器的话把 stop
换成 kill
就行了。
例如
docker container stop ubuntu_test
执行结果
ubuntu_test
返回容器名称,说明容器已经停止。
7.8 删除一个容器
常用格式
docker container rm <容器名>
⚠️ 注意:运行中的容器不能被删除。
例如
我们把刚才个使用 hello-world
镜像的容器给删掉,容器名从上面 7.4
中得到。
docker container rm practical_rosalind
执行结果
practical_rosalind
返回容器名称,说明容器已经删除。
7.9 查看镜像信息
常用格式
docker images [--all]
例如
docker images
执行结果
这里我们顺便回顾一下,一个镜像是这样标识的: <仓库名>:<标签名(版本号)>
。
REPOSITORY TAG IMAGE ID CREATED SIZE
#<所在仓库> <标签> <镜像 ID> <创建时间> <大小>
ubuntu latest ccc7a11d65b1 4 weeks ago 120MB
hello-world latest 1815c82652c0 2 months ago 1.84kB
7.10 删除一个镜像
常用格式
docker image rm <镜像名>
⚠️ 注意:如果有基于要删除镜像的容器,则该镜像不能被删除。
例如
我们把刚才个下载的 hello-world:latest
镜像给删掉。
docker image rm hello-world:latest
执行结果
Untagged: hello-world:latest
Untagged: hello-world@sha256:f3b3b28a45160805bb16542c9531888519430e9e6d6ffc09d72261b0d26ff74f
Deleted: sha256:1815c82652c03bfd8644afda26fb184f2ed891d921b20a0703b46768f9755c57
Deleted: sha256:45761469c965421a92a69cc50e92c01e0cfa94fe026cdd1233445ea00e96289a
镜像已经删除。
7.11 使用一次性容器(推荐用于测试或开发环境)
上述步骤目的其实是为了让大家更好地理解 Docker 的结构。
我认为 Docker 有一个缺点,那就是容器一旦创建完成之后,想要修改配置就有点麻烦。而在测试或开发环境中,经常需要修改容器的配置。
好在,容器非常轻,完全可以做到“用时创建、用完即删”!
所以,我还是推荐大家使用以下命令,来做到容器创建、启动、删除三合一。
常用格式
docker container run --rm [--detach] --interactive --tty [--name=<容器名>] <镜像名> [要运行的程序和参数]
其他选项请参考 7.2
。
执行完该命令之后,容器会自动创建然后启动。如果没有加入 --detach
选项,容器启动完成后会直接进入到容器中操作(可随时脱开)。
而容器停止之后,容器就会马上被删除,非常方便。
下文均使用一次性容器。
7.12 配置容器自重启(推荐用于生产环境)
常用格式
在 7.2
或 7.11
的 --tty
后面插入以下任一选项:
选项功能--restart on-failure:<次数>
容器停止时,若出现错误则自动重启(进程返回值不为 0)。
⚠️ 注意:如果执行了 docker container stop
或者 docker container kill
命令,容器自重启将失效。
以上选项不能和 --rm
同时使用,也就是说不适用于一次性容器。
7.13 限制容器占用的资源
常用格式
在 7.2
或 7.11
的 --tty
后面插入以下任一选项(可同时使用):
例如
运行一个 hello-world:latest
镜像的一次性容器,限制使用 2 个 CPU 以及 128M 内存。
docker container run --rm --interactive --tty --cpus 2 --memory 128M hello-world:latest
7.14 查看容器的详细配置信息
把容器所有配置参数以 json 格式显示出来,这里只做了解。
常用格式
docker container inspect <容器名>
7.15 查看镜像的详细信息
把镜像所有参数以 json 格式显示出来,这里只做了解。
常用格式
docker image inspect <镜像名>
7.16 手动构建镜像
在很多时候,我们需要从包含 Dockerfile 的 Docker 项目中构建镜像。
例如这个项目:
docker-node-hello/
├── Dockerfile
├── Makefile
├── README.md
├── Vagrantfile
├── index.js
├── package.json
└── supervisord
└── conf.d
├── node.conf
└── supervisord.conf
常用格式
cd <项目所在目录> && docker image build --tag [<注册点名>/]<仓库名>[:<标签名(版本号)>] .
例如
把上面的 Docker 项目构建成镜像,命名为 hello/hello:latest
(当前目录已经是项目所在的目录)。
docker image build --tag hello/hello:latest .
执行结果
运行之后,系统会根据 Dockerfile 中的指令自动构建镜像(Dockerfile 指令语法请查阅参考文献)。
Sending build context to Docker daemon 36.35kB
Step 1/13 : FROM node:0.10
0.10: Pulling from library/node
386a066cd84a: Pull complete
75ea84187083: Pull complete
# 此处省略
Step 13/13 : CMD ["supervisord", "-n"]
---> Running in 5ac9cc1c0c33
Removing intermediate container 5ac9cc1c0c33
---> 1742ecbad743
Successfully built 1742ecbad743
Successfully tagged hello/hello:latest
# 构建完成
构建完成之后我们用它来建立一个一次性容器并运行。
docker container run --rm --interactive --tty hello
Hello from Docker!
This message shows that your installation appears to be working correctly.
To generate this message, Docker took the following steps:
1. The Docker client contacted the Docker daemon.
2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
(amd64)
3. The Docker daemon created a new container from that image which runs the
executable that produces the output you are currently reading.
4. The Docker daemon streamed that output to the Docker client, which sent it
to your terminal.
To try something more ambitious, you can run an Ubuntu container with:
$ docker run -it ubuntu bash
Share images, automate workflows, and more with a free Docker ID:
https://cloud.docker.com/
For more examples and ideas, visit:
https://docs.docker.com/engine/userguide/
运行成功。
八、保存容器中的数据
前面我们已经说过,容器一旦停止,容器内文件的所有改动都将丢失。
所以,我们必须指定一个可以存储数据的方法,才能保存容器内的数据。
8.1 使用数据卷
简单地说,数据卷就是在容器内指定一个目录,存储在这个目录下的数据都可以持久化保存。
常用格式
在 7.2
或 7.11
的 --tty
后面插入如下格式的内容
--volume [<实体机文件或目录>:]<容器内文件或目录> [--volume [<实体机文件或目录>:]<容器内文件或目录>] ...
⚠️ 注意:有些本身就需要持久化存储的容器(例如 mysql
)在创建的时候系统就会自动为其创建一个数据卷。其在实体机上的存储位置可在 7.1.4
命令的运行结果中找到。
例如
以 ubuntu
为镜像,建立一个名为 ubuntu_test2
的容器并启动,将实体机上的 /root/ubuntu_files1
目录挂载到容器中的 /test/ubuntu_files1
目录中去(实体机上的目录已存在)。
docker container run --rm --interactive --tty --volume /root/ubuntu_files1:/test/ubuntu_files1 --name=ubuntu_test2 ubuntu:latest
执行完该命令后,我们已经是在容器内操作了。此时我们来看看容器内是否出现了挂载的目录。
ls /test/ubuntu_files1
如果没有返回错误信息,说明挂载成功。现在我们来向里面写一点东西,看下能不能保存。
echo "File saved" > /test/ubuntu_files1/1.txt
然后按 Ctrl + D
关闭容器。我们就来到实体机下了,接下来我们来看看实体机有没有这个文件。
cat /root/ubuntu_files1/1.txt
如果返回了 File saved
,说明数据已经可以保存了!
您也可以再次创建容器,然后在容器内看看 /test/ubuntu_files1/1.txt
这个文件在不在。
8.2 打包一个新的镜像(不推荐)
这种方法十分简单粗暴,就是把容器内现有文件全部打包成一个新的镜像,然后新建一个使用该镜像的容器即可实现文件的保存。
之所以不推荐,主要是因为这样做会把容器内运行程序的缓存等无用文件一并打包下来。如果多次执行该操作,容器会变得非常臃肿。其次也可能会造成一定的安全隐患。
常用格式
docker container commit <需要保存的容器名> <打包之后的镜像名>
这里就不举例了。
九、容器的网络连接
9.1 容器联网的基本方式
NAT 模式是容器默认的联网模式。
在启动 Docker 服务之后,Docker 会自动往实体机内添加一个名为 docker0
的网桥,这个网桥默认可以与实体机内所有的网络接口通信。
我们通过执行 brctl show
这条命令来看一下 docker0
网桥的状态。
执行结果
bridge name bridge id STP enabled interfaces
docker0 8000.024229c84e5a no
当容器启动之后,会生成一个形如 vethXXXXXXX
的容器专用接口。这个接口也会加入到 docker0
的桥接列表中。
docker0
上面有 IP 地址,也可以自动为每个容器分配 IP 地址(非 DHCP 协议)。
我们通过执行 ip addr show dev docker0
还有 brctl show docker0
这条两命令来看一下。
执行结果
6: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP
link/ether 02:42:29:c8:4e:5a brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:29ff:fec8:4e5a/64 scope link
valid_lft forever preferred_lft forever
======================================================================
bridge name bridge id STP enabled interfaces
docker0 8000.024229c84e5a no vethcd2a637
其实 docker0
就相当于一个普通的路由器,通过 NAT 转换实现容器间的相互通信和连接外网。
我们通过执行 iptables -t nat -L POSTROUTING -v -n
来查看相关的 NAT 规则。
执行结果
Chain POSTROUTING (policy ACCEPT 373 packets, 31640 bytes)
pkts bytes target prot opt in out source destination
12 729 MASQUERADE all -- * !docker0 172.17.0.0/16 0.0.0.0/0
很显然,存在 docker0
网段的 SNAT 规则,说明容器都是通过 NAT 的方式与实体机共享网络的。
如需查看容器的 IP 地址,请执行以下命令:
docker container inspect --format='{{.NetworkSettings.IPAddress}}' <容器名>
9.2 自定义网桥 & 容器 IP 地址
使用默认网桥一般是不能自定义容器 IP 地址的,会提示以下错误:
User specified IP address is supported only when connecting to networks with user configured subnets
这时候,我们就需要自定义一个网桥。
9.2.1 自定义网桥
常用格式
docker network create --driver bridge --subnet <网桥网段> <网桥名>
例如
创建一个名为 docker_br1
的网桥,网段为 192.168.10.0/24
docker network create --driver bridge --subnet 192.168.10.0/24 docker_br1
执行结果
46cc818c92f0780ccd89811c12906c4527b554d18a61e72b0b2337b663ebab5f
这是自动生成的网桥长 ID。
网桥的管理和删除命令格式和上面镜像管理的相似,这里就不再说了。
9.2.2 自定义容器 IP 地址
常用格式
在 7.2
或 7.11
的 --tty
后面插入如下格式的内容
--network=<网桥名> --ip=<IP地址>
例如
创建并运行一个使用刚才创建的 docker_br1
网桥的容器,把 IP 地址设定为 192.168.10.211
,然后验证结果。
为了方便,这里将直接运行一个包含 ifconfig
命令的镜像的容器,然后执行 ifconfig eth0
命令来验证。
docker container run --rm --interactive --tty --network=docker_br1 --ip=192.168.10.211 --name=see_ip_addr ianneub/network-tools ifconfig eth0
执行结果
#镜像下载过程略
eth0 Link encap:Ethernet HWaddr 02:42:c0:a8:0a:02
inet addr:192.168.10.211 Bcast:0.0.0.0 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:2 errors:0 dropped:0 overruns:0 frame:0
TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:180 (180.0 B) TX bytes:0 (0.0 B)
显然,这里的 IP 地址已经是我们设定的 192.168.10.211
。
9.3 端口映射
如果容器需要对外提供服务,在默认情况下需要把容器内的端口映射到实体机上。
常用格式
在 7.2
或 7.11
的 --tty
后面插入如下格式的内容
-p [<实体机接口 IP 地址>:]<实体机端口>:<容器内端口>[/<tcp|udp>] [-p [<实体机接口 IP 地址>:]<实体机端口>:<容器内端口>[/<tcp|udp>]] ...
可以创建多个端口映射。
例如
运行一个提供 HTTP 服务的镜像(这里用 nginx)的容器,然后把容器中的 80 端口映射到实体机上的 8888 端口,后测试能否访问。
docker container run --detach --rm --interactive --tty -p 8888:80 --name=nginx_test nginx && curl 127.0.0.1:8888
执行结果
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
......
如果含有以上内容的界面,说明端口映射成功。
9.4 为容器设置域名解析
在很多情况下,我们需要在容器之间进行网络通信。而它们的 IP 地址又是不固定的,这就需要为容器固定一个 DNS 名称。
假设现在有一个容器 A ,而新建的容器 B 需要访问容器 A 上的网络服务,在没设置域名解析的情况下容器 B 只能通过容器 A 的 IP 地址来访问容器 A 。而如果在容器 B 建立的时候设置了域名解析,容器 B 就可以通过容器 A 的名称或别名来访问容器 A 。
常用格式
在 7.2
或 7.11
的 --tty
后面插入如下格式的内容
--link <容器名称>[:<容器别名>]
9.5 桥接到物理网络
个人不太推荐使用这种方法。
首先,容器都无法靠自身获取 IP 地址,必须借助 pipework
工具来设置。
而且,容器内一般是没有防火墙的,这样会降低整个容器的安全性。
如果需要使用物理网络上的不同 IP 提供不同服务的话,建议在实体机的物理网卡上绑定多个地址,然后把容器特定端口映射到特定的地址上去。
以下简单地说一下设置的方法。
9.5.1 设置网桥
请参考 Linux 网桥的相关教程,新建一个网桥,网桥成员为物理网络接口,并根据实际情况设置网桥的 TCP/IP 参数。
9.5.2 安装 pipework
git clone https://github.com/jpetazzo/pipework.git && cp pipework/pipework /usr/bin && rm -rf pipework
9.5.3 修改 docker 默认使用的网桥
cp /lib/systemd/system/docker.service /etc/systemd/system/docker.service
然后修改 /etc/systemd/system/docker.service
:
找到 ExecStart=
这一行,把这一行改成 ExecStart=/usr/bin/dockerd -b <网桥名>
,保存文件。
9.5.4 通过 pipework 指定容器 IP 地址
常用格式
pipework <网桥名> `<docker container run 完整命令>` <IP地址/前缀长度@网桥IP>
⚠️ 注意:pipework
只能修改运行中容器的网络配置,并且容器要持续运行。
十、其他实用的命令
10.1 查看 Docker 服务器的基本信息
docker info
10.2 查看容器占用的资源
docker container stats
该命令可以查看所有运行中容器的 CPU、内存使用情况。
状态是实时显示的,查看完毕请按 Ctrl+C
退出。
10.3 查看容器内运行的进程
常用格式
docker container top <容器名>
该命令以宿主机的命名空间来显示容器进程信息。
建议使用这个命令看看容器内运行哪些进程就好了,不要过分纠结 PID 和 UID。
例如
docker container top CentOS_Host
执行结果
UID PID PPID C STIME TTY TIME CMD
root 4072 4056 0 02:35 ? 00:00:00 /bin/bash
root 4138 4072 0 02:35 ? 00:00:00 sleep 10000
10.4 查看 Docker 的事件
常用格式
docker events [--since <yyyy-MM-ddThh:mm:ss> [--until <yyyy-MM-ddThh:mm:ss>]]
通过事件流,我们可以知道一个容器发生了什么事。比如开启、停止等。
事件是实时显示的,如果查看完毕请按 Ctrl+C
退出。
例如
显示从 2018 年 4 月 1 日 00:00:00 到 2018 年 4 月 1 日 12:00:00 的所有事件。
docker events --since="2018-04-01T00:00:00" --until="2018-04-01T12:00:00"
执行结果
2018-04-01T10:57:20.011080986+08:00 network connect 99ef690ad66b76dd2a9d6e6ba85da4984a8845ae42d4d4cf5db8f8546ed73626 (container=473b6de7768fd77297b996b7abcce8f93db62ecccdabad9acbfd664a408e68cc, name=bridge, type=bridge)
2018-04-01T10:57:20.437781611+08:00 container start 473b6de7768fd77297b996b7abcce8f93db62ecccdabad9acbfd664a408e68cc (build-date=20180302, image=centos, license=GPLv2, name=CentOS_Host, vendor=CentOS)
2018-04-01T10:58:16.764205384+08:00 container pause 473b6de7768fd77297b996b7abcce8f93db62ecccdabad9acbfd664a408e68cc (build-date=20180302, image=centos, license=GPLv2, name=CentOS_Host, vendor=CentOS)
2018-04-01T10:58:25.290369808+08:00 container unpause 473b6de7768fd77297b996b7abcce8f93db62ecccdabad9acbfd664a408e68cc (build-date=20180302, image=centos, license=GPLv2, name=CentOS_Host, vendor=CentOS)
...
10.5 查看容器的日志
常用格式
docker container logs <容器名>
日志一般记录着容器的 stdout
与 stderr
,可用于容器的调试与排错。
10.6 查看容器存储层的文件变化
常用格式
docker container diff <容器名>
可查看容器存储层相对于原始镜像的变化。
例如
docker container diff 9ffd2df5d849
执行结果
A /11111
C /root
A /root/.ash_history
10.7 快速删除所有容器
常用格式
docker container rm $(docker container ls --all -q)
⚠️ 注意:运行中的容器不能被删除。
10.8 快速删除所有镜像
常用格式
docker image rm $(docker image ls --all -q)
⚠️ 注意:如果有基于要删除镜像的容器,则该镜像不能被删除。