Docker中のウェブサーバプロセス数を制御する

2023年1月13日

ウェブサービス目的のDockerのコンテナでは、当然のことながら内部でウェブサーバを起動している。Apacheやnginxである。しかし、特にApacheの場合には、ほうっておくと起動プロセス数が多すぎ、メモリを圧迫し、Apacheではなく、他プログラムが落ちてしまうことがある。

実際に、Apacheのプロセス数が多すぎて、Javaのサーバプログラムが落ちてしまう事例に見舞われた。

その時の対処方法が、Apacheのメモリ消費を抑える(prefork)にあるが、この記事は古い。Apache2.4も含む説明については、Apache2.4 preforkパラメータの設定方法を参照のこと。

状況の確認

これはホスト側のメモリ状況を見てみればわかる。起動直後と、その後のメモリ消費状況をみてみると、明らかに大きく異なっており、何者かがメモリを食い尽くしているのがわかる。

特にapacheのプロセスを見てみると、こんな具合だ。もちろんホスト側を調べている。

# ps ax | grep apache
  43958 ?        Ss     0:04 apache2 -DFOREGROUND
  44051 ?        S      1:17 apache2 -DFOREGROUND
  44052 ?        S      1:18 apache2 -DFOREGROUND
  44053 ?        S      1:13 apache2 -DFOREGROUND
  44054 ?        S      1:12 apache2 -DFOREGROUND
  44055 ?        S      1:15 apache2 -DFOREGROUND
  44951 ?        S      1:15 apache2 -DFOREGROUND
  44952 ?        S      1:19 apache2 -DFOREGROUND
  44981 ?        S      1:14 apache2 -DFOREGROUND
  44982 ?        S      1:15 apache2 -DFOREGROUND
  44984 ?        S      1:18 apache2 -DFOREGROUND
  51945 ?        S      0:04 apache2 -DFOREGROUND
  52001 ?        S      0:20 apache2 -DFOREGROUND
  52002 ?        S      0:20 apache2 -DFOREGROUND
  52003 ?        S      0:20 apache2 -DFOREGROUND
  52004 ?        S      0:21 apache2 -DFOREGROUND
  52005 ?        S      0:21 apache2 -DFOREGROUND
  52811 ?        S      0:21 apache2 -DFOREGROUND
 702819 pts/0    S+     0:00 grep --color=auto apache

どうもDockerの環境において、pstreeを使っても、どのコンテナがこれらのプロセスを生み出しているのかわからない。何かしらそういう方法があるのかも、現在のところわからない。

コンテナ内のapacheプロセスを調べる

現在のところ、一つ一つコンテナを探っていくしか無いと判断した。

例えば、mailuシステムだが、これだけのコンテナが動作している。

# docker ps | grep mailu
4c7e64a48d01   mailu/roundcube:1.8             "docker-php-entrypoi…"   37 hours ago   Up 37 hours (healthy)   80/tcp                                                                                                                                                                                                                                                                                                                                                   mailu_webmail_1
4c926a10619c   mailu/postfix:1.8               "/bin/sh -c /start.py"   37 hours ago   Up 37 hours (healthy)   25/tcp, 10025/tcp                                                                                                                                                                                                                                                                                                                                        mailu_smtp_1
3d543fc97e02   mailu/dovecot:1.8               "/bin/sh -c /start.py"   37 hours ago   Up 37 hours (healthy)   110/tcp, 143/tcp, 993/tcp, 2525/tcp, 4190/tcp                                                                                                                                                                                                                                                                                                            mailu_imap_1
2255453af60a   mailu/rspamd:1.8                "/bin/sh -c /start.py"   37 hours ago   Up 37 hours (healthy)   11332/tcp, 11334-11335/tcp                                                                                                                                                                                                                                                                                                                               mailu_antispam_1
11cd1edf975c   mailu/admin:1.8                 "/bin/sh -c /start.py"   37 hours ago   Up 37 hours (healthy)   80/tcp                                                                                                                                                                                                                                                                                                                                                   mailu_admin_1
10afa7ffe8c3   mailu/fetchmail:1.8             "/fetchmail.py"          37 hours ago   Up 37 hours                                                                                                                                                                                                                                                                                                                                                                      mailu_fetchmail_1
bbc84e8aafe7   mailu/unbound:1.8               "/bin/sh -c /start.py"   37 hours ago   Up 37 hours (healthy)   53/tcp, 53/udp                                                                                                                                                                                                                                                                                                                                           mailu_resolver_1
7c7761781dbb   mailu/nginx:1.8                 "/bin/sh -c /start.py"   37 hours ago   Up 37 hours (healthy)   0.0.0.0:25->25/tcp, :::25->25/tcp, 0.0.0.0:110->110/tcp, :::110->110/tcp, 0.0.0.0:143->143/tcp, :::143->143/tcp, 0.0.0.0:465->465/tcp, :::465->465/tcp, 0.0.0.0:993->993/tcp, :::993->993/tcp, 80/tcp, 10025/tcp, 0.0.0.0:995->995/tcp, :::995->995/tcp, 10143/tcp, 0.0.0.0:8443->443/tcp, :::8443->443/tcp, 0.0.0.0:49156->587/tcp, :::49156->587/tcp   mailu_front_1
d38f37e58bd0   redis:alpine                    "docker-entrypoint.s…"   37 hours ago   Up 37 hours             6379/tcp                                                                                                                                                                                                                                                                                                                                                 mailu_redis_1

おそらくは、mailu_webmail_1というコンテナだろう。これを調べてみる。

# docker exec -it mailu_webmail_1 bash
root@4c7e64a48d01:/var/www/html# ps ax | grep apache
      7 ?        S      0:04 apache2 -DFOREGROUND
     29 ?        S      0:21 apache2 -DFOREGROUND
     30 ?        S      0:21 apache2 -DFOREGROUND
     31 ?        S      0:21 apache2 -DFOREGROUND
     32 ?        S      0:21 apache2 -DFOREGROUND
     33 ?        S      0:21 apache2 -DFOREGROUND
     60 ?        S      0:21 apache2 -DFOREGROUND
  35767 pts/1    S+     0:00 grep apache
r# cd /etc/apache2
# ls
apache2.conf    conf-enabled  magic           mods-enabled  sites-available
conf-available  envvars       mods-available  ports.conf    sites-enabled
# 

案の定、Apacheプロセスが不必要に起動している。私の環境では、使っても数人、それも同時に使うことはほとんど無いだろう。そこで、Apacheをチューニングしてプロセス数を減らすことにする。

現状のMPMを確認する

docker exec -it mailu_webmail_1 bash

として

apachectl -V | grep MPM

とすると、

Server MPM:     prefork

とpreforkになっていることがわかる。

Apacheの設定ファイルを外部に出す

まずは、現状ではコンテナ内にあるデフォルトのApache設定ファイルを外に出してやる。コンテナ内のままでも設定変更はできるが、再インストールの際には失われてしまうため、外に出した方が良い。

docker cp mailu_webmail_1:/etc/apache2 ./apache2

とし、docker-compose.ymlを書き換える。

  # Webmail
  webmail:
    image: ${DOCKER_ORG:-mailu}/${DOCKER_PREFIX:-}roundcube:${MAILU_VERSION:-1.8}
    restart: always
    env_file: mailu.env
    volumes:
      - "./webmail:/data"
      - "./apache2:/etc/apache2" # これを追加
    depends_on:
      - imap

Apache2の設定変更

問題としては、apacheのMPMがpreforkになっており、それがデフォルトで必要以上のプロセスを発生していることである。これについては、ApacheのMPMはpreform,worker,eventのどれを選ぶべきか?を参照のこと。

この設定を変更してみる。Apache2のバージョンや、構成によって異なるのかもれないが、設定ファイルは以下の構成になっている。

# ls -lR
.:
total 76
drwxr-xr-x. 8 root root  4096 Oct 12  2021 apache2
-rw-r--r--. 1 root root  7244 Oct 15  2021 apache2.conf
drwxr-xr-x. 2 root root  4096 Oct 15  2021 conf-available
drwxr-xr-x. 2 root root  4096 Oct 15  2021 conf-enabled
-rw-r--r--. 1 root root  1924 Oct 12  2021 envvars
-rw-r--r--. 1 root root 31063 Aug  8  2020 magic
drwxr-xr-x. 2 root root  8192 Oct 14  2021 mods-available
drwxr-xr-x. 2 root root  4096 Oct 14  2021 mods-enabled
-rw-r--r--. 1 root root   320 Aug  8  2020 ports.conf
drwxr-xr-x. 2 root root    54 Oct 12  2021 sites-available
drwxr-xr-x. 2 root root    30 Oct 12  2021 sites-enabled

バージョンやディストリビューションによって、様々な設定方法があるようだが、この環境では以下と同じ設定ファイル構成のようだ。

つまり、mods-available内に、使われているいないに関わらずあらゆる設定があり、そのうちの使うものがmods-enabledにリンクされているというだけだ。

mods-enabled内でls- lすると以下になる。

lrwxrwxrwx. 1 root root 36 Oct 12  2021 access_compat.load -> ../mods-available/access_compat.load
lrwxrwxrwx. 1 root root 28 Oct 12  2021 alias.conf -> ../mods-available/alias.conf
lrwxrwxrwx. 1 root root 28 Oct 12  2021 alias.load -> ../mods-available/alias.load
lrwxrwxrwx. 1 root root 33 Oct 12  2021 auth_basic.load -> ../mods-available/auth_basic.load
lrwxrwxrwx. 1 root root 33 Oct 12  2021 authn_core.load -> ../mods-available/authn_core.load
lrwxrwxrwx. 1 root root 33 Oct 12  2021 authn_file.load -> ../mods-available/authn_file.load
lrwxrwxrwx. 1 root root 33 Oct 12  2021 authz_core.load -> ../mods-available/authz_core.load
lrwxrwxrwx. 1 root root 33 Oct 12  2021 authz_host.load -> ../mods-available/authz_host.load
lrwxrwxrwx. 1 root root 33 Oct 12  2021 authz_user.load -> ../mods-available/authz_user.load
lrwxrwxrwx. 1 root root 32 Oct 12  2021 autoindex.conf -> ../mods-available/autoindex.conf
lrwxrwxrwx. 1 root root 32 Oct 12  2021 autoindex.load -> ../mods-available/autoindex.load
lrwxrwxrwx. 1 root root 30 Oct 12  2021 deflate.conf -> ../mods-available/deflate.conf
lrwxrwxrwx. 1 root root 30 Oct 12  2021 deflate.load -> ../mods-available/deflate.load
lrwxrwxrwx. 1 root root 26 Oct 12  2021 dir.conf -> ../mods-available/dir.conf
lrwxrwxrwx. 1 root root 26 Oct 12  2021 dir.load -> ../mods-available/dir.load
lrwxrwxrwx. 1 root root 26 Oct 12  2021 env.load -> ../mods-available/env.load
lrwxrwxrwx. 1 root root 29 Oct 12  2021 filter.load -> ../mods-available/filter.load
lrwxrwxrwx. 1 root root 27 Oct 12  2021 mime.conf -> ../mods-available/mime.conf
lrwxrwxrwx. 1 root root 27 Oct 12  2021 mime.load -> ../mods-available/mime.load
lrwxrwxrwx. 1 root root 34 Oct 12  2021 mpm_prefork.conf -> ../mods-available/mpm_prefork.conf
lrwxrwxrwx. 1 root root 34 Oct 12  2021 mpm_prefork.load -> ../mods-available/mpm_prefork.load
lrwxrwxrwx. 1 root root 34 Oct 12  2021 negotiation.conf -> ../mods-available/negotiation.conf
lrwxrwxrwx. 1 root root 34 Oct 12  2021 negotiation.load -> ../mods-available/negotiation.load
lrwxrwxrwx. 1 root root 27 Oct 14  2021 php7.load -> ../mods-available/php7.load
lrwxrwxrwx. 1 root root 33 Oct 12  2021 reqtimeout.conf -> ../mods-available/reqtimeout.conf
lrwxrwxrwx. 1 root root 33 Oct 12  2021 reqtimeout.load -> ../mods-available/reqtimeout.load
lrwxrwxrwx. 1 root root 31 Oct 12  2021 setenvif.conf -> ../mods-available/setenvif.conf
lrwxrwxrwx. 1 root root 31 Oct 12  2021 setenvif.load -> ../mods-available/setenvif.load
lrwxrwxrwx. 1 root root 29 Oct 12  2021 status.conf -> ../mods-available/status.conf
lrwxrwxrwx. 1 root root 29 Oct 12  2021 status.load -> ../mods-available/status.load

これをまずは変更する。

rm -f mpm_prefork.*
ln -s ../mods-available/mpm_event.load .
ln -s ../mods_available/mpm_event.conf ,

これでmailuを再起動してみる。すると、エラーが発生する。

webmail_1    | [Sat Oct 29 12:28:10.916685 2022] [php7:crit] [pid 7:tid 140663369444672] Apache is running a threaded MPM, but your PHP Module is not compiled to be threadsafe.  You need to recompile PHP.
webmail_1    | AH00013: Pre-configuration failed
mailu_webmail_1 exited with code 1
smtp_1       | Oct 29 12:28:11 mail 

PHPがスレッドセーフでないと言う。面倒なので元に戻す。ともあれ、外部に出したApache2の設定が反映されていることは確認できた。

rm -f mpm_event.*
ln -s ../mods-available/mpm_prefork.load .
ln -s ../mods_available/mpm_preform.conf ,

preforkのまま設定を変更する

eventにするにはPHPまで何らかの変更をしなければならないらしい。preforkのまま、メモリ使用量を減らすことにする。

mods-available/mpm_prefork.confを見ると以下の設定になっている。

<IfModule mpm_prefork_module>
        StartServers                     5
        MinSpareServers           5
        MaxSpareServers          10
        MaxRequestWorkers         150
        MaxConnectionsPerChild   0
</IfModule>

チューニングの仕方はApacheのメモリ消費を抑える(prefork)に書いたが、しかしこの頃とはチューニングパラメータが異なるようだ。以前の設定をそのまま移行することができない。迷惑な話だ。

今回はメールサーバのユーザインターフェースということもあり、最小限で十分だ。以下の設定をする。

<IfModule mpm_prefork_module>
        StartServers                     1
        MinSpareServers           1
        MaxSpareServers          1
        MaxRequestWorkers         1
        MaxConnectionsPerChild   0
</IfModule>

これで問題ないようだ。

# docker exec -it mailu_webmail_1 bash
# ps ax | grep apache

とすると、プロセスは二つしか起動していない。おそらく、複数の人間が使ったとしてもこのままだろう。

Nextcloudの設定

NextCloudも同様にApache2を使用していた。しかし、Nextcloudの場合には、上の設定だと全くページが表示されず、ログを見ると警告がでている。以下の値を変更した。

        MaxRequestWorkers         50

未分類

Posted by ysugimura