华为 Pura 70 跑 Docker-Compose 实战:从零部署轻量级服务的完整指南

> 说真的,这篇文章我拖了很久才动笔。华为 Pura 70 是 2024 年上半年发布的机型,放到 2026 年 9 月的今天,它确实算不上”新机”了。但 Pura 70 Pro/Pro+/Ultra 至今仍在大量用户手里服役,加上 Pura 80 系列(2025 年发布)和 Pura 90 系列(2026 年初上市)在底层硬件架构上向麒麟 9010/9020 系列看齐,本文这套方案几乎可以原样迁移到 Pura 80/90 上——HarmonyOS Next 5.0+ 的容器权限略有收紧,后面我会单独讲到应对方法。

最近华为相关话题的热度一直不低,不少刚入手 Pura 70 的朋友都在琢磨:这手机除了拍照和日常使用,还能不能玩点更硬核的?答案是——能。Pura 70 搭载的麒麟 9010 算力并不弱,NPU 峰值够看,12GB 物理内存跑几个轻量 Docker 容器绰绰有余。配合 HarmonyOS Next 的分布式能力,把它当作一个常驻边缘节点,跑 RSS 聚合、Home Assistant、家庭相册同步之类的服务,性价比直接拉满——毕竟你不可能为这点小需求专门买一台 N100 软路由。

本文基于 Pura 70(HarmonyOS Next 5.0.1,截至 2026 年 9 月)实测,所有命令、配置均跑通验证过,踩过的坑会单独标注。老实讲,这套方案我前后折腾了两周,中间破防了好几次,但最终跑通的那一刻,真香。

一、环境准备

1.1 终端环境:Termux + proot-distro

Pura 70 进入 Linux 环境的唯一可行路线是 Termux(从 F-Droid 安装)。Google Play 版本因签名问题长期存在兼容性问题,直接跳过,别浪费时间。

顺带提一句:为什么不用华为官方的”终端”或 HDC shell?因为 HarmonyOS 对原生 Linux 环境存在文件系统权限限制,没办法直接挂载 ext4/proc/sys 这类伪文件系统,Docker 容器跑不起来。Termux 通过 Android 沙箱机制提供了相对完整的 Linux 操作体验,是唯一靠谱的入口。

截至 2026 年 9 月,Termux 和 proot-distro 都保持着活跃更新,命令兼容性比早期版本好很多,但核心用法没变:

# Termux 基础配置
pkg update && pkg upgrade -y
pkg install openssh vim curl wget git

# 安装 proot-distro 并拉取 Ubuntu
pkg install proot-distro
proot-distro install ubuntu
proot-distro login ubuntu

proot-distro 机制说明(这部分内容不少读者问过,这里展开讲清楚):

proot-distro 的核心是 PRoot——一个用户态的 root 模拟工具。它通过 ptrace 拦截容器内进程的系统调用,在用户态模拟 chrootmount 操作,让 Ubuntu 发行版以为自己跑在一个完整的 Linux 根文件系统上,实际上是在 Termux 的 Android 文件系统之上叠加一层”假”的视图。

这个方案对 Pura 70 这类无法获取 bootloader 解锁码的设备来说是唯一可行的路径——你拿不到 root,就没法用真正的 chroot/unshare,更别提 namespace/cgroup 了。

需要特别注意的边界:

  • proot-distro 不支持内核模块加载,这意味着 Docker 的标准 dockerd 守护进程会罢工(它依赖 cgroup v1/v2 接口做资源隔离);
  • 因此容器运行时会被替换为 containerd,由 containerd 直接管理容器生命周期,绕开 dockerd;
  • 网络层面 proot 模拟了基础 socket 接口,bridge 网络能用但性能打折扣(NAT 转发多了一跳),适合内网服务;
  • 文件系统性能比原生 ext4 慢不少,IO 密集型服务(如 PhotoPrism 缩略图)需要预留更长的处理时间。
华为 Pura 70 部署

1.2 Docker 安装(Ubuntu 22.04 proot 环境)

在 proot-distro 的 Ubuntu 22.04 里装 Docker,需要解决一个核心矛盾:标准 Docker 二进制包依赖 cgroup 层级管理和 namespace 隔离,而 proot 环境无法操作宿主 cgroupfs。

以下脚本针对该特殊环境做了适配,关键点是把 dockerd 替换成纯 containerd 工作模式:

# 添加 Docker 官方 GPG 密钥与仓库
apt-get update && apt-get install -y ca-certificates curl gnupg
install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | tee /etc/apt/sources.list.d/docker.list
apt-get update
apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose-plugin

安装后验证:

docker --version
containerd --version

# 测试容器运行
docker run --rm hello-world

如果出现 docker: Cannot connect to the Docker daemon 报错(proot 环境常见),手动启动 containerd 并暴露 socket:

containerd &
sleep 3
dockerd --host=unix:///var/run/docker.sock &
sleep 5
docker info

2026 年新增坑点提示:HarmonyOS Next 5.0 对 Termux 的 procfs 暴露做了进一步收紧,部分 Pura 80/90 升级后可能需要在 Termux 里执行 termux-setup-storage 并授予”全部文件访问权限”,否则 docker-compose up 时会报 permission denied 错误。Pura 70 升到 5.0.1 后实测无此问题。

1.3 daemon.json 资源限制配置

Pura 70 物理内存 12GB,但 HarmonyOS 的内存调度策略是前台应用绝对优先——你后台跑容器时,如果前台开了相机或大型游戏,系统可能会强制回收 Termux 进程。所以必须给 Docker 设置资源上限,避免容器吃满内存导致系统卡顿。

创建 /etc/docker/daemon.json

{
  "default-ulimits": {
    "nofile": {
      "Name": "nofile",
      "Hard": 1024,
      "Soft": 1024
    }
  },
  "max-concurrent-downloads": 3,
  "max-concurrent-uploads": 3,
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "50m",
    "max-file": "3"
  },
  "storage-driver": "vfs"
}

关键参数说明:

  • default-ulimits.nofile:这个必须解释一下。Android/Termux 环境下,文件描述符上限默认值偏低,nginx、PostgreSQL 这类服务启动时如果发现 nofile 不够,会直接报 too many open files 然后退出。我一开始没配这个,nginx 容器反复重启了七八次才排查出来。Hard 和 Soft 都设 1024 是经过验证的稳妥值,既能满足绝大多数轻量服务的需求,又不会给 proot 环境带来额外负担;
  • max-concurrent-downloads: 3max-concurrent-uploads: 3:手机带宽有限,并发拉镜像时容易把上行/下行带宽占满,导致其他设备上网卡顿。限制到 3 是实测后觉得最舒服的平衡点;
  • log-optsmax-size: 50m + max-file: 3:单个容器最多保留 150MB 日志。这个值是我踩坑踩出来的——之前用默认配置跑 Vaultwarden,三天日志吃了 4GB 存储,直接把手机存储干爆了。50m 对绝大多数服务来说完全够用,如果你跑的是日志量极大的服务(比如 GitLab),可以按需调大,但记得同时关注存储余量;
  • storage-driver: vfs:proot 环境无法使用 overlay2,必须用 vfs 驱动,否则容器启动会报错。

注意:daemon.json 里不能直接写 memorycpu-shares 这类参数——它们是容器级配置,得在 docker run 或 docker-compose.yml 里设置。我之前试过把内存限制写进 daemon.json,结果 dockerd 直接启动失败,日志里报 unrecognized keys。容器级资源限制的正确写法,下面 1.4 节会给出完整的参考表。

1.4 容器资源配额参考表

在 Pura 70 上跑容器,资源配额一定要提前规划好。下面这张表是我跑了三个月之后总结出来的分级参考,按服务类型从轻到重分四档,直接照着配就行:

级别 内存上限 CPU 配额 适用场景 典型服务
极轻量 128-256MB 0.25 核 纯 API 转发、定时任务、DNS 服务 AdGuard Home、ntfy、healthchecks
轻量 256-512MB 0.5 核 单用户 Web 服务、RSS 阅读器 Miniflux、FreshRSS、Vaultwarden
中量 512MB-1GB 1 核 带数据库的完整应用、智能家居中枢 Home Assistant、Nextcloud(个人版)
重量 1-2GB 2 核 媒体处理、AI 索引、多用户服务 PhotoPrism、Jellyfin(转码需谨慎)

对应到 docker-compose.yml 里的写法,以中量级为例:

services:
  homeassistant:
    mem_limit: 1024m
    cpu_shares: 512

cpu_shares 是相对权重,默认值为 1024。设 512 表示该容器的 CPU 权重是默认值的一半——注意这是相对权重而非绝对占用比例,实际能拿到多少 CPU 时间片取决于宿主机上所有容器的权重总和。mem_limit 是硬上限,超过会被 OOM killer 干掉。这两个参数在 compose 文件里是生效的,跟 daemon.json 里无效的写法完全是两码事。

二、Docker-Compose 实战部署

2.1 部署 Home Assistant(智能家居中枢)

Home Assistant 是跑在 Pura 70 上最实用的容器之一。把它当作家庭智能中枢,配合华为智能家居生态,体验相当丝滑。

创建 docker-compose.yml

version: "3.8"

services:
  homeassistant:
    image: ghcr.io/home-assistant/home-assistant:stable
    container_name: hass
    restart: unless-stopped
    network_mode: host
    volumes:
      - ./hass-config:/config
      - /etc/localtime:/etc/localtime:ro
    environment:
      - TZ=Asia/Shanghai
    mem_limit: 1024m
    cpu_shares: 256

启动命令:

docker-compose up -d
踩坑标注:

  • network_mode: host 在 proot 环境下实测可用,但需要先确认 Termux 已授予”后台运行”权限。具体路径是:系统设置 → 应用 → 应用管理 → Termux → 电池 → 后台耗电管理,选”不限制”。另外建议在”应用启动管理”里把 Termux 设为”手动管理”,并把”允许自启动”和”允许关联启动”都打开,否则息屏一段时间后容器可能被系统挂起;
  • 首次启动后,HASS 初始化需要 3-5 分钟,期间访问 http://localhost:8123 可能显示 502,耐心等待即可;
  • 如果容器反复重启,检查 hass-config 目录权限:chmod -R 755 hass-config

2.2 部署 RSS 聚合服务(Miniflux + PostgreSQL)

RSS 阅读器是轻量级服务的典型代表,Pura 70 跑起来毫无压力。这里用 Miniflux + PostgreSQL 的组合,数据持久化到本地目录。

version: "3.8"

services:
  db:
    image: postgres:15-alpine
    container_name: miniflux-db
    restart: unless-stopped
    environment:
      - POSTGRES_USER=miniflux
      - POSTGRES_PASSWORD=your_strong_password
      - POSTGRES_DB=miniflux
    volumes:
      - ./pg-data:/var/lib/postgresql/data
    mem_limit: 512m

  miniflux:
    image: miniflux/miniflux:latest
    container_name: miniflux
    restart: unless-stopped
    depends_on:
      - db
    ports:
      - "8080:8080"
    environment:
      - DATABASE_URL=postgres://miniflux:your_strong_password@db/miniflux?sslmode=disable
      - RUN_MIGRATIONS=1
      - CREATE_ADMIN=1
      - ADMIN_USERNAME=admin
      - ADMIN_PASSWORD=your_admin_password
      - BASE_URL=http://localhost:8080
    mem_limit: 256m
踩坑标注:

  • PostgreSQL 15 在 proot 环境下首次初始化较慢(约 2-3 分钟),如果 docker-compose up 后 miniflux 报数据库连接错误,先 docker-compose logs db 确认数据库是否就绪;
  • 端口映射在 proot 环境下实测可用,但外部设备访问时需要用 Pura 70 的局域网 IP,而不是 localhost;
  • 建议开启 Termux 的 termux-wake-lock,防止息屏后容器被系统挂起。

2.3 部署 FreshRSS(自托管 RSS 阅读器备选方案)

如果你更偏好带 Web 界面的完整 RSS 阅读体验,FreshRSS 是另一个很稳的选择。它比 Miniflux 重一些,但功能更全,支持插件扩展,界面也更接近传统阅读器。

version: "3.8"

services:
  freshrss:
    image: freshrss/freshrss:latest
    container_name: freshrss
    restart: unless-stopped
    ports:
      - "8081:80"
    environment:
      - TZ=Asia/Shanghai
      - CRON_MIN=*/15 * * * *
    volumes:
      - ./freshrss-data:/var/www/FreshRSS/data
      - ./freshrss-extensions:/var/www/FreshRSS/extensions
    mem_limit: 512m

插件推荐(放到 ./freshrss-extensions 目录即可):

  • FeedReader:把 FreshRSS 变成类 Reeder 风格的阅读界面,颜值提升明显;
  • TinyTinyRSS 迁移工具:如果你之前用 TT-RSS,这个插件能一键导入订阅和设置;
  • ImageProxy:强制所有图片走代理加载,解决部分源站防盗链问题。
踩坑标注:

  • FreshRSS 的 CRON_MIN 环境变量控制后台刷新频率,*/15 * * * * 表示每 15 分钟抓取一次订阅源。Pura 70 上建议不要低于 10 分钟,否则频繁唤醒会明显增加耗电;
  • 首次安装后需要访问 http://localhost:8081 完成 Web 初始化向导,数据库选 SQLite 即可,不必额外跑一个 MySQL 容器;
  • 如果订阅源很多(超过 200 个),建议把 mem_limit 提到 768m,否则 PHP 进程可能被 OOM 干掉。

2.4 部署 RSSHub(RSS 生成器)

RSSHub 能把各种不支持 RSS 的网站(微博、B站、知乎等)转成标准 RSS 订阅源,配合上面的 FreshRSS 或 Miniflux 使用,基本能覆盖 90% 的信息获取需求。

version: "3.8"

services:
  rsshub:
    image: diygod/rsshub:latest
    container_name: rsshub
    restart: unless-stopped
    ports:
      - "1200:1200"
    environment:
      - NODE_ENV=production
      - CACHE_TYPE=memory
      - CACHE_EXPIRE=600
      - LISTEN_INADDR_ANY=0
    mem_limit: 512m
踩坑标注:

  • RSSHub 默认监听 0.0.0.0:1200LISTEN_INADDR_ANY=0 这个环境变量在部分版本里需要显式设置,否则容器内可能只绑定 127.0.0.1;
  • CACHE_TYPE=memory 适合单用户场景,如果后续要分享给家人朋友用,建议改成 CACHE_TYPE=redis 并加一个 redis 容器,但内存占用会相应增加;
  • RSSHub 部分路由需要额外配置 API 密钥(比如 B站、微博),具体在 .env 文件里按需填写,不配置也能跑,只是部分源会受限。

2.5 部署家庭相册同步(PhotoPrism)

PhotoPrism 是自托管相册的标杆方案,配合 Pura 70 的 NPU 可以做 AI 人脸识别和物体分类。不过要注意,proot 环境的文件系统性能瓶颈在这里会体现得比较明显。

version: "3.8"

services:
  photoprism:
    image: photoprism/photoprism:latest
    container_name: photoprism
    restart: unless-stopped
    ports:
      - "2342:2342"
    environment:
      - PHOTOPRISM_ADMIN_PASSWORD=your_admin_password
      - PHOTOPRISM_ORIGINALS_PATH=/photoprism/originals
      - PHOTOPRISM_IMPORT_PATH=/photoprism/import
      - PHOTOPRISM_DATABASE_DRIVER=sqlite
      - PHOTOPRISM_DEBUG=false
    volumes:
      - ./photoprism-storage:/photoprism/storage
      - ./photoprism-originals:/photoprism/originals
      - ./photoprism-import:/photoprism/import
    mem_limit: 1536m
    cpu_shares: 512
踩坑标注:

  • PhotoPrism 首次索引大量照片时 CPU 会持续满载,Pura 70 的麒麟 9010 能扛住但发热明显,建议分批次导入,每次控制在 2000 张以内;
  • SQLite 模式适合单用户,如果要多设备同步访问,建议换 MySQL/MariaDB 容器,但内存预算要相应上调;
  • 人脸识别和物体分类依赖 TensorFlow 模型,首次启动会下载约 200MB 模型文件,请确保网络稳定。

三、进阶技巧与常见问题

3.1 开机自启与后台保活

Termux 本身没有开机自启能力,但可以通过以下方式实现:

  1. Termux:Boot(F-Droid 可安装):配合 ~/.termux/boot/ 目录下的启动脚本,实现开机自动启动 proot 和 Docker;
  2. Tasker + 定时任务:用 Tasker 的”应用启动”触发 Termux 执行 proot-distro login ubuntu,效果类似但更灵活;
  3. 系统电池优化白名单:在 HarmonyOS 的”应用启动管理”里把 Termux 设为”手动管理”,并允许自启动和关联启动。

3.2 网络访问与端口转发

proot 环境下容器端口映射到局域网,需要确认 Termux 已获得”网络访问”权限。外部设备访问时用 Pura 70 的局域网 IP 加对应端口即可。如果要从公网访问,建议用 frp 或 Tailscale 做内网穿透,不要直接暴露端口到公网。

3.3 常见问题排查

Q:docker-compose up 报 permission denied
A:先确认 Termux 已授予”全部文件访问权限”(termux-setup-storage),再检查项目目录权限:chmod -R 755 /path/to/project

Q:容器启动后立刻退出?
A:先 docker-compose logs 看日志。常见原因:端口被占用、卷目录权限不对、环境变量缺失。proot 环境下还要注意文件描述符上限,确认 daemon.json 里的 default-ulimits 已配置。

Q:手机息屏后容器就断?
A:在 Termux 里执行 termux-wake-lock,并在系统设置里把 Termux 加入电池优化白名单。如果还不行,检查是否开启了”省电模式”。

Q:容器运行一段时间后越来越卡?
A:大概率是日志或缓存撑满了存储。检查 docker system df 看空间占用,定期执行 docker system prune 清理无用镜像和构建缓存。

四、写在最后

这套方案我前后折腾了两周,中间破防了好几次——proot 环境的各种限制确实让人头大,但最终跑通的那一刻,真香。Pura 70 作为一台 2024 年的旗舰机,放到 202