🐆
ボリュームマウントを使ってdocker開発を効率化するdocker-compose.yml集(Node.js, Go, Rails)
対象者
- docker-compose.ymlの文法がわかる方
- Node.js, Go, Ruby on Railsをdockerで開発している方
- 開発者体験に速度面で不満を抱えている方
何かお役に立てれば幸いです。
基本理念
- ホストとコンテナ間で同期するファイルを少なくすることによって高速化を試みる
- パッケージのインストールやキャッシュは再度インストールする必要がないように積極的にボリュームを使う
- コンテナの設定をできる限りdocker-compose.ymlに記述することで再度ビルドをすることなく設定を変更できるようにする
Node.js
docker-compose.yml
volumes:
node_modules:
yarn_cache:
services:
app:
image: node:19-alpine
working_dir: /app
volumes:
- .:/app
- node_modules:/app/node_modules
- yarn_cache:/usr/local/share/.cache/yarn/v6
# 以下略
- node_modulesをボリュームマウントする
サイズが巨大なnode_modulesをバインドマウントするとホストとコンテナ間の同期が足手まといになってyarn install
などが遅くなったり、require()を用いるjsの実行自体が遅くなったりすることがあります。(小規模のプロジェクトではあまり顕在化しないけど)
注意: 上記のように指定するとホストのnode_modulesがコンテナに同期されないので、コンテナでyarn install
をしてもホスト側のnode_modulesは空になります。よってコードを書く際はホスト側でもう一度yarn install
をしないといけません。これはちょっと面倒ですが、高速化とのトレードオフですね。
- yarnのcacheをボリュームマウントする
yarnのcacheを永続化すると再度同じパッケージを入れる場合yarn add
が速くなります。
Go
docker-compose.yml
volumes:
go_packages:
services:
app:
image: golang:1.19-alpine
working_dir: /app
volumes:
- .:/app
- go_packages:/go
environment:
GO111MODULE: 'on'
GOPATH: /go
こちらはgoのパッケージを永続化する設定です。永続化をしない場合、次のどちらかを選択することになります。
- Dockerfileで
go mod download
を記述して、パッケージが追加されるたびにdocker compose build
を行う
-> ローカルのイメージが無駄に増えてしまう - コンテナを作成するたびにgo.modに記述されたパッケージのうち足りないものをダウンロードする(Goが自動でやってくれる)
-> 通信量と時間が勿体無い
Ruby on Rails
Dockerfile
FROM ruby:2.6.3-alpine3.10 AS dev
WORKDIR /app
RUN apk update && \
apk add git gcc make g++ ca-certificates curl mysql-client mysql-dev nodejs tzdata && \
curl -o- -L https://yarnpkg.com/install.sh | sh && \
ln -s "$HOME/.yarn/bin/yarn" "/usr/local/bin/yarn"
docker-compose.yml
volumes:
ruby_gems:
rails_tmp:
services:
app:
build: .
working_dir: /app
environment:
GEM_HOME: /gem
BUNDLE_BIN: /gem/bin
PATH: "${PATH}:/gem/bin"
volumes:
- .:/app
- ruby_gems:/gem
- rails_tmp:/app/tmp
- gemを永続化
環境変数GEM_HOME
, BUNDLE_PATH
, BUNDLE_BIN
を自ら設定してgemが/gem
にインストールされるようし、/gem
をボリュームマウントしています。
こうすることでイメージを再度ビルドすることなく、コンテナ内で一度だけbundle install
をすればよくなります。
gemを永続化しない場合、Dockerfileでbundle install
を記述して、パッケージが追加されるたびにdocker compose build
を行うことになりますから、無駄なイメージを増やすことになってしまいます。
- railsのキャッシュを永続化
ここまでする必要はないかとは思いますが、tmp
ディレクトリは数十MBになったりするので、ホスト-コンテナ間の同期対象から取り除いて損はないと思います。
Discussion