Turborepo + PNPM + Remixで構成されたアプリケーションをFly.ioにデプロイする
Turborepoでmonorepo構成で、パッケージマネージャーはpnpm、アプリケーションのフレームワークにはRemixを採用したアプリケーションをFly.ioにデプロイするのに苦労しました。
Fly.ioのRun a Remix Appや、Monorepo and Multi-Environment Deploymentsなどの記事もあるし、なんか情報あるだろうと思っていたら全然なかった…。
サンプル
サンプルコードを用意しました。
polidog/turborepo-pnpm-remix-fiyio-deploy-example
そもそもflyioがpnpmに対応していない
flyioにはfly(flyctl)コマンドが用意されています。
たとえば apps/web
というremixアプリを作成して、fly launchします。
|
|
fly launchを実行すると以下のファイルが作成されます。
- dockerignore
- fly.toml
- Dockerfile
ここで生成されたDockerfileはremixアプリの実行環境なわけですが、pnpmには対応できてません。
|
|
おそらく flyctl/scanner/node.go
のこのあたりのコードをみるとpnpmではなくyarn or npmなのでおそらく対応できてないかなと思います。
https://github.com/superfly/flyctl/blob/c37a567828b464eb097defdf01f30ef0bb732884/scanner/node.go#L83-L93
しかもこれだとmonorepoにも対応できてません。
Dockefileを自分で用意する
ということで、自分でDockerfileを修正していくことにしました。 ベースはfly launchで生成されたdockerfileを修正しています。
|
|
修正内容
今回はbase,setup,build,runnerという4つのステージを用意してます。
ステージ | 内容 |
---|---|
base | 全体のイメージ共通での設定 |
setup | パッケージインストール、ビルド前にすること |
build | パッケージインストール、ビルド |
runner | 実行環境 |
という形で分けています。
turbo pruneについて
setupのステージで turbo prune --scope=web --docker
コマンドを実行してプルーニングしています。
プルーニングとは?
プルーニングとは、ビルド キャッシュの過成長を効率的に自動的に削除するプロセスです。プルーニングは、ロック ファイル内の依存関係のプルーニングを含め、monorepo のサブセットを作成します。
出典: What is Turborepo and Why Should You Care?
turbo pruneの場合、指定したscopeに最適化されたmonorepoが生成されます。
試しに手元で実行してみると outというディレクトリが作成されます。
|
|
apps/web
が依存しているパッケージを中心にmonorepoがoutディレクトリの中に生成されています。
dockerオプション
turbo pruneにはdockerオプションがあります。 これはDocker環境でビルドするときにDockerのキャッシュを最適にするために必要なオプションになります。
キャッシュの効率化については、以下の記事を参考にしていただければと思います。
- [How can I use the cache efficiently?](https://docs.docker.com/build/cache/#order-your-layers_
- Docker レイヤー キャッシュ(DLC) で高速なDockerビルドを理解。
雑に言ってしまえば、変更が入りやすいものはなるべくDockerfileの後ろにもっていくほうがいいということでいいのかな?
パッケージインストールまでを先に行って、ソースコードのCOPYを行うことで効率的にDockerのキャッシュが使えるということかと思います。
Runnerステージについて
一度Buildしてしまえばnode_modulesはいらなくなるのかなと思っていましたが、そうでもなかったです。
flyioの場合 remix-serve build
がproductionで実行されますが、結局nodeのランタイムで動くのでnode_modulesが必要になってしまいます。
ただしruntimeに必要なものだけになるのでdevDependenciesが必要なわけではないので --prod
オプションを付けています。
NODE_ENV=prodctionなんでいらない気もしますが、わざと明示的につけています。
|
|
サーバ側のランタイムで必要なnode_modulesだけをインストールしたかったんですが方法が見つからないので諦めました。
.dockerignoreについて
プロジェクトルートにdockerignoreを配置する必要があります。
node_modulesをignoreしたいのですが (apps|packages)/xxxx/node_modules
を拒否したいの **
を使って指定します。
(.gitignoreとちょっと違うの辛い…)
|
|
node_moduelsをignoreしないとビルド途中にエラーになります。
|
|
デプロイする
プロジェクトルートからfly deployコマンドを実行します。
|
|
Dockerイメージのサイズについて
どうしてもDockerイメージが1GBを超えてしまう。。。どうにかならないものか。。。。
最後に
自分のフロントエンド力とかDocker力が低いのでまだまだ改良の余地があるかと思います。
ただ現状これでfly.ioで動かすことはできました。
変更したほうが良い箇所があったら、教えていただけると本当に助かります。