🐳

[DevBase]TraefikとDnsmasqでDockerのWeb開発環境(TLSとSMTPもあるよ)もうポート番号割り当てで悩まない

2022/11/04に公開

この記事はDevBaseの紹介記事です。

https://github.com/arkbig/devbase

仕組みの説明はZennの本としてまとめましたので、ぜひそちらもみてください。ところどころの説明は解説本へのリンクにしています。

https://zenn.dev/arkbig/books/devbase-2022_b1b24e6e8db350a1f7f379af3833e90d79ad5

表紙

DevBase機能概要

  • TraefikとDnsmasqを使用して、ホスト名でコンテナにアクセスできます。
    • ポート番号の割り当てに悩む必要はありません!
  • MailHogを使って、ダミーメールの送信確認ができます。
    • 社内SMTPに大量メールを送りつけて怒られることもありません!
  • Exim4を使って、特定ドメインのみ正規SMTPへ転送します。
    • 社内利用を想定していて、間違えたアドレスを指定して情報漏洩することはありません。
  • OpenSSLを使って自己認証局&自己証明書を作ります。
    • 本番環境同様にhttpsアクセスができます。

Traefik Dashboard画面
Traefik Dashboard

使用ソフトウェア

DevBaseはDockerTraefikDnsmasqMailHogExim4OpenSSLsocatを使ったWeb開発環境基盤です。

ツール 提供サービス
Docker コンテナ環境としてDocker Engineを利用。
コンテナを使うとホストの環境が汚れないし、他マシンへのポータビリティも高いのでなるべく使うようにしています。
いずれはクラウドを意識してKubernatesを勉強し、Dockerなしで環境を構築したいところです。
OpenSSL 自己認証局・証明書を作るためOpenSSLを利用。
マルチドメイン&ワイルドカードに対応した証明書を作成し、ブラウザからアクセスで警告が出ないようにします。
OpenSSLの勉強としてコマンドを直接叩いていますが、世の中にはmkcertという便利なツールもあるようです。
Dnsmasq 簡易DNSとしてDnsmasqを利用。
"*.test"の名前解決をして、ホストのIPアドレスを返すようにします。
もし"http://*.localhost/"だけであればChromeを使えばDNS不要です。(Safariはダメでした)
socat UDPトンネルとしてsocatを利用。
ColimaのSSHトンネルがUDPに対応していなかったので、回避策とします。
TCPトンネルのように自動でできるようになると便利ですが、そこまでの機能はまだありません。
Traefik リバースプロキシとしてTraefikを利用。
"*.dev.test"のホスト名から対象のサービスを切り替えるようにします。
MailHog Fake SMTPとしてMailHogを利用。
ダミーメールボックスとしてブラウザからメールを読めるようにします。
Exim4 SMTPリレーとしてExim4を利用。
特定ドメイン宛のみ正規SMTPへリレーして、それ以外はMailHogにリレーします。

動作確認した環境

🍎Mac 🪟Windows 🐧Linux
OS macOS Monterey (12.3) Windows 10 Home (21H2) Ubuntu 20.04.4 LTS
マシン Mac mini (M1, 2020) CHUWI LakeBox Pro (Celeron J4125) WSL2
仮想マシン Colima version 0.3.4 WSL2 Ubuntu 20.04.4 LTS -
Docker client: v20.10.13
server: v20.10.11
client: v20.10.14
server: 20.10.14
client: v20.10.14
server: 20.10.14

LinuxはWSL2上のUbuntuでしか確認していませんが、ほかのLinuxでも動くといいな。(パスは読み替える必要がありそう)

Dockerセットアップ

Dockerセットアップが終わっていなければ、解説本のDockerの導入と各種設定の章をご確認ください。
docker、composeプラグインのインストールのほか、(説明しているプラットフォームが限られていますが)次のものが書いてあります。

リポジトリクローン

リポジトリをクローンします。(もしWindowsならWSL2上でクローンする)

git clone https://github.com/arkbig/devbase.git
cd devbase

compose.yaml

https://github.com/arkbig/devbase/blob/main/compose.yaml

これを使うため個人環境に合わせて設定をしていきましょう。

.env

sample.envファイルをGit管理外の.envファイルにコピーします。

cp sample.env .env

そして.envファイルの内容を自分の環境に合わせて変更します。変更内容についてはこの後各プラットフォームごとにまとめています。

🍎Macユーザー

【クリックで展開】Mac向けの個人設定。

CONTAINER_UID / CONTAINER_GID の変更

次のsedコマンドでCONTAINER_UID / CONTAINER_GIDを書き換えます。MacデフォルトのBSD版とLinuxのGNU版で-iオプションが違うので注意が必要です。

sed -i "" "s/^CONTAINER_UID=.*/CONTAINER_UID=$(id -u)/" .env
sed -i "" "s/^CONTAINER_GID=.*/CONTAINER_GID=$(id -g)/" .env

DNSMASQ_ADDR / DNSMASQ_SERVER

次のsedコマンドでDNSMASQ_ADDRを書き換えます。en0インタフェースを使っている例です。

use_eth=en0
sed -i "" "s/^DNSMASQ_ADDR=.*/DNSMASQ_ADDR=$(ifconfig "${use_eth}" |grep 'inet '|awk 'END {print $2}')/" .env

DNSMASQ_ADDRはドメインがDNSMASQ_DOMAINのDNS問い合わせ時に返答するアドレスです。

そして、Macでは使われませんがDNSMASQ_SERVERは次のワンライナーで書き換えられます。(Macは"*.test"ドメインのみDnsmasqへ問い合わせする設定にできるため)

sed -i "" "s/^DNSMASQ_SERVER=.*/DNSMASQ_SERVER=$(cat /etc/resolv.conf|grep '^nameserver '|awk 'NR==1 {print $2}')/" .env

EXIM4_RELAY_DOMAIN / EXIM4_RELAY_ADDR

必要に応じてEXIM4_RELAY_{DOMAIN,ADDR}を設定します。
これはExim4で受信したメールのうち、宛先がEXIM4_RELAY_DOMAINだったらEXIM4_RELAY_ADDRへ転送するのに使われます。

複数のEXIM4_RELAY_DOMAINが必要なら、.envではなくcompose.override.yamlで次のように設定します。

compose.override.yaml
services:
  exim4:
    environment:
      EXIM4_RELAY_DOMAIN: your-company.com
      EXIM4_RELAY_ADDR: smtp.your-company.com::25
      # 無印を0として連番
      EXIM4_RELAY_DOMAIN_1: your-company.co.jp
      EXIM4_RELAY_ADDR_1: smtp.your-company.co.jp::465
      # どちらかに「-」が指定されると、その番号はスキップ
      EXIM4_RELAY_DOMAIN_2: - #your-company.jp
      EXIM4_RELAY_ADDR_2: smtp.your-company.jp::465
      # 連番が途切れるまで続く
      EXIM4_RELAY_DOMAIN_3: your-company.co.jp
      EXIM4_RELAY_ADDR_3: smtp.your-company.co.jp::587

COMPOSE_PROFILES

Colima環境ならUDPトンネルを自前で用意する必要があります。
一応ここまでの設定でdocker compose up -dと起動して、sudo lsof -i:53でUDPの有無を確認してみてください。

sudo lsof -i:53
COMMAND PID USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
ssh     719  big   18u  IPv4 0x764ac823d019058d      0t0  TCP *:domain (LISTEN)

NODEの列にUDPがないので、自前のUDPトンネルを動かします。そのために、.envファイルにCOMPOSE_PROFILES=sslcert,udptunnelとしてデフォルトで有効にします。

🪟Windowsユーザー

【クリックで展開】Windows向けの個人設定。

CONTAINER_UID / CONTAINER_GID の変更

次のsedコマンドでCONTAINER_UID / CONTAINER_GIDを書き換えます。MacデフォルトのBSD版とLinuxのGNU版で-iオプションが違うので注意が必要です。

sed -i "s/^CONTAINER_UID=.*/CONTAINER_UID=$(id -u)/" .env
sed -i "s/^CONTAINER_GID=.*/CONTAINER_GID=$(id -g)/" .env

DNSMASQ_ADDR / DNSMASQ_SERVER

DNSMASQ_ADDRは、この後のWSL2へ付与する固定IPアドレスを書きますが、変更しないならデフォルトの192.168.100.100でいいです。

DNSMASQ_SERVERの書き換えはいいワンライナーが見つからなかったので、手動で設定します。
Windowsの「ネットワーク接続」で使用するアダプターからDNSサーバーを確認してください。
通常はコマンドプロンプトの「ipconfig」で表示されるDefault Gatewayと同じです。

参考:https://www.buffalo.jp/support/faq/detail/15844.html

EXIM4_RELAY_DOMAIN / EXIM4_RELAY_ADDR

必要に応じてEXIM4_RELAY_{DOMAIN,ADDR}を設定します。
これはExim4で受信したメールのうち、宛先がEXIM4_RELAY_DOMAINだったらEXIM4_RELAY_ADDRへ転送するのに使われます。

複数のEXIM4_RELAY_DOMAINが必要なら、.envではなくcompose.override.yamlで次のように設定します。

compose.override.yaml
services:
  exim4:
    environment:
      EXIM4_RELAY_DOMAIN: your-company.com
      EXIM4_RELAY_ADDR: smtp.your-company.com::25
      # 無印を0として連番
      EXIM4_RELAY_DOMAIN_1: your-company.co.jp
      EXIM4_RELAY_ADDR_1: smtp.your-company.co.jp::465
      # どちらかに「-」が指定されると、その番号はスキップ
      EXIM4_RELAY_DOMAIN_2: - #your-company.jp
      EXIM4_RELAY_ADDR_2: smtp.your-company.jp::465
      # 連番が途切れるまで続く
      EXIM4_RELAY_DOMAIN_3: your-company.co.jp
      EXIM4_RELAY_ADDR_3: smtp.your-company.co.jp::587

COMPOSE_PROFILES

Windows環境ならUDPトンネルは自前で用意しなくても大丈夫です。
一応ここまでの設定でdocker compose up -dと起動して、sudo lsof -i:53でUDPの有無を確認してみてください。

sudo lsof -i:53
COMMAND    PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
docker-pr 3076 root    4u  IPv4  22232      0t0  TCP *:domain (LISTEN)
docker-pr 3098 root    4u  IPv4  23870      0t0  UDP *:domain
#(IPv6は省略)

NODEの列にUDPがあるので、自前のUDPトンネルは不要です。.envファイルはデフォルトのCOMPOSE_PROFILES=sslcertのままで大丈夫です。

🐧Linuxユーザー

【クリックで展開】Linux向けの個人設定。(動作確認したWSL2上のUbuntuの例です)

CONTAINER_UID / CONTAINER_GID の変更

次のsedコマンドでCONTAINER_UID / CONTAINER_GIDを書き換えます。MacデフォルトのBSD版とLinuxのGNU版で-iオプションが違うので注意が必要です。

sed -i "s/^CONTAINER_UID=.*/CONTAINER_UID=$(id -u)/" .env
sed -i "s/^CONTAINER_GID=.*/CONTAINER_GID=$(id -g)/" .env

DNSMASQ_ADDR / DNSMASQ_SERVER

次のsedコマンドでDNSMASQ_ADDRを書き換えます。sed GNU版でeth0インタフェースを使っている例です。

use_eth=eth0
sed -i "s/^DNSMASQ_ADDR=.*/DNSMASQ_ADDR=$(ip a show ${use_eth}|grep 'inet '|awk 'END {print $2}'|awk -F '/' '{print $1}')/" .env

DNSMASQ_SERVERの書き換えはいいワンライナーが見つからなかったので、手動で設定します。
cat /etc/resolv.confのnameserverの値です。(resolv.confはこの後書き換えるので間違えてループしないように注意)

EXIM4_RELAY_DOMAIN / EXIM4_RELAY_ADDR

必要に応じてEXIM4_RELAY_{DOMAIN,ADDR}を設定します。
これはExim4で受信したメールのうち、宛先がEXIM4_RELAY_DOMAINだったらEXIM4_RELAY_ADDRへ転送するのに使われます。

複数のEXIM4_RELAY_DOMAINが必要なら、.envではなくcompose.override.yamlで次のように設定します。

compose.override.yaml
services:
  exim4:
    environment:
      EXIM4_RELAY_DOMAIN: your-company.com
      EXIM4_RELAY_ADDR: smtp.your-company.com::25
      # 無印を0として連番
      EXIM4_RELAY_DOMAIN_1: your-company.co.jp
      EXIM4_RELAY_ADDR_1: smtp.your-company.co.jp::465
      # どちらかに「-」が指定されると、その番号はスキップ
      EXIM4_RELAY_DOMAIN_2: - #your-company.jp
      EXIM4_RELAY_ADDR_2: smtp.your-company.jp::465
      # 連番が途切れるまで続く
      EXIM4_RELAY_DOMAIN_3: your-company.co.jp
      EXIM4_RELAY_ADDR_3: smtp.your-company.co.jp::587

COMPOSE_PROFILES

Linux環境ならUDPトンネルは自前で用意しなくても大丈夫です。
一応ここまでの設定でdocker compose up -dと起動して、sudo lsof -i:53でUDPの有無を確認してみてください。

sudo lsof -i:53
COMMAND    PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
docker-pr 3076 root    4u  IPv4  22232      0t0  TCP *:domain (LISTEN)
docker-pr 3098 root    4u  IPv4  23870      0t0  UDP *:domain
#(IPv6は省略)

NODEの列にUDPがあるので、自前のUDPトンネルは不要です。.envファイルはデフォルトのCOMPOSE_PROFILES=sslcertのままで大丈夫です。

オレオレ証明書を作成

TraefikでHTTPS通信するために、compose.yamlに書いたsslcertサービスでオレオレ認証局&証明書を作成します。
詳しくは解説本のオレオレ証明書の作成とOSへの登録の章をご確認ください。

mkdir sslcert/.certs
docker compose build sslcert
docker compose run --rm sslcert
# Ctrl-Cで停止してください

sslcert/.certsにオレオレ認証局とオレオレ証明書ができています。

自己証明書の有効期限は60日としています。これは、sslcertサービスを起動するように(COMPOSE_PROFILES=sslcertを指定)していれば、自動で更新されます。ただし、Colimaではバインドファイル変更の動的検知が正しくできないようなのでご注意ください。
期限が切れた場合は、docker compose restartすると反映されます。もしPCを毎日シャットダウンしていれば、Docker起動時にrestartされるのでそのタイミングで更新されます。

オレオレ認証局を信頼

ブラウザでHTTPSアクセスしたとき警告が出ないように、compose.yamlに書いたsslcertサービスで作成したオレオレ認証局を信頼します。

🍎Macユーザー

【クリックで展開】Mac向けのCA証明書の信頼方法。
  1. Finderからsslcert/.certs/ca-My-Test.cerを開くと、キーチェーンが起動します(ログイン項目にインストール)
    • キーチェーンに追加した証明書の情報を見る
    • 「信頼」の項目を「常に信頼」に設定する
      キーチェーンへ追加
  2. ウィンドウを閉じるとユーザーパスワードが求められ、登録完了
    • 赤色の×マークから青色の+マークに変わればOK 登録完了

🪟Windowsユーザー

【クリックで展開】Windows向けのCA証明書の信頼方法。
  1. WSL2側でexplorer.exe sslcert/.certsを実行するとExplorerが起動します
    • Explorerからsslcert/.certs/ca-My-Test.cerを開く
    • 「証明書のインストール」をクリック
    • 「次へ」をクリック(保存場所はどちらでも)
      証明書のインストール
  2. 証明書のインポートウィザードが開きます
    • 「証明書をすべて次のストアに配置する」を選んで、参照から「信頼されたルート証明機関」を選択
    • 「次へ」をクリックすると確認ダイアログが出るので「OK」で進めると登録完了
      証明書のインポートウィザード
  3. 登録できたかは「ユーザー証明書の管理」か「システム証明書の管理」(登録したほう)から確認できます
    登録確認

WSL2側も登録しておきます。

sudo mkdir /usr/share/ca-certificates/self
sudo cp ./sslcert/.certs/ca-My-Test.cer /usr/share/ca-certificates/self/
sudo echo "self/ca-My-Test.cer" >> /etc/ca-certificates.conf
sudo update-ca-certificates

🐧Linuxユーザー

【クリックで展開】Linux向けのCA証明書の信頼方法。(動作確認したWSL2上のUbuntuの例です)
sudo mkdir /usr/share/ca-certificates/self
sudo cp ./sslcert/.certs/ca-My-Test.cer /usr/share/ca-certificates/self/
sudo echo "self/ca-My-Test.cer" >> /etc/ca-certificates.conf
sudo update-ca-certificates

DNSサーバーの登録

Traefikで使う"*.dev.test"ワイルドカードドメインを解決するために、compose.yamlに書いたdnsmasqサービスを使うようOSに登録します。
詳しくは解説本のDnsmasqの構築とOSへの登録の章をご確認ください。

🍎Macユーザー

【クリックで展開】Mac向けのDNS設定。

resolverに登録

Macの場合は/etc/resolver/でドメインごとにDNSサーバーを設定できます。ここでは「test」ドメインを登録します。(ドメインがファイル名になる)

sudo mkdir /etc/resolver
sudo vi /etc/resolver/test
/etc/resolver/test
options timeout:1
options attempts:2
options use-vc
nameserver 127.0.0.1

udptunnelを起動

自前のUDPトンネルを使う場合は次のコマンドで実行します。.envにCOMPOSE_PROFILES=sslcert,udptunnelでコンテナ側の起動設定も忘れずに。
詳しくは解説本のsocatを使用したUDPトンネルの章をご確認ください。

brew install socat
./udptunnel/forward_udp.sh ./udptunnel/udp_forwarding.conf &

これはバックグラウンド起動します。psコマンドで起動しているプロセスが見られます。
解説本のColimaの起動スクリプト同様、devbase/udptunnel/forward_udp.sh devbase/udptunnel/udp_forwarding.conf &を起動時に実行するように登録しましょう。

ps
 PID TTY           TIME CMD
:
1001 ttys001    0:00.06 sh /Users/big/proj/devbase/udptunnel/forward_udp.sh /Users/big/proj/devbase/udptunnel/udp_forwarding.conf
2002 ttys001    0:10.73 sh /Users/big/proj/devbase/udptunnel/loop_cmd.sh socat -s UDP4-RECVFROM:53,reuseaddr TCP:127.0.0.1:1053
3003 ttys001    0:00.01 socat -s UDP4-RECVFROM:53,reuseaddr TCP:127.0.0.1:1053
:

これらのプロセスを一気に終了させるにはkillオプションを指定します。

./udptunnel/forward_udp.sh ./udptunnel/udp_forwarding.conf kill

🪟Windowsユーザー

【クリックで展開】Windows向けのDNS設定。

WSL2へ固定IPアドレス付与

WindowsからWSL2へ通信するためのブリッジがありますが、IPアドレスが固定ではないようです。そのため、先にWSL2へ固定IPアドレスを付与します。

wsl2/wsl_assign_ip.batを管理者権限で実行しますが、その前に個人設定をします。

cp wsl2/wsl_env.bat wsl2/.wsl_env.bat

.wsl_env.batのDNSMASQ_SERVERを.envに書いた$DNSMASQ_SERVERと同じ値を設定します。
ここに書かれた値を使って、固定IPアドレスが付与されます。

WSL2側でexplorer.exe wsl2を実行するとExplorerが起動しますので、wsl_assign_ip.batを管理者権限で実行します。

ネットワークアダプターのDNS設定

次にWindows側で使用するネットワークアダプターのDNS設定をします。上記バッチの「vEthenet (WSL)」にDNSサーバーを設定している部分と同じ方法でも可能ですが名前が各自違うのでGUI操作を示します。

  1. ネットワーク接続から使用しているアダプターのプロパティを開く
  2. インターネットプロトコルバージョン4(TCP/IPv4)のプロパティを設定
  3. 「次のDNSサーバーのアドレスを使う」で
    1. 優先DNSサーバーに「192.168.100.100」(上記%DNSMASQ_ADDR%)
    2. 代替DNSサーバーは自分のDNSサーバー(.envの$DNSMASQ_SERVER)

ネットワーク接続

WSL2側のresolv.conf設定

そしてWSL2側のDNSサーバーの設定もしましょう。WSL2上では/etc/resolv.confを利用しますが、これは自動生成されるものです。
まずは/etc/wsl.confに自動生成しないように制限します。

/etc/wsl.conf
[network]
generateResolvConf = false

次に/etc/resolv.confを書き換えますが、まずは自動生成されたファイルを削除してリンクを解除します。

sudo cp /etc/resolv.conf /etc/resolv.conf.bak
sudo rm /etc/resolv.conf
sudo mv /etc/resolv.conf.bak /etc/resolv.conf

そして/etc/resolv.confを次のように書きます。

/etc/resolv.conf
options timeout:1
options attempts:2
nameserver 127.0.0.1
# 以下は自分の環境に合わせて書き換える(.envの$DNSMASQ_SERVER)
nameserver 1.1.1.1

🐧Linuxユーザー

【クリックで展開】Linux向けのDNS設定。(動作確認したWSL2上のUbuntuの例です)

resolv.conf設定

/etc/resolv.confを次のように書きます。

/etc/resolv.conf
options timeout:1
options attempts:2
nameserver 127.0.0.1
# 以下は自分の環境に合わせて書き換える(.envの$DNSMASQ_SERVER)
nameserver 1.1.1.1

起動と動作確認

ここまでの設定が終わったらコンテナたちを起動します。

docker compose up -d

docker compose psで起動状況が確認できます。(初回は再度docker compose psが必要かも)
STATUSがrunningになっていないものがあれば、docker compose logs <サービス名>(<サービス名>はdnsmasqやtraefikです)でログが確認できます。

すべてのコンテナがrunningになれば次は動作確認です。

ブラウザでhttps://traefik.dev.test/にアクセスしてみてください。
うまく動いていればTraefikのダッシュボード画面が表示されます。

また、https://mailhog-devbase.dev.test/でMailHogのダミーメールボックスが表示されます。

他には次のサービスが起動しています。

  • http://hoge.dev.test/(hogeは任意の文字)にアクセスするとhttpsにリダイレクトされる。
  • TCP
    • 25番ポート(mailhog-devbase.dev.test:25)でFakeSMTPサーバーのMailHog
    • 53番ポート(dnsmasq-devbase.dev.test:53)でDNSサーバーのDnsmasq
    • 587番ポート(exim4-devbase.dev.test:587)でリレーSMTPサーバーのExim4
  • UDP
    • 53番ポート(dnsmasq-devbase.dev.test:53)でDNSサーバーのDnsmasq

Traefikの使用例

詳しくは解説本のTraefikでのTLSリバースプロキシの章をご確認ください。

docker runで起動するだけの例

docker run --rm -d --name caddyTest caddy

https://caddyTest.dev.test/でアクセス可能です。

caddyさんに退場してもらうにはdocker stop caddyTestで停止します(--rmつけて起動してたから)

ホスト名以外とmiddlewaresの例

compose.yaml ※Shift+マウスホイールで横スクロール
    labels:
      traefik.enable: true
      traefik.http.routes.cadvisor.entrypoints: https
      traefik.http.routes.cadvisor.rule: Host(`metrics.dev.test`) && PathPrefix(`/cadvisor/`)
      # faviconがサブディレクトリ対応してないので無理やり転送
      # ただし取得はできない(誤ったトップ階層のを取ってこないくらいの気持ち)
      traefik.http.routes.cadvisor-favicon.entrypoints: https
      traefik.http.routes.cadvisor-favicon.rule: Host(`metrics.dev.test`) && PathPrefix(`/favicon.ico`) && HeadersRegexp(`Referer`,`://metrics.dev.test/cadvisor/`)
      traefik.http.routes.cadvisor-favicon.middlewares: cadvisor-favicon-1
      traefik.http.middlewares.cadvisor-favicon-1.addprefix: /cadvisor/

rule&&を使ってand条件で複数指定できます。
ちなみにHost名を複数設定したい場合はHost(`hoge.dev.test`,`fuga-proj`)のようにカンマ区切りで指定もできます。

middlewaresで転送前にゴニョゴニョできます。ミドルウェアは別の場所で定義したものも参照できます。
Providerを跨いだ指定の場合はmy-basic-auth@fileみたいに名前の後に@fileとプロバイダ名をつければ参照できます。
複数サービスで共有するような認証設定などで使うと便利でしょう。

コンテナが複数のポートをEXPOSEしている例

compose.yaml ※Shift+マウスホイールで横スクロール
    labels:
      - traefik.enable=true
      # SMTP側
      - traefik.tcp.routers.mailhog.entrypoints=smtp
      - traefik.tcp.routers.mailhog.rule=HostSNI(`*`)
      - traefik.tcp.routers.mailhog.service=mailhog
      - traefik.tcp.services.mailhog.loadbalancer.server.port=1025
      # HTTPS側
      - traefik.http.routers.mailhog.entrypoints=https
      - traefik.http.routers.mailhog.service=mailhog
      - traefik.http.services.mailhog-${COMPOSE_PROJECT_NAME:-devbase}.loadbalancer.server.port=8025

routers.<name>.serviceでサービス名を指定し、services.<name>.loadbalancer.server.portに対応するポート番号を指定します。
もし<name>の部分が同じであれば、routers.<name>.serviceでサービス名を指定しなくても自動で対応付けされます。

TCPでTLS通信の例

TraefikでのTLS終端

compose.yaml
    labels:
      - traefik.enable=true
      - traefik.tcp.routers.mongo.entrypoints=mongodb
      - traefik.tcp.routers.mongo.rule=HostSNI(`mongo-proj.dev.test`)
      - traefik.tcp.routers.mongo.tls=true

TCPでホスト名を使ってサービス分岐したいだけの場合は.tls=trueとTLSを有効にすると、デフォルトの.tls.passthrough=falseになります。

パススルー

compose.yaml
    labels:
      - traefik.enable=true
      - traefik.tcp.routers.mongo.entrypoints=mongodb
      - traefik.tcp.routers.mongo.rule=HostSNI(`mongo-proj.dev.test`)
      - traefik.tcp.routers.mongo.tls.passthrough=true

TCPでサービス側までTLS通信したい場合は.tls.passthrough=trueでパススルーします。

PlantUMLサーバーを使う例

PlantUMLサーバーをローカルで立ち上げると、VS CodeのMarkdown preview enhanced拡張でUMLが描画でき便利です。

  1. ローカル変更用にブランチを切り替える(オプション)

    git checkout -b local
    
  2. compose.yamlにplantumlサービスを追加

    compose.yaml
      plantuml:
        image: plantuml/plantuml-server
        init: true
        restart: unless-stopped
        ports:
          - 127.0.0.1::8080
        labels:
          - traefik.enable=true
          - traefik.http.routers.plantuml-${COMPOSE_PROJECT_NAME:-devbase}.entrypoints=https
    
  3. 動作確認のためhttps://plantuml-devbase.dev.testにアクセス

  4. VS Codeの設定でPlantUMLサーバーのアドレスを入力

        "markdown-preview-enhanced.plantumlServer": "https://plantuml-devbase.dev.test/svg/"
    

これで、VS Codeのマークダウンでplantumlまたはpumlのコードブロックが描画されるようになります。

Markdown
```plantuml
@startuml
Bob -> Alice : hello
@enduml
```

カスタマイズについて

コンテナはcommand:でコマンドを指定したり、environment:で環境変数を渡したり、設定ファイルをvolumes:でマウントしたりすると挙動を変えることができます。

【クリックで展開】カスタマイズリスト。

コマンドのカスタマイズ

デフォルト設定とカスタム説明です。

  • dnsmasq:
    • デフォルト:"dnsmasq"
      • "dnsmas opts..."で指定もできるし、"opts..."だけの指定もできる
      • このオプションの前に$DNSMASQ_ARGS -A ... -S ...が自動付与されます
  • exim4:
    • デフォルト:"exim -bd -q10m -v"
      • "exim opts..."で指定もできるし、"opts..."だけの指定もできる
      • 指定されたオプションは加工せずそのまま使われる
  • mailhog:
    • デフォルト:""
      • ENTRYPOINTがMailHogですので、オプションが指定できる
  • sslcert:
    • デフォルト:"./generatecerts.sh"
      • ユーザーを切り替えて実行しています
      • 指定されたコマンドは加工せずそのまま使われる
  • traefik:
    • デフォルト:"traefik"
      • traefikのサブコマンド"healthcheck"と"version"が指定できる
  • udptunnel:
    • デフォルト:"./receive_udp.sh ./udp_forwarding.conf"
      • ユーザーを切り替えて実行しています
      • 指定されたコマンドは加工せずそのまま使われる

環境変数のカスタマイズ

デフォルト設定と説明です。

  • dnsmasq:
    • DNSMASQ_ARGS: "-h -k -n -R -u root -8 -" # Dnsmasqの起動引数
    • DNSMASQ_DOMAIN: .test # DNS登録するワイルドカードドメイン
    • DNSMASQ_ADDR: 192.168.100.100 # 名前解決したIPアドレス
    • DNSMASQ_DOMAIN_1: "" # 複数登録する場合は、連番で指定
    • DNSMASQ_ADDR_1: "" # "-"を指定すると、抜け番としてスキップ
    • DNSMASQ_SERVER: 1.1.1.1 # 登録したドメインではないときに使用するDNSサーバー
    • DNSMASQ_SERVER_1: "" # 複数登録する場合は、連番で指定
    • DNSMASQ_SERVER_2: "" # "-"を指定すると、抜け番としてスキップ
  • exim4:
    • EXIM4_SMARTHOST: mailhog::1025 # 通常の転送先(コロン2つなのに注意)
    • EXIM4_RELAY_DOMAIN: "" # 宛先がこのドメインなら特別な転送先へ送る
    • EXIM4_RELAY_ADDR: "" # 対応するドメイン時の宛先(コロン2つなのに注意)
    • EXIM4_RELAY_DOMAIN_1: "" # 複数登録する場合は、連番で指定
    • EXIM4_RELAY_ADDR_1: "" # "-"を指定すると、抜け番としてスキップ
  • mailhog:
  • sslcert:
    • CONTAINER_UID: 1000 # コマンド実行アカウントのユーザーID
    • CONTAINER_GID: 1000 # コマンド実行アカウントのグループID
    • CERTS_OUT: /certs # 証明書の出力フォルダ(コンテナ内パス)
    • CA_CN: "My Test" # 自己認証局の名称
    • CA_FILEBODY: $(normalized CA_CN) # 生成する自己認証局ファイルのbasename
    • CA_CERT: $CA_FILEBODY.cer # OSに登録する自己認証局の証明書ファイル名
    • CA_KEY: $CA_FILEBODY.key # 証明書発行時に使用する自己認証局の秘密鍵
    • CA_PASS: $CA_FILEBODY.pass # 秘密鍵の保存時の暗号パスワード(空文字なら平文保存)
    • CA_SUBJ: /CN=$CA_CN # 自己認証局の属性 /CN=が未指定なら自動で/CN=$CA_CNが付与される
    • SSL_CN: dev.test # 自己証明書の名称(古いシステム用のドメイン)
    • SSL_ADDEXT: "subjectAltName=DNS:test,DNS,dev.test,DNS:*.dev.test,DNS:localhost,DNS:dev.localhost,DNS:*.dev.localhost,IP:127.0.0.1" # SANsなど
    • SSL_FILEBODY: $(normalized SSL_CN) #生成するファイルの自己証明書のbasename
    • SSL_CERT: $SSL_FILEBODY.cer # サーバーに設定する自己証明書(公開鍵)
    • SSL_KEY: $SSL_FILEBODY.key # サーバーに設定する自己証明書の秘密鍵
    • SSL_CSR: $SSL_FILEBODY.csr # 認証局への署名リクエストファイル(手抜きなので本番には使えない)
    • SSL_PASS: "" # 自己証明書の保存時の暗号パスワード(空文字なら平文保存)
    • SSL_SERIAL: $SSL_FILEBODY.srl # 自己証明書のシリアル番号保存ファイル
    • SSL_SUBJ: /CN=$SSL_CN # 自己証明書の属性 /CN=が未指定なら自動で/CN=$CA_CNが付与される
  • traefik:
    • なし
  • udptunnel:
    • CONTAINER_UID: 1000 # コマンド実行アカウントのユーザーID
    • CONTAINER_GID: 1000 # コマンド実行アカウントのグループID

設定ファイルのカスタマイズ

  • dnsmasq
    • /etc/dnsmasq.conf # デフォルトのまま使用
  • exim
    • /etc/exim4/exim4.conf.localmacros # exim4/exim4.conf.localmacrosがコンテナbuild時にコピーされる
    • /etc/exim4/exim4.conf.template # exim4/exim4.conf.templateがコンテナbuild時にコピーされる
    • /etc/exim4/update-exim4.conf.conf # exim4/update-exim4.conf.confがコンテナbuild時にコピーされ、dc_smarthostが$EXIM4_SMARTHOSTへ動的に変更される
  • mailhog:
  • sslcert
    • /etc/ssl/openssl.cnf # デフォルトのまま使用
  • traefik
    • /etc/traefik/traefik.yaml # traefik/が/etc/traefikへコンテナ起動時にバインドマウントされる
    • /etc/traefik/dynamic/*.yaml # traefik/が/etc/traefikへコンテナ起動時にバインドマウントされる
  • udptunnel
    • /home/udpstaff/udp_forwarding.conf # udptunnel/udp_forwarding.confがコンテナ起動時にバインドマウントされる

まとめ

arkbig/devbaseリポジトリを使とサービス開発の初速が速くなること間違いなし🎉。
Let's enjoy development!!

実装について気になる方は、解説本もぜひ読んでみてください。

Discussion