docker-mailserverをbash4.4未満で生き抜く


はじめに

このドキュメントは、docker-mailserverをbash4.4未満で使うためのメモです。
docker-mailserverのsetup.shでは、「shopt -s inherit_errexit」を使用しています。このコマンドはbash4.4以上でないと使用できません。

setup.sh
set -euEo pipefail
shopt -s inherit_errexit
trap '__err "${BASH_SOURCE}" "${FUNCNAME[0]:-?}" "${BASH_COMMAND:-?}" "${LINENO:-?}" "${?:-?}"' ERR

bash4.4未満の環境ではsetup.shをそのまま実行することはできません。例えば、CentOS7のbashは4.2系です。サポートの関係でCentOS8へ移行せず、CentOS7でいけるところまで引っ張る場合、問題となります。

$ bash --version
GNU bash, バージョン 4.2.46(2)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2011 Free Software Foundation, Inc.
ライセンス GPLv3+: GNU GPL バージョン 3 またはそれ以降 <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

解決方法1:bash4.4以上をローカルにインストールする

setup.sh実行用にbash4.4以上をインストールする方法です。
CentOS7上でbash5.1.6をインストールする方法を以下に示します。configure実行時のprefixは必要であれば変更してください。

# env LANG=C yum -y groupinstall "Development Tools"
# curl -LO https://ftpmirror.gnu.org/bash/bash-5.1.16.tar.gz
# tar zxvf bash-5.1.16.tar.gz
# cd bash-5.1.16
# ./configure --prefix=${HOME}/bash
# make && make install

setup.shを上記でインストールしたbashを使用するよう変更します。

setup.sh
#! /home/user1/bash/bin/bash

# version   v1.0.0
# executed  manually / via Make
# task      wrapper for various setup scripts

CONFIG_PATH=
CONTAINER_NAME=

解決方法2:docker runでsetupを実行する

setup.shの本体はコンテナの中に入っています。setup.shはコンテナ内のsetupを呼び出すためのラッパーです。なので、setup.shが叩けないなら直接コンテナ内のsetupを呼び出す、という方法があります。

公式のStarting for the first timeにも本手順が記載されています。docker run実行時configディレクトリをdocker-compose.ymlと同じようにマウントしてあげる必要があります。

$ docker run --rm -v "${PWD}/docker-data/dms/config/:/tmp/docker-mailserver/" docker.io/mailserver/docker-mailserver setup email add [email protected] password

この方法でsetupを実行する場合、ユーザ追加はパスワードを省略することはできません(setup.shだと、パスワードを省略して実行すると、パスワードを聞いてきます)。

また、本方法では一部表示されない情報があります。例えば、コンテナ動作時「/setup.sh email list」を実行すると、クォータ情報も表示されます。

$ ./setup.sh email list
* [email protected] ( 0 / ~ ) [0%]

dockerコマンドでsetupを実行した場合、クォータ情報は表示されません。

$ docker run --rm -v "${PWD}/docker-data/dms/config/:/tmp/docker-mailserver/" docker.io/mailserver/docker-mails
erver setup email list
* [email protected]

稼働中のコンテナでsetupを実行すると、上記情報も表示されます。

$ docker exec mailserver setup email list
* [email protected] ( 0 / ~ ) [0%]

コンテナが動いているときはdocker exec、動いていないときはdocker runと判断する必要があるので、通常の使用では何も考えずdocker runを使うのが楽ちんだと思います。

解決方法3:docker-composeでsetupを実行する(お勧めしない)

docker runだとボリュームのマウントを指定する必要があるので面倒です。なので、docker-compose runで同じことできるんじゃないか、と考えました。結果、できるんだけどやめておいたほうがいい・・・ようです。

例えば「setup email list」を実行すると、以下のようにエラーが出ます。

$ docker-compose run mailserver setup email list
doveadm([email protected])<37><>: Error: auth-master: userdb lookup([email protected]): connect(/run/dovecot/auth-userdb) failed: No such file or directory
doveadm([email protected]): Error: User lookup failed: Internal error occurred. Refer to server log for more information.
/usr/local/bin/listmailuser: line 19: notify: command not found
/usr/local/bin/listmailuser: line 19: notify: command not found
* [email protected] (  /  ) [%]

これはmailserver.env定義の有無で挙動を変える、という実装があるためです。docker-compose runの場合、コンテナにはmailserver.envの内容が反映されます。mailserver.env定義が存在する場合、各種サービス(postfixとか)が動いている前提でsetupは動きます。
しかし、docker-compose runの場合、postfixなど各種サービスは停止した状態です。そのため、上記のようなエラーが出ます。

mailserver.env定義の有無で挙動を変えるため、docker-compose runで破壊的な問題が出ないという可能性が0ではないです。そのため、docker-composeでのsetup実行は令和4年2月時点ではやめておいたほうが良い、という結論になりました。