「Docker」- 配置端口监听(以允许 Docker Engine API 访问)

更新日期:2021年02月22日
@P2TT

问题描述

我们需要调用 Docker Engine API 以获取某些数据,主要用于调试及查看。(在程序集成时,应该使用类库,而不是直接调用接口)

但是 Docker 默认监听 Unix Domain Socket 文件,因此无法使用 Postman 接口调试工具。解决方法是使 Docker 服务监听 TCP 端口。

该笔记将记录:如何使 Docker 服务监听 TCP 端口。

注意事项

虽然使用 Insomnia Designer 可以访问 Unix Domain Socket 文件,但是开启 Docker 服务的 TCP 监听还是有意义的。

在下面的演示中,我们同时进行 UDS 与 TCP 监听,可以根据实际情况进行调整。

我们使用 Debian GNU/Linux 10 (buster) 作为测试环境,但也应该适用于其他 Linux 发行版。

解决方法

我们有以下几种方案:
1)修改 docker.service 配置;(适用于在安装时设置,此时没有正在运行的容器)
2)启用 docker live-restore 配置,然后再修改;(适用于生产环境)
3)使用 Nginx 反向代理;(该方案对于 docker 的无侵入性,且可操作性强)

方案一、修改 docker.service 配置(常规方法)

// 修改 docker.service 配置,添加如下配置

# systemctl edit docker.service
[Service]
ExecStart=
ExecStart=/usr/sbin/dockerd -H fd:// -H tcp://127.0.0.1:2375 $DOCKER_OPTS

// 重启服务

# systemctl restart docker.service

// 测试接口

# curl http://127.0.0.1:2375/v1.39/containers/json
[]

注意事项:
1)我们只监听 127.0.0.1:2375 端口以测试,所以外部主机无法访问。如果需要外部主机访问,可以修改为 0.0.0.0:2375 地址,但是要做好网络安全设置,或者启用 TLS 认证。
2)在测试主机中,由于没有运行中的容器,所以最后的测试接口返回空数组([]);

方案二、针对生产环境(复杂操作,但推荐)

Enable TCP port 2375 for external connection to Docker
dockerd | Docker Documentation
Keep containers alive during daemon downtime | Docker Documentation
How do I expose the docker API over TCP? - Server Fault
sudo - How to resolve "service start-limit-hit" - Ask Ubuntu

在生产环境中,我们不能重启 Docker 服务,否则容器会停止。当容器停止后,我们不仅要处理被停止的容器,可能还要处理其他连带问题(比如容器启动依赖顺序)。

操作步骤

下面是解决该问题的操作步骤(请理解步骤含义之后,再进行操作):

// 开启 live-restart 功能,使 docker 的重启不会导致 containerd 结束容器

# vim /etc/docker/daemon.json
{
    ...
    "live-restore": true,
    ...
}

// 使 live-restore 配置生效

# systemctl reload docker.service

// 追加配置,使其 dockerd 监控 TCP(新增)与 UDS(原有)

# vim /etc/docker/daemon.json
{
    ...
    "hosts": ["tcp://0.0.0.0:2375", "unix:///var/run/docker.sock"]
    ...
}

// 修改 docker.service 文件,追加如下配置。这里只是删除  -H fd:// 选项(因为 -H 不能与 hosts 共存)

# systemctl edit docker.service
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd --containerd=/run/containerd/containerd.sock

// 重启服务
// 注意事项:在重启时,服务会中断(因为 docker-proxy 重启,但是并不是因为容器停止)

# systemctl restart docker.service

// 访问验证

# curl http://127.0.0.1:2375/v1.39/containers/json

解释说明

这里需要明白以下几点:
1)docker client => docker server => containerd => our containers
2)而 live-restore 的作用就是“剥离” dockerd 与 containerd 服务的影响关系;

在启用 live-restore 特性时,使用 killall -KILL dockerd 服务,容器并不会停止,停止的只是 dockerd 与 docker-proxy 服务,所以会出现中断(这是是网络中断)。

但是当 dockerd 再次启动时,1)会连接 containerd 服务,继续管理原有容器,2)启动 docker-proxy 服务,即网络恢复。

注意事项

所以该方法的缺点就是「短暂的服务中断」(中断时间约为 systemctl restart docker.service 重启时间),但是总好过「直接重启 docker 服务再处理停止的容器」。

docker.service: Failed with result 'start-limit-hit'.
1)通常不会遇到该错误,该错误是因为我们频繁执行 systemctl restart docker.service 进行验证。
2)可以执行 systemctl reset-failed docker.service 进行解决

方案三、使用 Nginx 代理

修改 docker.service 的麻烦在于会影响升级,即使使用 systemctl edit docker.service 也有可能存在该问题。

此时,可以通过 Nginx 反向代理 Unix Socket 解决(这里不再展开详细说明,根据实际情况进行配置即可):

server {
	listen 127.0.0.1:2375;
	location / {
		proxy_pass http://unix:/var/run/docker.sock:/;
	}
}

该方法完全无需修改 Docker 任何配置,但是引入 Nginx 也许会增加些复杂性。

此外,Nginx 需要具有访问 /var/run/docker.sock 权限。在 Ubuntu 18.04 中,通过将 www-data 加入 docker 组来授权(执行 adduser www-data nginx 命令)。

附加说明

关于 fd:// 参数:它并不是告诉 Docker 打开 UDS 监听,而是 systemd 处理并传递给 Docker 服务。可以在命令行中直接执行 ExecStart 命令进行验证。—— sockets - what does fd:// mean exactly in dockerd -H fd:// - Stack Overflow

参考文献

Develop with Docker Engine API | Docker Documentation
api - How to make docker listening to unix and TCP socket under centos with systemd - Stack Overflow
Proxy a unix socket HTTP server to a tcp port using nginx.


ToC

问题描述

注意事项

解决方法

方案一、修改 docker.service 配置(常规方法)

方案二、针对生产环境(复杂操作,但推荐)

操作步骤

解释说明

注意事项

方案三、使用 Nginx 代理

附加说明

参考文献