Featured image of post Docker Remote API 与 2375 端口:从开启到 IDE 集成的安全实践

Docker Remote API 与 2375 端口:从开启到 IDE 集成的安全实践

Docker 1.0 时代的远程管理方案:开启 2375 端口暴露 Docker daemon、用 IDE / Portainer 远程连接、安全加固与替代方案

Docker 1.0 在 2014 年 6 月正式发布时,伴随的不仅是一个稳定版,更是一套被广泛复用的管理接口——Docker Remote API。基于 HTTP + REST 风格,把 daemon 暴露在 2375 端口(未加密)或 2376 端口(TLS 加密),让 IDEA、Portainer、Shipyard、命令行客户端都能远程控制容器。

这一篇把"如何开启 2375 端口 + 如何用 IDEA 远程连接 + 为什么必须配 TLS"这条主线串起来。

阅读对象:需要从开发机远程管理服务器 Docker daemon 的开发者、运维同学 覆盖范围:systemd 开启 2375/2376 端口 + IDEA Docker 插件 + TLS 证书生成 + 风险与替代方案

一、为什么需要 Remote API

本地 docker 命令行直接走 /var/run/docker.sock Unix socket。一旦要在另一台机器上管理这个 daemon,要么 SSH 登过去,要么把 daemon 暴露成 HTTP 服务

Remote API 的典型场景:

  • 开发机远程管理生产 / 测试 Docker daemon——开发笔记本 IDEA 上点 “Redeploy”,触发远端容器重建
  • 可视化平台集中管控——Portainer、Shipyard、Rancher 通过 Remote API 拉取容器列表 / 镜像 / 日志
  • CI 节点操作远端 daemon——Jenkins Agent 在 K8s 节点内,通过 Remote API 控制宿主机 Docker(早期 docker-in-docker 方案)

到 2014 年中 Docker 1.0 时代,2375 是事实上的标准端口。Docker 1.11+(2016-04)又新增了 2376 作为 TLS 加密端口,逐步成为生产推荐。

二、开启 2375 端口(systemd 方式)

绝大多数 Linux 发行版(CentOS 7+、Debian 8+、Ubuntu 16.04+)的 Docker 由 docker.service 守护,通过 systemd 管理。修改启动参数是开启 Remote API 的标准做法

1
2
# 编辑 docker.service
vim /usr/lib/systemd/system/docker.service

ExecStart 这一行追加 -H tcp://0.0.0.0:2375 -H unix://var/run/docker.sock

1
2
3
4
5
6
7
8
[Service]
Type=notify
ExecStart=/usr/bin/dockerd \
  -H fd:// \
  -H tcp://0.0.0.0:2375 \
  -H unix:///var/run/docker.sock
ExecReload=/bin/kill -s HUP $MAINPID
...

Why 加 -H fd:// + -H unix:///var/run/docker.sock:保留 fd 协议(systemd socket activation)和 Unix socket,让本机 docker 命令继续可用。如果不加 Unix socket,本机 docker ps 会全部失效。

修改完之后:

1
2
3
4
5
6
7
8
9
# 重新加载 systemd 配置
systemctl daemon-reload

# 重启 docker
systemctl restart docker

# 验证端口是否真的开了
ss -tlnp | grep 2375
# 期望输出:LISTEN 0 128 *:2375 *:* users:(("dockerd",pid=...,fd=...))

从远端测试一下:

1
2
3
# 在另一台机器上
docker -H tcp://<docker-host>:2375 images
# 期望输出:该 daemon 上的镜像列表

注意<docker-host> 是 daemon 所在机器的 IP。不要写 0.0.0.0——客户端必须用真实可达 IP(如内网 IP 或公网 IP)。

三、IDEA 集成 Docker

IntelliJ IDEA(2017.2+ Ultimate 内置 Docker 插件,2017.3 起 Community 也支持)能直接连 Docker daemon。

3.1 在 IDEA 中配置

Settings → Build, Execution, Deployment → Docker

  • TCP Socket: tcp://<docker-host>:2375(明文)或 tcp://<docker-host>:2376(TLS)
  • Docker Compose executable:选 docker-compose 可执行文件路径

如果走 TLS,需要提前准备:

字段含义
CA cert证书颁发机构(.crt 文件)
Client cert客户端证书(.cert 文件)
Client key客户端私钥(.key 文件)

填完之后,IDEA 会在底部 Services 面板里新增 Docker 节点,可以看到远端容器、镜像、卷、网络,并支持:

  • 一键 Run / Debug 容器(自动构建镜像 → 启动)
  • 实时查看容器 stdout / stderr
  • Exec into container(类似 docker exec -it
  • 资源图表(CPU / 内存 / 网络 IO)

3.2 实际工作流

1
2
3
4
5
6
7
[IDEA]
  ↓ Run 'Docker' configuration
  ↓ docker build -t myapp:dev .
  ↓ docker run -d -p 8080:8080 myapp:dev
[远端 Docker daemon (2375/2376)]
  ↓ 拉取基础镜像 / 构建 / 启动容器
  ↓ 把 stdout/stderr 推回 IDEA

开发阶段,所有 build / run / debug 都在远端完成,本地不需要装 Docker Desktop——这是 2014-2017 时代跨平台开发的常见模式。

四、风险与生产建议

明文 2375 端口 = 把 daemon root 权限交给任何能访问到的人。攻击者只要能连到这个端口,就能:

  • 跑特权容器 → 逃逸到宿主机
  • 拉取 / 推送任意镜像
  • 删除所有数据卷
  • 挂载宿主机任意目录

4.1 必须做的安全加固

  1. 绝不放公网:2375 端口只能在 VPC 内网开放,不要在云厂商安全组里把 2375 对 0.0.0.0/0 开放
  2. 必须配 TLS(2376):用 OpenSSL 生成 CA、server、client 证书,配置 tlsverify + tlscacert + tlscert + tlskey
  3. 防火墙白名单:iptables / nftables / 云安全组只放行可信 IP 段
  4. 避免 rootless 之外运行:Docker 默认以 root 运行,任何 Remote API 调用都是 root 等价

4.2 最小化配置示例(TLS)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# 1. 生成 CA、server、client 证书(简化版,参考 dockerd 官方文档)
cd /etc/docker/tls
openssl genrsa -aes256 -out ca-key.pem 4096
openssl req -new -x509 -days 365 -key ca-key.pem -sha256 -out ca.pem
# ... 生成 server-cert.pem / server-key.pem / client-cert.pem / client-key.pem

# 2. 修改 docker.service
ExecStart=/usr/bin/dockerd \
  --tlsverify \
  --tlscacert=/etc/docker/tls/ca.pem \
  --tlscert=/etc/docker/tls/server-cert.pem \
  --tlskey=/etc/docker/tls/server-key.pem \
  -H tcp://0.0.0.0:2376 \
  -H unix:///var/run/docker.sock

systemctl daemon-reload
systemctl restart docker

4.3 替代方案

如果不想在每台机器上维护 TLS 证书,SSH 隧道是更轻量的选择

1
2
3
4
5
6
7
# 在客户端机器上,把远端 docker.sock 转到本地
ssh -L 2375:localhost:2375 user@<docker-host> \
  -o "StreamLocalBindUnlink=yes" \
  -- docker system

# 现在本地 docker 命令会走 SSH 隧道
docker -H tcp://localhost:2375 ps

或者用反向 SSH 隧道让远端 daemon 主动连出:

1
2
# 在 docker-host 上
ssh -R 2375:unix:///var/run/docker.sock user@jumphost

五、常见问题

5.1 Cannot connect to the Docker daemon at tcp://...

按顺序排查:

  1. 端口是否真的开放:ss -tlnp | grep 2375 / telnet <host> 2375
  2. 防火墙是否放行:iptables -L -n / firewall-cmd --list-all
  3. 云安全组:检查入方向规则
  4. dockerd 启动参数:检查 -H tcp://0.0.0.0:2375 是否拼对(注意是 tcp:// 不是 tcp:\\\\

5.2 IDEA 连上之后看不到容器

  • 确认 IDEA 里填的端口和 daemon 一致
  • 如果是 2376,所有三份证书都要正确(CA + client cert + client key)
  • daemon.json 里查看 "hosts" 字段确认没被覆盖

5.3 TLS 连不上

检查证书的 SAN(Subject Alternative Name)字段,必须包含客户端实际访问的 IP / 域名。Docker 18.09+ 启用了严格的证书校验,SAN 不匹配直接 tls: invalid certificate 报错。

六、要点回顾

  1. 2375 = 明文,2376 = TLS——生产环境只用 2376
  2. 保留 Unix socket——-H unix:///var/run/docker.sock 必须有,否则本机 docker 命令会失效
  3. systemd reload ≠ restart——改完 docker.service 必须 daemon-reload + restart,reload 不会重读 service 文件
  4. IDEA Docker 插件 是 Remote API 最常见的消费方,从 2017.2 起 Ultimate 内置,2017.3 起 Community 可用
  5. SSH 隧道是 2375 的"穷人版安全"——比明文好,但仍需 root 信任 SSH 通道

七、小结

Remote API 打开了 Docker 生态的"分布式管理"大门——从 CI 节点到 IDE,从可视化平台到跨主机编排,几乎所有上层工具都建立在 Remote API 之上。但 2375 明文端口的安全代价极高,生产部署必须走 2376 + TLS

下一步:理解了 Remote API,下一层是 Docker Compose v2(2020-08 GA)的声明式管理——把多个容器、网络、卷用一个 YAML 描述,daemon 自动调谐到期望状态。Compose v2 内部仍依赖 Docker SDK(Remote API 的 Go 封装),2375/2376 是它的"地基"

参考资料

使用 Hugo 构建
主题 StackJimmy 设计