news 2026/9/14 15:07:46

Dozzle 容器分组机制:默认分组、Swarm 服务分组与 dev.dozzle.group 自定义标签

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Dozzle 容器分组机制:默认分组、Swarm 服务分组与 dev.dozzle.group 自定义标签

Dozzle 容器分组机制:默认分组、Swarm 服务分组与 dev.dozzle.group 自定义标签

【免费下载链接】dozzleRealtime log viewer for containers. Supports Docker, Swarm and K8s.项目地址: https://gitcode.com/GitHub_Trending/do/dozzle

Dozzle 会自动按 Stack 名称或 Swarm 服务名把容器归组,你也可以通过dev.dozzle.group标签创建自己的分组。本文以 Dozzle 官方文档的"容器分组"为主题,完整覆盖默认分组规则与自定义标签用法,并结合仓库源码深入讲解分组标签的解析优先级、Swarm 服务级标签合并机制,以及分组日志流的 API 实现链路。

一、分组的基本原理

Dozzle 的分组逻辑核心就是一条:容器上的 label 决定了它属于哪个分组。官方文档 docs/guide/container-groups.md 给出的规则有两条:

  1. 默认分组:在主机(host)模式下,容器默认按其 stack 名称分组;如果容器带有com.docker.swarm.service.name标签,Dozzle 会自动进入"Swarm 模式",把所有服务名相同的容器合并到同一组;
  2. 自定义分组:给容器打上dev.dozzle.group=<组名>标签,所有同组名的容器会在界面中合并显示。例如组名为myapp时,所有带dev.dozzle.group=myapp标签的容器会被归到一组。

从源码结构看,分组结果最终体现在 internal/container/types.go 中Container结构体的Group字段上——这是后端与前端共享的契约,也是后面所有分组行为(列表归组、分组日志流、分组页面)的数据源头。

二、默认分组:Stack、Compose 与 Swarm 三种场景

2.1 主机模式:按 stack / compose 项目名分组

在普通 Docker 主机模式下,分组依据来自两个由 Docker 自动写入的标签:com.docker.stack.namespacedocker stack deploy部署时写入)和com.docker.compose.projectdocker compose up时写入)。这一机制在 docs/guide/swarm-mode.md 中也有明确说明:

com.docker.stack.namespaceandcom.docker.compose.projectlabels are used for grouping containers. For services, Dozzle uses the service name as the group name which iscom.docker.swarm.service.name.

前端模型 assets/models/Container.ts 中的namespace计算属性完整呈现了这条标签读取链(含自定义分组在内的完整回退顺序):

get namespace() { return ( this.labels["dev.dozzle.group"] || this.labels["coolify.projectName"] || this.labels["com.docker.stack.namespace"] || this.labels["com.docker.compose.project"] ); }

即:dev.dozzle.group优先,其后依次回退到coolify.projectNamecom.docker.stack.namespacecom.docker.compose.project。测试用例 assets/models/Container.spec.ts 用一组断言锁定了这个回退顺序(falls back through coolify, stack, then compose)。

2.2 Swarm 模式:按服务名合并

当容器带有com.docker.swarm.service.name标签时,意味着它由某个 Swarm service 调度。此时 Dozzle 将该标签的值作为分组名,把同一 service 的所有 task 容器合并展示——这正是文档中所说的"自动启用 Swarm 模式"。前端 assets/stores/swarm.ts 通过遍历容器标签中的com.docker.swarm.service.name来构建服务列表;而分组日志流的订阅则直接按标签过滤(见第四节useServiceStream)。

三、自定义分组:dev.dozzle.group 标签

3.1 用法示例

给容器添加dev.dozzle.group标签即可创建自定义分组,标签值就是组名。以下示例来自官方文档,可直接复制使用。

使用 Docker CLI:

docker run --label dev.dozzle.group=myapp hello-world

使用 Docker Compose(docker-compose.yml):

services: dozzle: image: hello-world labels: - dev.dozzle.group=myapp

打上该标签后,所有dev.dozzle.group=myapp的容器会在 Dozzle 界面中合并为一个分组入口,点击后即可查看整组的聚合日志。

3.2 后端如何解析分组标签

后端在把 Docker API 返回的原始容器数据转换为Container对象时解析分组,逻辑位于 internal/docker/client.go:

group := "" if c.Labels["dev.dozzle.group"] != "" { group = c.Labels["dev.dozzle.group"] } else if c.Labels["coolify.projectName"] != "" { group = c.Labels["coolify.projectName"] }

两个关键事实:

  • 优先级dev.dozzle.group优先于coolify.projectName(后者是对 Coolify 平台的适配,作为无 dozzle 标签时的兜底);
  • 两条构建路径共用同一套规则newContainer(来自 list summary,internal/docker/client.go#L610-L654)与newContainerFromJSON(来自 inspect,internal/docker/client.go#L666-L671)都执行相同的dev.dozzle.groupcoolify.projectName回退逻辑,保证增量推送与完整检查两条数据路径的分组结果一致。

这一优先级由单元测试 internal/docker/client_test.go 中的Test_newContainer_labelPriority明确锁定,其中dozzle labels take priority用例验证了当dev.dozzle.groupcoolify.projectName同时存在时,取 dozzle 标签的值;docker name as final fallback用例则验证了无任何分组标签时Group为空字符串(容器不入组)。

3.3 命名与分组标签的配套

dev.dozzle.group常与同族标签dev.dozzle.name(自定义显示名)配合使用,两者在同一优先级体系中并列处理(dev.dozzle.namecoolify.serviceName→ 容器名)。相关标签的完整说明可参考 docs/guide/container-names.md 与 docs/guide/container-links.md。

四、Swarm 下的进阶:服务级 deploy.labels 的合并

这是文档未展开、但实际使用中非常关键的细节。Swarm 会把 compose 文件中deploy.labels写下的标签打在service上,而不是打在 task 容器上——直接 inspect 容器根本看不到这些标签。Dozzle 的解决方案在 internal/docker/service_labels.go:

  1. serviceLabelCache30 秒 TTLserviceLabelTTL)缓存一次ServiceList调用结果,把"每个容器一次 API 调用"摊薄为"每次刷新一次";缓存刷新失败时会保留旧值,避免瞬时错误导致标签在界面上消失;
  2. mergeServiceLabels通过com.docker.swarm.service.id标签把 service 标签合并到其 task 容器上,容器自身的标签更具体、永远优先maps.Copy(merged, serviceLabels)先铺底,maps.Copy(merged, c.Labels)再覆盖);
  3. 合并后重新推导NameGroup(internal/docker/service_labels.go#L97-L108),沿用与newContainer相同的优先级:dev.dozzle.group优先于coolify.projectName
  4. 该合并仅在 manager 节点(Swarm.ControlAvailable为真)执行,worker 节点上的 agent 会跳过,其容器仅保留自身标签。

由此得到一个实用结论:在 Swarm 环境下,dev.dozzle.group既可以写在docker service create --label上,也可以写在 compose 的deploy.labels,后者由 service 继承合并而来。这一点由 internal/docker/service_labels_test.go 中Test_mergeServiceLabels_redoes_name_and_group用例验证:service 上带dev.dozzle.group=cloud时,task 容器的Group会被重算为cloud

五、分组日志流的 API 链路

分组不只是列表上的视觉归组,更重要的是"整组日志合并查看"。其实现链路贯穿前后端:

  • 路由层:分组日志流端点注册在 internal/web/routes.go——r.Get("/groups/{group}/logs/stream", h.streamGroupedLogs)
  • 前端订阅:assets/composable/logs/eventStreams.ts 中useGroupedStream通过EventSource连接/api/groups/{group}/logs/stream,服务端将组内所有容器的日志按时间交错排序后以 SSE 推给浏览器;
  • 同类端点:stack 分组走标签过滤/api/labels/com.docker.stack.namespace:{name}/logs/streamuseStackStream),Swarm 服务走/api/labels/com.docker.swarm.service.name:{name}/logs/streamuseServiceStream),多容器任意合并走/api/hosts/{host}/logs/mergedStream/{ids}useMergedStream)——四种入口最终复用同一套带搜索过滤、级别过滤、断线重连的useLogStream底座;
  • 页面入口:分组详情页为 assets/pages/group/[name].vue,路由形如/group/{组名},与dev.dozzle.group的标签值直接对应。

六、适用前提与小结

  • 分组标签对 Docker、Swarm 与 Kubernetes 场景通用,其中 Swarm 场景依赖 service 标签合并,worker 节点上的远程 agent 容器只有自身标签可参与分组;
  • dev.dozzle.group的优先级高于coolify.projectName,且都高于com.docker.stack.namespace/com.docker.compose.project的自动回退(该回退链定义在前端 assets/models/Container.ts);
  • 一个容器只能归属一个分组(Group为单值字符串),需要更细的合并视图时可用多容器 merged stream 或按标签过滤。

小结:Dozzle 的分组体系 = "自动标签(stack/compose/swarm service)+ 自定义dev.dozzle.group标签"。给容器打一个标签就能完成归组,而分组的解析优先级、Swarm service 标签的 30 秒缓存合并、以及/api/groups/{group}/logs/stream日志流端点,共同构成了这一机制从容器标签到合并日志界面的完整实现链路。

【免费下载链接】dozzleRealtime log viewer for containers. Supports Docker, Swarm and K8s.项目地址: https://gitcode.com/GitHub_Trending/do/dozzle

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/14 15:05:59

2026年上位机选型指南:C#、LabVIEW与Qt三大路线解析

1. 为什么2026年的上位机选型&#xff0c;反而比十年前更难了先说个反直觉的现象&#xff1a;十年前做上位机&#xff0c;根本不需要纠结选型。那时候工控现场清一色是组态软件&#xff0c;或者谁熟用什么就上什么。但到了2026年&#xff0c;我收到的私信里十有八九都在问同一个…

作者头像 李华
网站建设 2026/9/14 15:05:14

从个人效率到组织智能:企业级Agent平台关键能力与落地实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/14 15:04:54

STM32F103ZET6+STemWin实现GIF动图显示的完整例程与内存优化

简介&#xff1a;STM32F103ZET6单片机STemWin-GIF图片显示实验例程源码&#xff0c;面向使用该型号单片机的嵌入式开发者&#xff0c;演示如何在STemWin图形库中加载与播放GIF动态图片。例程涵盖LCD显示初始化、外设配置、STemWin库初始化等流程&#xff0c;并展示图片尺寸调整…

作者头像 李华
网站建设 2026/9/14 15:04:33

Fluent许可证成本分摊模型与优化实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/14 15:04:27

AI降重工具退款政策实测与避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/14 15:02:57

汽车气动噪声仿真:CFD与SEA技术应用详解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华