docker-compose upするだけでDB作成とマイグレーションもしたい!

はじめに

FundastA Inc.の片田です!

趣味でやってるチーム開発のメンバーからある日こんな要望が。

「docker-compose upした後に毎回rails db:create, rails db:migrateするの面倒すぎる。なんとかしろ。」

とのお達しがあったので、主にDocker、CircleCI、AWS周りを担当する僕が対応することとなりました。

僕も元々Railsからプログラマーの世界に飛び込んでいるので、Railsを書いていた時は思考停止して一つ一つのコマンドを叩いていたのですが、

確かにこれ面倒臭い…。

ということでさっさと自動化していきましょう〜!

コマンド一発でrails db:createするには?

今回実現すること

今まで、

と順番にコマンドを叩いていたところを、

だけで上記の3つのコマンドを叩いたのと同じ状態にします。

とりあえずやってみた

だいたいdocker-compose.ymlいじれば行けそうな気がしたんで、早速修正。

元のdocker-compose.ymlがコチラ。

修正したものがコチラ。

commandの部分にギチギチに詰め込んでみました。

見栄えは悪いですが、これで実現できるんじゃないか…!

と思ったのですが、これだとエラーが発生します。

エラーの内容は下記の通りです。

DBコンテナへのコネクションエラーです。

ただ、このエラー、コンテナの初回起動時のみ発生して、もう一度docker-compose upすると普通に起動できるようになるんです。

上記のdocker-compose.ymlでも、depends_onでDBコンテナへの依存関係は定義しているはずだし、DBコンテナの外部ポートも開けてる…。

それに、DBコンテナが起動していない状態なら、dbというホストが見つからないよ!とうエラーが出るはずなので、DBコンテナは問題なく起動できているっぽい。

原因が分からず、チームメンバーのDockerに詳しい方に相談しつつ1日半がたったある日、衝撃の事実を知りました。

depends_onは、起動順序だけを管理しており、コンテナが起動し終えるのを待ってくれない。

コチラをご覧ください。

Compose はコンテナの準備が「整う」まで待ちません(つまり、特定のアプリケーションが利用可能になるまで待ちません)。単に起動するだけです。

とのことです。。初めて知りました。

上記のdocker-compose.ymlで初回のみDBコネクションエラーが起きるのは、DBが起動を完了するのを待たずにAPIコンテナが起動し、rails db:createコマンドを実行していたため、エラーが発生していた模様です。

DBコンテナが起動し終えてからAPIコンテナを起動するには?

上記の公式ドキュメントに方法が書いてありました。

wait-for-it や dockerize のようなツールを使います。これらはラッパー用のスクリプトであり、アプリケーションのイメージに含めることができます。また特定のホスト側のポートに対して、TCP 接続を受け入れ可能です。

今回はwait-for-itを使ってみることにしました。

wait-for-itのリポジトリはコチラ

ここに使い方云々は書いてあるので、その通りに使っていきます。

  1. wait-for-itリポジトリをローカルにクローンする
  2. wait-for-it.shをrailsプロジェクトのあるルートディレクトリ直下に配置
  3. wait-for-it.shのwait_for_wrapperメソッドに下記を追加
wait-for-it.shの完成形は下記の通りです。

  1. docker-compose.ymlから、起動時に作成したシェルファイルを叩くようにする
引数のdb:3306はwait-for-it.shに書いてあったので指定しました。

docker-compose.ymlの完成形が下記の通りです。

これで無事、docker-compose upコマンド一発でDBの作成、マイグレーションまでを行うことに成功しました!!

おわりに

今回はチームメンバーからの要望を無事に実現できたわけですが、これがベストプラクティスでは無いような気がします…。(特にシェルスクリプトの部分とか)

この記事をご覧になった有識者の方、是非是非ご指摘ください。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA