Docker+Railsでサーバーを立ち上げた時のメモです。
元々Dockerを使わずに運営していたのですが、CentOS6がサポート切れになったことやbundle installでよく苦戦する事もあって環境を作り直す事にしました。
今回のOSはmacOSになります。
今回の構成ですがまずはCentOSのImageにRailsやMySQLを乗せていく形で作っていきます。
DBやアプリケーションサーバーを分ける構成が推奨されているのですが、いきなり分割するのは難易度が高いので最初は1つのコンテナにすべて詰め込みます。
ローカル環境構築
まずはMacにDockerをインストールします。
インストールは下のサイトから行いました。
続けてDockerfileを作っていきます。
ここではrbenvを使ったRubyのインストールをしています。
下の方にあるENVはパスを通すためのコマンドです。
Dockerの実行中は.bash_profileを読んでくれないのでENVコマンドでパスを通しています。
FROM centos:8 # Ruby RUN yum -y install git gcc make bzip2 openssl-devel readline-devel zlib-devel RUN git clone https://github.com/sstephenson/rbenv.git ~/.rbenv RUN cd ~/.rbenv && src/configure && make -C src RUN git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build RUN echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile && echo 'eval "$(rbenv init -)"' >> ~/.bash_profile ENV PATH /root/.rbenv/bin:/root/.rbenv/shims:$PATH RUN rbenv install 2.5.1 && rbenv global 2.5.1
続けて下コマンドでImageを作成します。
tオプションはImageの名前やタグを指定するためのものです。
docker build -t my_image .
buildの後にdocker imagesコマンドを打つとImageが作られている事が分かります。
Imageを消したい場合はdocker rmi xxx(ImageのIDか名前)で削除する事ができます。
ImageIDは先頭の数文字だけでも問題ありません。
すべて一気に削除したい時は下コマンドが便利です。
docker images -aq | xargs docker rmi
次はImageからコンテナを作成して起動します。
起動は下のコマンドです。
docker run -itd --name my_container -p 3000:3000 --privileged my_image /sbin/init
http://localhost:3000
でDockerの3000ポートに繋ぎたかったので下のように-pオプションでポートを指定しています。
他オプションですがdはバックグラウンド起動のため、iはホストの入力をコンテナに送るため、tはコンテナからの出力を受けるためのものです。
--privilegedはホスト側などへのアクセス権限を与えるオプションです。
マウント周りで権限関連のエラーが出たので追加したのですが、本番環境などでは避けた方が良いかもしれません。
コンテナへのアクセスする場合は下コマンドを使います。
loginオプションはbash_profileの読み込みの為に入れています、ただDockerfileのENVでRubyのパスを追加したので除いてもいいかもしれません。
docker exec -it my_container bash --login
試しにRubyバージョンを確認した所、無事に2.5.1が入っていました。
execを使うとコンテナ上でコマンドを実行します。
そのためbash --loginをlsに置き換えると下のようにファイル一覧を表示します。
立ち上げたコンテナですが停止したい時はdocker stop xxx(コンテナのIDか名前)、削除したい時はdocker rm xxx(コンテナのIDか名前)を使います。
起動中のコンテナを削除したい時は下のようにrmにfオプションを付けます。
docker rm -f xxx(コンテナのIDか名前)
次にMySQLをインストールします。
Dockerfileの下部に下の行を追加してImageを作り直して実行します。
# MySQL RUN yum -y install mysql mysql-server
起動すると下のように実行できるようになっています。
最後にRailsを導入します。
Dockerfile最下部に下の処理を追加します。
# Rails RUN yum -y install mysql-devel gcc-c++ nodejs crontabs wget fontconfig-devel RUN wget https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-2.1.1-linux-x86_64.tar.bz2 && tar jxf phantomjs-2.1.1-linux-x86_64.tar.bz2 && cp phantomjs-2.1.1-linux-x86_64/bin/phantomjs /usr/bin/ RUN gem install bundler --version=1.16.3 RUN mkdir /my_app WORKDIR /my_app COPY . /my_app RUN bundle install
rails s の-bオプションは127.0.0.1で立ち上げるとうまく動かないためです。
こちらは下サイトを参考にしました。
docker上のアプリにlocalhostでアクセスしたらERR_EMPTY_RESPONSEが出る - Qiita
この状態でコンテナに入り下コマンドを実行するとサーバーを起動できます。
systemctl start mysqld rake db:create && rake db:migrate rake db:seed bin/rails s -b 0.0.0.0
MySQLのデータの永続化
次はデータベースのデータの永続化をします。
今はコンテナを削除するとデータが消えてしまうので、volumeを作る事で永続化しようと思います。
最初はホスト側にデータを保存しようと思ったのですが、MySQLの起動がうまくいかなかったのでvolumeを作る事にしました。
まずは下コマンドでvolumeを作成します。
docker volume create my_volume
docker volume lsコマンドを打つと今作ったvolumeを確認する事ができます。
削除はdocker volume rmコマンドを使います。
volumeはdocker runの-vオプションで指定します。
今回はMySQLのデータ部分をvolumeに保存したかったので-v my_volume:/var/lib/mysqlというオプションを付けました。
docker run -itd --name my_container -p 3000:3000 -v my_volume:/var/lib/mysql --privileged my_image /sbin/init
これでコンテナを作り直してもデータを保持するようになりました。
Docker Composeでコンテナを管理
次はDocker Composeを使ってコンテナを管理します。
Docker Composeを複数のコンテナを管理できるツールです。
まずは下コマンドでDocker Composeが入っていることを確認します。
入ってない場合は各環境に応じた方法でインストールします。
docker-compose version
次はDocker Composeの設定ファイルであるdocker-compose.ymlを作成して下のように記述します。
version: '3' services: app: container_name: my_container privileged: true volumes: - my_volume:/var/lib/mysql ports: - 3000:3000 command: /sbin/init build: . volumes: my_volume:
起動コマンドは下のとおりです。
先程使っていたdocker runに比べると非常にシンプルになりました。
docker-compose up -d
コンテナの停止と削除は下コマンドになります。
docker-compose down
Imageの削除も行いたい場合は下のオプションを追加します。
docker-compose down --rmi all
データベースを別コンテナ化
Docker Composeを入れたので、コンテナもアプリケーションとデータベースで分けたいと思います。
下のようにdocker-compose.ymlにデータベースコンテナを追加します。
ホスト側からDBにアクセスしない場合はportsの部分は削除して構いません。
environmentのMYSQL_USERとMYSQL_PASSWORDではユーザーを作成しています。
MYSQL_DATABASEでデータベースの作成とそのデータベースへの権限付与を行います。
appの方にはdepends_onを追加します。
これによってdbを起動してからappを起動できるようになります。
version: '3' services: app: container_name: my_container_app privileged: true volumes: - my_volume:/var/lib/mysql ports: - 3000:3000 command: /sbin/init build: . depends_on: - "db" db: container_name: my_container_db image: mysql:8.0 volumes: - my_volume:/var/lib/mysql environment: MYSQL_USER: user MYSQL_PASSWORD: password MYSQL_DATABASE: my_db MYSQL_ROOT_PASSWORD: password hostname: db_container ports: - 3306:3306 volumes: my_volume:
起動するとデータベースのコンテナも作られている事が分かります。
ホスト側からは下コマンドでアクセスできるようになります。
mysql -h localhost -u test --protocol=tcp -p
次はアプリケーション用コンテナから今作ったデータベースを見るようにします。
まずはDockerfileから下のようにMySQL関連の処理を削除します。
FROM centos:8 # Ruby RUN yum -y install git gcc make bzip2 openssl-devel readline-devel zlib-devel RUN git clone https://github.com/sstephenson/rbenv.git ~/.rbenv RUN cd ~/.rbenv && src/configure && make -C src RUN git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build RUN echo 'export PATH="$HOME/.rbenv/bin:$PATH"' >> ~/.bash_profile && echo 'eval "$(rbenv init -)"' >> ~/.bash_profile ENV PATH /root/.rbenv/bin:/root/.rbenv/shims:$PATH RUN rbenv install 2.5.1 && rbenv global 2.5.1 # Rails RUN yum -y install mysql-devel gcc-c++ nodejs crontabs wget fontconfig-devel RUN wget https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-2.1.1-linux-x86_64.tar.bz2 && tar jxf phantomjs-2.1.1-linux-x86_64.tar.bz2 && cp phantomjs-2.1.1-linux-x86_64/bin/phantomjs /usr/bin/ RUN gem install bundler --version=1.16.3 RUN mkdir /my_app WORKDIR /my_app COPY . /my_app RUN bundle install
Railsのdatabase.ymlにDBコンテナのパスワードやホスト情報を追加します。
default: &default adapter: mysql2 reconnect: false pool: 5 username: user password: password host: db_container development: <<: *default database: my_db test: <<: *default database: my_db production: <<: *default database: my_db
これでデータベースのコンテナを分割する事ができました。
あとは下コマンドでアプリサーバーを立ち上げれば完了です。
rake db:create && rake db:migrate rake db:seed bin/rails s -b 0.0.0.0
起動に関する処理の自動化
次は上に記載したrails sなども自動化していきます。
まずは自動化用のファイルdocker_app_command.shを作成して下のように記述します。
#!/bin/sh rake db:create && rake db:migrate rake db:seed bin/rails s -b 0.0.0.0
ファイルには実行権限を与えておきます。
chmod 755 docker_app_command.sh
次はdocker-compose.ymlにcommandを追加して先程追加したファイルをセットします。
commandはコンテナ起動時に呼ばれる処理になります。
services: app: container_name: my_container_app ports: - 3000:3000 build: . command: /sbin/init && ./docker_app_command.sh
ローカルでの更新を即時反映する
次はホスト側で編集したコードを即時反映されるようにします。
今は変更の度にImageの作り直しが必要なので時間がかかってしまいます。
コードの反映はdocker-syncというツールを使います。
ホスト側をマウントする形も考えたのですがパフォーマンスが良くないようなのでdocker-syncで進めていきたいと思います。
まずは下コマンドでdocker syncをインストールします。
gem install docker-sync
次にdocker-sync.ymlというファイルを作って下のように記述します。
version: "2" syncs: my_sync_volume: src: "." sync_excludes: - "log" - "tmp" - ".git"
docker-compose.ymlのservices → app → volumesとvolumesにdocker-sync.ymlで定義したVolumeを追加します。
services: app: volumes: - "my_sync_volume:/my_app:nocopy" volumes: my_volume: my_sync_volume: external: true
Docker Syncは下コマンドで動かします。
docker-sync start
docker-sync利用時ですが.docker-syncというフォルダが作られるので下のように.gitignoreに追加すると良いかと思います。
.docker-sync
同時にアプリケーションサーバーのDockerfileも修正します。
今までプロジェクト全体をCOPY . /my_appでコピーしていましたが下のように最小限にします。
そうする事で更新が最小限になってbundle install部分もレイヤーキャッシュを使ってくれるようになります。
COPY Gemfile /my_app/Gemfile COPY Gemfile.lock /my_app/Gemfile.lock RUN bundle install
コンテナ起動時にもbundle installをしてほしいのでdocker_app_command.shにbundle installを追加します。
#!/bin/sh bundle install rake db:create && rake db:migrate rake db:seed bin/rails s -b 0.0.0.0
これで無事にRailsを立ち上げられるようになりました。
その他利用したコマンド
キャッシュの全削除。
docker builder prune
キャッシュ利用状況の確認
docker system df
CentOS8へのインストール
Dockerをyumでインストールしたらうまくいかなかったので下コマンドでインストールと起動をしました。
dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo dnf -y install --nobest docker-ce docker-ce-cli systemctl enable docker systemctl start docker
Docker Composeのインストールは下コマンドで実施しました。
wget https://github.com/docker/compose/releases/download/1.25.5/docker-compose-Linux-x86_64 mv docker-compose-Linux-x86_64 /usr/local/bin/docker-compose chmod +x /usr/local/bin/docker-compose
参考URL
Docker入門(第一回)~Dockerとは何か、何が良いのか~ | さくらのナレッジ
【Docker】コンテナの停止と削除を同時に行う - (O+P)ut