可能な限りDocker公式が提供しているチュートリアルに沿って、Ruby on rails + MySQLの環境構築を行います。
はじめに
こんにちわ、2022年4月よりエンジニアとして働き始めたばかりのUdai(ゆうだい)です!
今回は、Docker公式チュートリアルを行った際に大量のWorningやErrorに苦しんだので、これからチュートリアルに訪れる初学者の同士が同様に躓かないようにと思い筆を取りました。
如何せん、私はまだまだ駆け出しのエンジニアですので、本記事はDockerを知らない人や名前だけは知っているよといった初学者向けの記事となっております。そのため、粒度はかなり細かいものとなっております。
また、それでも一読してくださる寛大なシニアなエンジニアの先輩方は記事の内容に誤りがございましたら、遠慮なく指摘・訂正していただけると幸いです。
※ 注意点
- チュートリアルとデータベースが異なります。(PostgreSQLからMySQLへ変更)
- 手早く同上の環境構築を行いたい方は他の素晴らしい記事を参照してください。
対象
- 実際にDockerを動かしたい人
- Docker公式チュートリアルがエラーばかりで進まなかった人
- 何となく動くまでフローが知りたい人
動作環境
- macOS Monterey 12.2.1
- Apple M1 Chip
- Docker Compose v2.4.1
前提知識
- dockerについてのなんとなくの知識(イメージ・コンテナ)
- CLIでの操作
※ 分からない点がございましたら、コメントにちょこっと書いていただけると自分の理解の範囲で記事を随時更新します。
なぜ公式チュートリアルなのに上手く動作しないのか?
更新頻度が低いため
これはどうしようもない話なのですが、公式チュートリアルというのはその対象について初めて書かれる指南書になる訳です。なので、その対象のバージョンが更新されていくにつれて書かれている内容と実環境での齟齬が発生します。なので、私たち初学者が出来ることはチュートリアルが上手くいかないことを嘆き、そこで挫折するのではなく、なぜそのようなところでErrorが出るのかという点を切り口にして学びを深めていくことです。
チュートリアル(1):定義ファイルの作成
ここから、実際のチュートリアルと変更点を挙げながら説明を行なっていきます。
1. Dockerfileの作成
CLIをお使いの方はTerminalでtouch Dockerfile
とGUIをお使いの方はFinderやVScodeなどのエディタ上でDockerfileを作成してください(拡張子は必要ありません)
作成後、以下の内容をDockerfileに記述してください。
FROM ruby:2.7
RUN apt-get update -qq && apt-get install -y nodejs postgresql-client
WORKDIR /myapp
COPY Gemfile /myapp/Gemfile
COPY Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
COPY . /myapp/
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000
CMD ["rails", "server", "-b", "0.0.0.0"]
Dockerfileはイメージの管理を行なうファイルです。
変更点としてはrubyのversionを2.5から2.7に変更しております。
また多くの記事でWORKDIRコマンドの前にRUN mkdir /directory_nameと記述している場合がありますが、WORKDIRコマンドは参照するディレクトリがない場合に勝手にディレクトリを作成してくれるので記述する必要がありません。各項目の詳しい説明は別記事にて行います。
2. Gemfileの作成
1.と同様の方法にてGemfileを作成してください。Gemfileも拡張子をつける必要がありません。
作成後、以下の内容をGemfileに記述してください。
source 'https://rubygems.org'
gem 'rails', '~>5'
Gemfileは、gem(RubyGems)と呼ばれるrubyのパッケージ管理システムの依存関係を記述するためのファイルです。よりわかりやすい記事があるので詳しく知りたい人はそちらを参照してください。
https://qiita.com/nishina555/items/1b343d368c5ecec6aecf
3. Gemfile.lockの作成
上記と同様にてGemfile.lockを作成してください。こちらは上記の記事にもあるとおり、bundleコマンド実行後に更新されるので、特に内容は空で大丈夫です!
4. docker-compose.yml
ファイルを作成するのは最後になります!docker-copose.ymlファイルを作成し、以下を記述してください。
version: "3.9"
services:
db:
# 追記:Apple M1 Chipに対応させるため
platform: linux/x86_64
image: mysql:5.7
environment:
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: root
volumes:
- ./tmp/db:/var/lib/mysql
ports:
- "3306:3306"
web:
build: .
command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
volumes:
- .:/myapp
ports:
- "3000:3000"
depends_on:
- db
公式はdocker-compose.ymlに対してis where the magic happens / 魔法がかかる場所
と比喩していてすごくオサレだなと感じました。そうです、docker-composeの肝となるファイルなのです!docker-composeではそれぞれ異なるコンテナを一元管理するための記述が行われています。
ここでは、Apple M1 Chipに対応させるための追記を行なっております。
チュートリアル(2):プロジェクトのビルド
まずは、やるべきことを先に記載したのちに、どのような問題が起こったのかを記載します。
1. docker-compose run
以下のコマンドをCLI(ターミナル等)で実行してください。docker-compose runを行うことで設定ファイルで定義された通りに、新たなコンテナを作成します。
docker-compose run web rails new . --force --no-deps --database=mysql
2. docker-compose build
以下のコマンドを実行してください。docker-compose buildを行うことでサービスのビルドを実行します。
docker-compose build
3.config/database.ymlファイルの書き換え
# MySQL. Versions 5.1.10 and up are supported.
#
# Install the MySQL driver
# gem install mysql2
#
# Ensure the MySQL gem is defined in your Gemfile
# gem 'mysql2'
#
# And be sure to use new-style password hashing:
# https://dev.mysql.com/doc/refman/5.7/en/password-hashing.html
#
default: &default
adapter: mysql2
encoding: utf8
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: root
password:
host: localhost
development:
<<: *default
database: myapp_development
host: db
username: root
password: password
![スクリーンショット 2022-04-13 17.13.29(2).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2615389/cf95b545-6bfe-b2cd-8175-c5021d77c217.png)
test:
<<: *default
database: myapp_test
host: db
username: root
password: password
production:
<<: *default
database: myapp_production
username: myapp
password: <%= ENV['MYAPP_DATABASE_PASSWORD'] %>
4. データベースの作成
docker-compose run web rails db:create
5. コンテナの軌道
docker-compose up
ここまで出来たら、ブラウザでlocalhost:3000にアクセスしてもらうと以下のようなページが表示されたら成功です!
え?これで終わり...?めっちゃ簡単じゃんw
って思っている時期が自分にもありました。ErrorやWarningに苦しめられたのはここからです笑
どのようなエラーが起こったのか?
ここからErrorやWarningの原因が相互に関係して発生したと考えられるので、問題を羅列する形で記載します。
1. bundle installが走らない問題
$ docker-compose run web rails new . --force --no-deps --database=mysql
[+] Running 1/0
⠿ Container exec-docker-db-1 Running 0.0s
[+] Building 3.1s (14/16)
~~ 省略 ~~
=> ERROR [6/8] RUN bundle install 0.3s
------
> [6/8] RUN bundle install:
#0 0.303 You must use Bundler 2 or greater with this lockfile.
------
failed to solve: executor failed running [/bin/sh -c bundle install]: exit code: 20
ここでの解決法は、以下の問題の依存関係が原因となって起こっていると考えられるので一度スキップします...ごめんなさい。ちなみに、自分は/bin/sh -c bundle installを行なっても治りませんでした。
2. ローカルのRubyのVersionが異なる問題
次に、色々修正を加えていると1のErrorは出なくなり以下のErrorが出ました。
$ docker-compose run web rails new . --force --no-deps --database=mysql
~~ 省略 ~~
=> [6/8] RUN bundle install 7.1s
=> [7/8] COPY entrypoint.sh /usr/bin/ 0.0s
~~ 省略 ~~
Running `bundle update` will rebuild your snapshot from scratch, using only
the gems in your Gemfile, which may resolve the conflict.
run bundle exec spring binstub --all
bundler: command not found: spring
Install missing gem executables with `bundle install`
ここで言われた通りにbundle exec spring binstub -all
を行うとローカルのrubyのversionが異なると言われたので、versionを2.7.6に合わせました。(これに関しても詳しい方法は別の記事にまとめます。)
3. mysql2が見つからない問題
$ docker-compose run web rails new . --force --no-deps --database=mysql
[+] Running 1/0
⠿ Container exec-docker-db-1 Running 0.0s
Could not find gem 'mysql2 (>= 0.4.4, < 0.6.0)' in any of the gem sources listed in your Gemfile.
Run `bundle install` to install missing gems.
そもそもgemの’mysql2’が本当にないか自分の目で確かめに... 結果:本当になかった(当たり前w)
gem list
#~~~Cound no find gem 'mysql2'~~~
また、gemを使って直接インストールを試みたが失敗
gem install mysql2 -v '0.5.3' --source 'https://rubygems.org/'
ld: library not found for -lssl
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [mysql2.bundle] Error 1
make failed, exit code 2
Gem files will remain installed in /Users/yudaikato/.rbenv/versions/2.7.6/lib/ruby/gems/2.7.0/gems/mysql2-0.5.3 for inspection.
Results logged to /Users/yudaikato/.rbenv/versions/2.7.6/lib/ruby/gems/2.7.0/extensions/arm64-darwin-21/2.7.0/mysql2-0.5.3/gem_make.out
ところが、ここで思わぬ収穫が...
opensslのPATHが通っていないことが明らかになり1と3の問題を同時に解決することができた!
brew info openssl
~~ 省略 ~~
For compilers to find openssl@3 you may need to set:
export LDFLAGS="-L/opt/homebrew/opt/openssl@3/lib"
export CPPFLAGS="-I/opt/homebrew/opt/openssl@3/include"
~~ 省略 ~~
この2行のexport文を直接.bundle/configファイルを書き換えた
vi .bundle/config
すると、大方エラーが消えて、あとはエラーが出る前に作成したコンテナを再度削除し作り直すことでチュートリアル2のコマンドを正常に実行できるようになりました!やった〜!
参考になった記事orサイト
https://docs.docker.com/compose/profiles/
https://qiita.com/ryouzi/items/b89965b76cef546e3046
https://qiita.com/croquette0212/items/7b99d9339fd773ddf20b
謝辞
本記事を書くにあたりまして、ご協力をいただきました皆様に厚くお礼申し上げます。