1.11 树莓派安装 Linux + Docker-in-Docker

预计阅读时间:13 分钟

📖 目录

树莓派是学习 Linux、嵌入式开发和家庭服务器的最佳低成本平台。本篇从系统安装、远程管理、Docker 部署到 Docker-in-Docker(DinD)配置,覆盖完整的搭建流程。

学习目标

学完本章后,你将能够:

  • 使用 Raspberry Pi Imager 或 dd 烧录系统,完成 Headless 无显示器安装
  • 通过 SSH 与 VNC 远程管理树莓派
  • 在 ARM 架构上安装 Docker,并用 buildx 交叉构建多平台镜像
  • 配置 Docker-in-Docker(DinD),理解 --privileged 与 Rootless 的取舍
  • 部署 Home Assistant、Nextcloud、Pi-hole 等家庭服务器服务
  • 针对 SD 卡寿命、电源散热、日志轮转与数据备份做优化

前置知识

1. 树莓派系统安装

1.1 Raspberry Pi OS

# 使用 Raspberry Pi Imager 烧录 Lite 版(无桌面,适合服务器)
# 或命令行烧录
sudo dd if=2024-xx-xx-raspios-bookworm-arm64-lite.img of=/dev/sdb bs=4M status=progress
sync

1.2 Ubuntu ARM

# 下载 Ubuntu 24.04 LTS ARM64 并烧录
wget https://releases.ubuntu.com/24.04/ubuntu-24.04.1-live-server-arm64.iso
sudo dd if=ubuntu-24.04.1-live-server-arm64.iso of=/dev/sdb bs=4M status=progress
sync
提示:树莓派 4/5 建议使用 ARM64(aarch64)系统。32 位系统无法使用 4GB+ 内存的全部空间。

1.3 Headless 无显示器安装

# Raspberry Pi OS:在 boot 分区创建 SSH 文件
touch /boot/firmware/ssh

# 配置 Wi-Fi
cat > /boot/firmware/wpa_supplicant.conf <<'EOF'
country=CN
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
network={
    ssid="YourSSID"
    psk="YourPassword"
    key_mgmt=WPA-PSK
}
EOF
系统Headless 方式默认用户
Raspberry Pi OS创建 ssh + wpa_supplicant.confpi / raspberry
Ubuntu Server ARM安装时配置网络自定义
Debian ARM创建 /root/.ssh/authorized_keysroot

2. 远程管理

2.1 SSH 连接

ssh pi@raspberrypi.local
ssh pi@192.168.1.100

# 配置密钥登录
ssh-copy-id pi@192.168.1.100
sudo sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo systemctl restart sshd

2.2 VNC 远程桌面

# 启用 VNC
sudo raspi-config  # Interface Options → VNC → Enable
# 或命令行
sudo apt install realvnc-vnc-server
sudo systemctl enable vncserver-x11-serviced
注意:VNC 默认端口 5900 使用明文传输,仅限局域网。远程访问建议 SSH 隧道:ssh -L 5900:localhost:5900 pi@your-server

3. Docker 安装

3.1 ARM 原生 Docker

# 一键安装
curl -fsSL https://get.docker.com | sh

# 将用户加入 docker 组
sudo usermod -aG docker $USER
newgrp docker

# 验证架构
docker info | grep Architecture

3.2 binfmt 交叉编译

在 x86 主机上为树莓派 ARM 构建镜像:

# x86 主机注册 binfmt
docker run --rm --privileged multiarch/qemu-user-static --reset -p yes

# 使用 buildx 交叉构建 ARM64 镜像
docker buildx create --name arm-builder --use
docker buildx build --platform linux/arm64 -t myapp:arm64 --push .
场景方式
树莓派上直接开发ARM 原生 Docker
CI/CD 为树莓派构建binfmt 交叉编译
多架构统一管理buildx 多平台构建

4. Docker-in-Docker(DinD)

4.1 场景

  • CI/CD 流水线:在容器内构建和测试 Docker 镜像(GitLab Runner)
  • 隔离测试:在容器中运行嵌套容器,不影响宿主机
  • 多租户:为不同用户隔离 Docker 环境

4.2 基本配置

# 独立 DinD(容器内有独立 Docker daemon)
docker run --privileged --name dind -d docker:24-dind
docker exec -it dind sh

# Socket 挂载(共享宿主机 Docker)
docker run -v /var/run/docker.sock:/var/run/docker.sock -d docker:24-cli

4.3 树莓派 DinD

# ARM 原生 DinD
docker run --privileged --name rpi-dind -d arm64v8/docker:24-dind

# 自定义存储驱动
docker run --privileged --name rpi-dind \
  -v rpi-dind-data:/var/lib/docker \
  -d arm64v8/docker:24-dind dockerd --storage-driver=overlay2

# 测试嵌套容器
docker exec -it rpi-dind docker run --rm alpine echo "Hello from nested"
注意:DinD 需要 --privileged,会削弱容器安全隔离。生产环境建议 Rootless DinD 或 Podman。

4.4 Rootless DinD

# 宿主机安装 rootless Docker
dockerd-rootless-setuptool.sh install

# 运行 rootless DinD
docker run --userns=host --cap-add SYS_ADMIN \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -d docker:24-cli

4.5 Docker Compose 编排 DinD

# docker-compose.dind.yml
version: '3.8'
services:
  dind:
    image: arm64v8/docker:24-dind
    privileged: true
    volumes:
      - dind-data:/var/lib/docker
    ports:
      - 2376:2376
  client:
    image: docker:24-cli
    environment:
      - DOCKER_HOST=tcp://dind:2376
    depends_on:
      - dind
volumes:
  dind-data:

5. 家庭服务器应用场景

服务Docker 镜像用途
Home Assistanthomeassistant/home-assistant智能家居中枢
Portainerportainer/portainer-ceDocker 可视化管理
Nginx Proxy Managerjc21/nginx-proxy-manager反向代理 + HTTPS
Pi-holepihole/piholeDNS 广告过滤
Grafanagrafana/grafana监控面板
Jellyfinjellyfin/jellyfin媒体服务器
Syncthingsyncthing/syncthing文件同步

5.1 Home Assistant 部署详解

# Home Assistant 容器部署
docker run -d \
  --name homeassistant \
  --privileged \
  --restart=unless-stopped \
  -v /home/pi/homeassistant/config:/config \
  -v /etc/localtime:/etc/localtime:ro \
  --network=host \
  homeassistant/home-assistant:stable

# 使用 Docker Compose 部署(推荐)
# docker-compose.ha.yml
version: '3.8'
services:
  homeassistant:
    container_name: homeassistant
    image: homeassistant/home-assistant:stable
    volumes:
      - /home/pi/homeassistant/config:/config
      - /etc/localtime:/etc/localtime:ro
    restart: unless-stopped
    network_mode: host
    privileged: true
Home Assistant 提示:使用 --network=host 可以让 Home Assistant 直接发现局域网中的智能设备。如果使用桥接网络,需要额外映射 UDP 广播端口(8123、5353 等)。

5.2 Nextcloud 私有云部署

# Nextcloud + MySQL 完整部署
# docker-compose.nextcloud.yml
version: '3.8'
services:
  nextcloud:
    image: nextcloud:stable
    restart: unless-stopped
    ports:
      - 8080:80
    volumes:
      - /home/pi/nextcloud/data:/var/www/html
    environment:
      - MYSQL_HOST=db
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
      - MYSQL_PASSWORD=your_password
    depends_on:
      - db

  db:
    image: mariadb:10.11
    restart: unless-stopped
    environment:
      - MYSQL_ROOT_PASSWORD=root_password
      - MYSQL_DATABASE=nextcloud
      - MYSQL_USER=nextcloud
      - MYSQL_PASSWORD=your_password
    volumes:
      - /home/pi/nextcloud/db:/var/lib/mysql

volumes:
  data:
  db:

5.3 Pi-hole DNS 过滤部署

# Pi-hole 容器部署
docker run -d \
  --name pihole \
  -p 53:53/tcp -p 53:53/udp \
  -p 8081:80 \
  -e TZ=Asia/Shanghai \
  -e WEBPASSWORD=your_password \
  -v /home/pi/pihole/etc:/etc/pihole \
  -v /home/pi/pihole/dnsmasq:/etc/dnsmasq.d \
  --restart=unless-stopped \
  pihole/pihole:latest

# 查看 Pi-hole 日志
docker logs -f pihole

# 更新 Pi-hole
docker pull pihole/pihole:latest
docker stop pihole && docker rm pihole
# 重新运行上面的 docker run 命令
Pi-hole 注意:Pi-hole 的 DNS 端口(53)可能与系统自带的 systemd-resolved 冲突。部署前需要禁用:sudo sed -i 's/#DNSStublyListener=yes/DNSStublyListener=no/' /etc/systemd/resolved.conf && sudo systemctl restart systemd-resolved

5.4 家庭监控系统

# 轻量级监控:Uptime Kuma
docker run -d \
  --name uptime-kuma \
  -p 3001:3001 \
  -v /home/pi/uptime-kuma/data:/app/data \
  --restart=unless-stopped \
  louislam/uptime-kuma

# Prometheus + Grafana 监控栈
# docker-compose.monitoring.yml
version: '3.8'
services:
  prometheus:
    image: prom/prometheus:latest
    ports:
      - 9090:9090
    volumes:
      - /home/pi/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
    restart: unless-stopped

  grafana:
    image: grafana/grafana:latest
    ports:
      - 3000:3000
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin
    volumes:
      - /home/pi/grafana/data:/var/lib/grafana
    restart: unless-stopped

  node-exporter:
    image: prom/node-exporter:latest
    ports:
      - 9100:9100
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
    restart: unless-stopped

6. 性能优化

6.1 SD 卡寿命保护

# 减少 SD 卡写入
# 将日志和临时文件挂载到 tmpfs
echo 'tmpfs /tmp tmpfs defaults,noatime,nosuid,nodev,noexec,mode=1777,size=100m 0 0' | sudo tee -a /etc/fstab

# Docker 日志限制(防撑爆 SD 卡)
# /etc/docker/daemon.json
{
  "log-driver": "json-file",
  "log-opts": { "max-size": "10m", "max-file": "3" }
}

# 将 Docker 数据目录迁移到 USB SSD
sudo systemctl stop docker
sudo mv /var/lib/docker /mnt/usb/docker
sudo ln -s /mnt/usb/docker /var/lib/docker
sudo systemctl start docker

6.2 CPU 性能调优

# 查看当前 CPU 频率
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq

# 设置性能模式(需要安装 cpufrequtils)
sudo apt install cpufrequtils
sudo cpufreq-set -g performance

# 持久化 CPU 性能模式
echo 'GOVERNOR="performance"' | sudo tee /etc/default/cpufrequtils
sudo systemctl restart cpufrequtils

# 树莓派 5 超频(谨慎操作)
# 编辑 /boot/firmware/config.txt
arm_freq=2800
over_voltage=6
gpu_freq=700

6.3 内存优化

# 查看内存使用
free -h

# 减少 GPU 预留内存(Lite 版无需 GPU)
# /boot/firmware/config.txt
gpu_mem=16

# 使用 zswap 压缩交换
sudo modprobe zswap
echo 1 | sudo tee /sys/module/zswap/parameters/enabled

# 清理系统缓存
sudo sync && echo 3 | sudo tee /proc/sys/vm/drop_caches

6.4 存储性能优化

# 使用 fio 测试 SD 卡/SSD 性能
sudo apt install fio
fio --name=seq-write --rw=write --bs=1M --size=1G --numjobs=1 --runtime=30

# 优化 ext4 文件系统
sudo tune2fs -o journal_data_writeback /dev/mmcblk0p2

# 禁用 atime 更新(减少写入)
# /etc/fstab 中添加 noatime 选项
/dev/mmcblk0p2 / ext4 defaults,noatime 0 1

6.5 Docker 专项优化

# 限制容器资源
docker run -d --memory=512m --cpus=1.5 my-app

# 使用轻量级基础镜像
docker pull alpine:latest        # 5MB
docker pull debian:bookworm-slim # 80MB
docker pull ubuntu:24.04         # 77MB

# 多阶段构建减小镜像体积
FROM golang:1.22 AS builder
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 go build -o myapp

FROM alpine:latest
COPY --from=builder /app/myapp /myapp
CMD ["/myapp"]

# 清理未使用的 Docker 资源
docker system prune -a --volumes
docker builder prune -a

7. 硬件兼容性问题与解决方案

7.1 常见硬件问题

问题原因解决方案
USB 设备不识别供电不足使用官方电源适配器(5V/3A)
SD 卡读写速度慢低速卡使用 A1/A2 等级的 microSD 卡
网卡不稳定驱动问题安装最新固件:sudo rpi-update
散热风扇噪音大PWM 控制不当使用温控脚本自动调节转速
DS18B20 温度传感器不读取未加载 w1-gpiosudo modprobe w1-gpio && sudo modprobe w1-therm

7.2 外设驱动安装

# 安装 GPIO 库
pip3 install RPi.GPIO gpiozero

# 安装 I2C/SPI 支持
sudo raspi-config  # Interface Options → I2C → Enable
sudo raspi-config  # Interface Options → SPI → Enable

# 安装摄像头驱动(树莓派专用)
sudo apt install libraspberrypi-bin
# 测试摄像头
raspistill -o test.jpg

# 安装 NVMe SSD 支持(树莓派 5)
# 确保使用最新固件
sudo apt update && sudo apt upgrade -y
sudo raspi-config  # Advanced Options → NVMe

7.3 显示屏兼容性

# 官方触摸屏配置
# /boot/firmware/config.txt
dtoverlay=rpi-ft5406

# HDMI 输出配置(树莓派 5)
# /boot/firmware/config.txt
hdmi_group=2
hdmi_mode=82    # 1080p 60Hz

# 竖屏显示(旋转 90 度)
# /boot/firmware/config.txt
lcd_rotate=1

8. Docker ARM 特殊考量

8.1 镜像架构兼容性

# 检查镜像是否支持 ARM
docker manifest inspect nginx:latest | grep -A 5 architecture

# 查看本地 Docker 架构
docker info | grep Architecture

# 为 ARM 构建自定义镜像
docker buildx build --platform linux/arm64,linux/arm/v7 -t myapp:multi .

8.2 ARM 专用基础镜像

通用镜像ARM 替代大小对比
nginx:latestarm64v8/nginx:alpine187MB → 42MB
node:20arm64v8/node:20-alpine1.1GB → 180MB
python:3.12arm64v8/python:3.12-slim1.0GB → 150MB
mysql:8arm64v8/mysql:8支持原生 ARM
redis:7arm64v8/redis:7-alpine130MB → 32MB
ARM 镜像建议:对于树莓派,优先使用 alpine 变体的基础镜像,体积小、启动快。对于数据库类服务,使用官方 ARM 版本而非通用版本,性能更好。

8.3 交叉编译最佳实践

# 在 x86 主机上为树莓派构建
# Dockerfile.arm64
FROM --platform=linux/arm64 node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
CMD ["node", "server.js"]

# 构建命令
docker buildx build \
  --platform linux/arm64 \
  --file Dockerfile.arm64 \
  --tag myapp:rpi \
  --push .

# 本地测试(使用 QEMU)
docker run --rm -it --platform linux/arm64 myapp:rpi sh

8.4 存储驱动选择

# 推荐使用 overlay2(性能最佳)
# /etc/docker/daemon.json
{
  "storage-driver": "overlay2",
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}

# 验证存储驱动
docker info | grep "Storage Driver"

9. 电源管理与散热

9.1 电源需求

型号推荐电源最低电压功耗范围
树莓派 3B+5V/2.5A4.75V0.5W - 7W
树莓派 4B5V/3A (USB-C)4.75V0.5W - 8W
树莓派 55V/5A (USB-C)4.75V1W - 12W
树莓派 Zero 2W5V/2.5A4.75V0.2W - 3.5W
# 监控电源状态
vcgencmd get_throttled
# 返回值含义:
# 0x0 = 正常
# 0x50005 = 降频(过温或欠压)
# 0x50000 = 欠压降频

# 监控 CPU 温度
cat /sys/class/thermal/thermal_zone0/temp
# 温度 = 值 / 1000(摄氏度)

# 持续监控脚本
watch -n 2 'vcgencmd measure_temp && vcgencmd get_throttled'

9.2 散热方案

散热方式适用场景温度降低噪音
被动散热片轻度负载5-10°C
小型风扇中度负载15-25°C
散热外壳持续运行10-20°C低-中
水冷系统超频/高负载25-35°C

9.3 温控风扇脚本

# 自动温控风扇脚本 /usr/local/bin/fan-control.sh
#!/bin/bash
FAN_PIN=18
TEMP=$(cat /sys/class/thermal/thermal_zone0/temp)
TEMP_C=$((TEMP / 1000))

if [ $TEMP_C -ge 60 ]; then
    gpio -g mode $FAN_PIN out
    gpio -g write $FAN_PIN 1
elif [ $TEMP_C -le 50 ]; then
    gpio -g mode $FAN_PIN out
    gpio -g write $FAN_PIN 0
fi

# 添加到 crontab 每分钟执行
# crontab -e
* * * * * /usr/local/bin/fan-control.sh

9.4 UPS 不间断电源

# 使用 PiSugar 电池模块
pip3 install pisugar

# 配置自动关机(低电量保护)
# /etc/systemd/system/low-battery.service
[Unit]
Description=Low Battery Shutdown
After=multi-user.target

[Service]
Type=simple
ExecStart=/usr/local/bin/low-battery-check.sh
Restart=always

[Install]
WantedBy=multi-user.target

# 低电量检查脚本
#!/bin/bash
BATTERY=$(cat /sys/class/power_supply/BAT/capacity)
if [ $BATTERY -le 10 ]; then
    shutdown -h now
fi

10. 常见问题排查

# "could not select device driver" → 加载内核模块
sudo modprobe br_netfilter

# SD 卡写满 → 清理 Docker 资源
docker system prune -a --volumes

# DinD 无法拉取镜像 → 检查 DNS
docker exec rpi-dind cat /etc/resolv.conf
docker run --privileged --dns 8.8.8.8 -d docker:24-dind

# 确认镜像 ARM 支持
docker manifest inspect alpine:latest | grep architecture

常见错误

  1. Docker 启动失败 Cannot connect to the Docker daemon:通常是因为 Docker 服务未启动或当前用户未加入 docker 组。执行 sudo systemctl start docker && sudo systemctl enable docker 启动服务,sudo usermod -aG docker $USER 后重新登录。
  2. ARM 镜像拉取失败 no matching manifest for linux/arm/v7:说明该镜像不支持 ARM 架构。用 docker manifest inspect 镜像名:tag 检查架构支持,或使用 docker buildx 自行构建 ARM 版本。
  3. SD 卡空间不足:Docker 镜像和容器日志会快速占满 SD 卡。定期执行 docker system prune -a --volumes 清理,并在 /etc/docker/daemon.json 中限制日志大小。
  4. DinD 容器内 DNS 无法解析:嵌套容器的 DNS 配置可能丢失。启动时指定 --dns 8.8.8.8 或挂载宿主机的 /etc/resolv.conf
  5. br_netfilter 模块未加载导致网络异常:Docker 依赖桥接网络模块。执行 sudo modprobe br_netfilter 并写入 /etc/modules-load.d/ 确保开机自动加载。

最佳实践

  1. 使用 Lite 版系统:树莓派作为服务器不需要桌面环境,选择 Raspberry Pi OS Lite 或 Ubuntu Server ARM64,节省内存和 SD 卡空间。
  2. 优先使用 USB 存储:SD 卡读写寿命有限,频繁 I/O 的 Docker 工作负载建议将根文件系统迁移到 USB SSD,性能和可靠性都会大幅提升。
  3. 禁用 swap:Docker 不支持基于 swap 的内存限制,且 swap 会加速 SD 卡磨损。用 dphys-swapfile uninstall 禁用后配合 --memory 参数精确控制容器内存。
  4. 配置日志轮转:在 /etc/docker/daemon.json 中设置 "max-size": "10m""max-file": "3",防止容器日志把存储撑满。
  5. 生产环境避免 --privileged:DinD 的 --privileged 会暴露宿主机全部能力。正式环境应使用 Rootless DinD 或 Podman 降低安全风险。
  6. 使用 Docker Compose 管理多容器:家庭服务器通常运行多个服务,用 docker-compose.yml 编排可以统一管理、一键启停,比单独 docker run 更易维护。
  7. 配置自动备份:使用 cron 定时备份重要数据到外部存储或云服务,防止 SD 卡故障导致数据丢失。

练习题

  1. 在树莓派上完成以下操作:安装 Docker → 运行一个 nginx 容器并映射端口 → 配置 Docker 日志轮转(限制 10MB × 3 份)→ 写出完整命令。
  2. docker buildx 在 x86 主机上为树莓派交叉构建一个包含自定义 Dockerfile 的 ARM64 镜像,将构建好的镜像推送到 Docker Hub,写出步骤和关键命令。
  3. 配置一个 Docker Compose 编排,同时运行 Portainer(Docker 可视化管理)和 Nginx Proxy Manager(反向代理),要求它们通过 Docker 网络互通,写出完整的 docker-compose.yml 文件。

本章总结

树莓派是低成本、低功耗的家庭服务器首选,配合 Raspberry Pi OS Lite 与 SSH 即可完成无显示器部署。Docker 在 ARM 上运行顺畅,DinD 适合 CI 等隔离场景但需权衡 --privileged 的安全风险;结合 SD 卡寿命保护、日志轮转与定期备份,才能让家庭服务长期稳定运行。

延伸阅读

↑ 回到顶部