目录

隐藏
  1. 宿主如果和容器系统不同的话,那不是和虚拟机一样,一层层的调用,那么 Docker 和虚拟机还有什么差别?
  2. 怎么固定容器 IP 地址?每次重启容器都要变化 IP 地址怎么办?
  3. docker pull 下来的镜像文件都在哪?
  4. Docker 怎么这么多软件,我该装哪个?
  5. docker pull 好慢啊怎么办?
  6. Docker 资料好少啊?网上的命令怎么不能用?
  7. 是直接用 yum / apt-get 安装 Docker 吗?
  8. 总说看官方文档,可是 Docker 官网文档经常被墙,看不了怎么办?
  9. 我要映射好几百个端口,难道要一个个 -p 么?
  10. 如何选择 Docker 书籍?
宿主如果和容器系统不同的话,那不是和虚拟机一样,一层层的调用,那么 Docker 和虚拟机还有什么差别?
要把 Windows 和 Linux 分清楚,更要把内核(kernel)和用户空间(userland)分清楚。

容器内的进程是直接运行于宿主内核的,这点和宿主进程一致,只是容器的 userland 不同,容器的 userland 由容器镜像提供,也就是说镜像提供了 rootfs。

假设宿主是 Ubuntu,容器是 CentOS。CentOS 容器中的进程会直接向 Ubuntu 宿主内核发送 syscall,而不会直接或间接的使用任何 Ubuntu 的 userland 的库。

这点和虚拟机有本质的不同,虚拟机是虚拟环境,在现有系统上虚拟一套物理设备,然后在虚拟环境内运行一个虚拟环境的操作系统内核,在内核之上再跑完整系统,并在里面调用进程。

还以上面的例子去考虑,虚拟机中,CentOS 的进程发送 syscall 内核调用,该请求会被虚拟机内的 CentOS 的内核接到,然后 CentOS 内核访问虚拟硬件时,由虚拟机的服务软件截获,并使用宿主系统,也就是 Ubuntu 的内核及 userland 的库去执行。

而且,Linux 和 Windows 在这点上非常不同。Linux 的进程是直接发 syscall 的,而 Windows 则把 syscall 隐藏于一层层的 DLL 服务之后,因此 Windows 的任何一个进程如果要执行,不仅仅需要 Windows 内核,还需要一群服务来支撑,所以如果 Windows 要实现类似的机制,容器内将不会像 Linux 这样轻量级,而是非常臃肿。看一下微软移植的 Docker 就非常清楚了。

所以不要把 Docker 和虚拟机弄混,Docker 容器只是一个进程而已,只不过利用镜像提供的 rootfs 提供了调用所需的 userland 库支持,使得进程可以在受控环境下运行而已,它并没有虚拟出一个机器出来。

参考:
https://www.docker.com/what-docker
视频笔记: Windows Server 和 Docker - John Starks

怎么固定容器 IP 地址?每次重启容器都要变化 IP 地址怎么办?
一般情况是不需要指定容器 IP 地址的。这不是虚拟主机,而是容器。其地址是供容器间通讯的,容器间则不用 IP 直接通讯,而使用容器名、服务名、网络别名。

为了保持向后兼容,docker run 在不指定 --network 时,所在的网络是 default bridge,在这个网络下,需要使用 --link 参数才可以让两个容器找到对方。

这是有局限性的,因为这个时候使用的是 /etc/hosts 静态文件来进行的解析,比如一个主机挂了后,重新启动IP可能会改变。虽然说这种改变Docker是可能更新/etc/hosts文件,但是这有诸多问题,可能会因为竞争冒险导致 /etc/hosts 文件损毁,也可能还在运行的容器在取得 /etc/hosts 的解析结果后,不再去监视该文件是否变动。种种原因都可能会导致旧的主机无法通过容器名访问到新的主机。

参考官网文档: https://docs.docker.com/engine/userguide/networking/default_network/dockerlinks/

如果可能不要使用这种过时的方式,而是用下面说的自定义网络的方式。

而对于新的环境(Docker 1.10以上),应该给容器建立自定义网络,同一个自定义网络中,可以使用对方容器的容器名、服务名、网络别名来找到对方。这个时候帮助进行服务发现的是Docker 内置的DNS。所以,无论容器是否重启、更换IP,内置的DNS都能正确指定到对方的位置。

参考官网文档: https://docs.docker.com/engine/userguide/networking/work-with-networks/#linking-containers-in-user-defined-networks

建议参考一下我写的 LNMP 的例子:
https://coding.net/u/twang2218/p/docker-lnmp/git

docker pull 下来的镜像文件都在哪?
初学 Docker 要反复告诫自己,Docker 不是虚拟机。

Docker不是虚拟机,Docker 镜像也不是虚拟机的 ISO 文件。Docker 的镜像是分层存储,每一个镜像都是由很多层,很多个文件组成。而不同的镜像是共享相同的层的,所以这是一个树形结构,不存在具体哪个文件是 pull 下来的镜像的问题。

具体镜像保存位置取决于系统,一般Linux系统下,在 /var/lib/docker 里。对于使用 Union FS 的系统(Ubuntu),如 aufs, overlay2 等,可以直接在 /var/lib/docker/{aufs,overlay2} 下看到找到各个镜像的层、容器的层,以及其中的内容。

但是,对于CentOS这类没有Union FS的系统,会使用如devicemapper这类东西的一些特殊功能(如snapshot)模拟,镜像会存储于块设备里,因此无法看到具体每层信息以及每层里面的内容。

需要注意的是,默认情况下,CentOS/RHEL 使用 lvm-loop,也就是本地稀疏文件模拟块设备,这个文件会位于 /var/lib/docker/devicemapper/devicemapper/data 的位置。这是非常不推荐的,如果发现这个文件很大,那就说明你在用 devicemapper + loop 的方式,不要这么做,去参照官方文档,换 direct-lvm,也就是分配真正的块设备给 devicemapper 去用。

Docker 怎么这么多软件,我该装哪个?
好吧,我决定要装 Docker 了,于是来打开 Docker 安装文档 看看怎么装吧……呃,然后就傻了,怎么这么多种选择啊?!

首先,Docker 有好几个版本,社区版(Community Edition)、企业基础版(Enterprise Edition Basic)、企业标准版(Enterprise Edition Standard)、企业高级版(Enterprise Edition Advanced)。对于我们一般学习使用而言,使用社区版就已足够,所以记住CE就可以了。

其次,我们会看到一堆平台特定的版本,Docker for Mac、Docker for Windows、Docker Toolbox、Docker for Azure、Docker for AWS 等等,还有一堆不同 Linux 的发行版。那我们应该用哪个?其实不难选择,这都是平台特定的东西嘛,选择自己平台就完了:

macOS 就选择 Docker for Mac
阿里云(未及时更新): https://mirrors.aliyun.com/docker-toolbox/mac/docker-for-mac/stable/

Linux 就选择自己平台的 Docker 源:
Ubuntu: https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/
Debian: https://docs.docker.com/engine/installation/linux/docker-ce/debian/
CentOS: https://docs.docker.com/engine/installation/linux/docker-ce/centos/
Fedora: https://docs.docker.com/engine/installation/linux/docker-ce/fedora/

Windows 要麻烦些:
如果是 Windows 10 专业版、企业版、教育版,并且版本在 10586 以后,并且不打算在 Docker 运行同时再运行其它虚拟机的情况下,可以装 Docker for Windows
阿里云(未及时更新): https://mirrors.aliyun.com/docker-toolbox/windows/docker-for-windows/stable/
其它情况都装 Docker Toolbox
阿里云: https://mirrors.aliyun.com/docker-toolbox/windows/docker-toolbox/

如果是特定云服务平台,可以考虑特定服务平台的版本(当然,这不是必须):
AWS:Docker for AWS
Azure:Docker for Azure

最后是发布通道,从今年初开始,也就是从 1.13 以后,Docker 使用了新的版本号规则,将采用类似 Ubuntu 那种 <年>.<月> 的形式,比如 17.03, 17.06 等。并且,将发布通道分为前沿版本(Edge)和稳定版本(Stable)。前沿通道将基本每个月发布一个版本,而稳定通道将基本每3个月发布一个版本。这样 Docker 的发布将有规律可寻。对于喜欢尝鲜的可以选择前沿版本,对于需要稳定的,可以选择稳定版本。

这里面需要注意的是,在参考 官方安装文档配置 Linux 源的时候,如果是国内服务器,要将其中的 https://download.docker.com/linux/ 替换为 https://mirrors.aliyun.com/docker-ce/linux/。

比如,文档如果要求执行下面的命令:

$ sudo add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"

那么就替换为:

$ sudo add-apt-repository \
"deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu \
$(lsb_release -cs) \
stable"

这样安装 Docker 就会使用阿里云的软件源,而不需要翻墙了。(注:这不是加速器,不要搞错了,加速器依旧需要配!)

docker pull 好慢啊怎么办?
首先,要“感谢”伟大的墙及其亲属。

然后,我们可以使用 Docker 镜像加速器来解决这个问题,加速器就是镜像、代理的概念。国内有不少机构提供了免费的加速器以方便大家使用,这里列出一些常用的加速器服务:

注意:不要使用加速器网站所给的配置脚本,容易导致错误。我们只需获取其提供的加速器地址即可。

Ubuntu 14.04 配置加速器(或其它使用 Upstart 的系统)

Ubuntu 14.04 是使用 upstart 进行系统初始化的,对于这类系统,可以用通过编辑配置文件的方法来配置加速器。

如果是 Ubuntu 14.04,那么编辑 /etc/default/docker,在里面寻找 DOCKER_OPTS 环境变量设置的这一行,在其后添加 -–registry-mirror=<加速器地址>。如果发现该行已被注释,或者不存在该行,那么新添一行即可。

比如,在使用官方源安装了 docker-engine 后,会建立一个默认的 /etc/default/docker,其中相关 DOCKER_OPTS 的行是这样的:

# Use DOCKER_OPTS to modify the daemon startup options.
#DOCKER_OPTS="--dns 8.8.8.8 --dns 8.8.4.4"
假设我们得到的加速器地址为 http://abcd.m.daocloud.io,我们添加一行配置,将其改为:

# Use DOCKER_OPTS to modify the daemon startup options.
#DOCKER_OPTS="--dns 8.8.8.8 --dns 8.8.4.4"
DOCKER_OPTS="--registry-mirror=http://abcd.m.daocloud.io"
保存文件后,重启 Docker 引擎:

$ sudo service docker restart
docker stop/waiting
docker start/running, process 3620
重启成功后,确认一下配置是否已经生效:

$ sudo ps -ef | grep dockerd
root      3620     1  0 04:26 ?        00:00:00 /usr/bin/dockerd --registry-mirror=http://abcd.m.daocloud.io --raw-logs
如果配置成功,生效后这里就会看到自己所配置的加速器的内容。

Ubuntu 16.04 或 CentOS 7 配置加速器(或其它使用 Systemd 的系统)

Ubuntu 16.04 和 CentOS 7 这类系统都已经开始使用 systemd 进行系统初始化管理了,对于使用 systemd 的系统,应该通过编辑服务配置文件 docker.service 来进行加速器的配置。

在启用服务后

$ sudo systemctl enable docker
可以直接编辑 /etc/systemd/system/multi-user.target.wants/docker.service 文件来进行配置。

sudo vi /etc/systemd/system/multi-user.target.wants/docker.service
在文件中找到 ExecStart= 这一行,并且在其行尾添加上所需的配置。假设我们获得的加速器地址为 https://jxus37ac.mirror.aliyuncs.com,那么可以这样配置:

ExecStart=/usr/bin/dockerd --registry-mirror=https://jxus37ac.mirror.aliyuncs.com

注: Docker 1.12 之前的版本,dockerd 应该换为 docker daemon,更早的版本则是 docker -d。不过还在用那些版本的童鞋,升级吧…


保存退出后,重新加载配置并启动服务:

sudo systemctl daemon-reload
sudo systemctl restart docker
确认一下配置是否已经生效:

sudo ps -ef | grep dockerd
如果配置成功,生效后就会在这里看到自己所配置的加速器。

在 1.13 版本以后,可以直接 docker info 查看,如果配置成功,加速器 Registry Mirror 会在最下面列出来。

如果重启后发现无法启动 docker 服务,检查一下服务日志,看看是不是之前执行过那些加速器网站的脚本,如果有做过类似的事情,检查一下是不是被建立了 /etc/docker/daemon.json 以配置加速器,如果是的话,删掉这个文件,然后在重启服务。

使用配置文件是件好事,比如修改配置不必重启服务,只需发送 SIGHUP 信号即可。但需要注意,目前在 dockerd 中使用配置文件时,无法输出当前生效配置,并且当 dockerd 的参数和 daemon.json 文件中的配置有所重复时,并不是一个优先级覆盖另一个,而是会直接导致引擎启动失败。很多人发现配了加速器后 Docker 启动不起来了就是这个原因。解决办法很简单,去掉重复项。不过

因此在这些问题解决前,建议使用修改 docker.service 这类做法来实现配置,而不是使用配置文件 daemon.json。


Docker 资料好少啊?网上的命令怎么不能用?
首先,做技术工作,请珍惜生命,远离百度;
其次,不翻墙、不用Google、不看英文资料,那请转行,没法混。

然后是回答问题,Docker的资料其实很丰富,特别是官方文档讲解非常详细。

https://docs.docker.com/

另外,Docker有丰富的镜像库,Docker Hub,特别是官方(Official)的镜像可以直接在生产环境中使用,制作比较精良。

https://hub.docker.com/explore/

所有的官方镜像都有 Dockerfile,以及在github上有全部生成镜像的配套文件,遵循了Dockerfile的最佳实践,这些也是很好地学习资料。

另外,在 YouTube 的 Docker 官方频道下有几百个视频讲座,从初级到高级用户都能从里面学到很多东西。

https://www.youtube.com/user/dockerrun

是直接用 yum / apt-get 安装 Docker 吗?
很多人问到 docker, docker.io, docker-engine 甚至 lxc-docker 都有什么区别?

其中,RHEL/CentOS 软件源中的 Docker 包名为 docker;Ubuntu 软件源中的 Docker 包名为 docker.io;而很古老的 Docker 源中 Docker 也曾叫做 lxc-docker。这些都是非常老旧的 Docker 版本,并且基本不会更新到最新的版本,而对于使用 Docker 而言,使用最新版本非常重要。另外,17.04 以后,包名从 docker-engine 改为 docker-ce,因此从现在开始安装,应该都使用 docker-ce 这个包。

不要使用操作系统提供的软件源中的 Docker 包,去使用 Docker 官方源的包。

正确的安装方法有两种:

一种是参考官方安装文档去配置 apt 或者 yum 的源;
另一种则是使用官方提供的安装脚本快速安装。
官方文档对配置源的方法已经有很详细的讲解,这里就不赘述,需要的直接去看 官方文档。这里只介绍使用官方的脚本快速安装:

17.04 及以后的版本

从 17.04 以后,可以用下面的命令安装。

export CHANNEL=stable
curl -fsSL https://test.docker.com/ | sh -- --mirror Aliyun
这里使用的是官方脚本安装,通过环境变量指定安装通道为 stable,(如果喜欢尝鲜可以改为 edge, test),并且指定使用阿里云的源(apt/yum)来安装 Docker CE 版本。

17.03 及以前的版本

早期的版本可以使用阿里云或者 DaoCloud 老的脚本安装:

使用阿里云的安装脚本:

curl -sSL http://acs-public-mirror.oss-cn-hangzhou.aliyuncs.com/docker-engine/internet | sh -


使用DaoCloud的Docker安装脚本:


curl -sSL https://get.daocloud.io/docker | sh


总说看官方文档,可是 Docker 官网文档经常被墙,看不了怎么办?
首先感谢伟大的墙及其先祖。

然后,我们可以本地运行 Docker 官方文档的网站,以 docker 的方式:

$ docker run -d -p 80:4000 docs/docker.github.io


这样访问 Docker 宿主的 80 端口,如 http://localhost,就会看到官网文档了。

对于那些访问不了我的问答录的童鞋,同样可以用这样的方式来本地运行:

$ docker run -d -p 80:80 twang2218/blog.lab99.org


然后就可以访问本地 80 端口看到最新的问答录了。

我要映射好几百个端口,难道要一个个 -p 么?
-p 是可以用范围的:

-p 8001-8010:8001-8010


如何选择 Docker 书籍?
Docker 属于敏捷开发的产品,并且处于高速创新阶段,每年都会有很多版本发布。由于这种快速开发的特性,Docker 一般只保留几个版本内的向后兼容性,再之后就会废弃。因此选择图书的时候,不应该选择比当前版本低超过2-3个版本的书籍。换句话说,市面上大部分书籍,特别是中文书籍、网文,很可能都过时了。

Docker 版本号在 2017 年以前,使用 <大版本号>.<小版本号>.<补丁版本号> 的结构,那时 Docker 基本会保持 3 个小版本号 之内的兼容性(如果一个特性宣布废弃,一般会在 3 个版本后才彻底移除)。

而从 2017 年春以后,Docker 使用了新版本号结构:<年>.<月>.<补丁版本号>,并且将每月发布一个前沿(Edge)版本,每季度发布一个稳定(Stable)版本。因此选择书籍也应该以介绍 2-3个季度以内版本 的书籍为准。那些介绍一年以前发布的 Docker 版本的书籍不应该再看了。

因此在购买 Docker 图书的时候,应该遵循这样的原则:观察一下当前的 Docker 版本号,选择不要晚于 3 个版本的 Docker 书籍。 比如写这段文字时为 17.06,那么就不要购买介绍 Docker 1.12 及其以前版本的书籍了,否则看到的很多东西可能将会因过时而无法使用,或者已经不必如此繁琐有更简单的方式去实现了。

所以,对于 Docker 学习而言,最好的书籍是官网文档,官网的文档很丰富。

新手教程: https://docs.docker.com/get-started/
大量的例子: https://docs.docker.com/samples/
用户文档: https://docs.docker.com/engine/userguide/
镜像: https://docs.docker.com/engine/userguide/eng-image/dockerfile_best-practices/
存储: https://docs.docker.com/engine/userguide/storagedriver/
网络: https://docs.docker.com/engine/userguide/networking/
管理文档: https://docs.docker.com/engine/admin/
存储: https://docs.docker.com/engine/admin/volumes/
安全: https://docs.docker.com/engine/security/security/
集群: https://docs.docker.com/engine/swarm/
对于新手而言,应该先从新手教程开始,内容还是很简单易懂的,很容易上手。然后,可以把用户文档好好看一遍,里面把很多 Docker 的基础概念讲的很清楚。概念清晰后,可以去把官网给出的例子好好的学习一下,这些例子都是具体怎么应用 Docker 的,有文字说明以及具体的考虑,很适合学习。