rails6が出たんですよ
いい加減コード書いてる記事を上げていきたいのですが、相変わらずこんな構築関係だったりミドルウェアの話だったりしか書けていません。良くない。なので、rails6の環境を作ったら、railsの記事とかを上げていきたいと思っています。今回は、その旗揚げのための記事になります。
Dockerfileとdocker-compose.ymlってどう書かれていくの?
ものすごく詳しく書くとタイトルに書きましたが、端的に言うと、Dockerfileとdocker-composeがどう書かれていって、最終的にrailsが立ちあがるところまでの状態になっていくかってことを書きます。大抵の記事って、完成形がドンとあって、こうしてこうでこう、はい完成!みたいな感じで、一向にプロセスが見えてこないので、?が残りやすい気がするんですよね。え?そんなことない?私はそうなので、書きます。いきなりあんな完璧なDokcerfileとdocker-compose.ymlが読書感想文書くみたいなノリでサクサク書けるわけないんですよ。と言うわけで、今回はどう言う風にファイルが継ぎ足されていって出来上がっていくかを書いていきたいと思います。
使用頻度が高いdockerコマンド
upしたコンテナの**CONTAINER_ID**を表示する
$ docker ps
buildしたコンテナの**IMAGE_ID**で表示する
$ docker images
一時的にコンテナを立ち上げ、コンテナ内に入る(この立ち上げでもプロセスができるので、docker cpを使える)
$ docker run -it IMAGE_ID /bin/bash
upしたコンテナ内に入る
$ docker exec -it CONTAINER_ID /bin/bash
プロセスを削除する
$ docker rm CONTAINER_ID
ビルドしたイメージを削除する
$ docker rmi IMAGE_ID
$ docker rmi -f IMAGE_ID
使用頻度の高いdocker-composeコマンド
コンテナをビルドすることでコンテナイメージを作成する
$ docker-compose build
コンテナをupする
$ docker-compose up
コンテナを一次的に上げる
$ docker-compose run コンテナ名 bash
プロセスを確認する
$ docker-compose ps
ステップ1:何も入ってなくていいからbuildできるようにする
ベースイメージはCentOSの8を指定するだけでいきます。何も具体的なものは入っていないコンテナがとりあえず立ちあがるところまで書いていきます。
Dockerfileを書く
FROM centos:centos8
docker-compose.ymlを書く
version: '3'
services:
db:
image: mysql:8.0
container_name: rails-sql
command: mysqld --collation-server=utf8mb4_unicode_ci
ports:
- 3307:3307
web:
build: .
command: bundle exec rails s -p 3000 -b '0.0.0.0'
volumes:
- ./rails-app:/root/rails-app
ports:
- 3000:3000
depends_on:
- db
必要なのは、DBのコンテナと、rails本体が動くwebコンテナなので、それぞれの設定を必要最小限書きます。ここでいう必要最小限は、お互いのコンテナを繋げること、ポートを開けておくこと、docker run、もしくはupしたらコンテナが立つようになってること、railsアプリの共有化がされるようになっていることです。
ステップ2:buildしたコンテナ内に入り、環境構築する
$ docker run -it image_id /bin/bash
ここからはターミナル画面を2画面にスプリットして、片方でコンテナ内で操作、片方でDockerfileに記述する、と言う方法でガンガン作業を進めていきます。
ruby2.6.5をローカルインストール
rubyのローカルインストールする方法は様々あれど、環境を汚してしまうことを気にしなくていいので、ソースからビルドしてやる方法を取って見たいと思います。
上記のサイトのダウンロードリンクをコピーしてきて、それを引数にwgetしてきたら、tarで解凍して、makeでビルドします。
取り敢えず、先ほど作ったDockerfileからイメージを作成し、コンテナ内に入ります。
$ docker-compose build
$ docker run -it IMAGE_ID /bin/bash
Dockerfileに書いていく内容はこのコンテナ内でrubyをインストールできるまでのプロセス全てになります。
まず、rubyのダウンロードリンクを使ってパッケージを落としてきたいわけですが、wgetコマンドが今のCentOS8には入っていません。試しに打って見てください。command not foundになるはずです。なので、yumを使ってwgetをインストールします。そうして手に入れたtarファイルをtarコマンドで解凍します。makeしてみようとすると、またコマンドが無いのでyumを使ってmakeをインストールします。これでmakeしようとすると、いくつかのパッケージが足らないと言われ、エラーが出ます。その足りていないパッケージはエラーを読むとgcc zlib-devel openssl-devel readline-devel libffi-develですので、これもyumで全部インストールします。これでようやくrubyをインストールすることができます。
これをプロセスとして正しい処理順に並び替えて、Dockerfileに記述します。必要なパッケージが全てインストールされた状態から、wget、tar、makeの順で実行されるようにします。
FROM centos:centos7
RUN echo 'export LC_ALL=C' >> /root/.bash_profile && \
yum clean all && \
yum update -y && \
yum install wget -y && \
yum install make -y && \
yum install gcc zlib-devel openssl-devel readline-devel libffi-devel -y && \
cd usr/local/src/ && \
wget https://cache.ruby-lang.org/pub/ruby/2.6/ruby-2.6.5.tar.gz && \
tar -zxvf ruby-2.6.5.tar.gz && \
cd ruby-2.6.5 && \
./configure && \
make && \
make install
すると、ここまででruby2.6.5が入った状態のdockerイメージがbuildされるようになることが保証されます。
完成したGemfileとGemfile.lockを共有化
完成したGemfileというのは、rails newをして作られた時にできるGemfileということです。
では、早速コンテナの中に入って、bundle initします。Gemfileをviで開き、railsのコメントアウトを外し、bundle updateをかけたら、足りないパッケージ、sqlite-develがエラーで表示されたので、これをインストールします。そして
bundle installをします。すると、nokogiriで落ちます。エラーを見ると足りてないパッケージ、libxml2-devel libxslt-develがあったので、これをyumでインストールします。かつ、nokogiriはオプション付きで単体インストールしないと入らなかったので、こいつはdockerfileでもbundle install前に個別に書きます。
以上の作業を行うことで、綺麗にbundle installできるようになったGemfileをコンテナ内で作ることができました。このGemfileを永続化しますので、docker cpを使用します。
$ docker cp CONTAINER_ID:/root/rails-app-name/Gemfile ./
$ docker cp CONTAINER_ID:/root/rails-app-name/Gemfile.lock ./
これでローカルにGemfileとGemfile.lockが出来上がり、永続化ができました。ここからrailsアプリ本体を扱えるようにDockerfileを記述していきます。
bundle initするために作ったディレクトリを作らせ、WORKDIRをrailsのアプリを置いたところへ設定します。
ここにGemfileとGemfile.lockをaddされるように指定し、nokogiriをオプション付きでインストールしたコマンドを実行し、最後にbundle installをするように設定します。そして最後にrails本体がaddされるようにします。すると下記のようになります。
FROM centos:centos8
RUN echo 'export LC_ALL=C' >> /root/.bash_profile && \
yum clean all && \
yum update -y && \
yum install wget -y && \
yum install make -y && \
yum install gcc zlib-devel openssl-devel readline-devel libffi-devel -y && \
yum install libxml2-devel libxslt-devel -y && \
yum install sqlite-devel -y && \
cd usr/local/src/ && \
wget https://cache.ruby-lang.org/pub/ruby/2.6/ruby-2.6.5.tar.gz && \
tar -zxvf ruby-2.6.5.tar.gz && \
cd ruby-2.6.5 && \
./configure && \
make && \
make install
RUN mkdir /root/scheran-app
WORKDIR /root/scheran-app
ADD Gemfile /root/scheran-app/Gemfile
ADD Gemfile.lock /root/scheran-app/Gemfile.lock
RUN gem install nokogiri -- --use-system-libraries=true --with-xml2-include=/usr/include/libxml2/ && \
bundle update && bundle install
ADD . /
railsアプリ本体を共有化してdocker-compose upの準備
docker-compos.ymlにvolumesを加えてこの後に行うwebpackerをインストールできるようにしてからコンテナ内でrails newをしでできたrails本体をdockr cpして、rails本体の共有化をできるようにします。
version: '3'
services:
db:
image: mysql:8.0
container_name: rails-sql
command: mysqld --collation-server=utf8mb4_unicode_ci
ports:
- 3307:3307
web:
build: .
command: bundle exec rails s -p 3000 -b '0.0.0.0'
volumes:
- .:/root/scheran-app/
ports:
- 3000:3000
depends_on:
- db
webpackerをinstallできるようにする
bundle installすると、このような下記の表示が出ているので、これを修正します。rails6からはwebpackerが備え付けで入っているので、これを入れられるようにしていきます。
Use `bundle info [gemname]` to see where a bundled gem is installed.
run bundle binstubs bundler
run bundle exec spring binstub --all
* bin/rake: Spring inserted
* bin/rails: Spring inserted
rails webpacker:install
sh: node: command not found
sh: nodejs: command not found
Node.js not installed. Please download and install Node.js https://nodejs.org/en/download/
まずは、nodejsをソースからビルドしていき、そこで一緒に入ってくるnpmを使ってyarnをインストールすることができれば、webpackerはインストールすることができますので、nodejsをビルドする際に必要なパッケージを先にyumでインストールします。必要なパッケージは./configureを実行してcommand not foundって言われたやつをパカパカ入れて行くのと、プ公式のインストール方法を読めば絶対に入ります。公式だけ読めばいいじゃんと思うかもしれませんが、意外と環境によっちゃ入ってないものがあってかつ公式では入ってること前提で端折られていることもあるので、双方向からやる必要があります。そして、今回必要だったパッケージは、gcc-c++、which、python2でした。これをインストールして、wgetでソースコードを引っ張ってきて、tarで解凍、然るのちにmakeでビルドしてやればnodejsのインストールは完了するので、npmが使えるようになります。これでyarnを入れて、最後にrails webpacker:installを実行してwebpackerをインストールしてあげれば、rails6の環境構築が完了したコンテナイメージが作れるDockerfileが出来上がります。
以上の記述を書き起こしたDockerfileが下記になります。これで完成です。
FROM centos:centos8
RUN echo 'export LC_ALL=C' >> /root/.bash_profile && \
yum clean all && \
yum update -y && \
yum install wget -y && \
yum install make -y && \
yum install gcc zlib-devel openssl-devel readline-devel libffi-devel -y && \
yum install libxml2-devel libxslt-devel -y && \
yum install sqlite-devel -y && \
yum install gcc-c++ which python2 -y && \
yum clean all && \
cd usr/local/src/ && \
wget https://cache.ruby-lang.org/pub/ruby/2.6/ruby-2.6.5.tar.gz && \
tar -zxvf ruby-2.6.5.tar.gz && \
wget https://nodejs.org/dist/v12.13.0/node-v12.13.0.tar.gz && \
tar -xvf node-v12.13.0.tar.gz && \
rm -rf ruby-2.6.5.tar.gz && \
rm -rf node-v12.13.0.tar.gz && \
cd ruby-2.6.5 && \
./configure && \
make && \
make install && \
cd .. && \
cd node-v12.13.0 && \
./configure && \
make -j4 && \
make install && \
npm install --global yarn -y
RUN mkdir /root/scheran-app
WORKDIR /root/scheran-app
ADD Gemfile /root/scheran-app/Gemfile
ADD Gemfile.lock /root/scheran-app/Gemfile.lock
RUN gem install nokogiri -- --use-system-libraries=true --with-xml2-include=/usr/include/libxml2/
ADD ./scheran-app /root/scheran-app
RUN bundle update && bundle install && rails webpacker:install
mysqlの設定をする
database.ymlにデータベースの情報を記述します。情報を隠蔽する為に.envで読ませる形にしたいと思います。
version: '3'
services:
db:
image: mysql:8.0
container_name: rails-sql
command: mysqld --collation-server=utf8mb4_unicode_ci
ports:
- 3307:3307
env_file: .env
SQL_USER=user_name
MYSQL_ROOT_PASSWORD=password
以上のようにします。これによってmysqlの初期化が行われます。
コンテナ内に入ってrails new .
ここでコンテナに入って、rails new .をしてあげます。webpackerもこの時に一緒に入ってくれます。できたrailsのプロジェクトをdocker cpしてローカルに置いときます。前の段階で共有化する準備はできているので、これで殆ど準備完了です。
Dockerコンテナのメンテナンス
最後に、初期でcpしたADDしたGemfileとGemfile.lockの部分を、rails newで作成してできたプロジェクトの中にあるGemfileへと変更します。
そうしないと、docker-compose.ymlで書いたvolumeしている部分が常にコンテナを立ち上げた時の状態になってしまいます。
volumeのdirectoryはいい感じにファイルをマージしてくれているわけではなく、ディレクトリごと上書きしてしまいます
なので、アップデートがgemやyarnなどにあった場合、buildしたコンテナ内ではDockerfileによって、bundle installやyarn upgradeされていたとしても、addされた内容が古い状態になってしまっているので、そこでバージョンに差異ができてしまい、upできなくなる現象が発生します。
ここがこの先、開発をしていく時のコンテナのメンテナンス部分になってくると思います。新しくgemを追加した時はもちろん、gemの仕様変更などでbundle installしてgemが更新された時などでコンテナが立ち上がらなくなる可能性があります。
ADD Gemfile /root/scheran-app/Gemfile
ADD Gemfile.lock /root/scheran-app/Gemfile.lock
これを・・・
ADD ./scheran-app/Gemfile /root/scheran-app/Gemfile
ADD ./scheran-app/Gemfile.lock /root/scheran-app/Gemfile.lock
にします。そうすることで、今後、gemやyarnにアップデートがあった場合、コンテナをrunで立ち上げて、手動でbundle installしたり、yarn upgradeをかけた時でも、自動的にvolume先に更新部分が反映されます。
作ったコンテナでupしてみる
作られたコンテナをupしてrailsサーバーにアクセス、loclahost:3000でrailsの画面が出たら、完成です。
感想
細かくやってみたものの、結構詰まってしまった。いつになったらサクサク環境構築できるようになるのやら・・・
docker-compose upの時のエラー(exit code ~)はdocker-compose.ymlの記述ミスを疑わないとね・・・当たり前だけど・・・
docker用途別記事
コンテナを作成中に使うコマンドや運用中に使うコマンド、エラーが起きたら使うコマンドの記事は下記にまとめています。
増えすぎたnoneのdockerイメージや、バックで動くコンテナプロセスを全て削除する