Docker 监控API流量

1 背景知识

本章使用 socat 命令进行 Docker 命令 的调试

2 为什么需要调试docker 命令?

有时 Docker 命令 可能不会按照预期工作,多数是命令行语法错误,不过也有严重的BUG问题。
可以查看 Docker 客户端Docker 守护进程 的网络数据包,以确认问题根源。

Docker 客户端
Docker 客户端
HTTP
HTTP
HTTP
HTTP
Docker 守护进程
Docker 守护进程
私有Docker
注册中心
私有Docker...
Docker Hub
Docker Hub
另一个公共的Docker
注册中心
另一个公共的Docker...
私有网络
私有网络
互联网
互联网
Docker Hub是由Docker 公司运营的一个公共注册中心。
Docker Hub是由Docker 公司运营的一个公共注册中心。
互联网上也存在其他公共的注册中心。
互联网上也存在其他公共的注册中心。
私有Docker注册中心存储Docker镜像。
私有Docker注册中心存储Docker镜像。
Docker 守护进程使用HTTP协议接收来自Docker 客户端的请求并返回响应
Docker 守护进程使用HTTP协议接收来自Docker 客户端的请求并返回响应
调用Docker客户端可以从守护进程获取信息或向其发送指令。
调用Docker客户端可以从守护进程获取信息或向其发送指令。
安装了Docker 的宿主机。宿主机一般放在一个私有网络上。
安装了Docker 的宿主机。宿主机一般放在一个私有网络上。
Text is not SVG - cannot display

3 调试方法和说明

用户将在自己请求与服务器套接字之间插入一个代理 Unix 域套接字,并查看网络内容。注意这个方案需要使用rootsudo 权限。

3.1 Docker 和服务器交互流程

HTTP请求/响应
HTTP请求/响应
Docker 客户端
Docker 客户端
Unix域套接字
Unix域套接字
HTTP请求/响应
HTTP请求/响应
Docker 服务器
Docker 服务器
当用户在命令行中发送docker 命令时,一个HTTP请求将发送本机上的Docker 服务器。Docker 服务器执行这一命令并返回HTTP响应,后者将由docker 命令进行解释
当用户在命令行中发送docker 命令时,一个HTTP请求将发送本机上的Docker 服务器。Docker 服务器执行这一命令并返回HTTP响应,后者将由docker 命令进行解释
通信通过Unix域套接字完成。这里的功能是作为一个文件,用户可以进行写入与读取,就像操作一个TCP套接字那样。用户可以使用HTTP与另一个进程通信而无需指定端口,并使用的是文件系统目录结构。
通信通过Unix域套接字完成。这里的功能是作为一个文件,用户可以进行写入与读取,就像操作一个TCP套接字那样。用户可以使用HTTP与另一个进程通信而无需指定端口,并使用的是文件系统目录结构。
Docker服务器是使用Go语言编写的标准的应用程序,他返回的是HTTP响应。
Docker服务器是使用Go语言编写的标准的应用程序,他返回的是HTTP响应。
Text is not SVG - cannot display

3.2 socat 的调试架构

HTTP请求/响应
HTTP请求/响应
Docker 客户端
Docker 客户端
HTTP请求/响应
HTTP请求/响应
Unix域套接字
Unix域套接字
HTTP请求/响应
HTTP请求/响应
Docker 服务器
Docker 服务器
Unix域套接字(代理)
Unix域套接字(代理)
输出到终端中的
API请求/响应
输出到终端中的API请求/响应
Text is not SVG - cannot display

4 使用socat监控Docker API流量

4.1 安装socat 命令

yum install socat -y

4.2 创建套接字

sudo socat -v UNIX-LISTEN:/tmp/dockerapi.sock UNIX-CONNECT:/var/run/docker.sock &

4.3 捕获API流量

4.3.1 创建socat 套接字

docker -H unix:///tmp/dockerapi.sock ps -a

4.3.2 捕获docker ps -a 命令信息

> 2023/02/27 13:25:58.663334  length=80 from=0 to=79
HEAD /_ping HTTP/1.1\r
Host: docker\r
User-Agent: Docker-Client/23.0.1 (linux)\r
\r
< 2023/02/27 13:25:58.664207  length=316 from=0 to=315
HTTP/1.1 200 OK\r
Api-Version: 1.42\r
Builder-Version: 2\r
Cache-Control: no-cache, no-store, must-revalidate\r
Content-Length: 0\r
Content-Type: text/plain; charset=utf-8\r
Docker-Experimental: false\r
Ostype: linux\r
Pragma: no-cache\r
Server: Docker/23.0.1 (linux)\r
Swarm: inactive\r
Date: Mon, 27 Feb 2023 05:25:58 GMT\r
\r
> 2023/02/27 13:25:58.665422  length=101 from=80 to=180
GET /v1.42/containers/json?all=1 HTTP/1.1\r
Host: docker\r
User-Agent: Docker-Client/23.0.1 (linux)\r
\r
< 2023/02/27 13:25:58.666918  length=1026 from=316 to=1341
HTTP/1.1 200 OK\r
Api-Version: 1.42\r
Content-Type: application/json\r
Docker-Experimental: false\r
Ostype: linux\r
Server: Docker/23.0.1 (linux)\r
Date: Mon, 27 Feb 2023 05:25:58 GMT\r
Content-Length: 824\r
\r
[{"Id":"d0f633afaf8ce16d86bf740ab2f80e15f9d6be23d75c18b3a968950b70ba30aa","Names":["/kcm_centos01"],"Image":"centos:7.2.1511","ImageID":"sha256:9aec5c5fe4ba9cf7a8d2a50713dd197c3b0cbd5f5fcd03babe4c1d65c455dabf","Command":"/bin/sh -c 'while true; do echo hello world; sleep 1; done'","Created":1677463602,"Ports":[],"Labels":{"license":"GPLv2","name":"CentOS Base Image","vendor":"CentOS"},"State":"exited","Status":"Exited (137) 54 minutes ago","HostConfig":{"NetworkMode":"default"},"NetworkSettings":{"Networks":{"bridge":{"IPAMConfig":null,"Links":null,"Aliases":null,"NetworkID":"fb5ab4c9409d08df5f1b2e74c86399d1e1be1de786a72f68da0f3a1ff4a36bff","EndpointID":"","Gateway":"","IPAddress":"","IPPrefixLen":0,"IPv6Gateway":"","GlobalIPv6Address":"","GlobalIPv6PrefixLen":0,"MacAddress":"","DriverOpts":null}}},"Mounts":[]}]
CONTAINER ID   IMAGE             COMMAND                  CREATED       STATUS                        PORTS     NAMES
d0f633afaf8c   centos:7.2.1511   "/bin/sh -c 'while t…"   3 hours ago   Exited (137) 54 minutes ago             kcm_centos01

4.3.3 日志说明

(1)用于查看请求与响应所发送的命令。
(2)HTTP请求从此处开始,左侧带有右尖括号 >
(3)HTTP响应从此处开始,左侧带有左尖括号 <
(4)来自Docker服务器的响应JSON内容。
(5)用户正常看到的输出,由Docker 客户端从前面的JSON 解析而来。