OpenWrt 安装 Docker – wiki基地


在 OpenWrt 上部署 Docker:释放路由器的无限潜力

前言:为何要在 OpenWrt 上安装 Docker?

OpenWrt 是一个功能强大的嵌入式 Linux 发行版,专为路由器和其他嵌入式设备设计。它提供了远超原厂固件的灵活性和可定制性,允许用户安装各种软件包来扩展设备的功能。而 Docker 是一个开源的应用容器引擎,它允许开发者将应用及其依赖项打包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上。

将 Docker 引入 OpenWrt 生态系统,就好比给你的路由器插上了翅膀。一个原本可能只用于拨号上网、NAT 转换、Wi-Fi 广播的设备,摇身一变成为一个微型的应用服务器。这开启了无数可能性:

  1. 简化应用部署: 想在路由器上运行 AdGuard Home 进行去广告?或者部署一个小型 Web 服务器?再或者一个简单的下载工具?使用 Docker,你无需担心依赖库的冲突,每个应用都运行在独立的容器中,环境纯净且易于管理。
  2. 环境隔离与安全: 容器提供了进程级别的隔离。即使容器内的应用出现问题,也不会影响到 OpenWrt 系统本身或其他容器,提高了整体系统的稳定性与安全性。
  3. 应用生态丰富: Docker Hub 以及其他容器镜像仓库提供了海量的现成应用镜像。很多在 Linux 服务器上运行的应用都有现成的 Docker 镜像,可以轻松地拉取并在 OpenWrt 上运行(前提是架构兼容)。
  4. 资源利用率高: 相比于传统的虚拟机,容器更加轻量级,启动速度更快,对系统资源的占用更少。这对于资源相对有限的嵌入式设备尤为重要。
  5. 易于管理与维护: Docker 提供了一套标准的命令行工具和服务管理接口,方便应用的启动、停止、更新和删除。Portainer 这样的图形化工具也可以进一步简化管理。
  6. 可移植性: 在一台 OpenWrt 设备上配置好的 Docker 应用,可以轻松地迁移到另一台支持 Docker 的 OpenWrt 设备上,甚至是其他 Linux 服务器上,大大提高了部署效率。

当然,在 OpenWrt 这样资源受限的环境中运行 Docker 也面临挑战,最主要的包括:

  • 硬件限制: CPU 性能、内存大小和存储空间是主要的瓶颈。低端设备可能无法流畅运行 Docker 甚至无法安装。
  • 存储空间: Docker 镜像和容器运行时数据通常需要大量的存储空间,OpenWrt 设备的内置闪存往往不足以容纳。通常需要外接存储设备(如 USB 硬盘、SD 卡)来解决。
  • 架构兼容性: Docker 镜像通常是针对特定 CPU 架构构建的。你的 OpenWrt 设备是什么架构(x86、ARM、MIPS 等),就需要找到对应架构的 Docker 镜像。主流应用通常提供 x86 和 ARM 镜像,但 MIPS 架构的设备可能选择较少。
  • 内核模块: Docker 需要特定的内核模块支持,OpenWrt 内核可能需要额外安装这些模块。

尽管存在这些挑战,对于拥有较新、配置较好的 OpenWrt 设备(如采用 ARM 架构、拥有 256MB 或更多内存、支持 USB 接口等)的用户来说,安装并使用 Docker 绝对是物超所值的。

本文将详细介绍在 OpenWrt 上安装和配置 Docker 的完整过程,包括前期的准备、核心软件包的安装、关键配置、启动与验证,以及一些基础的使用和常见问题的解决。

前期准备:软硬件要求与环境配置

在开始安装之前,请确保你的 OpenWrt 设备满足以下条件并做好必要的准备:

  1. 兼容的 OpenWrt 版本: Docker 支持通常在较新版本的 OpenWrt 中提供(例如 OpenWrt 19.07 或更高版本,推荐使用最新的稳定版)。确保你的设备已经刷写了兼容版本的 OpenWrt 固件。
  2. 充足的硬件资源:
    • 内存 (RAM): 推荐至少 256MB RAM。虽然 Docker 本身运行所需内存不多,但运行容器时会消耗内存。128MB 的设备可能只能运行非常少的、轻量级的容器,且容易因内存不足导致不稳定。512MB 或更高则更佳。
    • 处理器 (CPU): ARMv7、ARMv8 (AArch64) 或 x86/x86_64 架构的处理器通常能获得较好的 Docker 支持和性能。MIPS 或 MIPSEL 架构的设备虽然理论上可能支持 Docker,但性能通常较低,且容器镜像可能较少。在安装前了解你的设备 CPU 架构(可以使用 uname -m 命令查看)。
    • 存储空间 (Flash): OpenWrt 内置的 Flash 空间通常只有几十到几百 MB。Docker 软件包本身可能只需要几 MB 到十几 MB,但 Docker 镜像文件、容器的读写层数据、卷(Volumes)等会占用大量空间。内置 Flash 绝对不足以存放这些数据。因此,必须准备额外的存储设备。
  3. 外接存储设备: 这是安装 Docker 的核心要求之一。你需要准备一个:
    • USB 接口的硬盘或 U 盘
    • SD 卡(如果设备有读卡器)
    • 通过网络挂载的存储(如 NFS、CIFS/Samba),但 USB 硬盘/U 盘通常是最简单可靠的方式。
      这个外接存储设备将用于存放 Docker 的运行时数据(/var/lib/docker,包括镜像、容器、卷等)。请确保设备格式化为 Linux 支持的文件系统,推荐使用 ext4
  4. SSH 访问能力: 你需要通过 SSH 连接到 OpenWrt 设备的命令行界面来执行安装和配置命令。确保你已经知道设备的 IP 地址,并且 SSH 服务是开启的。
  5. 稳定的网络连接: 安装过程需要从互联网下载 Docker 软件包及其依赖,以及后续拉取 Docker 镜像。确保你的 OpenWrt 设备可以正常访问互联网。
  6. 基本 Linux 命令行知识: 理解常用的 Linux 命令(如 cd, ls, df, mkdir, mount, vi/nano 编辑器, service 等)将非常有帮助。

步骤一:准备外部存储设备

如前所述,外部存储设备对于在 OpenWrt 上运行 Docker 至关重要。这一步的目标是将外部存储设备识别、格式化并永久挂载到 OpenWrt 系统中。

1. 连接外部存储设备

将准备好的 USB 硬盘或 U 盘插入 OpenWrt 设备的 USB 接口。

2. 安装必要的软件包

通过 SSH 连接到 OpenWrt。首先更新软件包列表:

bash
opkg update

然后安装用于文件系统支持和挂载管理的软件包。通常需要以下几个:

  • kmod-usb-storage: USB 存储驱动。
  • block-mount: 用于管理块设备(硬盘、分区)的挂载,特别是自动挂载。
  • kmod-fs-ext4: ext4 文件系统支持(如果你打算使用 ext4 格式化)。
  • e2fsprogs: 用于创建和检查 ext4 文件系统的工具 (mkfs.ext4)。
  • kmod-usb-ohcikmod-usb2kmod-usb3: 取决于你的设备支持的 USB 版本,通常安装对应的驱动。

根据你的设备和需求,安装命令可能如下:

bash
opkg install kmod-usb-storage block-mount kmod-fs-ext4 e2fsprogs kmod-usb2 kmod-usb3

3. 识别外部存储设备

安装完成后,系统应该能识别到你的 USB 设备。查看系统日志 (logread) 或者 /dev/ 目录来确认设备名称。

bash
logread | grep usb
ls /dev/sd*

通常,USB 硬盘或 U 盘会被识别为 /dev/sda,如果它有分区,第一个分区可能是 /dev/sda1。记下这个设备名称(例如 /dev/sda1)。

4. 格式化分区 (如果需要)

如果你的外部存储设备是新的,或者上面有你不想要的数据,你需要对其进行分区和格式化。最简单的方式是直接格式化整个设备或其第一个分区。推荐使用 ext4 文件系统。

注意: 格式化会擦除设备上的所有数据,请提前备份!

假设你的设备是 /dev/sda1,格式化为 ext4 的命令如下:

bash
mkfs.ext4 /dev/sda1

格式化过程可能需要一些时间,取决于设备大小和速度。

5. 创建挂载点

创建一个目录作为将来 Docker 数据存放的根目录,并将其作为外部存储的挂载点。例如,我们创建一个 /mnt/docker_data 目录:

bash
mkdir /mnt/docker_data

6. 永久挂载外部存储

为了让外部存储在设备启动时自动挂载,我们需要配置 /etc/config/fstab

使用编辑器(如 vinano)打开 /etc/config/fstab

bash
vi /etc/config/fstab

找到 config global 部分,确保 anon_mount 设置为 1,表示启用匿名挂载:

ini
config global
option anon_swap '0'
option anon_mount '1' # 确保这个是 1
option auto_swap '0'
option auto_mount '1' # 确保这个是 1
option delay_root '5'
option check_fs '0'

在文件的末尾添加一个新的 config mount 部分,用于挂载你的外部存储分区。你需要填写 uuiddevicetargetfstype 等信息。

获取分区的 UUID 是更推荐的方式,因为设备名称(如 /dev/sda1)在不同启动时可能变化,而 UUID 是固定的。使用 block info 命令获取 UUID:

bash
block info /dev/sda1

会显示类似 UUID="xxxx-xxxx-xxxx-xxxx-xxxx" VERSION="1.0" TYPE="ext4" 的信息。复制 UUID。

/etc/config/fstab 中添加如下配置(替换 UUID 和 target 路径):

ini
config mount
option target '/mnt/docker_data' # 你的挂载点目录
option uuid 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx' # 你的分区 UUID
option fstype 'ext4' # 文件系统类型
option options 'rw,sync' # 挂载选项,rw读写,sync同步写入
option enabled '1' # 启用此挂载项

保存并关闭文件。

现在,尝试手动挂载一次以测试配置是否正确:

bash
mount /dev/sda1 /mnt/docker_data # 或者使用 mount /mnt/docker_data

如果挂载成功,使用 df -h 命令查看,应该能看到 /mnt/docker_data 已经被挂载,并且空间是你外部存储设备的大小。

bash
df -h

接下来,让 block-mount 服务重新加载配置并尝试自动挂载:

bash
service fstab reload
service fstab boot

如果一切顺利,你的外部存储设备现在应该已经永久挂载到了 /mnt/docker_data。即使重启 OpenWrt 设备,它也会自动挂载。

最后,在挂载好的目录内为 Docker 数据创建一个子目录:

bash
mkdir /mnt/docker_data/docker

这个目录 /mnt/docker_data/docker 将成为 Docker 存放所有数据(镜像、容器等)的根目录。

步骤二:安装 Docker 软件包

外部存储准备妥当后,就可以开始安装 Docker 本身了。

1. 更新软件包列表

再次确认软件包列表是最新的:

bash
opkg update

2. 安装 Docker 和相关软件包

安装 Docker 主程序、Docker CLI 以及一些可能需要的依赖或工具,例如 docker-compose(用于管理多容器应用,非常推荐安装)。

主要的软件包是 docker。安装命令如下:

bash
opkg install docker docker-compose

opkg 会自动解析并安装 dockerdocker-compose 所依赖的其他软件包,这可能包括 containerd, runc, 各种 kmod-overlay 等。

3. 验证安装

安装完成后,可以检查 Docker 版本:

bash
docker --version
docker-compose --version # 如果安装了 docker-compose

如果命令输出了版本信息,说明软件包已经成功安装。

步骤三:配置 Docker 数据目录和存储驱动

这是 Docker 在 OpenWrt 上成功运行的关键一步。默认情况下,Docker 会尝试将数据存放在 /var/lib/docker,而这个目录通常位于 OpenWrt 的内置 Flash 上,空间不足且写入次数有限。我们需要配置 Docker 将数据存放在我们准备好的外部存储上,并确保使用合适的存储驱动。

1. 创建 Docker 配置文件目录

bash
mkdir /etc/docker

2. 创建或编辑 Docker 配置文件 daemon.json

Docker 的全局配置通过 /etc/docker/daemon.json 文件进行。使用编辑器创建或编辑这个文件:

bash
vi /etc/docker/daemon.json

添加以下内容:

json
{
"data-root": "/mnt/docker_data/docker",
"storage-driver": "overlay2",
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
},
"exec-opts": ["native.cgroupdriver=cgroupfs"]
}

解释这些配置项:

  • "data-root": "/mnt/docker_data/docker": 这是最重要的配置项。它告诉 Docker 将所有的运行时数据(镜像、容器、卷等)存放在我们准备好的外部存储上的 /mnt/docker_data/docker 目录。务必确保这个路径正确且外部存储已成功挂载。
  • "storage-driver": "overlay2": 指定 Docker 使用的存储驱动。overlay2 是目前 Linux 上推荐的存储驱动,效率高且节省空间。OpenWrt 内核需要编译时启用相应的 overlay 文件系统支持(通常是默认启用的)并且需要安装 kmod-overlay 内核模块(安装 Docker 时通常会自动作为依赖安装)。在 OpenWrt 这种精简系统上,确保使用兼容且高效的驱动至关重要。
  • "log-driver": "json-file""log-opts": 配置容器的日志记录方式和选项。这里设置为使用 JSON 文件记录日志,并限制每个日志文件最大 10MB,最多保留 3 个文件,防止日志文件无限增长占用空间。
  • "exec-opts": ["native.cgroupdriver=cgroupfs"]: 指定 Docker 使用的 cgroup 驱动。在某些 OpenWrt 版本或特定设备上,明确指定使用 cgroupfs 可能解决一些容器启动或资源限制相关的问题。你可以尝试不加这一行,如果遇到问题再添加。

保存并关闭文件。

3. 重载并重启 Docker 服务

配置文件修改后,需要重启 Docker 服务使其生效。

bash
service docker restart

如果重启过程中遇到错误,可以使用 logreadservice docker status 查看日志,排查问题。常见问题可能是 data-root 路径不对、外部存储未挂载、存储驱动 (overlay2) 相关的内核模块缺失或不支持等。

步骤四:启动 Docker 并设置为开机自启

服务成功重启后,确保它已经运行起来。

1. 检查 Docker 服务状态

bash
service docker status

应该显示 Docker 服务正在运行。

2. 设置 Docker 开机自启

为了确保 Docker 在 OpenWrt 设备启动后自动运行,需要启用服务:

bash
service docker enable

这将创建一个符号链接,使得 Docker 服务在系统启动时被 /etc/init.d/ 脚本执行。

步骤五:验证 Docker 安装

安装和配置完成后,通过运行一个简单的测试容器来验证 Docker 是否工作正常。

1. 拉取并运行 hello-world 镜像

Docker 官方提供了一个非常小的 hello-world 镜像,用于测试 Docker 环境。

bash
docker run hello-world

第一次运行这个命令时,Docker 会先尝试从 Docker Hub 拉取 hello-world 镜像(因为本地没有)。拉取完成后,它会自动创建一个基于该镜像的容器并运行其中的命令。

如果一切正常,你应该会看到类似以下输出:

“`
Unable to find image ‘hello-world:latest’ locally
latest: Pulling from library/hello-world
… (下载进度) …
Digest: sha256:…
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.
… (更多关于 Docker 的信息) …
“`

这表明 Docker 守护进程正常运行,能够下载镜像,创建容器并执行命令。

2. 检查 Docker 信息

使用 docker info 命令可以查看 Docker 的详细配置和状态信息,包括版本、存储驱动、数据根目录、运行时信息等。

bash
docker info

检查输出中的 Storage Driver 是否为 overlay2Data Root Dir 是否指向你配置的外部存储路径(/mnt/docker_data/docker),以及 Operating SystemArchitecture 是否符合你的设备。

3. 检查已停止的容器

hello-world 容器运行完成后就会退出。可以使用 docker ps -a 命令查看包括已停止在内的所有容器:

bash
docker ps -a

你应该会看到一个状态为 Exited (...)hello-world 容器。

至此,恭喜你!你已经在 OpenWrt 设备上成功安装并配置了 Docker。

Docker 基础使用与管理

安装完成后,就可以开始探索 Docker 的世界了。以下是一些常用的 Docker 命令:

  • 拉取镜像: docker pull <image_name>[:tag] (例如: docker pull alpine:latest)
  • 列出本地镜像: docker images
  • 运行容器: docker run [options] <image_name> [command]
    • -d: 后台运行容器。
    • -p host_port:container_port: 将容器的端口映射到宿主机的端口。
    • -v host_path:container_path: 将宿主机的路径挂载到容器内,用于数据持久化。
    • --name container_name: 为容器指定一个名称。
    • --restart always: 设置容器在退出时总是重启(或设备启动时重启)。
    • --network <network_mode>: 设置容器的网络模式(bridge, host, none, container:)。
  • 列出运行中的容器: docker ps
  • 列出所有容器 (包括停止的): docker ps -a
  • 停止容器: docker stop <container_id_or_name>
  • 启动已停止的容器: docker start <container_id_or_name>
  • 重启容器: docker restart <container_id_or_name>
  • 删除容器: docker rm <container_id_or_name> (需要先停止)
  • 删除镜像: docker rmi <image_id> (需要先删除基于该镜像的容器)
  • 查看容器日志: docker logs <container_id_or_name>
  • 进入运行中的容器: docker exec -it <container_id_or_name> /bin/bash (或者容器内默认的 shell)
  • 清理不再使用的 Docker 对象 (镜像、容器、网络、卷): docker system prune (谨慎使用,会删除所有停止的容器、未使用的网络和悬空镜像)
  • 更激进的清理 (包括未被任何容器使用的镜像): docker system prune -a (更谨慎使用)

使用 docker-compose

对于涉及多个容器的应用(如 Web 应用 + 数据库),或者配置项较多的容器,使用 docker-compose 会更方便。它允许你用一个 YAML 文件来定义和管理多个容器服务。

创建一个 docker-compose.yml 文件,然后使用 docker-compose up -d 命令即可启动文件中定义的所有服务。

安装了 docker-compose 后,你就可以在 OpenWrt 上方便地部署基于 docker-compose 的应用了,例如 Portainer、一些监控工具等。

进阶话题与注意事项

  1. 资源限制: 在 OpenWrt 设备上运行容器,尤其是多个容器或资源密集型应用,要时刻关注设备的 CPU 和内存占用。可以使用 htop 或 OpenWrt LuCI 界面中的实时状态查看资源使用情况。如果资源不足,可能会导致系统不稳定甚至崩溃。对于资源受限的设备,选择轻量级的应用和镜像(如基于 Alpine Linux 的镜像)非常重要。
  2. 存储空间管理: 虽然使用了外部存储,但 Docker 镜像和容器数据依然会随着使用而增长。定期使用 docker system prune 清理不再需要的对象是保持存储空间充足的好习惯。
  3. 网络配置:
    • Bridge Mode (桥接模式): Docker 默认模式。容器在独立的虚拟网络中,通过 NAT 与宿主机和外部网络通信。如果需要从外部访问容器的服务,需要使用 -p 参数进行端口映射。
    • Host Mode (主机模式): 容器直接使用宿主机的网络栈,共享宿主机的 IP 地址和端口空间。这种模式没有网络隔离,但也避免了端口映射的麻烦。适用于需要直接访问宿主机网络或性能要求高的场景,但要注意端口冲突。使用 --network host 参数。
    • Macvlan/Ipvlan Mode: 更高级的网络模式,可以让容器直接在你的局域网中获得一个独立的 IP 地址,就像网络中的一个独立设备一样。这需要 OpenWrt 内核和 Docker 支持,配置相对复杂,但提供了更好的隔离性和直接性。如果你的应用需要在局域网中被其他设备直接发现或访问独立 IP,可以考虑这种模式。
  4. 持久化数据 (Volumes): 容器的文件系统是临时的,容器被删除后,其中的数据也会丢失。为了持久化应用数据(如数据库文件、配置文件等),应使用 Docker Volumes 或 Bind Mounts。如前所述,Bind Mounts (-v host_path:container_path) 是将宿主机上的目录直接挂载到容器中,host_path 应该指向你的外部存储设备上的目录。
  5. 架构兼容性: 务必确认你拉取的 Docker 镜像支持你的 OpenWrt 设备架构 (uname -m 查看)。尝试运行不兼容架构的镜像会失败,并可能报告 exec user process caused "exec format error" 等错误。
  6. 防火墙: 如果你的容器通过 Bridge 模式运行并映射了端口到宿主机,你需要确保 OpenWrt 的防火墙允许外部流量访问这些端口。通常在 OpenWrt LuCI 界面或 /etc/config/firewall 中配置端口转发规则。
  7. 更新 Docker: 可以通过 opkg update && opkg upgrade docker 来更新 Docker 软件包。更新前最好停止所有正在运行的容器,更新后再启动。
  8. 故障排除:
    • Docker daemon 无法启动: 检查 /etc/docker/daemon.json 配置是否正确,特别是 data-root 路径和 storage-driver。检查外部存储是否正确挂载。查看系统日志 logread | grep docker
    • 无法拉取镜像: 检查网络连接是否正常,DNS 解析是否正确。确保镜像名称和标签拼写无误。
    • 容器无法启动: 使用 docker logs <container_id_or_name> 查看容器的启动日志,通常能找到错误原因。可能是配置错误、依赖缺失、资源不足或架构不兼容等。
    • 存储驱动问题: 如果 docker info 显示存储驱动不是你配置的 overlay2 或报告错误,可能是相关的内核模块缺失或内核不支持。尝试手动安装 kmod-overlay 或检查内核配置。

常见应用示例(通过 Docker 在 OpenWrt 上运行)

一旦 Docker 成功运行,你可以尝试部署一些常见的轻量级应用:

  • AdGuard Home: DNS 过滤,提供强大的广告拦截和家长控制功能。官方提供 Docker 镜像,部署简单。
  • Portainer: Docker 的图形化管理界面。非常方便管理容器、镜像、卷等。Portainer 也有轻量级的 Docker 镜像,可以在资源允许的情况下部署。
  • ** pequenos Web 服务器 (nginx/caddy):** 运行一个静态文件服务器或反向代理,提供简单的网页访问能力。
  • alist: 一个文件列表程序,支持多种云存储挂载,通过 Web 界面访问。
  • DDNS 客户端: 虽然 OpenWrt 内置了 DDNS 客户端,但使用 Docker 运行特定的 DDNS 客户端可能提供更多功能或支持更多服务商。
  • VPN 客户端: 在容器内运行 OpenVPN 或 WireGuard 客户端,让容器内的应用流量通过 VPN。

部署这些应用通常只需要执行一个 docker run 命令(可能带上端口映射 -p 和卷挂载 -v)或者编写一个简单的 docker-compose.yml 文件。务必查看每个应用官方提供的 Docker 部署文档,并根据你的 OpenWrt 架构选择合适的镜像。

总结

在 OpenWrt 设备上安装和运行 Docker 是一项非常有价值的改造。它极大地扩展了路由器的功能边界,将一个原本相对封闭的网络设备变成了一个开放的、可编程的微型服务器。虽然需要注意硬件限制、存储需求和架构兼容性等问题,但通过本文介绍的详细步骤和配置方法,特别是正确准备和配置外部存储,你完全可以在兼容的 OpenWrt 设备上成功部署 Docker,并开始利用丰富的容器化应用生态。

从简单的广告拦截到更复杂的网络服务,Docker 让你的 OpenWrt 路由器拥有了前所未有的灵活性和强大功能。投入时间和精力进行这次改造,你将收获一个远超预期的智能网络中心。开始你的 Docker 容器之旅吧!

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部