LoginSignup
2
4

More than 3 years have passed since last update.

Elasticsearch podでfile descriptor数制限が発生した時に、やったことまとめ

Posted at

EKS上でElasticsearchを稼働させていた時のこと。
Elasticsearch内でインデックスが多くなりすぎ、java.io.IOException: Too many open filesが発生しました。

File descriptor数が上限に達してしまっていることが原因だろう、と原因については割と早く当たりがつきました。
そこでnofileを変更しようとなったのですが、ではどうやってnofileを変更するか、というところで時間がかかってしまったので、うまくいった方法とうまくいかなかったことをまとめます。

環境(EKS)

Kubernetes バージョン: 1.12
プラットフォームのバージョン: 7

うまくいった方法

docker.serviceが読み込む環境変数ファイルを編集する

参考: ulimit of nofile in Amazon ECS-optimized AMI
方針として、dockerコンテナのnofileを変更するために、Workerノードで実行されるdocker daemonのdefault-ulimit設定を変更することにします。
Workerノードの作成時に、以下の設定を追記してdaemonを再起動します。xxxxxには、nofileのsoft limit/hard limitとして適切な値を記載します。

/etc/sysconfig/docker
OPTIONS="--default-ulimit nofile=xxxxx:xxxxx"

/etc/sysconfig/dockerは、docker.serviceが起動する時にサービスファイル内で読み込まれる環境変数ファイルです。
systemdによってdaemonが起動する時に、上記のオプション付きで起動され、コンテナを起動する際のデフォルトのnofileを変更することができます。

実際に設定を投入する際には、CloudFormationテンプレートにて、UserDataにノード作成時の処理を記載すれば良いです。
設定投入後、サービスを再起動します。

Resources:
  NodeLaunchConfig:
    Properties:
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash
          echo 'OPTIONS="--default-ulimit nofile=xxxxx:xxxxx"' >> /etc/sysconfig/docker
          systemctl restart docker.service

うまくいかなかった方法

以下、うまくいかなかった方法を列挙します。
なお、なぜうまくいかなかったのか、と言うところまでは調査しきれていないです(そのため、単なる記載誤りの可能性もあります)。

/etc/sysconfig/dockerではなく、ExecStartに直接オプションを追記する

参考: Can I set ulimit for containers in k8s?
同じくdefault-ulimitを変更するために、docker.serviceのサービスファイルを、以下のように編集して再起動してみました。

/usr/lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd --default-ulimit nofile=xxxxx:xxxxx

こちらの方法では、nofileの値が反映されませんでした。

/etc/docker/daemon.jsonに、default-ulimit設定を追記する

参考: How do I set ulimit for containers in Kubernetes?
こちらもdefault-ulimitを変更する方針。
docker daemonの設定ファイルに、default-ulimit設定を記載してみましたが、こちらも正しく反映されませんでした。

/etc/docker/daemon.json
{
...
  "default-ulimits": {
    "nofile": {
      "Name": "nofile",
      "Soft": xxxxx,
      "Hard": xxxxx
    }
  },
...
}

Kubernetesのマニフェスト中で、InitContainerを使って設定する

参考: GKE でカーネルパラメータの設定
参考: How to set ulimit using kubernetes?
時系列的には、一番最初に試した方法です。
InitContainerでカーネルパラメータが設定できるなら、nofileも設定できないかな、と思って試したものです。
nofileの変更はプロセス単位で反映されます。そのため、この方法でnofileを変更した場合、変更はInitContainerとして実行したコンテナにのみ反映され、Pod内で実際にワークロードを実行したいコンテナには引き継がれません(カーネルはホストと共有しているため、カーネルパラメータの変更は有効です)。

...
  spec:
    initContainers:
    - image: alpine:3.6
      command: ["sh", "-c", "ulimit", "-n", "xxxxx"]
      name: init-container
      securityContext:
        privileged: true
...

まとめ

上記の通り、docker daemonに対してnofileを設定するのが良さそうです。
が、何で/etc/sysconfig/dockerに書く方法だけうまくいくんだろう・・・

現状、コンテナごとにnofileを変更する手立てはなく、Workerノードで稼働しているdocker daemonのデフォルト設定を変更することが必要です。
そのため、複数のアプリケーションでnofileに上限を設けることが必要な場合は、最も大きな上限に合わせなければなりません。
(Kubernetesでも、コンテナごとに変更する機能はサポートしていないようです。こちらに言及があります。)
また、nofile以外のリソース制限についても、同様の方法で変更することができそうです。

2
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4