🐬

MySQL コンテナのメモリドカ食いをとりあえずなんとかする

2023/03/08に公開

ある日突然、MySQL の Docker コンテナがめちゃくちゃメモリを消費するようになったので、その対応のメモです。

現象

  • Docker Compose で設定していた MySQL のサービスを up しようとしたら、やけに遅い。
  • メモリを大量に消費していることに気づく。25GB / 32GB くらい。

環境

  • ホスト Linux
$ uname -a
Linux x1-carbon-gen10-arch 6.2.2-arch1-1 #1 SMP PREEMPT_DYNAMIC Fri, 03 Mar 2023 15:58:31 +0000 x86_64 GNU/Linux
$ cat /etc/os-release
NAME="Arch Linux"
PRETTY_NAME="Arch Linux"
ID=arch
BUILD_ID=rolling
ANSI_COLOR="38;2;23;147;209"
HOME_URL="https://archlinux.org/"
DOCUMENTATION_URL="https://wiki.archlinux.org/"
SUPPORT_URL="https://bbs.archlinux.org/"
BUG_REPORT_URL="https://bugs.archlinux.org/"
PRIVACY_POLICY_URL="https://terms.archlinux.org/docs/privacy-policy/"
LOGO=archlinux-logo
  • systemd
$ systemctl --version
systemd 253 (253.1-1-arch)
+PAM +AUDIT -SELINUX -APPARMOR -IMA +SMACK +SECCOMP +GCRYPT +GNUTLS +OPENSSL +ACL +BLKID +CURL +ELFUTILS +FIDO2 +IDN2 -IDN +IPTC +KMOD +LIBCRYPTSETUP +LIBFDISK +PCRE2 -PWQUALITY +P11KIT -QRENCODE +TPM2 +BZIP2 +LZ4 +XZ +ZLIB +ZSTD +BPF_FRAMEWORK +XKBCOMMON +UTMP -SYSVINIT default-hierarchy=unified
  • Docker
$ docker version
Client:
 Version:           23.0.1
 API version:       1.42
 Go version:        go1.20
 Git commit:        a5ee5b1dfc
 Built:             Sat Feb 11 13:58:04 2023
 OS/Arch:           linux/amd64
 Context:           default

Server:
 Engine:
  Version:          23.0.1
  API version:      1.42 (minimum version 1.12)
  Go version:       go1.20
  Git commit:       bc3805a0a0
  Built:            Sat Feb 11 13:58:04 2023
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          v1.6.19
  GitCommit:        1e1ea6e986c6c86565bc33d52e34b81b3e2bc71f.m
 runc:
  Version:          1.1.4
  GitCommit:        
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0
  • MySQL イメージタグ:5.7

原因

コンテナ内のファイルディスクリプタの設定値が大きすぎて遅くなっていた可能性が高い。

詳しいこと

調査中…

とりあえず頑張って起動したコンテナに入って ulimit で確認すると、約10億程度の数値でした。

# ulimit -Sn
1073741816
# ulimit -Hn
1073741816

やったこと

ファイルディスクリプタの上限値を適当な値に制限します。

やり方 - 1

デーモンの設定ファイルを作成(編集)します。

$ sudo vi /etc/docker/daemon.json
{
    "default-ulimits": {
        "nofile": {
            "Name": "nofile",
            "Hard": 4096,
            "Soft": 4096
        }
    }
}

再起動します。

$ sudo systemctl restart docker

やり方 - 2

昔のドキュメントに書かれていて、今は先述の方法になっていたので、多分古い方法です。

$ sudo vi /etc/default/docker
DOCKER_OPTS="--default-ulimit nofile=4096:4096"

systemd で動かしている Docker の場合、サービスの設定も必要です。
EnvironmentFile に、先ほど作った /etc/default/docker を指定します。

$ sudo vi /etc/systemd/system/docker.service.d/docker.conf
[Service]
EnvironmentFile=-/etc/default/docker
ExecStart=
ExecStart=/usr/sbin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock $DOCKER_OPTS

1つ目の ExecStart= でデフォルト設定を無効化し、2つ目で上書きします。

dockerd の場所は環境によって異なるので、調整します。

$ which dockerd
/usr/sbin/dockerd

デーモンの設定ファイルをリロードし、再起動します。

$ sudo systemctl daemon-reload
$ sudo systemctl restart docker

これが正常に起動し、EnvironmentFiles の設定が正しく入って入れば OK です。

$ systemctl show docker | grep EnvironmentFile
EnvironmentFiles=/etc/default/docker (ignore_errors=yes)

参考

Discussion