Docker 应用:去广告与影音

为什么是 Docker

软路由上玩应用,绕不开 Docker 的一处争议:装在软路由系统里,还是装在旁边的虚拟机或 NAS 上。前者的优势是网络拓扑最简单、容器与路由同层可以做旁路由式劫持;后者则把应用与网络核心解耦,Docker 应用与各家固件深度集成带来的反复折腾这里全部规避。Electron 类全家桶套件在路由系统里升级撞车、依赖冲突的故事一搜一大把,把应用留在专门的 Docker 宿主上,路由只管转发,彼此相安无事。

选型定下之后,Docker 本身的学习成本并不高:镜像拉下来、端口与目录映射出去、环境变量填好,一条命令跑通。难点在于组织:几十个服务不可能一条条手敲,compose 文件集中管理、数据目录统一规划、更新与备份流程化,这三件事做到位,后期维护成本逼近于零。下面按家庭最常用的两类应用——去广告与影音——把从部署到维护的完整链路讲清楚。

家庭Docker应用分层

AdGuard Home 部署

AdGuard Home 是去广告的核心组件,用 Docker 部署的 compose 片段:

services:
  adguardhome:
    image: adguard/adguardhome
    container_name: adguard
    restart: unless-stopped
    volumes:
      - ./work:/opt/adguardhome/work
      - ./conf:/opt/adguardhome/conf
    ports:
      - "3000:3000"    # 初始化与网页管理
      - "53:53/tcp"    # DNS
      - "53:53/udp"

初次访问 3000 端口完成初始化向导(设密码、选监听端口),之后管理界面就是 80 或你指定的端口。把内网设备的 DNS 指向这台机器,过滤立刻生效。注意 53 端口如果被宿主的 systemd-resolved 占用,容器会启动失败,改宿主解析或改映射端口都行。

过滤列表数量 内存占用 解析速度 误杀风险
两三个主流列表 小 快 低
十个以上列表 明显增大 首请求略慢 中
全量规则包 大幅增加 慢 高

新手最爱犯的错是一次订阅一堆规则包,然后奇怪为什么家里的智能电视、打印机开始抽风——过滤规则越激进,误杀 IoT 设备通信域名的概率越高。稳妥的路线是只开两个主流列表,观察一周,出问题就看查询日志加白名单,逐条积累而不是一步到位。AdGuard Home 的管理后台可以直接看每个域名的处理结果(放行、过滤、上游转发),排查体验远好过黑盒的 hosts 方案。

影音服务部署

影音方案的选择要分两层看:媒体管理(整理刮削元数据、生成海报墙、记录播放进度)与播放转码(在不同终端上解码播放)。Jellyfin 这类一站式方案把两层都做了,部署一个 compose 即可,Emby/Plex 同类。工具机性能弱就只做管理与播放(客户端自带解码),需要给老电视或转码低端播放器救场时再考虑开启硬件转码——这台宿主机有核显且能直通时才值得上。

services:
  jellyfin:
    image: jellyfin/jellyfin
    container_name: jellyfin
    restart: unless-stopped
    volumes:
      - ./config:/config
      - ./cache:/cache
      - /mnt/media:/media        # 影音目录只读挂载
    ports:
      - "8096:8096"

媒体目录挂载是重点:配置与缓存走容器本地的 SSD 目录,影音体量太大放在独立数据盘上,以绑定目录方式挂进来。播放卡顿先分清是网络问题还是解码问题——千兆内网拖动 4K 原盘很轻松,卡顿多半在客户端解码能力上;直接拷一集播放卡的视频到客户端本地播放一遍,就能区分。

数据组织与更新

所有容器的数据目录按服务名列好,docker-compose 文件集中放一个目录用 git 管理。更新模板基本统一:docker compose pull 拉新镜像、docker compose up -d 重建(旧容器配置自动复用)。升级前 docker compose 停一下不是必须但更稳,重大版本升级前把对应目录整个 tar 一份(配置加数据库),失败了解压回来即可,比依赖应用自身的回滚靠谱得多。

版本策略要有计划:跟随 latest 标签虽然省事,但某天应用大版本升级做了破坏性变更,全家一起翻车。稳妥做法是 compose 里钉次要版本号,手动有节奏地升级;AdGuard Home 这类核心服务尤其要慢半拍,DNS 挂了全家断网。升级窗口选在睡觉前,应急手段(回滚脚本、宿主 DNS 备用)提前备好。

端口与反向代理

服务一多端口管理就乱:8096、3000、8080 一堆数字谁也记不住。规范做法是启动一套反向代理(Nginx 或 Traefik),把每个服务映射到子域名,配合通配 HTTPS 证书。内网也能自动部署证书,DNS 挑战最方便。反向代理不只解决记忆问题,还顺便给所有服务统一了访问入口、加上了速率限制与来源控制,是应用层的总闸门。

不熟端口与代理概念的读者,可以先读 计算机网络入门 打底,再回来配代理会顺畅很多。管理这些容器与服务大多通过 SSH 远程完成,常用命令见 SSH 远程登录与加固。

常见问题与优化

问得最多的三个问题。第一:为什么容器总是无缘无故重启?九成是 OOM——某个服务内存膨胀被系统杀掉,compose 里加 mem_limit 并配合 restart 策略即可,同时说明资源本来就紧张,应该考虑换大内存机器。第二:为什么端口映射之后外面死活访问不到?先看容器内服务绑定的是 127.0.0.1 还是 0.0.0.0,前者即使映射也连不通;再看宿主防火墙是否放行;最后看是不是有另一个服务先占了端口(docker ps 与 ss -tlnp 对着查)。第三:为什么数据写入慢?多半是 volume 落在了慢盘上,或挂载点经过网络文件系统又套了一层,本地 SSD 做配置目录是通用答案。

性能优化集中在三个旋钮:把重 IO 的缓存目录显式指向 SSD;关闭容器不需要的日志(或至少限大小,防止日志撑爆磁盘);后台任务型的容器加 cpu 份额限制避免抢交互服务的资源。容器数量一多,编排上往 Docker Swarm 或 k8s 方向想是自然的冲动,家用请按住这个冲动——单机 compose 加几条脚本足以支撑二十个以内的服务,多机编排的维护成本远高于收益。

最后一点关于数据安全:容器自身的镜像重建成本极低(拉镜像加 compose 文件),真正贵的是 volume 里的数据。所以备份策略只盯 volume 目录与数据库导出文件,别费劲备份镜像本身。给每个 volume 目录配上定时 tar 或 rsync,配合 NAS 的快照体系,Docker 应用层的数据就稳了。

家庭场景的镜像来源也值得讲究:优先用官方镜像与应用官方仓库,第三方打包镜像方便但存在维护与信任问题(哪天作者不更新了就成了孤儿镜像)。任何镜像拉下来先看一眼它的环境变量与默认配置(hub 页面的文档),尤其是默认密码与数据目录,这两项藏着懒惰配置的雷。统一用 linuxserver 系或官方镜像的好处是文档格式一致, compose 模板可复用,维护成本随服务数量增长得很慢。

容器生态的成熟让家庭 Docker 用法的最佳实践高度集中在三点:数据与镜像分离、配置版本化、更新节奏化。把这三条变成肌肉记忆之后,AIO 上的应用层就是一个安静扩展的模块化系统——要什么服务拉什么服务,出问题就回滚,再没有比这省心的玩法了。家里来客人看到整面墙的应用图标以为多复杂,其实 compose 文件加备份目录就是全部家当。

Docker应用更新流程

容器化时代的另一个红利是迁移:整套家庭应用换个宿主只需要复制 compose 目录与数据目录、在新机器上 docker compose up -d。AIO 玩家换机器的痛苦从“重装三天”压缩到“一个下午”,这是纯粹的数据与配置分离带来的收益。所以重要的不是 Docker 本身,而是它逼着你养成的组织习惯。

容器达人的三个阶段

玩 Docker 通常经历三个阶段:第一阶段按教程敲命令把服务跑起来,充满成就感;第二阶段服务变多,开始整理 compose 与目录结构,学会备份与版本管理;第三阶段回归克制,只保留真正常用的服务,每个都配置得稳定漂亮。家庭环境的终点是第三阶段——十几个精心维护的服务远胜过五十个半死不活的容器。每个季度清理一次不再使用的容器,是网络空间版的“断舍离”。

延伸阅读