树莓派内存不够跑Docker直接卡死?配置虚拟内存一招让4G变8G,使用效果显著
说实话,我第一次在树莓派4B上跑Docker的时候,真的是被坑得够惨。那时候我装了HomeAssistant、Portainer,再来个Nginx反向代理,眼睁睁看着树莓派直接卡死,SSH都连不上,屏幕上的风扇呼呼转,但就是没有任何响应。
后来折腾了好几天,终于找到了解决方案——配置虚拟内存(Swap)。这一步操作下来,内存直接”从4G变8G”,效果真的立竿见影。今天就把这个完整的过程跟你们好好聊聊,保证你看懂就会用。
为什么树莓派跑Docker会卡死?
先说清楚一个概念:树莓派4B的4GB内存,是实打实的物理内存。但Docker容器不是魔法,每个容器启动都会占用独立的内存空间。
举个例子,我当时的场景是这样的:
树莓派4B(4GB RAM)正在运行的容器:
├── HomeAssistant → 约 400MB
├── Portainer → 约 150MB
├── Nginx → 约 50MB
├── Mosquitto → 约 30MB
├── Grafana → 约 200MB
└── PostgreSQL → 约 300MB
合计已用:约 1130MB
剩余可用:约 200-300MB(系统本身也要用)
看起来好像还够用对吧?但问题在于,Docker容器在运行过程中会有内存突刺,特别是HomeAssistant启动时会一次性加载大量插件,瞬间内存使用量可能飙到2GB以上。
当物理内存用光时,Linux系统会尝试杀掉一些进程来释放内存——这也就是为什么有时候你发现Docker容器突然自己死了,不是Bug,是系统OOM Killer(内存溢出杀手)出手了。
更糟糕的是,如果系统找不到可以杀掉的进程,或者干脆卡住不动,那就是彻底死机了。
Swap是什么?为什么它能救命?
Swap(交换分区/交换文件)是Linux系统利用硬盘空间来扩展内存的一种机制。当物理内存不够用时,系统会把一些暂时不用的内存数据”搬”到硬盘上的Swap区域,给当前急需内存的进程腾出空间。
这就好比你的书桌(物理内存)放不下了,你把一些暂时不用的书放到旁边的书架(硬盘Swap)上,需要的时候再取回来。
但这里有个关键点需要提醒你们:
树莓派用的是SD卡或者NVMe SSD,它们的读写速度和寿命跟普通硬盘不一样,所以要谨慎配置,不能照搬服务器的做法。
完整配置教程(手把手教学)
第一步:查看当前内存和Swap状态
SSH登录到你的树莓派,先运行这个命令看看现状:
free -h
输出大概会是这样:
total used free shared buff/cache available
Mem: 3.7G 3.4G 150M 80M 250M 200M
Swap: 100M 90M 10M
看到没?Swap只有100MB,这基本等于没有。而且available只有200MB,说明物理内存已经快告急了。
再运行:
cat /proc/swaps
查看当前Swap文件的具体信息。
第二步:创建Swap文件
这是最关键的一步。我们来创建一个2GB的Swap文件:
# 切换到root权限操作
sudo -i
# 创建2GB的空白文件(这个过程可能需要几十秒到一分钟,耐心等)
sudo fallocate -l 2G /swapfile
# 如果fallocate命令报错说"not implemented",用这个代替:
# sudo dd if=/dev/zero of=/swapfile bs=1M count=2048
# 设置文件权限为600(只有root能读写,安全第一)
sudo chmod 600 /swapfile
# 格式化为Swap格式
sudo mkswap /swapfile
# 启用Swap
sudo swapon /swapfile
# 再次查看内存状态
free -h
这时候你应该能看到Swap变成2GB了:
total used free shared buff/cache available
Mem: 3.7G 2.8G 300M 80M 600M 800M
Swap: 2.0G 100M 1.9G
第三步:让Swap设置永久生效
刚才的操作重启后就没了,需要写入配置文件:
# 编辑/etc/fstab文件
sudo nano /etc/fstab
在文件末尾添加这一行:
/swapfile none swap sw 0 0
保存退出(Ctrl+O,回车,Ctrl+X)。
第四步:优化Swap参数(重要!)
这里有个很关键的参数叫vm.swappiness,它决定了系统有多”积极”地使用Swap。
- 默认值通常是10或60
- 值越小,越倾向于使用物理内存
- 值越大,越倾向于把数据移到Swap
对于树莓派这种小内存设备,我建议设置为10:
# 查看当前值
cat /proc/sys/vm/swappiness
# 临时修改(重启失效)
sudo sysctl vm.swappiness=10
# 永久修改,编辑配置
sudo nano /etc/sysctl.conf
在文件末尾添加:
vm.swappiness=10
保存退出。
还有一个参数叫vm.vfs_cache_pressure,控制系统回收 inode 和 dentry 缓存的倾向,建议也设置为100:
sudo nano /etc/sysctl.conf
添加:
vm.vfs_cache_pressure=100
第五步:优化Docker的内存使用
光有Swap还不够,Docker本身也可以优化:
# 编辑Docker的daemon.json配置文件
sudo nano /etc/docker/daemon.json
添加以下配置:
{
"storage-driver": "overlay2",
"log-opts": {
"max-size": "10m",
"max-file": "3"
},
"default-cgroupns-mode": "host"
}
这几个配置的作用:
- storage-driver: overlay2 — 使用更高效的存储驱动
- log-opts — 限制每个容器日志文件大小,防止日志撑爆磁盘
- default-cgroupns-mode — 优化容器隔离方式
然后重启Docker让配置生效:
sudo systemctl restart docker
第六步:限制各个容器的内存使用
这是最推荐的长期方案——给每个容器设置内存上限,防止某个容器吃光所有内存:
# 停止并删除旧的容器(先备份好数据!)
docker stop homeassistant
docker rm homeassistant
# 重新启动,限制最大内存为1GB,Swap为512MB
docker run -d \
--name homeassistant \
--restart unless-stopped \
--memory=1g \
--memory-swap=1.5g \
--cpus=2 \
-v /home/pi/homeassistant/config:/config \
--network=host \
ghcr.io/home-assistant/home-assistant:stable
同理,给其他容器也加上限制:
# Portainer
docker run -d \
--name portainer \
--restart unless-stopped \
--memory=256m \
--memory-swap=384m \
-p 9000:9000 \
-v /var/run/docker.sock:/var/run/docker.sock \
-v portainer_data:/data \
portainer/portainer-ce:latest
# Nginx
docker run -d \
--name nginx \
--restart unless-stopped \
--memory=128m \
--memory-swap=192m \
-p 80:80 \
-p 443:443 \
-v /home/pi/nginx/conf.d:/etc/nginx/conf.d \
nginx:alpine
# Mosquitto(MQTT Broker,很轻量)
docker run -d \
--name mosquitto \
--restart unless-stopped \
--memory=64m \
--memory-swap=96m \
-p 1883:1883 \
-v /home/pi/mosquitto/config:/mosquitto/config \
-v /home/pi/mosquitto/data:/mosquitto/data \
-v /home/pi/mosquitto/log:/mosquitto/log \
eclipse-mosquitto:2
第七步:验证效果
现在我们来测试一下效果:
# 查看内存状态
free -h
# 查看Docker容器内存使用情况
docker stats
# 查看Swap使用详情
cat /proc/swaps
# 实时监控系统内存和Swap
watch -n 1 'free -h && echo "---" && docker stats --no-stream'
你应该能看到:
- 物理内存使用量大幅下降(因为系统会把不常用的数据移到Swap)
- Docker容器内存被严格限制在设定值内
- 系统不再因为内存不足而卡死
重要提醒:关于树莓派使用Swap的注意事项
1. 不要用Swap替代真正的内存
Swap只是应急方案,它比物理内存慢几千倍。如果你的树莓派经常需要大量Swap,说明你跑的服务确实太多了。长期来看,建议:
- 精简容器,只跑必要的服务
- 考虑升级到树莓派5(8GB版本)
- 或者用更轻量的替代方案(比如用Caddy替代Nginx,用SQLite替代PostgreSQL)
2. SD卡的寿命问题
频繁读写Swap会加速SD卡老化。如果你用的是质量好的工业级SD卡,问题不大。但我个人更推荐:
- 把Swap文件放到USB外接的SSD上
- 或者使用树莓派5的NVMe支持
3. 如果 Swap 效果不够怎么办?
如果配了2GB Swap还是不够用,可以扩展:
# 先关闭现有Swap
sudo swapoff /swapfile
# 删除旧文件,创建更大的
sudo rm /swapfile
sudo fallocate -l 4G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
# 更新fstab
sudo nano /etc/fstab
# 确认里面有这行:/swapfile none swap sw 0 0
实际使用效果对比
我给你们看一下我实际折腾前后的数据对比:
优化前:
内存使用:92%(经常触发OOM Killer)
Docker容器数:6个(其中Grafana和HomeAssistant经常同时崩溃)
系统稳定性:平均每天需要重启1-2次
优化后(配置了2GB Swap + 容器内存限制):
内存使用:60-70%(偶尔峰值到80%)
Swap使用:300-500MB(平时几乎不用)
Docker容器数:5个(去掉了不常用的)
系统稳定性:连续运行30天无重启
说实话,这个改变是真的香。之前每天担惊受怕怕树莓派又死了,现在基本可以做到”装好就不管”了。
总结一下
配置树莓派的虚拟内存其实就这几步:
- 创建Swap文件(2GB足够)
- 启用并设置开机自动挂载
- 调整swappiness参数为10
- 给Docker容器设置内存上限
- 限制Docker日志大小
别被这些步骤吓到,其实每一步都很简单,复制粘贴就行。关键是要理解背后的原理——Swap是救命稻草,但不是长久之计。合理控制容器数量和内存使用,才是让树莓派稳定运行的根本之道。
如果你的树莓派5已经到手了,那这个问题基本就不存在了。但如果你跟我一样,手里还有一台树莓派4B,那这个配置绝对值得试一试。
有什么问题的话,随时在评论区留言,我看到都会回复。祝大家都能让树莓派跑得稳稳的!