こんにちは。エンジニアの森田です。 MFクラウド会計の開発を担当しています。
今月入社したばかりなのですが、実は入社前からDockerで開発環境を作ろうと心に決めていました。 なぜなら、下記のような問題によく悩まされていたからです。
- OSやRubyのバージョンアップの度にbundle installがこける。
- Windowsを使っているデザイナさん向けに動作環境を作るのが大変。
- ブランチを切り替えるとDBのスキーマが違うため動かない。
- ライブラリを新しいものに差し替えたら既存のアプリがおかしくなる。
そこで実際にDockerを導入してみました。 今回はDocker導入に際しての問題とその対応について紹介します。
発覚した問題と対応
コーディングの際はMac上のエディタを使いたいので、Dockerのディレクトリ共有機能を使ってコンテナとホストでプロジェクトのディレクトリを共有していたところ、Webサーバのレスポンスがめちゃくちゃ遅くなってしまいました。(VirtualBox上のDockerだから?)
また、ファイルを更新してもRailsが認識してくれず、Railsを再起動しないと反映されない状態になりました。
共有を諦めて仮想環境上でファイルを更新すればいいのですが、それはそれでいろいろ制限があります。
そこで、Dockerの共有機能を使うのではなく、コンテナ側にsshdを立てて、ホスト側(Mac)にlsyncdをインストールして使うことにしました。 それにより、ホストとコンテナのファイルがほぼリアルタイムに同期され、Webサーバのレスポンスも快適になり、ファイルの更新も反映されるようになりました。
かなり快適に開発できるようになったので、設定を共有したいと思います。
Dockerの基本的な操作に関しては前佛 雅人様が素晴らしい記事を上げてくださっているのでそちらを参照してください。
Docker
インストール
dockerのインストールはMacでもWindowsでもboot2dockerを使えば簡単なので割愛させていただきます。
コンテナ作成から起動まで
プロジェクトで必要なライブラリを含めたImageを作成するためにDockerfileを作成し ます。
Dockerfile
FROM centos:centos6 RUN yum -y update RUN yum -y install gcc git rsync tar openssl openssl-devel readline-devel zlib-devel libffi-devel gdbm-devel tk tk-devel tcl tcl-devel patch gcc-c++ which sqlite-devel wget openssh-server # rbenvのインストール RUN git clone https://github.com/sstephenson/rbenv.git /root/.rbenv RUN git clone https://github.com/sstephenson/ruby-build.git /root/.rbenv/plugins/ruby-build RUN ./root/.rbenv/plugins/ruby-build/install.sh ENV PATH /root/.rbenv/bin:$PATH RUN echo 'export PATH=/root/.rbenv/bin:$PATH' >> /root/.bashrc RUN echo 'eval "$(rbenv init -)"' >> /root/.bashrc # rubyのインストール ENV CONFIGURE_OPTS --disable-install-doc RUN rbenv install 2.2.2 RUN rbenv global 2.2.2 RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key -C '' -N '' RUN ssh-keygen -t dsa -f /etc/ssh/ssh_host_dsa_key -C '' -N '' EXPOSE 22 3000 CMD ["/usr/sbin/sshd", "-D"]
上記のDockerfileはCentOS上でrubyアプリ(Rails等)を作成するための環境用です。
Dockerfileからイメージ(ruby_app:1.0)作成
docker build -t ruby_app:1.0 .
作成したイメージ(ruby_app:1.0)を使ってコンテナ(mf_dev)を起動
docker run -d -p 80:3000 -p 2022:22 --name mf_dev -i -t ruby_app:1.0
ホストからコンテナ(mf_dev)にログイン
docker exec -it mf_dev bash
コンテナ(mf_dev)上でssh keyを登録
mkdir ~/.ssh vi ~/.ssh/authorized_keys #ホスト(Mac)のid_rsa.pubを記述
lsyncd
インストール
Macのrsyncが古くてlsyncdが動かないため、rsyncを置き換えています。
brew update brew install rsync lsyncd lua sudo mv /usr/bin/rsync /usr/bin/rsync_orig sudo ln -s /usr/local/bin/rsync /usr/bin/rsync
Boot2dockerのIP確認
boot2docker ip
設定ファイル作成
lcync.cnf
settings { logfile = "/tmp/lsyncd.log", statusFile = "/tmp/lsyncd-status.log", maxProcesses = 2,<-最大プロセス数 delay = 3,<-変更反映をまつ時間 nodaemon = false,<-trueだとデーモンにしない } sync { default.rsync, source = "/Users/morita/sample/",<-ホスト(Mac)側のディレクトリ target = "192.168.59.103:/root/sample/",<-Boot2dockerのIP:コンテナ側ディレクトリ rsync = { archive = true, links = true, update = true, verbose = false, rsh = "/usr/bin/ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -p 2022 -i /Users/morita/.ssh/id_rsa",<-秘密鍵の場所を指定する } }
起動
#/dev/fseventにアクセスするためroot権限が必要 sudo lsyncd lsync.conf
ホスト(Mac)からコンテナへの一方通行の同期のため、コンテナ上でrails g migration等でファイルを作成、更新した場合は自分でホスト側に反映する必要があります。
コンテナ上でRailsアプリ実行
gem install bundler --no-ri --no-rdoc cd /root/sample bundle install bundle exec rake db:migrate bundle exec rake db:seed bundle exec spring rails s -b 0.0.0.0
表示確認
ブラウザで下記アドレスアクセス http://Boot2dockerのIP
tips
コンテナ上でscreenを実行すると '/dev/pts/1': No such file or directory のエラーになりますが、screen実行前に script /dev/null を実行するとscreenが使えるようになります。
まとめ
Docker最高。 今流行りのDockerを活用しつつ、慣れることもできるのでオススメです。
7/12追記 docker-osx-devを使うといいよ教えてくださった方がいました。 docker-osx-devのページにBoot2Dockerのディレクトリ共有で使うVirtualBoxのvboxsfに関して下記のように記載されていました。
1.ファイルアクセスが10〜20倍遅い 2.トリガーが壊れているため、inotifyによるファイルの更新を検知できない。
そのため、docker-osx-devは、VirtualBoxのvboxsfによる共有機能ををOFFにして、rsyncを使ってホスト(Mac)側とBoot2Dockerの仮想マシンとOne wayで同期を取るようデーモンを起動する仕組みになっています。 仮想マシンとコンテナ間はdockerの-vによるディレクトリ共有機能を使います。 lsyncdによる同期とは違って、コンテナにrsync,sshdをインストールする必要がないです。
docker-osx-devを実際に使ってみましたが、簡単にインストールでき、問題なく動作しました。
ただ、docker-osx-devを再起動したところ、下記のようなワーニングが出力されました。
chown: /Users/morita/.boot2docker/boot2docker-vm.sock: Operation not supported
同期自体は動くのですが、下記のようにマシン負荷が高まりつづけてしまいます。
Command %CPU VBoxHeadless 162.6
仮想マシン内を見ると、同期指定していないディレクトリまでコピーされていたりしてちょっと謎です。
また記事にあるlsyncd形式にすると、下記のメリットもあるので、個人的にはlsyncd形式でいこうかと思っています。
- 同期するディレクトリをDocker run実行後以降も選択できる
- 同期していないディレクトリのファイルもホスト側で編集できる。(GUIのscpツールやエディタのリモート編集etc)
最後に
マネーフォワードでは、Railsエンジニアを募集しています。 お互いに改善案を出し合いながら、サービスと共に一緒に成長出来る仲間をお待ちしています!
【採用サイト】 ■『マネーフォワード採用サイト』 https://recruit.moneyforward.com/ ■『Wantedly』 https://www.wantedly.com/companies/moneyforward
【公開カレンダー】 ■マネーフォワード公開カレンダー
【プロダクト一覧】 ■家計簿アプリ・クラウド家計簿ソフト『マネーフォワード』 https://moneyforward.com/ ■家計簿アプリ・クラウド家計簿ソフト『マネーフォワード』 iPhone,iPad ■家計簿アプリ・クラウド家計簿ソフト『マネーフォワード』 Android ■クラウド型会計ソフト『MFクラウド会計』 https://biz.moneyforward.com/ ■クラウド型請求書管理ソフト『MFクラウド請求書』 https://invoice.moneyforward.com/ ■クラウド型給与計算ソフト『MFクラウド給与』 https://payroll.moneyforward.com/