Docker 是一个 Client-Server 架构的应用,人家是有官称的:Docker Engine。Docker 只是你们对 Docker Engine 的昵称,固然 Docker 还有其余的意思,好比一家公司的名称。简单起见,本文中的 Docker 等同于 Docker Engine。docker
提到 Docker 咱们必需要知道它包含了三部份内容:安全
Docker daemon网络
一套与 Docker daemon 交互的 REST API架构
一个命令行客户端socket
下图很清晰的展现了它们之间的关系:tcp
Docker Machine 则是一个安装和管理 Docker 的工具。它有本身的命令行工具:docker-machine。ide
Docker daemon socket既然 Docker 客户端要和 Docker daemon 经过 REST API 通讯,那就让咱们看看它们能够采用的方法有哪些:工具
Unix socket加密
Systemd socket activationspa
Tcp
咱们能够简单的把 1 和 2 理解成一种方式,就是同一台主机上的进程间通讯。至于 3 则很好理解:经过 tcp 协议进行跨网络的通讯。
既然 1 和 2 用于同一台机器上的进程间通讯,那么咱们能够猜测:安装在同一主机上的 Docker 客户端和 Docker daemon 就是经过这种方式来通讯的。事实也正是如此,咱们能够查看安装 Docker 时默认添加的 Docker daemon 启动配置,打开文件 /etc/systemd/system/multi-user.target.wants/docker.service:
图中的 -H 用来指定 Docker Daemon 监听的 socket,此处指定的类型为 system socket activation。使用类型 1 和 2 进行通讯须要进程具备 root 权限。这也是 Docker 安装过程当中会自动建立一个具备 root 权限的用户和用户组的主要缘由。新建立的用户和用户组名称为 docker,建议你们把须要操做 Docker 的用户都加入到这个组中,不然当你执行命令时就会碰到下图显示的问题:
咱们还能够同时指定多个 -H 参数让 Docker daemon 同时监听不一样的 socket 类型。好比要添加对 TCP 端口 2376 的监听就可使用下面的命令行参数:
$ sudo dockerd -H fd:// -H tcp://0.0.0.0:2376
运行上面的命令,而后查看本机监听的端口:
此时咱们就能够从远程主机上的 Docker 客户端访问这部主机的 2376 端口了。
DOCKER_HOST 环境变量Docker 客户端默认的配置是访问本机的 Docker daemon,当你指定了 DOCKER_HOST 变量后,Docker 客户端会访问这个变量中指定的 Docker daemon。让咱们回顾一下 docker-machine env 命令:
原来咱们在前文中执行的 $ eval $(docker-machine env krdevdb) 命令就是在设置 DOCKER_HOST 环境变量。
解决安全问题咱们的 Docker daemon 监听了 tcp 端口,糟糕的是此时咱们没有作任何的保护措施。所以任何 Docker 客户端均可以经过 tcp 端口与咱们的 Docker daemon 交互,这显然是没法接受的。解决方案是同时启用 Docker daemon 和 Docker 客户端的 TLS 证书认证机制。这样 Docker daemon 和 Docker 客户端之间的通讯会被加密,而且只有安装了特定证书的客户端才可以与对应的 Docker daemon 交互。
至此本文的铺垫部分终于结束了,接下来咱们将讨论 Docker Machine 相关的内容。
Docker Machine create 命令根据 Docker Machine 驱动的不一样,create 命令执行的操做也不太同样,但其中有两步是咱们在这里比较关心的:
docker-machine 会在您指定的主机上执行下面的操做:
安装 Docker,并进行配置。
生成证书保护 Docker 服务的安全。
Docker 的安装过程并无什么秘密,这里再也不赘述。咱们重点关注 Docker daemon 的配置。仔细观察咱们会发现,经过 docker-machine 安装的 Docker 在 /etc/systemd/system 目录下多出了一个 Docker 相关的目录:docker.service.d。这个目录中只有一个文件 10-machine.conf:
好吧,-H tcp://0.0.0.0:2376 出如今这里并无让咱们太吃惊。在咱们作了巨多的铺垫以后,你应该以为这是理所固然才是。--tls 开头的几个参数主要和证书相关,咱们会在后面的安全设置中详细的介绍它们。让人多少有些疑惑的地方是上图中的 /usr/bin/docker。当前最新版本的 Docker Machine 还在使用旧的方式设置 Docker daemon,但愿在接下来的版本中会有所更新。
这个配置文件相当重要,由于它会覆盖 Docker 默认安装时的配置文件,从而以 Docker Machine 指定的方式启动 Docker daemon。至此咱们有了一个能够被远程访问的 Docker daemon。
咱们在 Docker daemon 的配置文件中看到四个以 --tls 开头的参数,分别是 --tlsverify、--tlscacert、--tlscert和 –tlskey。其中的 --tlsverify 告诉 Docker daemon 须要经过 TLS 来验证远程客户端。其它三个参数分别指定了一个 pem 格式文件的路径,按照它们指定的文件路径去查看一下:
对比一下手动安装的 Docker,会发现 /etc/docker 目录下并无这三个文件。毫无疑问它们是 Docker Machine 生成的,主要是为了启用 Docker daemon 的 TLS 验证功能。关于 TLS,笔者在《局域网内部署 Docker Registry》一文中略有涉及,当时是手动配置的证书,感兴趣的朋友能够参考一下。
如今让咱们回到安装了 Docker Machine 的主机上。
查看 /home/nick/.docker/machines/krdevdb 目录,发现了一些同名的文件(ca.pem、server-key.pem 和 server.pem),和主机 drdevdb 上的文件对比一下,发现它们是同样的!
让咱们再来观察一下这幅图:
除了咱们关注过的 DOCKER_HOST,还有另外三个环境变量。其中的 DOCKER_TLS_VERIFY 告诉 Docker 客户端须要启用 TLS 验证。DOCKER_CERT_PATH 则指定了 TLS 验证所依赖文件的目录,这个目录正是咱们前面查看的 /home/nick/.docker/machines/krdevdb 目录。
行文至此,困扰咱们的安全问题终于获得了解释:Docker Machine 在执行 create 命令的过程当中,生成了一系列保证安全性的秘钥和数字证书(*.pem)文件。这些文件在本地和远程 Docker 主机上各存一份,本地的用于配置 Docker 客户端,远程主机上的用于配置 Docker daemon,让两边都设置 TLS 验证的标记,依此实现安全的通讯。