はじめに
コツコツと環境構築する様をアウトプットしていきます。
ゴール
環境
- OS : macOS Mojave 10.14.3
- Docker : 18.09.2
準備
ディレクトリ作成
$ mkdir rails_minimum
$ cd rails_minimum
Dockerfile作成
$ touch Dockerfile
今回は元となるイメージとしてruby:2.5.1を指定します。
# 元となるイメージの指定
FROM ruby:2.5.1
FROM [イメージ名]:[タグ] | 元となるイメージの指定 |
---|
イメージをビルドする
まずは今あるイメージを表示してみます。
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
何もしていないので、何もありません。
minimumという名前を付けてDockerfileを元にイメージをビルドします。
タグを指定することでイメージのバージョンを管理することができますが、今回は特にタグの指定はしないのでデフォルトのlatestになります。
# docker build [Dockerfile配置ディレクトリ]
$ docker build . -t minimum
オプション | 説明 |
---|---|
-t [イメージ名]:[タグ] | イメージ名、タグの指定 |
イメージがビルドされました!
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ruby 2.5.1 3c8181e703d2 5 months ago 869MB
minimum latest 3c8181e703d2 5 months ago 869MB
コンテナを起動する
今あるコンテナを表示してみます。
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
オプション | 説明 |
---|---|
-a | 全てのコンテナを表示 |
何もしていないので、何もありません。
先ほどビルドしたminimumというイメージからminimumという名前をつけてコンテナを作成します。
# docker create [イメージ名]
$ docker create --name minimum -it minimum
オプション | 説明 |
---|---|
--name [コンテナ名] | コンテナ名の指定 |
コンテナができました!
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fed23d01ed83 minimum "irb" 8 seconds ago Created minimum
が、STATUSがCreatedでは起動はしていないので起動させます。
# docker start [コンテナ名]
$ docker start minimum
STATUSがUpになりコンテナが起動しました!
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fed23d01ed83 minimum "irb" 35 seconds ago Up 3 seconds minimum
なお、docker runでコンテナ作成+コンテナ起動もできます。
# docker run [コンテナ名]
$ docker run -d --name minimum -it minimum
オプション | 説明 |
---|---|
-d | バックグラウンドで起動 |
-i | 起動時にコンテナの標準出力にアタッチ |
-t | 擬似ターミナル割り当て |
コンテナ内で操作をする場合には-tが必須なようです。
コンテナを操作する
bashに入ってみます。
# docker exec [コンテナ名] [実行コマンド]
$ docker exec -it minimum bash
root@fed23d01ed83:/#
プロジェクト用のディレクトリを作成してみます。
root@fed23d01ed83:/# mkdir app
作成したディレクトリに移動します。
root@fed23d01ed83:/# cd app
root@fed23d01ed83:/app#
railsプロジェクトを初期化してみます。
root@fed23d01ed83:/# rails new .
bash: rails: command not found
「railsなんてコマンドないよー」って怒られました。
ということでrailsに必要なgemをコンテナにインストールしなければなりません。
コンテナ内にrailsを導入する
railsに必要なgemをインストールするために、Gemfileを作成します。
root@fed23d01ed83:/app# touch Gemfile
Gemfileを編集します。
が、vimが使えませんね...。
root@fed23d01ed83:/app# vim Gemfile
bash: vim: command not found
コンテナ内にvimをインストールします。
root@fed23d01ed83:/app# apt-get update
root@fed23d01ed83:/app# apt-get -y install vim
vimが使えるので、Gemfileを編集します。
今回のrailsのバージョンは5.1.6にします。
root@fed23d01ed83:/app# vim Gemfile
source 'https://rubygems.org'
gem 'rails', '5.1.6'
bundle経由で、Gemfileを元にrailsに必要なgemをインストールします。
root@fed23d01ed83:/app# bundle install
railsに必要なgemがインストールされたようです。
railsコマンドが使えるので、バージョンを確かめておきます。
root@fed23d01ed83:/app# rails -v
Rails 5.1.6
railsプロジェクトを初期化する
railsプロジェクトを初期化します。
すでにGemfileが存在するため、Gemfileが競合します。
上書いていいかを聞かれた場合は'y'を入力して下さい。
※-fオプションで強制的に上書くこともできます。
root@fed23d01ed83:/app# rails new .
無事作成できました。色々とできていますね。
root@fed23d01ed83:/app# ls
Gemfile Gemfile.lock README.md Rakefile app bin config config.ru db lib log package.json public test tmp vendor
これでコンテナ内でrailsプロジェクトを初期化することができましたが、これではコンテナを削除してしまえば全て消えてしまいますし、なにより毎回こんなことをするのは面倒です。
ここからはDockerfileを改善していきます。
Dockerfileを改善する
まずは作成したコンテナを思い切って削除してしまいましょう。
root@fed23d01ed83:/app# exit
# docker stop [コンテナ名]
$ docker stop minimum
# docker rm [コンテナ名]
$ docker rm minimum
イメージも削除します。
# docker rmi [イメージ名]
$ docker rmi minimum
ここで、今存在するコンテナとイメージを表示してみます。
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ruby 2.5.1 3c8181e703d2 5 months ago 869MB
minimumイメージを削除しただけなので、rubyイメージは残っていますが、元となるrubyイメージ自体には変更を加えないので、消す必要はありません。
イメージをビルドする際にすでにローカルに存在している場合はダウンロードせず、ローカルのイメージを利用してくれます。
処理をDockerfileに記述していきます。
が、全てをDockerfileに記述するわけではなく、一部はホスト側準備をします。
まずはGemfileを作成します。内容は先ほどと同じです。
source 'https://rubygems.org'
gem 'rails', '5.1.6'
空のGemfile.lockも作っておきましょう。
Dockerfileを編集します。
# FROM 元となるイメージ
FROM ruby:2.5.1
ENV APP_ROOT /app
# 作業ディレクトリを指定
# 指定したディレクトリが存在しない場合には作成してくれる
WORKDIR $APP_ROOT
# Gemfile、Gemfile.lockコピー
COPY Gemfile $APP_ROOT
COPY Gemfile.lock $APP_ROOT
# Gemfileを元にgemをインストール
RUN bundle install
説明 | |
---|---|
ENV [変数名] [値] | 環境変数を定義する |
WORKDIR [コンテナ内ディレクトリ] | コンテナ内の作業ディレクトリを指定 |
RUN [実行コマンド] | イメージビルド時にコマンドを実行 |
COPY [ホスト側コピー元] [コンテナ内コピー先] | ホスト側からコンテナ内にコピー |
一度イメージを作成してみます。
$ docker build . -t minimum
このタイミングで、先ほどのgemがインストールされた状態のイメージが作成されます。
コンテナを起動させます。
このとき、ボリュームの指定をすることで、指定したディレクトリでの編集が共有されます。
$ docker run -d --name minimum -it -v $PWD:/app minimum
オプション | 説明 |
---|---|
-v [ホスト側絶対パス] [コンテナ側絶対パス] | ボリュームの指定 |
コンテナに入ります。
$ docker exec -it minimum bash
先ほどWORKDIRで指定したディレクトリがカレントディレクトリになっていることがわかります。
railsプロジェクトを初期化します。
root@888d61342746:/app# rails new -f .
ボリューム指定をしているため、ホスト側にもrailsのファイル群が作成されています。
$ ls
Dockerfile Gemfile.lock Rakefile bin config.ru lib package.json test vendor
Gemfile README.md app config db log public tmp
サーバーを立ち上げてみます。
root@888d61342746:/app# rails server -d
エラーが出たかと思います。
railsの実行環境にはサーバーサイドでのJavaScript実行環境が必要(assetまわりのコンパイルで?)なようなのでnodejsをインストールします。
root@888d61342746:/app# apt-get update
root@888d61342746:/app# apt-get install -y nodejs
再度、サーバーを立ち上げる
root@888d61342746:/app# rails server -d
これで、晴れてサーバーが起動しました。
なにも考えずいつも通りブラウザからlocalhost:3000を表示してみると...アクセスできません!!
ブラウザからlocalhost:3000にアクセスした際にコンテナ内に立ち上がっているサーバーにアクセスできるように設定する必要があります。
localhost:3000でサーバーにアクセスできるようにする
一旦サーバーを止めます。
バックグラウンドでサーバーを起動している場合、tmp/pids/server.pidにサーバーが利用しているプロセス番号が書かれているので確認し、直接killします。
root@888d61342746:/app# cat tmp/pids/server.pid
863
root@888d61342746:/app# kill 863
コンテナを止め、削除します。
root@888d61342746:/app# exit
$ docker stop minimum
$ docker rm minimum
3000番ポートの開放、ポートの割り当て設定をしつつ、コンテナを起動します。
$ docker run -d --name minimum -it -v $PWD:/app -p 3000:3000 --expose 3000 minimum
オプション | 説明 |
---|---|
-p [ホスト側ポート番号]:[コンテナ側ポート番号] | ポートの割り当て |
--expose [コンテナ側ポート番号] | ポートの開放 |
コンテナに入り、先ほどrails new実行時に自動的に実行されたbundle installによってインストールされたgemが現在のコンテナには存在しないのでgemのインストールをします。
nodejsも消えてしまっているのでインストールし直します。
root@41febcaa682c:/app# bundle install
root@41febcaa682c:/app# apt-get update
root@41febcaa682c:/app# apt-get install -y nodejs
コンテナのbashに入り、外部からアクセスできる0.0.0.0を指定してサーバーを起動しなおします。
root@41febcaa682c:/app# rails server -d -b 0.0.0.0
ブラウザからlocalhost:3000にアクセスしてみると...できた!
ひとまず、ゴールは達成。
もう少しだけDockerfileを改善していきます。
nodejsのインストールをイメージビルド時に行います。
# FROM 元となるイメージ
FROM ruby:2.5.1
# 必要なものをインストール
RUN apt-get update
RUN apt-get install -y nodejs
ENV APP_ROOT /app
# 作業ディレクトリを指定
# 指定したディレクトリが存在しない場合には作成してくれる
WORKDIR $APP_ROOT
# Gemfile、Gemfile.lockコピー
COPY Gemfile $APP_ROOT
COPY Gemfile.lock $APP_ROOT
# Gemfileを元にgemをインストール
RUN bundle install
これで、イメージをビルドした段階でnodejsのインストールホスト側のGemfileに記述してあるgemのインストールが行われます。
docker-composeを利用したさらなる改善は第2章で。
Dockerで最低限のrails開発環境をコツコツ構築してみる〜第2章〜