DockerでRailsを実行する時に発生するエラーの解決方法

目次

概要

Ruby on Railsの開発環境を用意する方法として、Dockerを利用しています。

しかし、Dockerを使ってRailsの開発環境を用意した際に、起動プロセスに問題はないのに起動後にコンテナが終了してしまうという問題に遭遇しました。

ここでは、その問題の解決方法を紹介します。

環境

  • Docker
  • Debian 12

やりたいこと

今回やりたいことは、Railsの開発環境をDockerを利用して構築することです。 Dockerを使うことで、環境構築の手間を省き、実行環境が変わったとしてもすぐに開発を始められるようにします。

Dockerを使ってRailsの環境として、Railsを動かすWebアプリケーションのコンテナとデータベースのコンテナの2つを用意することにしました。 そこで、複数のコンテナを管理する場合は、Docker Composeを使うと楽なので、Docker Composeを使うことにしました。

Docker Composeを使って、RailsのWebアプリケーションとデータベースのコンテナを起動する設定ファイルを作成しました。 Webアプリケーションの起動には、CSSやJavaScriptのビルドも含めて実行できるように、bin/devを実行しています。

しかし、それを使って起動すると、Webアプリケーションのコンテナが起動後間もなく終了するという事態に遭遇しました。

次が想定していない状況で終了するコンテナのログです。

web-1 | Installing foreman…
web-1 | Successfully installed foreman-0.88.1
web-1 | 1 gem installed
web-1 | 07:59:06 web.1 | started with pid 21
web-1 | 07:59:06 js.1 | started with pid 22
web-1 | 07:59:06 css.1 | started with pid 24
web-1 | 07:59:06 css.1 | yarn run v1.22.19
web-1 | 07:59:06 js.1 | yarn run v1.22.19
web-1 | 07:59:06 js.1 | $ esbuild app/javascript/. –bundle –sourcemap –format=esm –outdir=app/assets/builds –public-path=/assets –watch
web-1 | 07:59:06 css.1 | $ tailwindcss -i ./app/assets/stylesheets/application.tailwind.css -o ./app/assets/builds/application.css –minify –watch
web-1 | 07:59:06 js.1 | [watch] stopped because stdin was closed (use “–watch=forever” to keep watching even after stdin is closed)
web-1 | 07:59:06 js.1 | Done in 0.04s.
web-1 | 07:59:07 css.1 | Browserslist: caniuse-lite is outdated. Please run:
web-1 | 07:59:07 css.1 | npx update-browserslist-db@latest
web-1 | 07:59:07 css.1 | Why you should do it regularly: https://github.com/browserslist/update-db#readme
web-1 | 07:59:07 web.1 | DEBUGGER: Debugger can attach via UNIX domain socket (/tmp/rdbg-0/rdbg-21)
web-1 | 07:59:07 web.1 | => Booting Puma
web-1 | 07:59:07 web.1 | => Rails 7.1.3.2 application starting in development
web-1 | 07:59:07 web.1 | => Run bin/rails server --help for more startup options
web-1 | 07:59:07 css.1 | Done in 0.24s.
web-1 | 07:59:07 web.1 | Puma starting in single mode…
web-1 | 07:59:07 web.1 | * Puma version: 6.4.2 (ruby 3.3.0-p0) (“The Eagle of Durango”)
web-1 | 07:59:07 web.1 | * Min threads: 5
web-1 | 07:59:07 web.1 | * Max threads: 5
web-1 | 07:59:07 web.1 | * Environment: development
web-1 | 07:59:07 web.1 | * PID: 21
web-1 | 07:59:07 web.1 | * Listening on http://127.0.0.1:3000
web-1 | 07:59:07 web.1 | * Listening on http://[::1]:3000
web-1 | 07:59:07 web.1 | Use Ctrl-C to stop
web-1 | 07:59:07 js.1 | exited with code 0
web-1 | 07:59:07 system | sending SIGTERM to all processes
web-1 | 07:59:07 css.1 | exited with code 0
web-1 | 07:59:07 web.1 | - Gracefully stopping, waiting for requests to finish
web-1 | 07:59:07 web.1 | Exiting
web-1 | 07:59:08 web.1 | terminated by SIGTERM

プログラムにエラーがあり、異常終了しているわけではありません。 そのため、Docker Composeの設定ファイルに問題があるのかと思い、調査を行いました。

解決方法

原因は、コンテナの起動時に実行しているbin/devにありました。 bin/devでは、内部でforemanという複数のコマンドを並列に実行できるツールを利用しています。 そのforemanは、Procfile.devファイルを見て、何を実行するのかを決めています。 その中のtailwandのビルド処理の結果として、SIGTERMシグナルを返すと分かりました。

通常、コンテナの実行中に、コンテナの終了命令を受け取る際にSIGTERMというシグナルを受け取ります。 そのため、tailwandのビルド処理の結果として返されるSIGTERMシグナルを、コンテナが受け取ってしまうため、コンテナが正常終了してしまいます。

これが今回の問題の原因でした。

そこで、今回はSIGTERMをコンテナで受け取ったとしても終了しないように、Docker Composeの設定を修正します。

解決方法は簡単で、tty: trueを追加します。

services:
  web:
    tty: true

この設定を追加することで、終了のシグナルを受け取ったとしても、コンテナを終了しないようにすることができます。

さいごに

過去にも似たようなことをやったことがあったのですが、プログラム自体に問題はないので、毎回この問題に遭遇すると驚きます。

コンテナで複数のプロセスを実行する場合に遭遇しやすいものであるため、そのような処理をDockerコンテナでやる場合は注意が必要かと思います。