Dozzle 容器 Shell 访问完全指南:浏览器内 Attach 与 Exec 实战
【免费下载链接】dozzleRealtime log viewer for containers. Supports Docker, Swarm and K8s.项目地址: https://gitcode.com/GitHub_Trending/do/dozzle
Dozzle 是一款面向容器的实时日志查看器,支持 Docker、Swarm 与 Kubernetes 等编排平台。除了日志流式查看,它还内置了基于 Web 的容器终端能力,允许用户直接从浏览器附加(attach)到运行中的容器,或在容器内执行命令(exec)。本文以官方文档 docs/guide/shell.md(含 德语版、中文版 等多语言副本)为核心骨架,结合仓库后端路由、CLI 参数解析、认证角色与前端 Terminal 组件的源码实现,系统讲解该功能的启用方式、工作原理、安全边界与 Kubernetes 下的注意事项。读完本文,你将掌握如何安全地为 Dozzle 开启 Shell 访问,并理解从浏览器点击到容器内进程间建立会话的完整链路。
功能概览:Dozzle 如何提供容器 Shell
Dozzle 的 Shell 访问能力包含两种操作模式:
- Attach(附加):接入运行中容器的主进程,直接观察并参与该进程的输入输出流,效果等同于
docker attach; - Exec(执行):在容器内启动一个新的交互式命令(默认探测并启动
bash或sh),效果等同于docker exec。
这两种操作都通过浏览器内的 WebSocket 会话完成,前端对应组件为 assets/components/containers/Terminal.vue。该组件基于 xterm.js 渲染终端界面,在挂载时通过new WebSocket(withBase(\/api/hosts/${container.host}/containers/${container.id}/${action}`))`(见 Terminal.vue)建立连接,随后将用户在终端中的输入与窗口 resize 事件编码为 JSON 事件发送到服务端,并把服务端回传的输出写入终端。
[!NOTE] 根据官方文档,Shell 访问应当适用于所有类型的容器,包括 Docker、Kubernetes 以及其他编排平台。
默认关闭与启用方式
由于浏览器终端意味着对容器的完全控制权,Dozzle 将该功能默认禁用。其开关在 CLI 参数定义中一目了然(见 internal/support/cli/args.go):
EnableShell bool `arg:"--enable-shell,env:DOZZLE_ENABLE_SHELL" default:"false" help:"enables shell access to containers from the web interface."`参数--enable-shell与环境变量DOZZLE_ENABLE_SHELL一一对应,默认值均为false。这意味着你既可以在启动命令中传参,也可以在容器编排文件中注入环境变量,两种方式等价。
方式一:docker run 命令行参数
docker run --volume=/var/run/docker.sock:/var/run/docker.sock -p 8080:8080 amir20/dozzle --enable-shell注意:
--volume挂载 Docker Socket 是 Dozzle 与 Docker 守护进程通信的前提,实际生产部署还应配置restart=always、时区、日志轮转等参数,此处仅保留与 Shell 功能直接相关的核心配置。
方式二:docker-compose 环境变量
services: dozzle: image: amir20/dozzle:latest volumes: - /var/run/docker.sock:/var/run/docker.sock ports: - 8080:8080 environment: DOZZLE_ENABLE_SHELL: true方式三:Kubernetes / Swarm 编排
在 Kubernetes 下部署时,只需在 Dozzle 的 Deployment 容器配置中加入同样的环境变量即可:
env: - name: DOZZLE_ENABLE_SHELL value: "true"完整可参考仓库中的 examples/k8s.dozzle.yml;Swarm 模式请参考 examples/docker.swarm.yml 与 examples/docker.swarm.auth.yml。
路由注册:开关如何在服务端生效
开关并不只是前端显示上的差异,而是决定后端是否注册对应 API 路由。在 internal/web/routes.go 中,路由创建逻辑如下:
if h.config.EnableShell { r.Get("/hosts/{host}/containers/{id}/attach", h.attach) r.Get("/hosts/{host}/containers/{id}/exec", h.exec) }当--enable-shell未开启时,/api/hosts/{host}/containers/{id}/attach与/api/hosts/{host}/containers/{id}/exec这两个 WebSocket 端点根本不会被注册——这与镜像检查等其他功能的“端点不存在”策略一致(见 routes.go 的注释),意味着关闭状态下连接请求将直接返回 404,从网络层面杜绝了攻击面。
同时可以注意到,这两个路由与日志流、容器操作等一样位于认证中间件之后(见 routes.go),也就是说任何访问这些端点的请求都会先经过认证层。
安全模型:从默认关闭到角色控制
官方文档明确警告:任何能访问 Dozzle 界面的人,都能在你的容器里打开终端,其权限等同于docker exec。因此,在公开可访问的 Dozzle 实例上启用--enable-shell之前,必须先配置认证。仓库实现的认证体系位于 internal/auth,支持simple(用户名密码)、oidc(OpenID Connect SSO)、forward-proxy等多种提供方,详细说明见 docs/guide/authentication.md。
角色:shell 权限的精细控制
仅开启认证还不够——Dozzle 提供基于角色的权限来进一步限制谁能使用 Shell。角色定义位于 internal/auth/roles.go:
type Role int const ( None Role = 0 Shell Role = 1 << iota // ... Actions、Download、Notifications、Cloud ) const All = Shell | Actions | Download | Notifications | Cloud角色解析支持shell与dozzle_shell两种写法(见 roles.go),并支持^前缀的排除语法,例如all,^shell表示“除 shell 外授予全部权限”(见 roles.go 的注释与实现)。这意味着即使启用了 Shell 功能,管理员仍可只将shell角色授予特定用户。
服务端二次校验
权限检查并不仅仅停留在路由层。即使某用户拿到了 WebSocket 端点地址,服务端处理器也会再次校验角色。在 internal/web/terminal.go 的attach处理器中:
permit := true if h.config.Authorization.Provider != NONE { user := auth.UserFromContext(r.Context()) ... permit = user.Roles.Has(auth.Shell) } if !permit { log.Warn().Msg("user is not permitted to attach to container") conn.WriteMessage(websocket.TextMessage, []byte("⛔ Access denied: attaching to this container is forbidden\r\n")) return }exec处理器(terminal.go)采用完全相同的校验逻辑。双重保障(路由注册 + 处理器内角色检查)确保安全边界在服务端得到严格执行。
容器过滤标签
此外,认证用户还可以通过容器过滤标签(user.ContainerLabels,见 terminal.go)将可访问范围限制到特定容器集合,从而实现“即使有 shell 权限,也只能进入被授权的那部分容器”的细粒度隔离。
浏览器到容器的完整链路
服务端处理流程
- 浏览器通过 WebSocket 连接
/api/hosts/{host}/containers/{id}/attach或/api/hosts/{host}/containers/{id}/exec; upgrader.Upgrade将 HTTP 请求升级为 WebSocket 连接(terminal.go,基于 gorilla/websocket 且刻意未开放任意 Origin,以防止跨站 WebSocket 劫持,见文件头部注释);- 处理器从 URL 参数中取出容器
id,通过h.hostService.FindContainer(hostKey(r), id, userLabels)按用户标签过滤后找到目标容器服务; attach调用containerService.Attach(ctx, eventReader, wsWriter)建立附加会话;exec则调用containerService.Exec(...)执行命令(terminal.go);- 服务端把 WebSocket 包装为
webSocketWriter(输出写入连接)与jsonEventReader(从连接读取 JSON 编码的ExecEvent,见 terminal.go),实现双向数据流。
exec 的默认命令探测
值得注意的细节是,exec模式并非简单地执行用户输入的第一条命令,而是先做一次 Shell 探测(terminal.go):
[]string{"sh", "-c", "command -v bash >/dev/null 2>&1 && exec bash || exec sh"}即:优先尝试bash,若容器内不存在则回退到sh。这保证了在仅有 POSIX sh 的精简镜像中也能打开终端。
远端主机与 Agent 支持
当目标容器位于远端主机时,Dozzle 通过 Agent 转发会话。仓库中的 internal/agent/client.go 与 internal/agent/client.go 分别实现了ContainerAttach与Exec的远程调用;gRPC 协议侧由 protos/rpc.proto 中的ContainerExecRequest/ContainerExecResponse双向流承载(对应服务端实现见 internal/agent/server.go 的ContainerExec)。这印证了官方文档“适用于所有编排平台”的说明在架构上是有保障的。
Kubernetes 模式下的特殊说明
在 k8s 模式下,Shell 访问不再经过 Docker API,而是直接走 Kubernetes API。因此目标 Pod 必须满足一个硬性前提:
目标 Pod 内必须存在可执行的 Shell(
/bin/sh、/bin/bash等)。
以下两类镜像无法附加:
- 基于
FROM scratch构建的极简镜像(不含任何用户空间工具); - 不带 Shell 的 Distroless 镜像(如仅含单一静态二进制、以非 root 运行的镜像)。
这类镜像连command -v bash探测都无法执行,docker exec/kubectl exec同样无能为力。实际排障时,若你的应用镜像确实缺少 Shell,可以考虑临时改用带 Shell 的调试镜像或 sidecar 容器方案,而非试图在 Dozzle 中强行附加。
生产环境安全清单
综合官方文档与源码实现,在公开环境启用 Dozzle Shell 访问前,建议按以下清单逐项确认:
- 认证先行:至少配置一种认证提供方(docs/guide/authentication.md),避免匿名访问 UI;
- 角色收敛:仅向确有排障需求的用户授予
shell角色,可利用^shell排除语法做反向收权(internal/auth/roles.go); - 容器过滤:为不同用户配置容器过滤标签,缩小可进入的容器范围(internal/web/terminal.go);
- 网络隔离:通过反向代理(参考 examples/ingress.yml)限制 Dozzle 的暴露范围,必要时启用 HTTPS;
- 日志审计:保持 Dozzle 日志级别可用,Shell 访问的失败尝试会以 warn 级别记录(见 terminal.go 的
log.Warn()); - 最小化开启:仅在实际需要调试时开启
--enable-shell,日常日志查看场景保持默认关闭,从路由注册层面(routes.go)消除攻击面。
小结
Dozzle 的 Shell 访问功能把docker attach/docker exec的能力完整搬进了浏览器,配合日志流、容器分组等能力,为容器化应用的日常排障提供了统一的 Web 入口。理解其「默认关闭 → 显式开启 → 认证 + 角色双重校验」的安全设计,以及 Docker / Kubernetes 两种后端路径的差异,是安全使用该功能的前提。若需进一步了解相关能力,可继续阅读仓库中的 docs/guide/authentication.md、docs/guide/container-groups.md 与 docs/guide/remote-hosts.md。
【免费下载链接】dozzleRealtime log viewer for containers. Supports Docker, Swarm and K8s.项目地址: https://gitcode.com/GitHub_Trending/do/dozzle
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考