大体イメージは Docker Hub に上がってることが多いので、個人的には Dockerfile 書くのは php の拡張を入れる時くらいしかないです。ただ、postfix は公式のイメージがなさそうなので、最初から作ってみることにしました。ひとまずメール送るだけの postfix を立てます。
Dockerfile (イメージ)作るときにやることとしては以下だと思います。
- ベースのイメージを指定
- 必要なパッケージ入れる
- コンテナ起動時のスクリプトを書く
- ログを標準出力に出すよう変更
- 設定ファイルの差し込み
作成した Dockerfile はこんな感じです。
FROM alpine:latest
EXPOSE 25 465 587
RUN apk add --update --no-cache ca-certificates postfix postfix-pcre \
mailx shadow cyrus-sasl-login cyrus-sasl-plain
ADD run.sh /run.sh
RUN chmod +x /run.sh
CMD ["/run.sh"]
run.sh
は以下です。
#!/bin/sh
update-ca-certificates
newaliases
postfix start-fg
イメージ作成のコマンドです。Dockerfile と run.sh と同じフォルダで実行します。
buildah bud -t my-postfix .
ベースのイメージを指定
ベースイメージは最近の流行りに乗って alpine です。軽量な Linux ということで、コンテナ界隈で人気があります。パッケージマネージャーは apk というコマンドです。
必要なパッケージ入れる
ca-certificates | ルート証明書を入れる |
postfix | postfix 本体 |
postfix-pcre | 設定ファイルで正規表現使う場合必要 |
mailx | メールの送信テスト用 |
cyrus-sasl-login | SASL を有効にする場合に必要 |
cyrus-sasl-plain | SASL を有効にする場合に必要 |
コンテナ起動時のスクリプトを書く
update-ca-certificates
証明書を更新します。定期的に実行しないと有効期限切れそうですがとりあえず起動時に。ホストの証明書入ってるディレクトリマウントした方が早いかもしれないです。
newaliases
postfix に aliase という機能があるのですが、要は転送設定ですね。webmaster@~~ に届いたメールは root@~~ に転送するといった感じです。設定書き換えた場合はこのコマンドを叩く必要があります。
postfix start-fg
postfix を立ち上げる時は foreground で実行します。バックグラウンドに行くとコンテナが片付けられてしまうためです。
ログを標準出力に出すよう変更
本来はイメージ作成の段階で設定するべきなのですが、 postfix の設定ファイルの都合上コンテナ立ち上げ時に行います。
設定ファイルの差し込み
こちらもイメージ作成時に仕組みを作るべきなのですが、スキップします。デフォルト設定をイメージに入れておいて、変更したい設定のみをコンテナ立ち上げ時に指定する仕組みです。
設定ファイルの作成
まずは標準のファイルを持ってきます。podman で試していますが、 docker でも動くはずです。
mkdir -p /srv/postfix/conf/
cd /srv/postfix/conf/
podman run -d --name tmp-postfix localhost/my-postfix
podman cp tmp-postfix:/etc/postfix/aliases .
podman cp tmp-postfix:/etc/postfix/main.cf .
podman cp tmp-postfix:/etc/postfix/master.cf .
podman rm -f tmp-postfix
設定ファイル書き換え
main.cf に以下を追記します。
# コンテナ用設定
mynetworks = 127.0.0.0/8 10.88.0.0/16
maillog_file = /dev/stdout
# ホスト名まわり
myhostname = mx1.example.com
mydomain = example.com
inet_interfaces = all
mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain
# セキュリティまわり
disable_vrfy_command = yes
smtpd_sasl_auth_enable = yes
smtpd_sasl_security_options = noanonymous
smtpd_sasl_local_domain = $myhostname
smtpd_sender_restrictions = reject_unknown_sender_domain
コンテナとして立ち上げる際に重要なのは上の2行です。後半は環境に応じて設定してください。
mynetworks には CNI の IP アドレスの範囲を指定する必要があります。以下のコマンドで取得可能です。ネットワーク名は postfix のコンテナと postfix を利用するコンテナが所属するネットワークに置き換えてください。Docker はデフォルトだと 172.17.0.0/16
、Podman は 10.88.0.0/16
です。
podman network inspect podman | grep subnet
docker network inspect bridge | grep subnet
これを指定しないと他のコンテナから sendmail とか mail コマンドを利用する際に認証エラーとなりました。ローカルからの場合は認証を迂回できるのですが、コンテナの IP をここに追加してあげないとローカル判定されず、認証を回避できません。
maillog_file には標準出力を指定しています。ホスト側で podman logs や docker logs を使って確認できるようにするためです。
コンテナ立ち上げ
podman run --detach \
--publish 25:25 --publish 587:587 \
--name postfix \
--restart always \
--volume /srv/postfix/conf/main.cf:/etc/postfix/main.cf \
--volume /srv/postfix/conf/master.cf:/etc/postfix/master.cf \
--volume /srv/postfix/conf/aliases:/etc/postfix/aliases \
localhost/my-postfix
こちらのコマンドで立ち上がります。内部から外へのメール送信は確認しました。外部からの受信は試していません。
メールの送り方
ホストからコマンドを叩く場合は以下のようになります。
# /usr/bin/podman exec -it postfix sendmail -t
From: root@localhost
To: root@localhost
Subject: 件名
本文
.
sendmail コマンドを使うプログラムに /usr/sbin/sendmail -t
が指定してあったので、これを /usr/bin/podman exec -i postfix sendmail -t
に置き換えたらメール送信されました。端末から試す場合は-it
オプション、プログラムから標準出力でメール内容を渡す場合は-i
オプションだけ付け忘れないようにしましょう。
他のコンテナから送る場合、 Alpine Linux ならば以下のように指定すれば送れます。
# export SMTPHOST=10.88.0.1:25
# sendmail -t
From: root@localhost
To: root@localhost
Subject: 件名
本文
.
busybox に入っている sendmail を使えば SMTP 経由で送れます。IP は環境に合わせて置き換えてください。
その他ディストリビューションだと、 null クライアント(メール送信専用)として postfix 立てないと sendmail コマンド使えないので、 postfix をコンテナで切り出した意味を見失いそうです。
まとめ
postfix はメール送信クライアント(sendmail コマンド)としての役割もあるので、コンテナ単体で立ち上げるというより各コンテナに入れるもののような気がしてきました。
ただ、 postfix の設定も大変ですし、各コンテナに入れるには多機能すぎます。リレーとか SMTP サーバーとか MTA 機能は不要なんですよね。postfix は1個所にまとめて、コンテナ側は SMTP に対応するのが理想でしょうか。大体ホスト側に postfix 入れると思うので、そこに SMTP 接続する構成がよさそうです。