我们正在 AWS EC2 内的 Centos7 之上构建的 Jenkins 实例中构建或运行 Docker 容器。我们有 2 个 t2.medium 实例,配有 2 个 CPU 和 3.5 GB 可用内存。
在一种情况下,我们在另一个容器中构建容器,我们只是拉动它们并运行(不同的容器)。
我们开始出现错误
open /var/lib/docker/overlay/<sha>-init/merged/dev/console: cannot allocate memory
我们journalctl
得到
page allocation failure: order:4
运行页面缓存转储可以暂时解决该问题
echo 1 > /proc/sys/vm/drop_caches
所以我注意到,在运行 docker 任务时,Dirty
内存块会出现峰值(正如它应该的那样)并Mapped
在其之后跳转。然而,DirectMap4k
相对接近这个跳跃。
例如:
闲置机
cat /proc/meminfo | grep -P "(Dirty|Mapped|DirectMap4k)"
Dirty: 104 kB
Mapped: 45696 kB
DirectMap4k: 100352 kB
主动机
cat /proc/meminfo | grep -P "(Dirty|Mapped|DirectMap4k)"
Dirty: 72428 kB
Mapped: 70192 kB
DirectMap4k: 100352 kB
因此,这台机器需要一些时间才能开始失败,而相同的机器会报告DirectMap4k: 77824 kB
并因此定期失败(它还必须处理构建更复杂的容器),但是sysctl vm
相同的。
docker 容器的构建/启动会引发内存不足错误,而问题是需要对内核进行哪些调整才能使其稳定。
Docker版本
Client:
Version: 17.06.0-ce
API version: 1.30
Go version: go1.8.3
Git commit: 02c1d87
Built: Fri Jun 23 21:20:36 2017
OS/Arch: linux/amd64
Server:
Version: 17.06.0-ce
API version: 1.30 (minimum version 1.12)
Go version: go1.8.3
Git commit: 02c1d87
Built: Fri Jun 23 21:21:56 2017
OS/Arch: linux/amd64
Experimental: false
核心3.10.0-327.10.1.el7.x86_64
系统控制虚拟机
vm.admin_reserve_kbytes = 8192
vm.block_dump = 0
vm.dirty_background_bytes = 0
vm.dirty_background_ratio = 10
vm.dirty_bytes = 0
vm.dirty_expire_centisecs = 3000
vm.dirty_ratio = 30
vm.dirty_writeback_centisecs = 500
vm.drop_caches = 1
vm.extfrag_threshold = 500
vm.hugepages_treat_as_movable = 0
vm.hugetlb_shm_group = 0
vm.laptop_mode = 0
vm.legacy_va_layout = 0
vm.lowmem_reserve_ratio = 256 256 32
vm.max_map_count = 65530
vm.memory_failure_early_kill = 0
vm.memory_failure_recovery = 1
vm.min_free_kbytes = 67584
vm.min_slab_ratio = 5
vm.min_unmapped_ratio = 1
vm.mmap_min_addr = 4096
vm.nr_hugepages = 0
vm.nr_hugepages_mempolicy = 0
vm.nr_overcommit_hugepages = 0
vm.nr_pdflush_threads = 0
vm.numa_zonelist_order = default
vm.oom_dump_tasks = 1
vm.oom_kill_allocating_task = 0
vm.overcommit_kbytes = 0
vm.overcommit_memory = 0
vm.overcommit_ratio = 50
vm.page-cluster = 3
vm.panic_on_oom = 0
vm.percpu_pagelist_fraction = 0
vm.stat_interval = 1
vm.swappiness = 30
vm.user_reserve_kbytes = 108990
vm.vfs_cache_pressure = 100
vm.zone_reclaim_mode = 0
答案1
长话短说
sudo su
sysctl -w vm.swappiness=10
解释
我创建了一个测试场景,可以重现此错误 10/10 次。这只是通过命令行直接构建一个更大的镜像,而不是通过 CI。
正如所提到的,我知道的解决方法是
echo 1 > /proc/sys/vm/drop_caches
所以我试图将其与DirectMap
价值观联系起来。由于我了解到这些值代表 TLB 负载并且无法直接调整,因此我查找了使用它们的首选项值,这就是交换性。
交换性
swappiness 值范围从 0 到 100,控制系统支持匿名内存或页面缓存的程度。高值可以提高文件系统性能,同时积极地将不太活跃的进程从 RAM 中交换出来。较低的值可以避免将进程交换出内存,这通常会以 I/O 性能为代价来减少延迟。默认值为 60。
警告
设置 swappiness==0 将非常积极地避免换出,这会增加在强内存和 I/O 压力下 OOM 杀死的风险。
因此减少它可以降低对内存缓存页面的依赖。默认情况下,我们使用的 EC2 Centos 7 映像将其设置为 30,因此将其减少到 10 可使大型映像成功构建 10/10 倍。