Dozzle Agent 模式完全指南:用 TLS 加密连接远程 Docker 主机
【免费下载链接】dozzleRealtime log viewer for containers. Supports Docker, Swarm and K8s.项目地址: https://gitcode.com/GitHub_Trending/do/dozzle
Dozzle 的 Agent(代理)模式允许你在远程 Docker 主机上部署一个轻量代理进程,让本地或其他位置的 Dozzle 实例通过一条 TLS 加密的私有通道连接它,从而安全地查看、流式读取甚至操作远端容器日志,全程无需暴露 Docker Socket。本文将基于 Dozzle 官方 Agent 模式文档(docs/guide/agent.md),结合仓库内internal/agent、internal/support/cli等源码实现,完整讲解 Agent 的创建、连接、主机分组、健康检查、过滤器与自定义证书,并给出 Agent 与远程连接(Remote Hosts)的选型对比。
Agent 模式是什么
Dozzle 可以以agent子命令启动,进入 Agent 模式。运行中的 Agent 会把自己所在主机的 Docker 容器暴露给其他 Dozzle 实例——换句话说,你可以在远程主机上部署 Dozzle Agent,然后从本地机器连接它,像查看本机容器一样查看远程容器的实时日志。
Agent 模式有两个关键特性:
- 所有通信走 TLS 加密连接:Agent 与主 Dozzle 实例之间的所有流量都通过一条安全通道传输。从源码看,这条通道是建立在 gRPC 之上的 TLS 连接(详见 internal/agent/server.go),并且要求客户端证书(
tls.RequireAndVerifyClientCert),即双向 TLS 认证,通信双方都需要持有私有的 Dozzle 证书。 - 仅限 Docker:Agent 模式是为 Docker(含 Swarm 节点)设计的。如果你使用的是Docker Swarm 模式,则不需要 Agent——Dozzle 会自动发现自身并通过 Swarm 模式组建集群,相关说明见 Swarm 模式指南。
注意:Agent 只展示运行 Agent 的这台主机上的容器,不会透传主实例所在主机的内容。
如何创建 Agent
创建 Agent 只需要以agent子命令运行 Dozzle 镜像,并挂载 Docker Socket 即可。以下两种方式等价:
docker run -v /var/run/docker.sock:/var/run/docker.sock -p 7007:7007 amir20/dozzle:latest agent或使用 docker-compose:
services: dozzle-agent: image: amir20/dozzle:latest command: agent volumes: - /var/run/docker.sock:/var/run/docker.sock:ro ports: - 7007:7007Agent 启动后会监听7007端口。你可以在 Dozzle 界面中通过输入 Agent 的 IP 和端口来连接它。
几点实用提示:
- 不必暴露 7007 端口:如果 Agent 与其他容器处于同一个 Docker 网络,同一网络内的容器直接访问 Agent 即可,无需把 7007 端口映射到宿主机。
- 不要再叠加 Socket 代理:如果你打算使用远程 Agent,不能在 Agent 之上再套一层 Docker Socket 代理。Dozzle 的 Agent 本身就是用来取代Socket 代理方案的;如果想用 Socket 代理而不是 Agent,请参考 远程主机指南。
- Socket 挂载权限:官方 compose 示例使用
:ro(只读)挂载 Socket,但注意 Agent 需要向 Docker 请求 API 才能工作;如果后续你需要在远程界面执行容器操作(启动/停止/重启等),请确保权限满足要求。
源码视角:Agent 启动过程
agent子命令对应 internal/support/cli/agent_command.go 中的AgentCmd.Run。它的大致流程是:
- 创建本地 Docker 客户端(
docker.NewLocalClient); - 读取(或生成内嵌的)TLS 证书;
- 在
--agent-addr(默认:7007,环境变量DOZZLE_AGENT_ADDR)上监听 TCP; - 以该 Docker 客户端为基础构建
ClientService,并交给 internal/agent/server.go 的agent.NewServer启动 gRPC 服务。
Agent 对外暴露的是AgentService这一 gRPC 服务,服务定义见 protos/rpc.proto,涵盖了容器列表、实时日志流、历史日志、原始字节流、事件流、统计信息、容器操作、镜像更新检查、终端 Exec/Attach 等全部能力。
如何连接到 Agent
在主 Dozzle 实例侧,通过--remote-agent参数(或环境变量DOZZLE_REMOTE_AGENT)指定 Agent 的地址与端口即可:
docker run -p 8080:8080 amir20/dozzle:latest --remote-agent agent:7007services: dozzle: image: amir20/dozzle:latest environment: - DOZZLE_REMOTE_AGENT=agent:7007 ports: - 8080:8080 # Dozzle 界面端口连接 Agent 时无需挂载本机的 Docker Socket——这种情况下,界面只会显示各 Agent 上的容器。若你希望界面上同时展示主实例本机的容器,再按快速开始中的示例挂载docker.sock即可。
同时连接多个 Agent
可以用逗号分隔多个地址,一次连接多个 Agent:
DOZZLE_REMOTE_AGENT=agent1:7007,agent2:7007命令行对应写法是重复传入--remote-agent参数,每个参数对应一个 Agent 地址。
源码视角:连接串如何解析
--remote-agent/DOZZLE_REMOTE_AGENT在 internal/support/cli/args.go 中定义为RemoteAgent []string,支持separate分隔。真正解析连接串的是 internal/agent/client.go 中的ParseEndpoint:它会按|把address|name|group拆成三部分(见下文主机分组),地址部分必填,名称与分组可省略。客户端还会对 gRPC 调用启用gzip 压缩(grpc.UseCompressor(gzip.Name))、10 MiB 的最大接收消息上限,以及 30 秒/10 秒的 keepalive 参数,以应对大流量日志流。
主机分组(Host Groups)
当需要管理分布在多个环境中的大量 Agent 时,可以给每个 Agent 分配一个命名分组。分组在侧边栏中以可折叠区块呈现,每个分组带一个"合并全部"按钮,可查看组内所有主机的合并日志流。
连接串的完整格式为endpoint|name|group,三部分均可选:
| 格式 | 结果 |
|---|---|
agent:7007 | 无名称覆盖,无分组 |
agent:7007|web-1 | 有名称覆盖,无分组 |
agent:7007|web-1|Production | 有名称覆盖 + 分组 |
agent:7007||Production | 默认主机名 + 分组 |
命令行示例:
docker run -p 8080:8080 amir20/dozzle:latest \ --remote-agent agent1:7007|web-1|Production \ --remote-agent agent2:7007|web-2|Production \ --remote-agent agent3:7007|dev-1|Developmentdocker-compose 等价写法:
services: dozzle: image: amir20/dozzle:latest environment: - DOZZLE_REMOTE_AGENT=agent1:7007|web-1|Production,agent2:7007|web-2|Production,agent3:7007|dev-1|Development ports: - 8080:8080此时侧边栏将显示:
▾ Production web-1 web-2 ▾ Development dev-1 ungrouped-host ← 未分组的 Agent 显示在下方- 点击分组名旁的合并图标,会打开一个从该分组所有主机实时流式合并日志的视图。
- 合并视图也可以通过 URL 直接访问:
/host-group/<group-name>。 - 未分组的 Agent 行为与之前完全一致,显示在分组区块下方。
从源码看,name与group两个字段被保存在Client结构体(internal/agent/client.go)中,并在Host()拉取主机信息时覆盖主机显示名称、填充分组归属——即使 Agent 暂时不可达,也会以Available: false的占位形式返回带名称与分组的主机信息,保证界面布局稳定。
常见问题:Agent 不出现
如果你在日志中看到:
An agent with an existing ID was found. Removing the duplicate host.说明有两台主机使用了相同的服务器 ID(Server ID)。Dozzle 通过 Docker API 收集主机信息,每个 Agent 都需要一个跨重启保持稳定且全局唯一的主机 ID 以便正确识别。目前 Agent 使用 Docker 的**系统 ID(system ID)或节点 ID(node ID)**来标识主机:
- 在 Swarm 环境中,使用节点 ID;
- 如果发现并非所有主机都可见,很可能是配置了多个具有相同主机 ID 的重复主机。
解决办法
删除系统中的/var/lib/docker/engine-id文件并重启 Docker,即可消除因主机 ID 重复引发的冲突。更多诊断信息可参考常见问题(FAQ)。
源码视角:主机 ID 的派生规则
主机 ID 的派生逻辑集中在 internal/container/host_id.go。DerivedHostID.Resolve会按优先级选择:SwarmNodeID(Swarm 节点 ID)> Podman 专属派生 ID >EngineID(Docker 写入/var/lib/docker/engine-id的引擎 ID,重启后仍存活)>Fallback。也就是说,文档中"删除 engine-id 以修复重复主机"的建议,正对应 Docker 引擎首次启动时把 ID 写入该文件、之后一直复用的实现细节。若派生 ID 仍冲突,还可以通过--host-id/DOZZLE_HOST_ID手工指定一个静态主机 ID(仅允许字母、数字、短横线、下划线和点)。
高级选项
配置健康检查(Healthcheck)
你可以为 Agent 配置健康检查,用法与主 Dozzle 实例相同。Agent 模式下,健康检查会检测 Agent 与 Docker 的连接——如果 Docker 不可达,Agent 会被标记为不健康,且不会显示在界面中。
使用healthcheck子命令配置:
services: dozzle-agent: image: amir20/dozzle:latest command: agent healthcheck: test: ["CMD", "/dozzle", "healthcheck"] interval: 5s retries: 5 start_period: 5s start_interval: 5s volumes: - /var/run/docker.sock:/var/run/docker.sock:ro ports: - 7007:7007源码视角:internal/support/cli/health_command.go 展示了healthcheck子命令的分流逻辑——Agent 启动时会把监听地址写入/tmp/dozzle-agent.addr,healthcheck 命令若读到该文件,就以 Agent 身份对127.0.0.1:<port>发起一次 RPC 探测(见 internal/healthcheck/rpc.go 的RPCRequest,实际是调用 Agent 的ListContainers);否则回退为主实例的 HTTP 健康检查。因此healthcheck同一个子命令可以同时服务于两种模式。
修改 Agent 名称
与主 Dozzle 实例一致,Agent 名称可以通过环境变量DOZZLE_HOSTNAME(或启动参数--hostname)修改:
docker run -v /var/run/docker.sock:/var/run/docker.sock -p 7007:7007 amir20/dozzle:latest agent --hostname my-special-nameservices: dozzle-agent: image: amir20/dozzle:latest command: agent environment: - DOZZLE_HOSTNAME=my-special-name volumes: - /var/run/docker.sock:/var/run/docker.sock:ro ports: - 7007:7007连接该 Agent 后,界面中即会以my-special-name显示。从源码看,--hostname对应 internal/support/cli/args.go 的Hostname字段(DOZZLE_HOSTNAME),在创建本地 Docker 客户端时传入并体现在主机信息中。注意:此名称与连接串第二段|name的"名称覆盖"是两套机制——前者在 Agent 侧生效,后者在连接侧生效(client 侧覆盖优先级更高)。
配置过滤器(Filters)
可以在 Agent 上配置过滤器,限制它能访问的容器范围。过滤器会直接传给 Docker,从而限制 Dozzle 可见的容器:
services: dozzle-agent: image: amir20/dozzle:latest command: agent environment: - DOZZLE_FILTER=label=color volumes: - /var/run/docker.sock:/var/run/docker.sock:ro上面的配置会让 Agent 只显示带有color标签的容器。需要理解的是,Agent 过滤器会与 UI 过滤器叠加生效,共同收窄可见容器集合。举例来说:如果 UI 层设置了--filter label=color,Agent 层设置了--filter label=type,那么只有同时具备color和type两个标签的容器才会被展示。过滤器语法与各类过滤条件详见过滤器文档(其中还提到了 UI 过滤器、Agent 过滤器、用户过滤器三层组合的规则)。
源码视角:DOZZLE_FILTER/--filter在 internal/support/cli/args.go 中被解析为key=value形式的 map(args.Filter),随后在 Agent 启动时通过docker_support.NewDockerClientService(client, args.Filter)注入。在 gRPC 服务端,过滤器会随ListContainers/FindContainer请求中的filter字段(map 类型,见 protos/rpc.proto)传递,并在 internal/agent/server.go 中还原成container.ContainerLabels交给 Docker API——因此"过滤器直接传给 Docker"从实现上完全成立。
使用自定义证书(Custom Certificates)
默认情况下,Dozzle 在 Agent 之间使用自签名证书进行通信。这份证书是私有的,仅对其他 Dozzle 实例有效,对大多数场景是安全且推荐的做法。但有一种攻击场景需要防范:如果 Dozzle 对外暴露,且攻击者精确知道 Agent 运行的端口,那么他可以自己起一个 Dozzle 实例并连接到你的 Agent。要杜绝这种可能,请提供你自己的证书。
提供自定义证书有两种方式:挂载文件或使用Docker secrets。默认情况下 Dozzle 从/dozzle_cert.pem与/dozzle_key.pem读取证书,可通过--cert/--key参数或DOZZLE_CERT/DOZZLE_KEY环境变量自定义路径。
方式一:使用默认路径 + Docker secrets
services: agent: image: amir20/dozzle:latest command: agent volumes: - /var/run/docker.sock:/var/run/docker.sock secrets: - source: cert target: /dozzle_cert.pem - source: key target: /dozzle_key.pem ports: - 7007:7007 secrets: cert: file: ./cert.pem key: file: ./key.pem方式二:自定义路径 + 环境变量
services: agent: image: amir20/dozzle:latest command: agent environment: - DOZZLE_CERT=/certs/my-cert.pem - DOZZLE_KEY=/certs/my-key.pem volumes: - /var/run/docker.sock:/var/run/docker.sock - ./certs:/certs ports: - 7007:7007方式三:命令行参数
docker run -v /var/run/docker.sock:/var/run/docker.sock -v ./certs:/certs -p 7007:7007 amir20/dozzle:latest agent --cert /certs/my-cert.pem --key /certs/my-key.pemservices: agent: image: amir20/dozzle:latest command: agent --cert /certs/my-cert.pem --key /certs/my-key.pem volumes: - /var/run/docker.sock:/var/run/docker.sock - ./certs:/certs ports: - 7007:7007要点提醒:
- 官方推荐优先使用Docker secrets提供证书:既可以通过
docker secret create命令创建,也可以像上面的 compose 示例一样在docker-compose.yml中声明。 - 连接 Agent 的那台 Dozzle 实例也必须使用同一套证书,否则双向 TLS 校验无法通过。
- 生成证书可参考以下 openssl 命令(Ed25519 算法 + 自签 X.509):
$ openssl genpkey -algorithm Ed25519 -out key.pem $ openssl req -new -key key.pem -out request.csr -subj "/C=US/ST=California/L=San Francisco/O=My Company" $ openssl x509 -req -in request.csr -signkey key.pem -out cert.pem -days 365源码视角:证书加载逻辑在 internal/support/cli/certs.go 的ReadCertificates——优先尝试加载--cert/--key指定的自定义证书对;若文件不存在则回退到内嵌于二进制中的shared_cert.pem/shared_key.pem(即默认自签名证书)。而 internal/agent/server.go 的NewServer会把同一份证书同时用作服务端证书与 CA 证书池(ClientCAs+tls.RequireAndVerifyClientCert),强制客户端也出示由该 CA 签发的证书——这正是"同一套证书必须同时给 Agent 和主实例"的根本原因。另外,internal/agent/client.go 的 TLS 配置中设置了InsecureSkipVerify: true,注释说明其目的是容忍证书主机名与地址不匹配(自签名证书场景),真正的认证保障来自双向证书校验。
附带功能:agent-test 子命令
除了文档中的健康检查,仓库还提供一个有用的调试子命令agent-test(见 internal/support/cli/agent_test_command.go),用法为dozzle agent-test <address:port>。它会用同样的证书建立连接并拉取一次HostInfo,成功后打印 Agent 的版本、名称与 ID,方便在界面排查之前快速验证 Agent 连通性与证书配置。
Agent 与远程连接(Remote Hosts)对比
Agent 与远程连接(Remote Hosts,即直接连接远端 Docker API / Socket 代理)功能相似,但 Agent 有若干优势,官方总体更推荐 Agent,主要出于性能与安全考量:
| 功能 | Agent | 远程连接 |
|---|---|---|
| 性能 | 更好,负载被分摊到远端 | 更差,压力集中在本机界面侧 |
| 安全性 | 私有 SSL(双向 TLS) | 不安全或依赖 Docker TLS |
| 易用性 | 开箱即用 | 需要暴露 Docker Socket |
| 权限控制 | 对 Docker 具有完整访问权限 | 可以通过 Socket 代理做细粒度控制 |
| 重连机制 | 自动重连 | 需要重启界面 |
| 健康检查 | 内置 healthcheck | 无 |
| 过滤器 | 支持 Agent 级过滤器 | 不支持 |
- 之所以 Agent 性能更好,从架构上很容易理解:日志抓取、解析、统计等工作在 Agent 侧完成,主实例只消费经过 gRPC 压缩传输的结果(参见 internal/agent/client.go 中的 gzip 压缩与 10 MiB 消息上限),网络开销显著降低。
- 如果你确实要使用远程连接,请务必用Docker TLS或反向代理保护连接,相关配置见远程主机指南。
总结
Dozzle Agent 模式是连接多台远程 Docker 主机的推荐方案:它用一个轻量容器承载本地 Docker API 的访问与日志处理,通过双向 TLS 的 gRPC 通道与主实例通信,天然具备自动重连、内置健康检查与过滤器支持,还能通过endpoint|name|group连接串组织起跨环境的主机分组,并在/host-group/<group-name>上直接查看合并日志流。若追求最大安全性,可以按本文方式用 openssl 生成自签证书、以 Docker secrets 挂载,并将同一套证书同时提供给 Agent 与连接方。当遇到 Agent 不显示的异常时,优先检查/var/lib/docker/engine-id是否存在重复的主机 ID,必要时删除该文件并重启 Docker 以重建唯一身份。
【免费下载链接】dozzleRealtime log viewer for containers. Supports Docker, Swarm and K8s.项目地址: https://gitcode.com/GitHub_Trending/do/dozzle
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考