Docker Daemon 默认情况下是只允许本地访问的,不允许远程访问。本文将首先介绍 Docker Daemon 的连接方式,然后说明如何配置远程访问。即实现通过本地 docker 客户端访问远程主机的 docker 服务端,以此来监控远程主机上的 Docker 容器。
如何配置:
有两种方式:
第一种(推荐)
是使用 systemctl edit docker
来调用文本编辑器修改指定的单元或单元实例,ubuntu 默认调用的是 nano 编辑器,不是很好用,如果不熟悉 nano 编辑器的操作可以使用 vim 编辑器。
主要也就是新建或修改 /etc/systemd/system/docker.service.d/override.conf
,其内容如下:
##Add this to the file for the docker daemon to use different ExecStart parameters (more things can be added here)
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd
解释一下:
默认情况下使用 systemd 时,docker.service 的设置为:
ExecStart=/usr/bin/dockerd -H fd://
,这将覆盖写到 daemon.json 中的任何 hosts 。通过在 override.conf 文件中将 ExecStart 仅仅定义为:ExecStart=/usr/bin/dockerd
,这将会使用在 daemon.json 中设置的 hosts 。这个文件中的第一行ExecStart=
必须要有,因为它将用于清除默认的 ExecStart 参数。如果是修改 docker.service 的文件而不是创建 override.conf,那么下次 systemd 重启时,docker.service 文件也会被重新创建。
然后在 /etc/docker/daemon.json
(没有就新建一个,下文统一简称 daemon.json)中写入以下内容
{
"hosts":[
"unix:///var/run/docker.sock",
"tcp://0.0.0.0:2375"
]
}
该文件必须符合 json 规范写法,否则 Docker 将不能启动
重新加载 daemon 并重启 docker 服务:
$ sudo systemctl daemon-reload
$ sudo systemctl restart docker.service
检查端口监听:
$ sudo netstat -ntlp |grep dockerd
tcp6 0 0 :::2375 :::* LISTEN 2439/dockerd
在远程主机上面通过 tcp socket 来访问本机的 Docker Daemon 服务:
$ docker -H 192.168.205.10:2375 images
$ docker -H 192.168.205.10:2375 ps
其中 192.168.1.130 是开放了远程访问的主机的 IP。
第二种
这种就很简单暴力,直接修改/lib/systemd/system/docker.service
文件,注释掉默认的 ExecStart 并添加新的 ExecStart 配置:
# ExecStart=/usr/bin/dockerd -H fd://
ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock
然后重启 docker.service:
$ sudo systemctl daemon-reload
$ sudo systemctl restart docker.service
这样 dockerd 就开始监听 tcp 端口 2375 了
第三种
Docker 客户端与 dockerd 之间就是通过 REST 的方式通信的。前面我们已经让 dockerd 监听 tcp 端口了,所以我们可以使用 curl 来代替 docker 客户端。这里我们简单的演示如何请求 dockerd 从 docker hub 上下载 hello-world 镜像:
$ curl '127.0.0.1:2375/images/create?fromImage=hello-world&tag=latest' -X POST
{"status":"Pulling from library/hello-world","id":"latest"}
{"status":"Digest: sha256:8c5aeeb6a5f3ba4883347d3747a7249f491766ca1caa47e5da5dfcf6b9b717c0"}
{"status":"Status: Image is up to date for hello-world:latest"}
如果去看看 Engine API,你会发现其它的请求也都是用类似方式发送的,更多API可以参考官方文档,目前最新的版本是v1.40:https://docs.docker.com/engine/api/v1.40/
CoreOS 官方文档提供的方法
官方文档:https://coreos.com/os/docs/latest/customizing-docker.html
新建 /etc/systemd/system/docker-tcp.socket
文件
[Unit]
Description=Docker Socket for the API
[Socket]
# ListenStream=127.0.0.1:2375
ListenStream=2375
BindIPv6Only=both
Service=docker.service
[Install]
WantedBy=sockets.target
重新启动服务
$ sudo systemctl daemon-reload
$ sudo systemctl enable docker-tcp.socket
$ sudo systemctl stop docker
$ sudo systemctl start docker-tcp.socket
$ sudo systemctl start docker
初始化完成后需要将DOCKER_HOST的地址设置为tcp://127.0.0.1:4243
export DOCKER_HOST=tcp://127.0.0.1:4243
配置安全连接
官方文档:https://docs.docker.com/engine/security/https/
上面我们配置的远程连接是不安全的,只能用于测试环境中。在生产环境中需要配置 TLS
安全连接,只有拥有密钥的客户端,才能连接到远程的服务端。
服务端配置
只能使用 Linux 下的 openssl
生成密钥,macOS 下的不可以。在 CoreOS
下执行以下操作
手动执行命令生成证书(不推荐)
这一步较复杂,你可以跳过这一方法,使用容器生成证书。此方法来自 Docker 官方文档 https://docs.docker.com/engine/security/https/。
文件总览
├── ca-key.pem # 妥善保管,连接时用不到
├── ca.pem # clent & server
├── ca.srl # 用不到
├── cert.pem # client
├── client.csr # 请求文件
├── extfile.cnf # 配置文件
├── key.pem # client
├── server-cert.pem # server
├── server.csr # 请求文件
└── server-key.pem # server
# 生成 CA 私钥
$ openssl genrsa -aes256 -out ca-key.pem 4096
# 需要输入两次密码(自定义)
# 生成 CA 公钥
$ openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem
# 输入上一步中设置的密码,然后需要填写一些信息
# 下面是服务器证书生成
# 生成服务器私钥
$ openssl genrsa -out server-key.pem 4096
# 用私钥生成证书请求文件
$ openssl req -subj "/CN=localhost" -sha256 -new -key server-key.pem -out server.csr
$ echo subjectAltName = DNS:localhost,DNS:www.khs1994.com,DNS:tencent,IP:192.168.199.100,IP:192.168.57.110,IP:127.0.0.1 >> extfile.cnf
# 允许服务端哪些 IP 或 host 能被客户端连接,下文会进行测试。
# DNS 我也不是很理解,这里配置 localhost ,公共 DNS 解析的域名,/etc/hosts 文件中的列表进行测试。
$ echo extendedKeyUsage = serverAuth >> extfile.cnf
# 用 CA 来签署证书
$ openssl x509 -req -days 365 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem
-CAcreateserial -out server-cert.pem -extfile extfile.cnf
# 再次输入第一步设置的密码
# 下面是客户端证书文件生成
# 生成客户端私钥
$ openssl genrsa -out key.pem 4096
# 用私钥生成证书请求文件
$ openssl req -subj '/CN=client' -new -key key.pem -out client.csr
$ echo extendedKeyUsage = clientAuth >> extfile.cnf
# 用 CA 来签署证书
$ openssl x509 -req -days 365 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem
-CAcreateserial -out cert.pem -extfile extfile.cnf
# 再次输入第一步设置的密码
# 删除文件,更改文件权限
$ rm -v client.csr server.csr
$ chmod -v 0400 ca-key.pem key.pem server-key.pem
$ chmod -v 0444 ca.pem server-cert.pem cert.pem
把 ca.pem
server-cert.pem
server-key.pem
三个文件移动到 /etc/docker/
文件夹中。
使用容器生成证书(推荐)
GitHub:https://github.com/khs1994-docker/dockerd-tls
方法来自 CoreOS
官方文档:https://coreos.com/os/docs/latest/generate-self-signed-certificates.html
既然使用容器那就可以在任何系统运行,只要把生成的证书文件对应的放到 Docker 客户端和服务端即可。
$ git clone --depth=1 https://github.com/khs1994-docker/dockerd-tls.git
$ cd dockerd-tls
在 ./cfssl/*.json
中配置好 CN
hosts
。
$ docker-compose up cfssl
命令执行完毕之后在 ./cfssl/cert
文件夹中可以看到证书文件,修改文件权限。
$ chmod -v 0400 ca-key.pem key.pem server-key.pem
$ chmod -v 0444 ca.pem server-cert.pem cert.pem
把 ca.pem
server-cert.pem
server-key.pem
三个文件移动到服务端 /etc/docker/
文件夹中。
CoreOS
请使用第二种方法,其他 Linux 系统根据上文选择的方法,这里选择对应的方法
通常的配置方法
修改 daemon.json
文件。
注意:非安全连接使用的是
2375
端口,安全连接使用的是2376
端口。当然这是推荐的端口配置,你可以配置任何端口!
{
"tlsverify": true,
"tlscert": "/etc/docker/server-cert.pem",
"tlskey": "/etc/docker/server-key.pem",
"tlscacert": "/etc/docker/ca.pem",
"hosts":[
"unix:///var/run/docker.sock",
"tcp://0.0.0.0:2376"
]
}
重新启动 Docker
$ sudo systemctl restart docker
CoreOS 官方文档的方法
首先需要修改 /etc/systemd/system/docker-tcp.socket
文件内容
ListenStream=2375
# 修改为
ListenStream=2376
修改 CoreOS
上的 daemon.json
文件。
{
"tlsverify": true,
"tlscert": "/etc/docker/server-cert.pem",
"tlskey": "/etc/docker/server-key.pem",
"tlscacert": "/etc/docker/ca.pem"
}
重新启动服务。
$ sudo systemctl daemon-reload
$ sudo systemctl stop docker
$ sudo systemctl restart docker-tcp.socket
$ sudo systemctl restart docker
上文已经提到了启动顺序,这里提示一下,不再赘述。
客户端远程安全连接
将 ca.pem
cert.pem
key.pem
三个文件通过 scp
下载到 macOS
。
在 macOS
执行以下命令,密钥路径请根据实际情况填写。
$ docker --tlsverify
--tlscacert=/Users/khs1994/test/ca.pem
--tlscert=/Users/khs1994/test/cert.pem
--tlskey=/Users/khs1994/test/key.pem
-H=192.168.57.110:2376
info
把密钥放入 ~/.docker
文件夹中
每次操作需要跟那么多参数,太麻烦了。我们可以把 ca.pem
cert.pem
key.pem
三个文件放入客户端 ~/.docker
中,然后配置环境变量就可以简化命令了。
$ export DOCKER_HOST=tcp://192.168.57.110:2376 DOCKER_TLS_VERIFY=1
$ docker info
你也可以选择其他路径,请通过环境变量
DOCKER_CERT_PATH
指定。
报错详情
不使用安全连接
$ docker -H 192.168.57.110:2376 info
Get http://192.168.57.110:2376/v1.34/containers/json?all=1: malformed HTTP response "x15x03x01x00x02x02".
* Are you trying to connect to a TLS-enabled daemon without TLS?
在非允许列表 IP 中登录
假如远程服务器还有一个 IP 10.141.20.83
,现在我们尝试使用这个 IP 作为服务端地址,看看客户端能否连接到。
$ docker -H 10.141.20.83:2376 info
error during connect: Get https://10.141.20.83:2376/v1.34/info: x509: certificate is valid for 192.168.57.110, 192.168.199.100, 127.0.0.1, not 10.141.20.83
在非允许列表 Host 中登录
$ docker -H localhost:2376 info
error during connect: Get https://localhost:2375/v1.34/info: x509: certificate is valid for coreos1, not localhost
fish shell
$ set -Ux DOCKER_HOST tcp://192.168.57.110:2376
$ set -Ux DOCKER_TLS_VERIFY 1
# 以上命令写入环境变量是永久存在的,通过以下命令删除环境变量
$ set -Ue DOCKER_HOST ; set -Ue DOCKER_TLS_VERIFY
服务端验证模式
tlsverify
,tlscacert
,tlscert
,tlskey
set: Authenticate clientstls
,tlscert
,tlskey
: Do not authenticate clients
客户端验证模式
tls
: Authenticate server based on public/default CA pooltlsverify
,tlscacert
: Authenticate server based on given CAtls
,tlscert
,tlskey
: Authenticate with client certificate, do not authenticate server based on given CAtlsverify
,tlscacert
,tlscert
,tlskey
: Authenticate with client certificate and authenticate server based on given CA
测试远程构建 Docker 镜像
在 macOS
新建 demo 文件夹并进入。
我们首先建一个文本文件 test.txt
hello!
然后新建一个简单的 Dockerfile
文件
FROM busybox
COPY ./test.txt /
CMD cat /test.txt
按照前面的方法设置好环境变量,这里不再赘述。
$ docker -H 192.168.57.110:2375 --tlsverify build -t khs1994/busybox .
在远程服务端查看
SSH 登录到 CoreOS
(这里为了便于理解,SSH 到远程服务器操作)。
$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
khs1994/busybox latest 368d23df8500 10 seconds ago 1.13MB
我们已经查看到了镜像。
$ docker run -it --rm khs1994/busybox
hello!
运行成功。
客户端恢复原状
你如果想在 macOS
操作本地的服务端,请将上面配置的环境变量删除,这里不再赘述。