如果你和我一样,服务器上攒了十几套 docker-compose 项目,散落在各个目录里,每次想重启其中一个服务,都得先在脑子里过一遍“它到底放在哪里”——那 Dockge 这款工具值得你花十分钟试试。简单说,Dockge 是一个专门用来管理 docker compose 栈的开源 Web 工具,它把每个 compose 项目当成一个独立的“栈”来管理,从编辑 YAML、部署启动、查看日志到监控状态,全部在一个页面上完成。它不是要把 Docker 变成图形化点击平台,而是把“用命令行管理 compose”这件日常事,做得更顺手、更直观。接下来我把部署过程、使用逻辑和踩过的坑都写一写,给正在观望或者已经装上还没玩明白的朋友做个参考。
1. 厌倦了满服务器找 Compose 文件之后,我开始用 Dockge
1.1 我日常最难受的三个瞬间
先说说槽点。早期我管理 compose 项目的方式非常原始:建一个目录,把 compose 文件丢进去,然后靠记忆维护。时间一长,问题就来了。
第一个瞬间是“忘了文件在哪”。某个服务最近没怎么动,等它出问题要重启时,我先得回忆这项目是放在 /opt 下面,还是放在那个带着日期的备份目录里,还是干脆就是当时测试时随手建的路径。运气好两分钟找到,运气不好得翻 history 和 bash 的搜索记录。这事儿看起来不大,但一个月来几次,真的烦。
第二个瞬间是“服务挂了不知道”。虽然容器 restart 策略一般能兜底,但有些服务是依赖其他服务的,上游一挂,下游一连串出错。没有统一的状态页,我只能一个个去 docker ps 看状态,再手动 docker logs 翻日志。排查一次故障,往往大半时间花在了确认“谁挂了”上。
第三个瞬间是“改 YAML 改错”。用 vi 在终端里改 compose 文件,最怕的就是缩进和引号问题。YAML 这东西,看着简单,真要手敲嵌套结构,分分钟给你来个 mapping values are not allowed in this context。改完还得小心翼翼执行 docker compose up -d,等报错才知道写错了。那感觉,怎么说呢,一次两次能忍,次数多了都想给自己写个校验脚本了。
这三个瞬间叠加起来,就是我开始找管理工具的直接原因。
1.2 Dockge 的管理单位是“栈”,不是“容器”
Dockge 的核心理念值得先说清楚:它管理的单位是 stack(栈),也就是一组通过同一个 compose 文件定义出来的服务集合,而不是单个容器。
一个栈对应一个目录,目录里放一个 compose 文件。这个设计非常对你的胃口,因为只要你以前是“一个项目一个目录”的管理方式,迁到 Dockge 几乎零成本。Dockge 会自动扫描你指定的 stacks 根目录,把每个包含 compose 文件的子目录识别为一个栈,然后在首页列出来。
你看首页的时候,一眼就能知道多少个栈在运行、每个栈里有几个容器、整体 CPU 和内存占用什么样。任何一个栈处于停止状态或者容器数量不对,马上就能发现,不用再对着终端逐行看 docker ps 了。
而且它没有引入数据库。所有状态都来自磁盘上的 compose 文件和 Docker API,这意味着一件事——你永远不会被关在一个私有格式里。哪怕哪一天你不用 Dockge 了,那一堆目录和 YAML 文件依然原样躺在服务器上,用命令行照样能管,完全没有迁移负担。
1.3 它和全功能 Docker 管理面板的路子不太一样
用过那种大而全的 Docker 管理面板的朋友应该明白我的意思:这类面板什么都管,容器、镜像、网络、卷,甚至能直接拉镜像创建容器。功能是强,但正因为太全,反而把常用场景的路径绕远了。对我来说,日常最密集的操作就是“改 compose 文件 → 重新部署 → 看日志”,在这种大面板里反而要层层找菜单。
Dockge 走了另一个方向:它不替你造容器,它只做 compose 项目管理。每个栈点进去,左边是编辑器,右边是运行状态和日志,顶上是操作按钮。你不需要跳出这个页面,就能完成从改配置到上看日志的完整闭环。
有人可能会问,那我直接在命令行里操作不也一样?是,如果你只管理一两个项目,命令行完全够用。但当你管理的项目多了以后,“全部项目在一个页面里看状态”和“记住每个项目在哪、怎么看日志”的体验差距就非常明显了。Dockge 的价值是在这个管理粒度上体现出来的,我后面细说。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 部署之前先弄明白:目录就是栈,socket 就是控制权
2.1 stacks 目录怎么设计才顺手
Dockge 要求你把所有栈统一放在一个根目录里,这个目录通过环境变量 DOCKGE_STACKS_DIR 指定,容器内默认是 /opt/stacks。我建议在宿主机上也直接用 /opt/stacks,省得两边路径对不上还要动脑子换算。
这个根目录下的每个子目录代表一个栈,子目录的目录名就是栈名。比如你要管一个叫 nextcloud 的项目,那就建一个 /opt/stacks/nextcloud 目录,里面放 compose.yaml,Dockge 首页就会自动出现名为 nextcloud 的栈。
这里有个容易被忽略的细节:目录名最终会成为 docker compose 的 project name。docker compose 默认用 compose 文件所在目录名作为 project name,所有容器和网络都会带上这个前缀。所以目录名最好只用小写字母、数字、下划线和中划线,不要用大写字母和特殊字符。别问我为什么强调这点,我后面踩坑章里有案例,目录叫 TestStack 结果 project name 变成了 teststack,排查的时候对不上号,费了好大劲。
2.2 挂载 docker.sock 意味着什么
部署 Dockge 的时候有一行挂载是绕不开的:/var/run/docker.sock:/var/run/docker.sock。很多第一次接触这工具的人会犹豫,把 Docker 的 socket 给一个容器,是不是风险太大?
先看原理。docker.sock 是 Docker Engine 的 API socket,谁拿到了它,就等于拿到了这台机器上 Docker 的完整控制权。Dockge 靠它来读取容器状态、执行 docker compose 相关命令、收集日志和资源占用数据。可以说没有这个 socket,Dockge 就是一个纯文本编辑器,什么也干不了。
风险边界也就在这里:谁能用 Dockge,谁就能间接控制这台机器上的所有 Docker 服务。因此我把这个工具的访问范围看得很紧。部署时我建议只在局域网范围使用,不要图省事把端口直接暴露到公网,因为 Dockge 本身没有内置登录认证体系。不要觉得这话多余,真的有人图方便把 5001 端口映射出去,结果被扫描器盯上,最后整个 Docker 环境被搞乱,这种事不是没发生过。
2.3 版本硬性要求:Docker 20.10+ 与 Compose v2
Dockge 内部执行的是 docker compose(Compose v2 插件)命令,不是老的 docker-compose 单文件命令。如果你的服务器还是老版本 Docker,或者还在用 docker-compose v1,那 Dockge 部署出来很可能各种操作失败,因为它在容器里找的是 docker compose 这个子命令。
部署前先花十秒钟自查一下,执行:
bash复制docker --version
docker compose version
docker compose version 如果输出类似 Docker Compose version v2.x.x 就说明有 v2 插件。如果提示找不到命令,说明要么 Docker 太老,要么没装 compose 插件。特别是某些带桌面版或老版本 Linux 发行版默认只有独立的 docker-compose,这时候需要先升级 Docker 版本,再确认插件可用,否则后面 Dockge 能启动但按钮点了没反应。
老系统用户的建议很简单:别折腾兼容,直接把 Docker 升到当前稳定版,正常情况下 docker compose 插件都会随包安装好。
3. 部署过程全记录:一份 Compose 文件加两个关键挂载点
3.1 官方推荐的 Compose 文件
Dockge 自己也是一个 Docker 容器,所以你可以用 docker compose 来部署它。我把当时实际使用的 compose 文件贴出来,配合注释说明每一行的作用:
yaml复制services:
dockge:
image: louislam/dockge:1
container_name: dockge
restart: unless-stopped
ports:
- "5001:5001"
environment:
- DOCKGE_STACKS_DIR=/opt/stacks
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- ./stacks:/opt/stacks
networks:
- default
逐个解释关键项:
- 镜像标签用
:1,对应 Dockge 的 1.x 主线版本,镜像本身会持续收到小版本更新。 - 宿主机的
5001端口映射到容器内5001,这是默认 Web 端口。如果你只想本机访问,改成127.0.0.1:5001:5001会更安全。 DOCKGE_STACKS_DIR必须设为容器内的栈目录路径,也就是/opt/stacks。这个值要和挂载的容器内路径一致,Dockge 就是拿这个路径去扫描和操作的。- 第一行挂载是 docker.sock,第二行把宿主机
./stacks目录挂到容器的/opt/stacks。注意./stacks是相对路径,它相对于你执行docker compose up时的目录,建议直接用绝对路径/opt/stacks:/opt/stacks,省得在不同目录下操作时搞错位置。
如果遇到文件权限问题,可以在 environment 里加上 PUID 和 PGID,指定成你登录用户的 uid 和 gid。这个看个人实际情况,我后面权限坑里详细说。
3.2 首次打开界面后的三件事
启动容器后,浏览器访问 http://服务器IP:5001,你会看到一个很清爽的界面。第一次打开,我建议别急着创建栈,先按顺序做三件事。
第一件事,看页面顶部的资源统计区。如果 CPU、内存、Docker 根目录占用都正常刷出来了,说明 Dockge 到 Docker API 的通道已经通了。如果这里空白或者报错,大概率是 docker.sock 挂载出了问题,或者容器内权限不够,先解决这个再继续。
第二件事,创建第一个栈。点击创建按钮,Dockge 会让填一个栈名,然后生成一个基本模板。用这个模板部署一个简单服务跑通流程,比如部署一个 nginx 或者 redis,确认页面上的部署按钮执行正常。
第三件事,把你现有的 compose 项目拖进去。在宿主机上把旧项目文件复制到 /opt/stacks/项目名/compose.yaml,Dockge 会自动识别,不需要重启。这一步做完,你就能体会到它“自动发现目录”的爽点:目录结构就是管理结构,文件到位,UI 自己就出来了。
我用一个表格整理三种情况下的处理方式,方便对照:
| 场景 | 操作方法 | 结果 |
|---|---|---|
| 全新项目 | 在 UI 里填栈名,写 compose 内容后部署 | 自动创建目录和 compose.yaml |
| 已有 compose 项目 | 复制到 stacks 下对应目录,重命名为 compose.yaml | UI 自动发现并显示 |
| 只有 docker-compose.yml | 复制为 compose.yaml 后再编辑 | 推荐统一命名,避免识别异常 |
3.3 自举:用 Dockge 管理 Dockge 自己
部署 Dockge 的方式是先写一个 compose 文件再启动,而这个 compose 文件本身也是标准 compose 项目。所以完全可以把它归入一个栈目录,让 Dockge 管理自己。
操作很简单:把上面那段 compose 文件保存到 /opt/stacks/dockge/compose.yaml,然后把原来的容器停掉删掉,再在 Dockge 的 UI 里对这个新出现的 dockge 栈执行部署。这样 Dockge 的启停、更新、日志查看就都统一到 UI 里了,不用再跑去命令行操作。以后升级 Dockge,直接在页面里点一下相关按钮就行。
不过自举有一个必须提醒的坑:如果对这个 dockge 栈执行了删除操作,当前正在跑的这个界面就会随容器一起消失。如果你立刻意识到误操作,还是可以用命令行把容器恢复回来的,毕竟 compose 文件还躺在磁盘上。我在操作的时候会特别注意,自举的栈确认没问题后,基本只碰“更新”按钮,不去碰删除类按钮。
4. Dockge UI 背后的 Docker 命令:按钮与真相
4.1 编辑器凭什么比 vim 好用
Dockge 每个栈内部默认停在“编辑”页,这个编辑器用的是 VS Code 同款的 Monaco 内核。第一次看到的时候我还愣了一下,这已经完全不是那种页面上放一个 <textarea> 的简陋编辑器了。
最直接的感受是 YAML 语法高亮和字段补全。你写 services: 它会自动提示可以填什么,写 image: 会提示常见镜像,缩进和层级错误会在编辑的时候直接标红,而不是等你点部署之后由 docker compose 来教育你。有过改错缩进经历的人应该能懂这个有多省事。
编辑器还有一个“环境变量”标签,用来修改这个栈的 .env 文件。compose 文件里常见的 ${变量名} 写法,配合这个标签,就能做到变量和主文件分开维护,界面里直接换值,不用回到终端去处理。
这个编辑器的意义在于:它把“写文件”和“执行部署”放到了同一个上下文里。你写完立刻能部署,部署完立刻能看到状态,不用在 vim、终端、浏览器三个地方来回切换。对像我这种长年靠命令行吃饭的人来说,这个流程理顺带来的效率提升非常明显。
4.2 按钮和实际命令对照表
UI 上每个按钮背后都是一条 docker compose 命令。理解这一点很重要,因为它决定了你点击按钮时会有什么预期。我用表格整理一下当前版本里主要按钮对应的实际操作:
| UI 按钮 | 实际动作 | 底层命令 |
|---|---|---|
| 部署(Deploy) | 创建/更新栈容器 | docker compose up -d |
| 停止(Stop) | 停止所有容器 | docker compose stop |
| 重启(Restart) | 重启所有容器 | docker compose restart |
| 更新(Update) | 拉取新镜像并重新部署 | docker compose pull && docker compose up -d |
| 移除(Remove) | 删除栈及其容器 | docker compose down |
| 日志(Logs) | 打开聚合日志页 | docker compose logs -f --tail=... |
从上表能看出来,Dockge 并没有做什么黑魔法,它就是把你平时在命令行做的事,封装成了清晰的按钮,并且顺带把操作前校验、结果反馈、状态刷新这几步自动化了。所以即使你完全不懂 UI,只要懂 docker compose 命令,就很容易推断出操作结果。
比较值得留意的是“部署”这个按钮。Dockge 在执行 up -d 之前会先用 docker compose config -q 做一次语法校验,如果 compose 文件有问题,它会直接告诉你哪里错了,不会真的去执行。这相当于多了一道安全闸门,比自己在终端里直接执行要稳。
日志页面也值得多说一句:Dockge 会把栈内容器的日志聚合成一个视图,支持按容器筛选、搜索关键词、暂停自动刷新。排查多容器项目时,这种聚合视图比开多个终端窗口切来切去高效很多。
4.3 状态数据与 Web 终端
Dockge 首页和栈详情页显示的 CPU、内存数据,不是它自己猜的,而是通过 Docker API 从引擎层拿到的实时数据。每个服务容器会单独显示资源占用,你可以快速定位哪个容器是“资源大户”,不用再手动 docker stats 盯着看。
还有一个很实用的功能是 Web 终端。在栈详情里可以对某个容器直接打开终端窗口,实际执行的是 docker exec -it <容器> sh 类似的逻辑,等于浏览器里开了一个容器内 shell。以前排查问题要先 docker ps 拿到容器 ID,再手动执行 exec 命令,现在点一下按钮就进去了,确实方便。
我用下来最深的感受是:Dockge 做的不是“把 Docker 变成点鼠标”,而是把高频操作跟命令学习的成本解耦。对于新手,可以先在 UI 里操作,慢慢对应底层命令;对于老手,则是把重复劳动减到最低。
5. 用了几个月,真正让我记住的五个坑
5.1 目录名大小写导致容器项目名与预期不符
这是第一个让我栽跟头的坑。我在 Dockge 里建了一个名为 TestStack 的栈,UI 里一切正常,结果进终端看容器时发现,容器前缀变成了 teststack,而不是我预期的 TestStack。
原因是 docker compose 在生成 project name 时会强制转成小写并过滤掉特殊字符。Docker 的 project name 规则比目录名严格得多,目录名里的“感觉没问题”和 Docker 实际解析出来的名,不一定是一个东西。后面排查日志、看网络名的时候对不上号,我一度以为是容器名字变了,实际就是大小写被归一化了。
所以现在我的习惯是:栈目录名一律小写字母开头,只用小写字母、数字、中划线、下划线,不用驼峰,不用空格,不用点号。这个习惯在 Dockge 内部可能无所谓,但一想到它要跟 Docker 的项目命名机制对齐,我就老老实实遵守。
5.2 外部改文件与 UI 不同步的怪现象
Dockge 会自动监控栈目录里的文件变化。这本来是好事,但如果你习惯于在宿主机上用 vim 改 compose 文件,同时 Dockge 的编辑器里又打开了这个文件,就会出现两边不同步的提示。Dockge 检测到磁盘文件变化后,会提示文件已在外部被修改,需要确认是否重新加载。
我遇到过的最尴尬的情况是:在 UI 里改了一半,又想起来有个参数不如直接去服务器上改,结果两边都改了一部分,最后保存的时候相互覆盖,丢了改动。别问怎么恢复,问就是白写了一小段。
后来我的做法很明确:同一个栈的 compose 文件,同一时间只允许一个编辑入口。要么用 Dockge 编辑器,要么用命令行编辑器,不混着来。Dockge 的文件监控功能这时候反而成了提醒器,它会告诉你“文件被外部改动过”,让你有个觉察的机会。
5.3 .env 变量加载机制
docker compose 在解析 compose 文件时,会自动读取同目录下的 .env 文件,把里面的变量填充到 ${VAR} 引用的位置。Dockge 的环境变量标签做的就是这个事,它让你直接在 UI 里读写 .env,不需要到目录里单独编辑。
初用者比较容易在这里困惑:我改了 compose 文件里的 ${MYSQL_PASSWORD},UI 也保存了,但你容器没重新部署,变量当然不会变。.env 的变量是在部署时被读取的,所以每次改完环境变量,记得要点一次部署按钮,让 compose 重新解析并应用变量。
另外注意 Docker 的变量替换规则:.env 里不要给值加不必要的引号,比如 MYSQL_PASSWORD="123456",这个引号可能成为实际值的一部分,而不是像你预期的“当作字符串边界处理”。这种问题最难排查,因为 YAML 层面看着完全正常,难受就难受在一致性上。
5.4 端口相关:DOCKGE_PORT 与子路径
Dockge 官方有一个不太起眼的配置项叫 DOCKGE_PORT,我的建议是轻易不要去设置它。这个环境变量的作用是告诉 Dockge 本机端口开放状态,但如果你手动设置了它,Dockge 就会用这个值来判断端口是否开放。一旦你设置的值和实际端口映射对不上,UI 里就会出现端口检查异常的提示,而且你很难猜到是自己环境变量写错了。
我自己见过有人为了消除这个提示,手动把 DOCKGE_PORT 设成跟映射一致的值,结果一台机器上跑多个实例时全乱了。官方文档里这个变量本身就不是必选项,默认不设置就是最好的状态,让端口以实际映射为准。
如果你打算用域名子路径的方式访问 Dockge,可以通过环境变量 BASE_URL 指定路径前缀。比如设置 BASE_URL=/dockge,访问入口就会变成 http://服务器IP:5001/dockge/。这个适合把 Dockge 收进你现有的统一访问入口后面。但注意,子路径只是区分路径,不是安全边界,Dockge 自己没有账号体系,访问控制还是要靠网关卡口解决。
5.5 文件权限与容器内用户
Dockge 容器在运行时可能以非 root 用户执行,这时候如果宿主机上的 stacks 目录属主不对,轻则 UI 保存失败,重则整个栈无法部署。
典型症状:在 UI 里编辑没有问题,但点保存时报错,或者部署时报权限 denied。检查方法很简单,在宿主机上看看 /opt/stacks 的属主:
bash复制ls -ld /opt/stacks
如果发现目录属主是 root,而容器内进程不是以 root 运行,那很明显写不进去。解决方式有两个:一是把目录属主改成容器内用户的 uid;二是在 Dockge 的 environment 里设置 PUID 和 PGID,让它以匹配你宿主机用户的身份运行。具体用哪个 UID,取决于你希望宿主机上谁能直接读写这些目录。我自己的习惯是用常见的 1000 用户 ID,然后确保登录用户有权限访问 /opt/stacks。
6. 我现在的日常:Dockge 改变了管理服务器的方式
说实话,刚开始用 Dockge 的时候,我觉得它就是把 compose 命令包装了一下,没什么技术含量。但用了两个月之后,我承认它确实改变了我的日常管理方式。现在我的服务器上一堆服务,几乎都在 /opt/stacks 下面统一纳管,平时排查问题就是打开 Dockge,看哪个栈状态不对,点进去看日志,顺手改配置重新部署,全程不需要再 SSH 到服务器上敲 docker 命令。
备份也变简单了。因为 Dockge 没有自己的数据库,所有状态就是那一堆 compose 文件和 .env 文件。我需要备份时,直接把 /opt/stacks 目录压缩带走,换一台新机器解压出来,挂上 docker.sock,Dockge 重新启动,所有栈就都回来了。对于我这种喜欢折腾服务器的人,这个“无状态”设计是很大的优势。
最后分享一个使用细节:我会定期在 Docker 里清理无用的悬空镜像,但 Dockge 的“更新”按钮只负责拉镜像和部署,不负责清理旧镜像。所以我习惯在更新完几个栈之后,顺手执行一次镜像清理,避免磁盘空间被旧版本镜像吃掉。这个小动作不在 Dockge 的 UI 里,但配合它使用,会让整个管理流程更完整。如果你想找一个能让 compose 管理不再靠记忆和翻目录的工具,Dockge 是值得认真试试的一个选择。
