生产环境如何调用 Docker API:从配置到实战避坑
Docker API接口调用教程|生产环境实测
在生产环境中,很多自动化运维、CI/CD、容器监控、资源编排、故障自愈系统,都会涉及 Docker 的 API 调用。相比直接使用 docker 命令行,Docker Engine API 更适合被程序调用,可以完成容器创建、启动、停止、日志读取、镜像拉取、网络管理、数据卷管理等操作。
本文将结合生产环境中的实际使用经验,系统讲解 Docker API 的调用方式、配置方法、常见接口、调用示例、安全注意事项以及生产环境最佳实践,帮助你快速掌握 Docker API 的使用。
一、Docker API是什么?
Docker API 通常指 Docker Engine API,它是 Docker Daemon 对外提供的一组 RESTful API。我们平时执行的很多命令,例如:
docker ps
docker images
docker run nginx
docker stop container_id
docker logs container_id
本质上都是 Docker CLI 与 Docker Daemon 通信后完成的操作。
Docker 的整体结构可以简单理解为:
Docker CLI ---> Docker Daemon ---> Containers / Images / Networks / Volumes
而 Docker API 则允许我们绕过 Docker CLI,直接通过 HTTP 请求与 Docker Daemon 通信。
常见调用方式包括:
- 通过 Unix Socket 调用;
- 通过 TCP 端口调用;
- 通过 SDK 调用,例如 Python SDK、Go SDK、Java SDK;
- 通过反向代理或网关封装后调用。
二、为什么生产环境要使用Docker API?
在生产环境中,Docker API 的用途非常广泛。下面是一些常见场景。
1. 自动化部署
例如业务系统发布时,可以通过 API 自动完成:
- 拉取最新镜像;
- 停止旧容器;
- 删除旧容器;
- 创建新容器;
- 挂载配置文件;
- 设置环境变量;
- 启动容器;
- 检查容器状态。
2. 容器监控
通过 Docker API 可以实时获取容器状态、CPU 使用率、内存使用率、网络流量、磁盘 IO 等数据。
例如调用:
GET /containers/{id}/stats
可以获取容器资源使用情况。
3. 容器日志采集
调用 Docker API 可以读取容器日志:
GET /containers/{id}/logs
这对于构建自己的日志平台或故障排查系统非常有用。
4. 运维平台集成
很多企业内部运维平台都需要提供容器管理功能,例如:
- 查看容器列表;
- 查看镜像列表;
- 启动、停止、重启容器;
- 查看容器日志;
- 查看资源监控;
- 删除无用镜像和容器。
这些功能都可以通过 Docker API 实现。
5. 故障自愈
通过定时检测容器状态,如果发现容器退出、异常、资源占用过高,可以自动重启容器或通知管理员。
三、查看Docker API版本
在调用 Docker API 之前,建议先查看当前 Docker 的 API 版本。
执行命令:
docker version
示例输出:
Client: Docker Engine - Community
Version: 24.0.7
API version: 1.43
Go version: go1.20.10
Server: Docker Engine - Community
Engine:
Version: 24.0.7
API version: 1.43
其中比较重要的是:
Server API version: 1.43
调用 API 时,接口路径中通常可以带上版本号,例如:
/v1.43/containers/json
如果不指定版本,Docker 会使用默认版本。但在生产环境中,建议显式指定 API 版本,避免 Docker 升级后接口兼容性出现问题。
四、Docker API的两种常见调用方式
Docker API 最常见的调用方式有两种:
- Unix Socket 调用;
- TCP 远程调用。
五、通过Unix Socket调用Docker API
默认情况下,Docker Daemon 监听在 Unix Socket 文件上:
/var/run/docker.sock
这个文件非常重要。Docker CLI 本质上也是通过它与 Docker Daemon 通信。
1. 查看docker.sock文件
ls -l /var/run/docker.sock
示例输出:
srw-rw---- 1 root docker 0 Jan 10 10:00 /var/run/docker.sock
如果用户属于 docker 用户组,就可以访问这个 Socket。
2. 使用curl调用Unix Socket
查看 Docker 版本:
curl --unix-socket /var/run/docker.sock http://localhost/version
查看容器列表:
curl --unix-socket /var/run/docker.sock http://localhost/v1.43/containers/json
查看所有容器,包括已停止容器:
curl --unix-socket /var/run/docker.sock "http://localhost/v1.43/containers/json?all=true"
查看镜像列表:
curl --unix-socket /var/run/docker.sock http://localhost/v1.43/images/json
3. Unix Socket方式的优点
- 不需要开放网络端口;
- 相对安全;
- 适合本机脚本、Agent、运维工具调用;
- 性能较好。
4. Unix Socket方式的缺点
- 只能本机调用;
- 权限控制较粗;
- 一旦拿到 docker.sock 权限,基本等同于拥有宿主机 root 权限。
生产环境提醒:不要随意把
/var/run/docker.sock挂载到不可信容器中,否则存在严重安全风险。
六、通过TCP端口调用Docker API
如果需要远程调用 Docker API,可以配置 Docker Daemon 监听 TCP 端口。
常见端口是:
2375:未加密端口,不推荐生产环境使用
2376:TLS加密端口,生产环境推荐使用
七、开启Docker远程API
下面以 Linux 系统为例。
1. 修改Docker服务配置
编辑 Docker systemd 配置文件:
sudo vim /usr/lib/systemd/system/docker.service
或者某些系统路径为:
sudo vim /lib/systemd/system/docker.service
找到:
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
修改为:
ExecStart=/usr/bin/dockerd -H unix:///var/run/docker.sock -H tcp://0.0.0.0:2375
然后重新加载配置:
sudo systemctl daemon-reload
sudo systemctl restart docker
检查端口是否监听:
ss -lntp | grep 2375
或者:
netstat -lntp | grep 2375
2. 测试远程API
假设 Docker 主机 IP 是:
192.168.1.100
在另一台机器上执行:
curl http://192.168.1.100:2375/version
查看容器列表:
curl http://192.168.1.100:2375/v1.43/containers/json
如果能正常返回 JSON 数据,说明远程 API 已经开启成功。
八、生产环境不建议直接开放2375端口
虽然 2375 端口使用起来非常方便,但它没有认证和加密。如果直接暴露在公网或不可信内网中,风险极高。
攻击者如果访问到 Docker API,可以执行以下操作:
- 查看所有容器;
- 启动恶意容器;
- 挂载宿主机目录;
- 读取宿主机敏感文件;
- 删除镜像和容器;
- 控制整个宿主机。
例如攻击者可以创建一个挂载宿主机根目录的容器:
docker run -v /:/host -it ubuntu
这意味着 Docker API 一旦被未授权访问,宿主机基本就失守了。
因此生产环境强烈建议:
- 不开放 2375;
- 使用 2376 + TLS;
- 使用防火墙限制访问 IP;
- 使用 VPN 或内网专线;
- 使用反向代理增加认证;
- 不要将 Docker API 暴露到公网。
九、Docker API常用接口实战
下面介绍一些生产环境最常用的 Docker API 接口。
十、查看Docker版本信息
接口:
GET /version
调用示例:
curl --unix-socket /var/run/docker.sock http://localhost/version
远程调用:
curl http://192.168.1.100:2375/version
返回示例:
{
"Platform": {
"Name": "Docker Engine - Community"
},
"Components": [],
"Version": "24.0.7",
"ApiVersion": "1.43",
"MinAPIVersion": "1.12",
"GitCommit": "afdd53b",
"GoVersion": "go1.20.10",
"Os": "linux",
"Arch": "amd64"
}
该接口常用于检测 Docker 服务是否正常。
十一、查看容器列表
接口:
GET /containers/json
查看运行中的容器:
curl --unix-socket /var/run/docker.sock http://localhost/v1.43/containers/json
查看所有容器:
curl --unix-socket /var/run/docker.sock "http://localhost/v1.43/containers/json?all=true"
常见参数:
| 参数 | 说明 |
|---|---|
all=true |
显示所有容器,包括停止状态 |
limit=10 |
限制返回数量 |
size=true |
显示容器大小 |
filters |
过滤条件 |
按名称过滤:
curl --unix-socket /var/run/docker.sock \
"http://localhost/v1.43/containers/json?all=true&filters=%7B%22name%22%3A%5B%22nginx%22%5D%7D"
其中 filters 是 URL 编码后的 JSON。
原始 JSON 为:
{
"name": ["nginx"]
}
十二、查看容器详情
接口:
GET /containers/{id}/json
示例:
curl --unix-socket /var/run/docker.sock \
http://localhost/v1.43/containers/nginx/json
如果容器名是 my-nginx,可以这样调用:
curl --unix-socket /var/run/docker.sock \
http://localhost/v1.43/containers/my-nginx/json
该接口返回信息非常详细,包括:
- 容器 ID;
- 创建时间;
- 启动命令;
- 环境变量;
- 挂载目录;
- 网络配置;
- 端口映射;
- 容器状态;
- 镜像 ID;
- 日志路径。
生产环境中常用于排查容器配置是否符合预期。
十三、创建容器
接口:
POST /containers/create
创建一个 nginx 容器:
curl --unix-socket /var/run/docker.sock \
-X POST "http://localhost/v1.43/containers/create?name=my-nginx" \
-H "Content-Type: application/json" \
-d '{
"Image": "nginx:latest",
"Cmd": [],
"ExposedPorts": {
"80/tcp": {}
},
"HostConfig": {
"PortBindings": {
"80/tcp": [
{
"HostPort": "8080"
}
]
},
"RestartPolicy": {
"Name": "always"
}
}
}'
说明:
name=my-nginx表示容器名称;Image表示镜像;ExposedPorts表示容器暴露端口;PortBindings表示宿主机端口映射;RestartPolicy表示重启策略。
如果镜像本地不存在,创建容器可能失败。因此生产环境一般会先调用镜像拉取接口。
十四、拉取镜像
接口:
POST /images/create
拉取 nginx 镜像:
curl --unix-socket /var/run/docker.sock \
-X POST "http://localhost/v1.43/images/create?fromImage=nginx&tag=latest"
拉取指定仓库镜像:
curl --unix-socket /var/run/docker.sock \
-X POST "http://localhost/v1.43/images/create?fromImage=registry.example.com/app/backend&tag=v1.0.0"
如果是私有仓库,通常需要认证。可以通过 X-Registry-Auth 请求头传递认证信息,该值是 Base64 编码后的 JSON。
原始认证 JSON:
{
"username": "admin",
"password": "123456",
"serveraddress": "registry.example.com"
}
编码后放入请求头:
-H "X-Registry-Auth: base64_string"
生产环境中,不建议在脚本里明文写密码,可以使用环境变量、密钥管理系统或 CI/CD 的 Secret 管理能力。
十五、启动容器
接口:
POST /containers/{id}/start
示例:
curl --unix-socket /var/run/docker.sock \
-X POST http://localhost/v1.43/containers/my-nginx/start
如果返回 HTTP 状态码 204,表示启动成功。
十六、停止容器
接口:
POST /containers/{id}/stop
示例:
curl --unix-socket /var/run/docker.sock \
-X POST "http://localhost/v1.43/containers/my-nginx/stop?t=10"
参数说明:
| 参数 | 说明 |
|---|---|
t |
等待容器优雅停止的秒数 |
例如 t=10 表示先发送停止信号,等待 10 秒,如果容器仍未退出,则强制停止。
十七、重启容器
接口:
POST /containers/{id}/restart
示例:
curl --unix-socket /var/run/docker.sock \
-X POST "http://localhost/v1.43/containers/my-nginx/restart?t=10"
十八、删除容器
接口:
DELETE /containers/{id}
删除已停止容器:
curl --unix-socket /var/run/docker.sock \
-X DELETE http://localhost/v1.43/containers/my-nginx
强制删除容器:
curl --unix-socket /var/run/docker.sock \
-X DELETE "http://localhost/v1.43/containers/my-nginx?force=true"
生产环境中,删除容器前建议先确认:
- 容器是否属于目标业务;
- 是否有持久化数据;
- 是否存在挂载目录;
- 是否需要保留日志;
- 是否有依赖关系。
十九、查看容器日志
接口:
GET /containers/{id}/logs
示例:
curl --unix-socket /var/run/docker.sock \
"http://localhost/v1.43/containers/my-nginx/logs?stdout=true&stderr=true&tail=100"
常见参数:
| 参数 | 说明 |
|---|---|
stdout=true |
返回标准输出 |
stderr=true |
返回标准错误 |
tail=100 |
返回最后 100 行 |
since |
从指定时间之后开始 |
follow=true |
持续跟踪日志,类似 docker logs -f |
实时查看日志:
curl --unix-socket /var/run/docker.sock \
"http://localhost/v1.43/containers/my-nginx/logs?stdout=true&stderr=true&follow=true"
需要注意的是,通过 API 返回的日志可能带有 Docker 的流头信息。如果用于日志平台采集,需要做解析处理。
二十、查看容器资源状态
接口:
GET /containers/{id}/stats
示例:
curl --unix-socket /var/run/docker.sock \
"http://localhost/v1.43/containers/my-nginx/stats?stream=false"
其中:
stream=false
表示只返回一次数据。
返回数据包括:
- CPU 使用情况;
- 内存使用情况;
- 网络收发;
- 块设备 IO;
- PIDs 数量。
生产环境中,可以根据返回数据计算 CPU 使用率和内存使用率。
CPU使用率计算思路
Docker stats 返回的数据中通常包含:
cpu_stats.cpu_usage.total_usageprecpu_stats.cpu_usage.total_usagecpu_stats.system_cpu_usageprecpu_stats.system_cpu_usagecpu_stats.online_cpus
计算公式大致如下:
cpu_delta = cpu_total - precpu_total
system_delta = system_total - presystem_total
cpu_percent = cpu_delta / system_delta * online_cpus * 100
实际开发时建议做好空值判断,避免某些字段不存在导致计算异常。
二十一、查看镜像列表
接口:
GET /images/json
示例:
curl --unix-socket /var/run/docker.sock \
http://localhost/v1.43/images/json
查看全部镜像:
curl --unix-socket /var/run/docker.sock \
"http://localhost/v1.43/images/json?all=true"
返回内容包括:
- 镜像 ID;
- RepoTags;
- RepoDigests;
- 创建时间;
- 镜像大小;
- 父镜像 ID。
二十二、删除镜像
接口:
DELETE /images/{name}
示例:
curl --unix-socket /var/run/docker.sock \
-X DELETE http://localhost/v1.43/images/nginx:latest
强制删除:
curl --unix-socket /var/run/docker.sock \
-X DELETE "http://localhost/v1.43/images/nginx:latest?force=true"
注意:如果镜像正在被容器使用,直接删除通常会失败。生产环境中不建议随意强制删除镜像,尤其是在多容器共享镜像的场景下。
二十三、使用Python调用Docker API
除了 curl,也可以用 Python 调用 Docker API。生产环境中更推荐使用 SDK,因为它封装了很多底层细节。
安装 Python Docker SDK:
pip install docker
1. 查看容器列表
import docker
client = docker.from_env()
containers = client.containers.list(all=True)
for c in containers:
print(c.id, c.name, c.status)
2. 拉取镜像
import docker
client = docker.from_env()
image = client.images.pull("nginx", tag="latest")
print(image.id)
3. 创建并启动容器
import docker
client = docker.from_env()
container = client.containers.run(
image="nginx:latest",
name="my-nginx-python",
ports={"80/tcp": 8081},
detach=True,
restart_policy={"Name": "always"}
)
print(container.id)
4. 获取日志
import docker
client = docker.from_env()
container = client.containers.get("my-nginx-python")
logs = container.logs(stdout=True, stderr=True, tail=100)
print(logs.decode("utf-8", errors="ignore"))
5. 停止并删除容器
import docker
client = docker.from_env()
container = client.containers.get("my-nginx-python")
container.stop(timeout=10)
container.remove()
二十四、使用Python requests调用Unix Socket
如果不想使用 Docker SDK,也可以通过 requests-unixsocket 调用。
安装依赖:
pip install requests requests-unixsocket
示例代码:
import requests_unixsocket
session = requests_unixsocket.Session()
url = "http+unix://%2Fvar%2Frun%2Fdocker.sock/v1.43/containers/json?all=true"
resp = session.get(url)
print(resp.status_code)
print(resp.json())
其中 /var/run/docker.sock 需要 URL 编码为:
%2Fvar%2Frun%2Fdocker.sock
这种方式适合需要直接控制 HTTP 请求细节的场景。
二十五、生产环境完整发布流程示例
下面给出一个生产环境中比较常见的容器发布流程。
目标:将业务服务 backend 更新到镜像版本 v2.0.0。
流程如下:
- 拉取新镜像;
- 检查旧容器是否存在;
- 停止旧容器;
- 删除旧容器;
- 创建新容器;
- 启动新容器;
- 检查容器状态;
- 检查健康接口;
- 如果失败则回滚。
示例API流程
拉取镜像:
curl --unix-socket /var/run/docker.sock \
-X POST "http://localhost/v1.43/images/create?fromImage=registry.example.com/backend&tag=v2.0.0"
停止旧容器:
curl --unix-socket /var/run/docker.sock \
-X POST "http://localhost/v1.43/containers/backend/stop?t=20"
删除旧容器:
curl --unix-socket /var/run/docker.sock \
-X DELETE "http://localhost/v1.43/containers/backend?force=true"
创建新容器:
curl --unix-socket /var/run/docker.sock \
-X POST "http://localhost/v1.43/containers/create?name=backend" \
-H "Content-Type: application/json" \
-d '{
"Image": "registry.example.com/backend:v2.0.0",
"Env": [
"APP_ENV=prod",
"TZ=Asia/Shanghai"
],
"ExposedPorts": {
"8080/tcp": {}
},
"HostConfig": {
"PortBindings": {
"8080/tcp": [
{
"HostPort": "8080"
}
]
},
"RestartPolicy": {
"Name": "always"
},
"Binds": [
"/data/backend/logs:/app/logs",
"/data/backend/config:/app/config"
]
}
}'
启动新容器:
curl --unix-socket /var/run/docker.sock \
-X POST "http://localhost/v1.43/containers/backend/start"
检查容器状态:
curl --unix-socket /var/run/docker.sock \
"http://localhost/v1.43/containers/backend/json"
检查业务健康接口:
curl http://127.0.0.1:8080/health
如果健康检查失败,可以删除新容器并重新启动旧版本镜像。
二十六、生产环境实测经验总结
在真实生产环境中,Docker API 调用并不复杂,真正容易出问题的是权限、安全、异常处理和发布流程设计。
1. 一定要处理HTTP状态码
不同接口的成功状态码不完全相同。例如:
| 操作 | 常见成功状态码 |
|---|---|
| 查看列表 | 200 |
| 创建容器 | 201 |
| 启动容器 | 204 |
| 停止容器 | 204 |
| 删除容器 | 204 |
| 拉取镜像 | 200 |
不要简单地认为只有 200 才是成功,否则会误判。
2. 创建容器前先检查同名容器
如果同名容器已存在,创建会失败。因此发布流程中通常要先调用:
GET /containers/{name}/json
如果存在,再决定是停止删除,还是跳过创建。
3. 镜像拉取要设置超时
生产环境拉取镜像可能受网络、仓库、镜像大小影响。如果程序没有超时控制,可能导致发布任务长期阻塞。
4. 日志接口要限制tail数量
不要随意拉取全量日志,尤其是长期运行的容器,否则可能造成接口卡顿甚至影响 Docker Daemon。
推荐使用:
tail=100
tail=500
tail=1000
5. stats接口不要高频调用
资源统计接口如果调用过于频繁,会给 Docker Daemon 带来压力。对于普通监控,5 秒到 15 秒采集一次通常已经足够。
6. 删除操作必须谨慎
对于以下操作,建议做二次确认或权限控制:
- 删除容器;
- 删除镜像;
- 删除数据卷;
- 强制停止容器;
- 强制删除容器。
7. 容器命名要规范
建议容器名称包含业务、环境和实例编号,例如:
prod-backend-01
prod-order-01
test-payment-01
这样 API 查询、日志检索、监控展示都会更清晰。
二十七、安全最佳实践
Docker API 的安全性必须高度重视。
1. 禁止公网暴露Docker API
不要把 Docker API 直接暴露在公网。即使使用了 TLS,也建议只允许内网访问。
2. 使用防火墙限制来源IP
例如只允许运维平台服务器访问 Docker API:
iptables -A INPUT -p tcp -s 192.168.1.10 --dport 2376 -j ACCEPT
iptables -A INPUT -p tcp --dport 2376 -j DROP
3. 使用TLS双向认证
生产环境推荐使用 TLS 双向认证,客户端必须携带证书才能访问 Docker API。
4. 不要在不可信容器中挂载docker.sock
很多工具会要求挂载:
-v /var/run/docker.sock:/var/run/docker.sock
这意味着容器内部可以控制宿主机 Docker。只有在完全可信的场景下才可以这样做。
5. 使用最小权限原则
如果是自研运维平台,不要把所有 Docker 操作都开放给普通用户。应该按角色授权,例如:
- 只读用户:查看容器、查看日志;
- 运维用户:启动、停止、重启;
- 管理员:删除容器、删除镜像、修改配置。
二十八、常见问题排查
1. curl调用返回权限不足
错误类似:
permission denied
可能原因:
- 当前用户没有访问
/var/run/docker.sock权限; - 用户不在 docker 组;
- Socket 文件权限异常。
解决方式:
sudo usermod -aG docker 当前用户名
重新登录后生效。
2. 远程调用连接不上
检查以下内容:
- Docker 是否监听 TCP 端口;
- 防火墙是否放行;
- 云服务器安全组是否放行;
- Docker 服务是否重启成功;
- 访问地址是否正确。
3. 创建容器失败
常见原因:
- 镜像不存在;
- 容器名称冲突;
- 端口被占用;
- 挂载目录不存在;
- JSON 格式错误;
- 镜像启动命令异常。
建议查看 Docker API 返回的错误信息,同时查看 Docker Daemon 日志:
journalctl -u docker -f
4. 容器启动后立即退出
可以查看容器日志:
curl --unix-socket /var/run/docker.sock \
"http://localhost/v1.43/containers/container_name/logs?stdout=true&stderr=true&tail=200"
也可以查看容器详情中的状态信息:
curl --unix-socket /var/run/docker.sock \
"http://localhost/v1.43/containers/container_name/json"
重点关注:
"State": {
"Status": "exited",
"ExitCode": 1,
"Error": ""
}
二十九、结语
Docker API 是生产环境容器自动化管理的重要工具。通过它,我们可以用程序完成容器生命周期管理、镜像管理、日志读取、资源监控和自动化发布等工作。
不过,Docker API 的能力越强,安全风险也越高。尤其是远程 API 和 /var/run/docker.sock,一旦被非授权用户访问,就可能导致宿主机被控制。因此在生产环境中,推荐优先使用 Unix Socket 本地调用;如果必须远程调用,应使用 TLS 双向认证、防火墙限制、内网访问和严格权限控制。
总结来说,生产环境调用 Docker API 时应重点关注以下几点:
- 显式指定 API 版本;
- 优先使用 Unix Socket;
- 远程调用必须加认证和访问控制;
- 正确处理 HTTP 状态码;
- 对创建、删除、停止等操作做好异常处理;
- 日志和 stats 接口避免高频、全量调用;
- 发布流程要包含健康检查和回滚机制;
- 不要将 Docker API 暴露给不可信环境。
掌握 Docker API 后,你就可以构建更灵活、更自动化、更贴近生产实际的容器管理系统。