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.2:安装 Linux 安装 Linux——发行版选择与系统安装流程
- 3.1:Docker 容器入门 Docker 容器入门——镜像、容器与
docker run基础用法 - 4.5:网络故障排查 网络故障排查——IP、DNS、端口映射与远程访问
- 5.2:Docker 生产实践 Docker 生产实践——容器部署与日常运维经验
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.conf | pi / raspberry |
| Ubuntu Server ARM | 安装时配置网络 | 自定义 |
| Debian ARM | 创建 /root/.ssh/authorized_keys | root |
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 Assistant | homeassistant/home-assistant | 智能家居中枢 |
| Portainer | portainer/portainer-ce | Docker 可视化管理 |
| Nginx Proxy Manager | jc21/nginx-proxy-manager | 反向代理 + HTTPS |
| Pi-hole | pihole/pihole | DNS 广告过滤 |
| Grafana | grafana/grafana | 监控面板 |
| Jellyfin | jellyfin/jellyfin | 媒体服务器 |
| Syncthing | syncthing/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-gpio | sudo 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:latest | arm64v8/nginx:alpine | 187MB → 42MB |
| node:20 | arm64v8/node:20-alpine | 1.1GB → 180MB |
| python:3.12 | arm64v8/python:3.12-slim | 1.0GB → 150MB |
| mysql:8 | arm64v8/mysql:8 | 支持原生 ARM |
| redis:7 | arm64v8/redis:7-alpine | 130MB → 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.5A | 4.75V | 0.5W - 7W |
| 树莓派 4B | 5V/3A (USB-C) | 4.75V | 0.5W - 8W |
| 树莓派 5 | 5V/5A (USB-C) | 4.75V | 1W - 12W |
| 树莓派 Zero 2W | 5V/2.5A | 4.75V | 0.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
常见错误
- Docker 启动失败
Cannot connect to the Docker daemon:通常是因为 Docker 服务未启动或当前用户未加入 docker 组。执行sudo systemctl start docker && sudo systemctl enable docker启动服务,sudo usermod -aG docker $USER后重新登录。 - ARM 镜像拉取失败
no matching manifest for linux/arm/v7:说明该镜像不支持 ARM 架构。用docker manifest inspect 镜像名:tag检查架构支持,或使用docker buildx自行构建 ARM 版本。 - SD 卡空间不足:Docker 镜像和容器日志会快速占满 SD 卡。定期执行
docker system prune -a --volumes清理,并在/etc/docker/daemon.json中限制日志大小。 - DinD 容器内 DNS 无法解析:嵌套容器的 DNS 配置可能丢失。启动时指定
--dns 8.8.8.8或挂载宿主机的/etc/resolv.conf。 br_netfilter模块未加载导致网络异常:Docker 依赖桥接网络模块。执行sudo modprobe br_netfilter并写入/etc/modules-load.d/确保开机自动加载。
最佳实践
- 使用 Lite 版系统:树莓派作为服务器不需要桌面环境,选择 Raspberry Pi OS Lite 或 Ubuntu Server ARM64,节省内存和 SD 卡空间。
- 优先使用 USB 存储:SD 卡读写寿命有限,频繁 I/O 的 Docker 工作负载建议将根文件系统迁移到 USB SSD,性能和可靠性都会大幅提升。
- 禁用 swap:Docker 不支持基于 swap 的内存限制,且 swap 会加速 SD 卡磨损。用
dphys-swapfile uninstall禁用后配合--memory参数精确控制容器内存。 - 配置日志轮转:在
/etc/docker/daemon.json中设置"max-size": "10m"和"max-file": "3",防止容器日志把存储撑满。 - 生产环境避免
--privileged:DinD 的--privileged会暴露宿主机全部能力。正式环境应使用 Rootless DinD 或 Podman 降低安全风险。 - 使用 Docker Compose 管理多容器:家庭服务器通常运行多个服务,用 docker-compose.yml 编排可以统一管理、一键启停,比单独 docker run 更易维护。
- 配置自动备份:使用 cron 定时备份重要数据到外部存储或云服务,防止 SD 卡故障导致数据丢失。
练习题
- 在树莓派上完成以下操作:安装 Docker → 运行一个 nginx 容器并映射端口 → 配置 Docker 日志轮转(限制 10MB × 3 份)→ 写出完整命令。
- 用
docker buildx在 x86 主机上为树莓派交叉构建一个包含自定义Dockerfile的 ARM64 镜像,将构建好的镜像推送到 Docker Hub,写出步骤和关键命令。 - 配置一个 Docker Compose 编排,同时运行 Portainer(Docker 可视化管理)和 Nginx Proxy Manager(反向代理),要求它们通过 Docker 网络互通,写出完整的
docker-compose.yml文件。
本章总结
树莓派是低成本、低功耗的家庭服务器首选,配合 Raspberry Pi OS Lite 与 SSH 即可完成无显示器部署。Docker 在 ARM 上运行顺畅,DinD 适合 CI 等隔离场景但需权衡 --privileged 的安全风险;结合 SD 卡寿命保护、日志轮转与定期备份,才能让家庭服务长期稳定运行。