Railsアプリの開発環境向けDockerfile + docker-compose.yml
人に説明するときに記事あると便利なので、開発環境向けのDockerfileとdocker-compose.ymlを書いておく。
Dockerfile
FROM ruby:3.0.0 WORKDIR /app # Using Node.js v14.x(LTS) RUN curl -fsSL https://deb.nodesource.com/setup_14.x | bash - # Add packages RUN apt-get update && apt-get install -y \ git \ nodejs \ vim # Add yarnpkg for assets:precompile RUN npm install -g yarn # Add Chrome RUN curl -sO https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb \ && apt install -y ./google-chrome-stable_current_amd64.deb \ && rm google-chrome-stable_current_amd64.deb # Add chromedriver RUN CHROME_DRIVER_VERSION=`curl -sS chromedriver.storage.googleapis.com/LATEST_RELEASE` \ && curl -sO https://chromedriver.storage.googleapis.com/$CHROME_DRIVER_VERSION/chromedriver_linux64.zip \ && unzip chromedriver_linux64.zip \ && mv chromedriver /usr/bin/chromedriver
- git: GitHubを参照してgemを入れるときに必要
- nodejs + yarn:
bin/rails assets:precompile
で必要 - vim:
bin/rails credentials:edit
で使う - Chrome + chromedriver: System Test で必要
docker-compose.yml
version: "3.8" services: db: image: postgres:12-alpine volumes: - postgres:/var/lib/postgresql/data environment: POSTGRES_HOST_AUTH_METHOD: trust redis: image: redis:5-alpine volumes: - redis:/data web: &web build: . image: app:1.0.0 stdin_open: true tty: true volumes: - .:/app:cached - bundle:/app/vendor/bundle - node_modules:/app/node_modules - rails_cache:/app/tmp/cache - packs:/app/public/packs - packs_test:/app/public/packs-test tmpfs: - /tmp environment: BUNDLE_PATH: "/app/vendor/bundle" BOOTSNAP_CACHE_DIR: "/app/vendor/bundle" WD_INSTALL_DIR: "/usr/local/bin" HISTFILE: "/app/log/.bash_history" EDITOR: "vi" DATABASE_URL: "postgres://postgres:postgres@db:5432" REDIS_URL: "redis://redis:6379/" RAILS_MASTER_KEY: depends_on: - db - redis command: ["bin/rails", "server", "-b", "0.0.0.0"] expose: ["3000"] ports: ["3000:3000"] user: root working_dir: /app worker: <<: *web command: ["bundle", "exec", "sidekiq"] expose: [] ports: [] volumes: postgres: redis: bundle: node_modules: rails_cache: packs: packs_test:
image: app:1.0.0
imageに名前とバージョンをつけておくことで、バージョンをインクリメントすると docker-compose run
のときに自動的にビルドが走る。
Dockerfileを変えたときにバージョンをインクリメントすることで、他の開発者が古いイメージを使い続けてしまう事を防ぐことができる。
stdin_open: true tty: true
byebug
などでデバッグできるようにするため。
volumes: - .:/app:cached - bundle:/app/vendor/bundle - node_modules:/app/node_modules - rails_cache:/app/tmp/cache - packs:/app/public/packs - packs_test:/app/public/packs-test
Docker for Mac遅い問題の対処。
ホストとの同期を減らすことで若干マシになる。遅いけど。
worker: <<: *web command: ["bundle", "exec", "sidekiq"] expose: [] ports: []
sidekiqを使う場合、基本的な設定はwebと同じなのでエイリアスを使う。
expose
, ports
はworkerで不要なので上書きする。
使い方
初回の環境構築
Dockerイメージを作成して、 bin/setup
を実行する。
$ docker-compose build $ docker-compose run --rm web bin/setup
サーバの起動
$ docker-compose run --rm --service-ports web
実行すると http://localhost:3000 でアクセスできる。
Railsコマンド類の実行
$ docker-compose run --rm web bin/rails -T
テストの実行
$ docker-compose run --rm -e RAILS_ENV=test web bin/rails db:test:prepare $ docker-compose run --rm -e RAILS_ENV=test web bin/rails test
コンテナ内で作業する
毎回コンテナの起動をすると遅いので、基本的にコンテナ内で作業した方が楽。
$ docker-compose run --rm web bash root@b419978e89ec:/app# bin/rails --version Rails 6.1.3
全てのvolumeを削除する
開発環境を一新したいときに使う。
$ docker-compose down --volumes
追加の説明
Dockerfileでbundle install
は不要なのか?
Dockerイメージのビルドでは不要です。
bin/setup
の実行で、マウントしてるvolumeにインストールされます。
なぜdocker-compose up web
で起動しないのか?
docker-compose up
で起動すると標準入力が使えなくなって、byebugでデバッグできなくなるため。
あと、コンテナを止めたときに稀にtmp/pids/server.pid
が残ることがある。*1
コマンドが長い
bibendi/dipを使うか、bashのエイリアスを使うと楽です。
開発用のイメージが大きい
alpineやmulti stage buildを使えば軽量化できるかもしれないですが、面倒だったので調べてないです。
開発環境用のDockerイメージが少し重くても、大して困らないため。
*1:原因の詳細は調べられていないですが、 docker-compose run では今まで起きていない。