PlantUML サーバーの Docker コンテナをオンデマンドで起動する

tl;dr

  • VSCode の PlantUML 拡張は便利だがデフォルトでは遅い (JVM 起動や各種 class ファイルのロードに時間がかかる?)
  • PlantUML サーバーをローカルで起動することで高速化可能
  • PlantUML のようなたまにしか使わないサービスを常時起動させておくのはなんとなく嫌
  • 本記事では特定のポートにアクセスがあった時点で PlantUML を起動するための設定方法を記す

使うもの

  • systemd
  • docker

手順1: PlantUML Docker サービスを systemd サービス化する

systemctl コマンドで PlantUML サーバーを起動できるようにします。 以下では TCP 51000番ポートを PlantUML サーバーへ割り当てます。

# unit ファイルの作成
$ sudo -E systemctl edit --force --full docker-plantuml.service

エディタが開くので以下を入力。

[Unit]
Description=PlantUML Server Container
After=docker.service
Requires=docker.service

[Service]
TimeoutStartSec=0
Restart=always
ExecStartPre=-/usr/bin/docker stop %n
ExecStartPre=-/usr/bin/docker rm %n
ExecStartPre=/usr/bin/docker pull plantuml/plantuml-server
ExecStart=/usr/bin/docker run --rm --name %n -p 51000:8080 plantuml/plantuml-server
ExecStartPost=/usr/bin/wget --quiet --method HEAD --waitretry 0.1 --tries 600 --retry-connrefused http://localhost:51000

[Install]
WantedBy=multi-user.target

参考にしたサイト では nc -z $host $port でサービス起動を待ち合わせていましたが、 PlantUML サーバーの場合は TCPポートへ connect(2) できるようになってから (コンテナが起動してから?) HTTP サーバーが応答を返せるようになるまで10秒弱程度のタイムラグがあるようなので、 wget(1) でポーリングするようにしています。

手順2: ソケット接続時に docker-plantuml サービスを起動する

systemd には socket activation という特定のポートへの接続があった時にサービスを起動するような仕組みがあります。 この仕組みを使うためにはは、起動されるサービス側が socket activateion に対応している必要があり、 残念ながら Docker は対応していません。

socket activation に対応したプロキシである systemd-socket-proxyd を利用し、 特定のポートへの接続と Docker の listen(2) しているポートへの接続を仲介することで、 特定の TCP ポートに接続があった時に Docker コンテナを起動させることができます。

以下では、 TCP 50000 番ポートへ connect(2) された場合に、 PlantUML のサービス (TCP 510000番) へ転送するように設定しています。

$ sudo -E systemctl edit --force --full docker-plantuml-proxy.socket

エディタが開くので以下を入力。

[Socket]
ListenStream=50000

[Install]
WantedBy=sockets.target
$ sudo -E systemctl edit --force --full docker-plantuml-proxy.service

エディタが開くので以下を入力。

[Unit]
Requires=docker-plantuml.service
After=docker-plantuml.service

[Service]
ExecStart=/usr/lib/systemd/systemd-socket-proxyd 127.0.0.1:51000

最後に、 docker-plantuml-proxy.socket を有効化 & 起動してください。

$ sudo systemctl enable docker-plantuml-proxy.socket
$ sudo systemctl start docker-plantuml-proxy.socket

手順3: VSCode の設定

以下のように設定すればOK!

{
    "plantuml.render": "PlantUMLServer",
    "plantuml.server": "http://localhost:50000/"
}

手順4: 動作確認

VSCode で PlantUML ファイルを開きプレビューすると、 PlantUML サーバーが起動してレンダリングされるはずです。

参考にしたサイト: