OOM Killer に kill されないように Docker Container のメモリ使用量を増加させる方法
Written by @ryysud Oct 8, 2018 21:13 · 1190 words · 3 minutes read
まえおき
“OOM Killer に関連するカーネルパラメータまとめ” なる記事を書いて、OOM Killer 周りのカーネルパラメータを理解したので適当にスクリプトを書くことにしました。
特定のプロセスを OOM Killer の kill 対象から除外する方法
OOM Killer の kill 対象から除外したいプロセスに対して、以下のどちらかを適用することで実現可能です。
- /proc/${pid}/oom_score_adj の値を -1000 に変更する(Linux 2.6.36 以降ではこちらのパラメータが推奨)
- /proc/${pid}/oom_adj の値を -17 に変更する
後述のスクリプトは Linux 2.6.36 以降であることを前提にしておりますので、Linux 2.6.36 以前で実行したい場合には、以下の処理をよしなに書き換えてください。
# Linux 2.6.36 以降
echo -n -1000 > /proc/${pid}/oom_score_adj
# Linux 2.6.36 以前
echo -n -17 > /proc/${pid}/oom_adj
事前に必要な作業
stress コマンドを用いるので、ベースイメージとしているOSに応じて適切な形でインストールしてください。( Alpine は stress コマンドを自前でビルドです…。悪しからず…。)
# RedHat系
$ yum install -y epel-release
$ yum install -y stress
# Debian系
$ apt-get update
$ apt-get install -y stress
# Alpine
$ apk add --update bash g++ make
$ wget -P /tmp https://people.seas.harvard.edu/~apw/stress/stress-1.0.4.tar.gz
$ cd /tmp
$ tar -xf stress-1.0.4.tar.gz
$ cd stress-1.0.4
$ ./configure
$ make
$ make install
スクリプトを Docker Container 内で実行する際には root ユーザーで –privileged オプションを忘れずに!
$ docker exec -it -u root --privileged <container name$ [bash|ash]
スクリプト
4つの worker process を起動して、それぞれに 1GB のメモリを確保させる形で合計 4GB のメモリを使用するロジックとなっております。お試しになりたい環境によって数値は調整してください。
#!/usr/bin/env bash
set -e
readonly WORKERS='4'
readonly MALLOC_MEMORY='1G'
stress --vm ${WORKERS} --vm-bytes ${MALLOC_MEMORY} --vm-hang 0 &
for pid in $(pgrep -f stress) ; do
echo -n -1000 > /proc/${pid}/oom_score_adj
done
実際に試してみる
RedHat系(CentOS)
使用可能メモリに 1GB の制限をかけてコンテナを起動
$ docker run -d \
--memory 1g \
--name centos \
centos:7 \
sleep 10000000000
$ docker stats --no-stream centos
CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
51ffd35556c2 centos 0.00% 888KiB / 1GiB 0.08% 898B / 0B 3.28MB / 69.6kB 1
rootユーザーで Docker Container に侵入(–privileged オプションを忘れずに!)
$ docker exec -it -u root --privileged centos bash
stress コマンドでメモリが食いつぶされてコンテナが停止する
# Docker Container の中
$ yum install -y epel-release
$ yum install -y stress
$ vi /tmp/stress.sh
$ bash /tmp/stress.sh
Debian系(Ubuntu)
使用可能メモリに 1GB の制限をかけてコンテナを起動
$ docker run -d \
--memory 1g \
--name ubuntu \
ubuntu:18.04 \
sleep 10000000000
rootユーザーで Docker Container に侵入(–privileged オプションを忘れずに!)
$ docker exec -it -u root --privileged ubuntu bash
stress コマンドでメモリが食いつぶされてコンテナが停止する
# Docker Container の中
$ apt-get update
$ apt-get install -y stress
$ apt-get install -y vim
$ vi /tmp/stress.sh
$ bash /tmp/stress.sh
Alpine
使用可能メモリに 1GB の制限をかけてコンテナを起動
$ docker run -d \
--memory 1g \
--name alpine \
alpine:3.8 \
sleep 10000000000
rootユーザーで Docker Container に侵入(–privileged オプションを忘れずに!)
$ docker exec -it -u root --privileged alpine ash
stress コマンドでメモリが食いつぶされてコンテナが停止する
# Docker Container の中
$ apk add --update bash g++ make
$ wget -P /tmp https://people.seas.harvard.edu/~apw/stress/stress-1.0.4.tar.gz
$ cd /tmp
$ tar -xf stress-1.0.4.tar.gz
$ cd stress-1.0.4
$ ./configure
$ make
$ make install
$ vi /tmp/stress.sh
$ bash /tmp/stress.sh
まとめ
stress コマンドに依存しているスクリプトで完全にイケてないので、誰かが更にいい感じのスクリプトをインターネットに放り投げてくれることを祈ります。アーメン。