Posted at

Dockerコンテナ内部からホストのSMTPを利用したい

More than 3 years have passed since last update.

ちょっとハマったのでメモ書き。

綺麗な形での解決はしていないです。


目的

Docker のホスト側には Postfix が設置してある。

Dockerコンテナの内部アプリからメール送信をする際に、このホスト側の Postfix を利用したい。


環境の説明

ホストは Debian7 GNU/Linux で、そこに Docker を導入しました。

元々ホスト側には内部からの通知のために Postfix が設置してありました。この Postfix は外部の SMTP にリレーをするだけのサテライトサーバーという構成です。

主に Wordpress からの通知やコンソールエラーの通知といった内部の情報をメールで送信するためのもので、外部からのリクエストは全て遮断し、localhost のリクエストのみ受け付ける形になっています。


問題点

Docker は標準状態では仮想ネットワークポートを利用したブリッジ接続を行います。

これは便利で良いのですが、Docker コンテナはホストから見て他のマシンに見えてしまいます。

また Docker コンテナ内部は通常の DNS 経由でしか外の状況がわからないので、ブリッジ上のホストのアドレスが分からない様です。


課題


  1. ホスト側の Postfix が Docker コンテナからのリクエストを受け入れること

  2. Docker コンテナ内でホストを認識できること


やったこと


ホスト側で Docker コンテナからのリクエストに応える

# ip a と入力しインタフェース一覧を確認します。

3: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP 

link/ether 66:ed:33:97:db:48 brd ff:ff:ff:ff:ff:ff
inet 172.17.42.1/16 scope global docker0
inet6 fe80::6819:82ff:fe40:a9c5/64 scope link
valid_lft forever preferred_lft forever

何番目かは環境に因りますが、手元では docker0 という名前でブリッジインタフェースが割り当てられていました。

IPv4 アドレスでいうと 172.17.42.1/16 です。

ブリッジネットワークは 172.17.0.0/16 なので、Docker コンテナはここのどこかにいることになります。

これまでの Postfix の設定は 127.0.0.1 のみ受け付ける様になっていたのですが、172.17.0.0/16 もローカルと見なして受け付けるように設定します。

mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128, 172.17.0.0/16

inet_interfaces = 127.0.0.1, 172.17.42.1

ちょいとハマったのが inet_interfaces で、default だと loopback-only(=127.0.0.1) になっていました。これまでは合致していたので問題なかったのですが、今回の目的では明記してやる必要があります。

ずいぶんと昔は default で全インタフェースだったそうで、その頃の記憶があって悩んでいたようです。


コンテナ内部でホストのブリッジ上アドレスを知る

ホスト側の 172.17.42.1 というアドレスに向かってコンテナ内部から SMTP リクエストを投げてやれば今回の目的は達成です。

さて、ホストのアドレスをどうやって取得するのか。

ホストはインターネット接続されていて DNS も振ってあるのですが、コンテナ内部から DNS で得たアドレスにアクセスすると docker0 インタフェースではなく、外部と接続されている eth0 インタフェースからのリクエストと認識してしまいます。

Postfix は外部からのリクエストを塞ぎたいというポリシーで設定していますので、これでは Docker コンテナからのリクエストも弾いてしまします。

今ひとつ有効な手段が見つからなかったので、コンテナ起動時に環境変数としてIPアドレスを渡してやることにしました。

ホスト側で docker0 インタフェースのアドレスを得る方法もわからなかったので ip コマンドの出力結果から抽出しています。

# ip r | grep 'docker0' | awk '{print $9}'

Docker コンテナの起動時にこれを環境変数として渡してやります。

# docker run -d -e "SMTPHOST=`ip r | grep 'docker0' | awk '{print $9}'`"

Docker コンテナ内部では SMTPHOST という環境変数でホストのIPアドレスが利用できる様になります。


fig から行うにはどうすれば?

Docker コンテナの起動管理に fig を使い始めているのですが、fig ファイルで上記の様なコマンド結果を含めるにはどうしたら良いのでしょうか?

流石にコマンド実行&展開はしてくれませんでした。

  environment:

- SMTPHOST=`ip r | grep 'docker0' | awk '{print $9}'`

最終的には諦めて、今回は IPアドレスの固定値を渡してやることにしました。

  environment:

- SMTPHOST=172.17.42.1

まあ、そうそう変わる情報でもないだろうという妥協のもとに。