Protobufをマウントする方法
Dockerで新たにWebアプリケーションをデプロイするときに、コンテナ間でファイルを共有するにはどうすればよいでしょうか。
正解はvolume
を使うのが一般的な解答ではあるのですが、必ずしもそれが正しいとは限らないこともあります。
gRPCを使うときにprotobuf形式のファイルを相互のコンテナ間で共有したいと考えました。
Gitリポジトリからクローンして、そのフォルダのなかでdocker-compose build
を実行して、docker-compose up
をするだけなら以下のように書けば問題ありません:
version: '3.8'
services:
foo:
volumes:
- ./hello.proto:/foo/hello.proto
bar:
volumes:
- ./hello.proto:/bar/hello.proto
しかしGitリポジトリからクローンするのであればDockerでなければならない理由はない気がします。
というのも、この構成だと水平スケーリングができません。
今の所私の環境はオンプレミスなので水平スケーリングをできる状況にはないことも事実ではありますが、やはりDockerを使う以上はDockerレジストリからコンテナをpullしてきて、そのコンテナを実行したいと思っています。
そうすると、上記のdocker-compose.yml
は使えません。なぜならhello.proto
というファイルは存在しえないからです。
もちろんAnsibleを利用して予めprotoファイルをサーバーに配置して、絶対パスで指定する方法も取れなくはありません。
ですが、この方法もやはり毎回Ansibleが必須になってしまうので残念ながら没にせざるをえません。
そんな状況で最初のvolume
に頼る方法が必ずしもうまくいくとは限らないわけ。
あらかじめdockerでデプロイする前にvolume
を作成しておいて、external
を指定して各コンテナで共有するというのもよいアイディアではあるのですが、protobufは永続性のあるデータではなくてむしろ毎回のビルドごとに確実に更新してほしいファイルです。
そこで、最終的に思いついたアイディアとしてはDockerfileのステージを利用する方法を思いつきました。
FROM registry.example.com/user/foo AS foo
FROM node:latest
# ...
COPY --from=app /app/protos/hello.proto /bar
このように書くとhello.proto
はfooにあるprotobufをbarでも共有できることに気づきました。
しかももとのイメージにも影響はなくて単純にファイルをCOPY
するだけだからレイヤーこそ増えてしまうものの無駄なものではありません。
言葉で説明するのはなかなか難しいですが、この方法はなかなかよい解決策だと思いました。
もちろんコンテナのビルドはなるべく他に影響を与えないことが好ましいとは思いますが、同じプロジェクト間で使いまわすなら問題はないかと思っています。
実際にデプロイしてみたところ、現時点では意図したとおりに動いてくれています。
Dockerにも限りませんが、何かしらこういった抜け道や、その方法を実現するのにただしそうな方法が見つかるのは気持ちが良いものです。