DockerでBunを使ってサーバーを立ててみた
はじめに
この記事では、JavaScriptランタイムであるBunをDockerコンテナ内で使う方法を紹介します。
その際、DockerからBunでサーバーを立ち上げ、ホストPCからアクセスするというのをやってみました。
Bunのホームページはこちら。
環境
- Docker 25.0.3
- VSCode 1.93.0
- Mac M1
やり方
やり方はいくつかあると思いますが、この記事では以下の方法を使います。
- Docker Composeを使用
- 公式から配布されているイメージを使用
また、exec
でコンテナに入れるようにします。
ざっくりとした手順はこちらです。
-
Dockerfile
にベースイメージを書く -
Dockerfile
にコンテナが終了しないためのコマンドを書く -
compose.yaml
に設定を書く - コマンドでコンテナを立ち上げる
Dockerfileを作成する
まずはプロジェクトルートに移動して、Dockerfile
を作成します。
ベースイメージを設定する
Bunの公式Dockerイメージはこちら。
今回はこのイメージを使ってコンテナを作成します。
Dockerfile
に以下を追記します。
# ベースイメージ
FROM oven/bun:latest
# プロジェクトルートを変更する(任意)
WORKDIR /project
コンテナが終了しないようにする
このイメージだけだと、私の環境ではコンテナが終了してしまいました。
今回はコンテナに入ってbun
コマンドを実行したいので、この状態を修正する必要があります。
Dockerfile
を以下のように編集してください。
# ベースイメージ
FROM oven/bun:latest
# プロジェクトルートを変更する(任意)
WORKDIR /project
# コンテナが終了しないようにする
CMD ["bash"]
ちなみにCMD ["bash"]
とcompose.yaml
のtty: true
を組み合わせることによって、コンテナが停止するのを防ぐことができます。
compose.yaml
に設定を書く
Docker Composeでコンテナを立ち上げるため、compose.yaml
を作成します。
そして内容を以下のように編集します。
version: '3'
services:
app:
build: .
tty: true
volumes:
- .:/project # パスはWORKDIRの記述と揃えるのがおすすめ
ports:
- 3000:3000
ここではapp
という名前のサービスを作成しています。
-
build: .
: カレントディレクトリにあるDockerfile
を使用 -
tty: true
: コンテナを終了させないように指定 -
volumes
: コンテナとホストでファイルを共有するのに使用 -
ports
: ホストからコンテナ内で立てたサーバーにアクセスするため、ポートを共有している
なお最後のports
は、Bunをサーバーの起動以外に使う場合は不要です。
また、サーバーを起動するポートをJavaScript側で変更する場合、こちらの設定を変更する必要があります。
コンテナを起動する
これで準備は済んだので、いよいよコンテナを起動してみます。
コンテナを起動して入るには、以下のコマンドを入力します。
docker compose up -d
docker compose exec app bash
実行すると、プロンプトが変わりDockerコンテナに入ることができるはずです。
bunコマンドが使えることを確認する
このコンテナはBunのイメージを使っているため、bun
コマンドが使えるはずです。
試しに以下のコマンドを実行してみてください。
bun --help
ヘルプが出力されたら成功です。
サーバーを起動してみる
では、JavaScriptで書いたサーバーをBunで動かしてみます。
まずはサーバーになるJavaScriptファイルを作成します。
index.js
を作成し、以下のように編集してください。
// サーバーを起動する
Bun.serve({
fetch(req) {
// リクエストが来たらログを出力
console.log('request!')
// Bunというレスポンスを返す
return new Response("Bun");
},
});
Bun.serve
関数については、ドキュメントが参考になると思います。
なお、コンテナとホストでファイルを共有(マウント)しているので、ホストでindex.js
を作成すると自動的にコンテナにもindex.js
が作成されます。
次に、このファイルをBunで実行してみます。
以下のコマンドを入力してください。
bun index.js
サーバーが起動できたら、ホストから http://localhost:3000 にアクセスしてみてください。
Bun
というレスポンスが返ってきたら成功です。
コンテナをサーバー起動用にする
ところで、こちらで作成したDockerコンテナですが、当然ながらBunのサーバーを終了してもコンテナは終了しません。
開発時はこれで大丈夫ですが、完成した時にこれだとサーバーの軌道に少し手間がかかります。
ということで、次はコマンド一つでコンテナが起動してサーバーが立ち上がり、そのコマンドを終了するとコンテナもサーバーも停止ようにします。
なお、作成したJavaScriptコードががサーバーのように常時稼働するものではない場合、JavaScriptコードはコンテナ内でBunによって実行され、実行が終わるとコンテナも終了します。
やり方
大まかには以下のような手順を踏みます。
-
Dockerfile
の常時起動用の行を削除する -
Dockerfile
にサーバーを起動するコマンドを書く -
compose.yaml
のtty
を削除する - Volumeを使っていたところを
COPY
に置き換える(任意) -
start-server.sh
を作成する(任意)
なお、Gitを使っている場合、この作業を始める前にブランチを分けておくことをお勧めします。
多分そうすれば本番環境用のブランチと開発用のブランチができると思います。多分。
Dockerfile
を書き換える
まずはDockerfile
を編集していきます。
ここでは常時起動用の行を削除し、代わりにサーバーを起動するためのコマンドを追記します。
# ベースイメージ
FROM oven/bun:latest
# プロジェクトルートを変更する(任意)
WORKDIR /project
# サーバーを起動する
CMD ["bun", "index.js"]
また、本番でファイルをマウントするならVolumeよりCOPY
を使ってコピーするのがおすすめだとChatGPTが言っていたので、こちらも書き換えてみます。
# ベースイメージ
FROM oven/bun:latest
# プロジェクトルートを変更する(任意)
WORKDIR /project
# ファイルをコピーする
COPY ./ ./
# サーバーを起動する
CMD ["bun", "index.js"]
ちなみにですが、おそらく変更しなくても動きます。
compose.yaml
を書き換える
次はcompose.yaml
の設定を変更します。
ここではtty
とvolume
の設定を削除します。
version: '3'
services:
app:
build: .
ports:
- 3000:3000
なお、上でDockerfile
にCOPY
を追加していない場合、volume
の削除は必要ありません。
ここまででサーバーを直接起動することができるようになったはずなので、一度試してみます。
コンテナを立ち上げるため、以下のコマンドを入力してください。
docker compose up --build
実行するとコンテナが起動し、その中でサーバーが立ち上がるはずです。
ホストから http://localhost:3000 にアクセスし、Bun
というレスポンスが返ってきたら成功です。
なお、--build
というオプションは、使用しているイメージをビルドし直すものになります。
イメージを作り直さないと、Dockerfile
に変更を加える前のイメージが使われてしまいます。
それを防ぐために今回はこのオプションをつけています。
サーバーを起動する実行ファイルを作る
サーバーを起動したいときにdocker
コマンドをいちいち打ってもいいですが、場合によっては少しわかりにくいかもしれません。
どうせなら一つのファイルにまとめてしまおうと思います。
ということで、start-server.sh
を作成し、内容を以下のようにします。
docker compose up
docker compose down
下の行は、コンテナが停止(docker compose up
が終了)した際に自動でコンテナを破棄するためのコマンドです。
ここにオプションを付与することで、イメージなどを自動で削除することもできるみたいです。
ファイルが作れたら、試しに実行してみます。
以下のコマンドで実行してみてください。
bash start-server.sh
もしくは、実行権限を付与して./start-server.sh
としても実行できます。
Discussion