配置内存限制后Splash容器启动失败问题排查求助
问题现象
使用Splash 3.0配合Docker Compose+HAProxy构建爬虫集群时,为Splash容器添加mem_limit: 1400m(或搭配memswap_limit: 1800m)配置后,启动报错:
ERROR: for aquarium_splash1_1 Cannot start service splash1: b'oci runtime error: container_linux.go:262: starting container process caused "process_linux.go:261: applying cgroup configuration for process caused "failed to write 1 to memory.kmem.limit_in_bytes: write /sys/fs/cgroup/memory/docker/1688a046edbf131e8abaffcf934a000f5f3d28b3baaee36dd8f9af0fb1800b48/memory.kmem.limit_in_bytes: operation not Creating aquarium_splash3_1 ... error
注释内存限制配置后,容器可正常启动,且服务器内存资源充足:
total used free shared buffers cached Mem: 15G 5.7G 9.9G 308M 129M 4.8G -/+ buffers/cache: 795M 14G Swap: 2.5G 33M 2.5G
核心原因
这个错误本质是Docker尝试为容器设置cgroup内存限制时,无法写入memory.kmem.limit_in_bytes文件,常见触发场景包括:
- 服务器内核未开启
CONFIG_MEMCG_KMEM配置,不支持内核内存(kmem)限制; - Docker版本较旧,对cgroup内存限制的处理存在bug;
mem_limit与Splash自身启动参数--maxrss存在冲突;- Docker使用的cgroup驱动(如cgroupfs)与系统环境不兼容。
排查与解决步骤
1. 检查内核kmem支持
执行以下命令查看内核是否开启了kmem限制支持:
grep CONFIG_MEMCG_KMEM /boot/config-$(uname -r)
- 如果输出为
CONFIG_MEMCG_KMEM=n或无结果,说明内核不支持kmem限制:- 方案一:升级内核并开启该配置(需重启服务器);
- 方案二:改用Docker的软内存限制(
mem_reservation)代替硬限制mem_limit,软限制不会强制限制内存,仅在系统资源紧张时触发回收,修改docker-compose配置:splash0: image: scrapinghub/splash:3.0 command: --max-timeout 3600 --slots 200 --maxrss 1000 --verbosity 1 expose: - 8050 mem_reservation: 1400m # 软限制,仅当系统内存不足时生效 restart: always
2. 调整内存限制参数
Splash自身通过--maxrss 1000参数限制进程驻留内存(RSS)为1000MB,外部设置的mem_limit:1400m需保证大于该值,否则可能触发冲突。可以尝试:
- 将
mem_limit调整为1500m以上,预留足够的缓冲区; - 若不需要Docker层面的硬限制,直接保留Splash自身的
--maxrss参数即可,放弃mem_limit配置。
3. 升级Docker并调整cgroup驱动
- 升级Docker到最新稳定版,老版本对cgroup内存限制的处理存在兼容性问题;
- 检查当前Docker使用的cgroup驱动:
docker info | grep Cgroup - 如果使用的是
cgroupfs,尝试切换为systemd驱动:- 创建/修改
/etc/docker/daemon.json:{ "exec-opts": ["native.cgroupdriver=systemd"] } - 重启Docker服务:
systemctl daemon-reload && systemctl restart docker
- 创建/修改
4. 调整memswap_limit配置
若必须设置memswap_limit:
- 确保
memswap_limit大于等于mem_limit; - 若内核不支持swap限制,可将
memswap_limit设为-1(表示容器可使用的swap等于主机swap总量加上mem_limit); - 尝试单独设置
mem_limit,不配置memswap_limit,看是否能正常启动。
内容的提问来源于stack exchange,提问作者user3520253

