はじめに
Linux環境にてFastAPIをgunicornで動かしています。
しばらく運用しているうちにローカルストレージの使用量が増えていっていることに気が付きました。
なぜなのか等、調査し対応したメモを残しておきます。
AWSのFargateでの事象および回避方法ですが、
オンプレサーバなどの環境でも設定方法が違うだけで内容は同じはずです。
なお、gunicornのバージョンは20.1.0です。
結論
max-threadsを設定するとコアダンプファイルがストレージを圧迫するので、
コアダンプが出力されないように設定しよう。
調査
Fargateの場合、Cloudwatch Container Insightを有効化することでコンテナのストレージ使用量(EphemeralStorageUtilized)を見ることができます。
有効化してしばらく運用していたところ、使用量が増えていっていることに気が付きました。
どんなファイルが増えていっているのか?
Fargateなので、コンテナに直接ログインしてみて中身を見てみます。
CloudShellからAmazon ECS Execを使ってコンテナにログインします。
あらかじめ設定等が必要ですが、こちらを参考に設定しておきます。
aws ecs execute-command \
--region ap-northeast-1 \
--cluster クラスタ名 \
--task XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX \
--container コンテナ名 \
--interactive \
--command "/bin/sh"
つながったらlsなどでFastAPIを動かしているディレクトリを見てみると、
core.999 という謎のファイルが多数、、、
/HOGE # ls -lh
total 2G
drwxr-xr-x 2 root root 4.0K Feb 28 07:30 __pycache__
-rw------- 1 root root 164.7M Feb 28 19:05 core.1058 ←???
-rw------- 1 root root 156.9M Feb 28 23:24 core.1257 ←???
-rw------- 1 root root 175.9M Feb 28 09:54 core.21 ←???
-rw------- 1 root root 178.7M Feb 28 13:01 core.337 ←???
drwxr-xr-x 1 root root 4.0K Feb 28 07:30 hogehoge
-rw-r--r-- 1 root root 3.7K Feb 21 00:39 main.py
-rw-r--r-- 1 root root 285 Feb 21 00:39 requirements.txt
/HOGE #
fileコマンドで何者かを確認してみましょう。
/HOGE # file core.1058
core.1058: ELF 64-bit LSB core file, x86-64, version 1 (SYSV), SVR4-style, from '/usr/local/bin/python /usr/local/bin/gunicorn main:app --workers 2 --worker-cla', real uid: 0, effective uid: 0, real gid: 0, effective gid: 0, execfn: '/usr/local/bin/gunicorn', platform: 'x86_64'
ELF 64-bit LSB core file
ということでコアダンプのファイルだとわかりました。
また、gunicornの異常終了でできたものであることもわかりました。
gunicornの異常終了はなぜ起こるのか
gunicornには指定回数分の処理をこなすとワーカープロセスを再起動してくれる設定(max_requests)があります。
これを設定しておくことで、万一メモリリークなどが発生していたとしても回避することが可能です。
今回、gunicornの起動オプションとして --max-requests 500
を指定していたため、
ワーカープロセスが再起動されるのですが、
その再起動が異常終了とみなされてコアダンプが生成されているようです。
対処
再起動してもコアダンプを出さないように設定することで対処します。
ulimitでcore file sizeを0に設定します。
Webコンソール > ECS > タスク定義 > 設定したいタスクの最新リビジョン
新しいリビジョンの作成 > JSONを利用した新しいリビジョンの作成
を開きます。
(2023/03現在、JSONでないと設定できません)
以下のように containerDefinitions.ulimits[] にcoreの設定を追加して、サービスに適用させれば完了です。
{
~略~
"containerDefinitions": [
{
~略~
"ulimits": [
{
"name": "core",
"softLimit": 0,
"hardLimit": 0
}
],
~略~
}
}
}
冒頭に記載しましたように、上記はFargateでの設定です。
オンプレ環境だと /etc/init.d/ や /etc/security/limits.conf にulimitの設定をすることになると思います。
おわりに
max-requestsを設定するときは同時にmax-requests-jitterも設定しましょう。という記載は比較的よく見かけるのですが、
コアダンプファイルへの注意を記載しているのが見つからなかったので、
今後のために記録しておきます。