こんにちは、エンジニアの濱崎です。10月にPHP Conferenceに参加して来たのですが、僕が参加したセッションの半分以上はDocker関連でした。
先月行われたAWS re:INVENT 2017でも、Amazon EKSなどDocker関連のサービスがいくつか発表されたり、Docker界隈がますます盛り上がりを見せていますね。
そんな中、クラシコムでも今年の10月に開発環境をVagrantからDockerに乗り換えました。
今回は、クラシコムで開発環境をDockerに移行したメリット・課題・今後の展望などについてお伝えします。
約3年間、Vagrant + Chefでやってきた
クラシコムでは今年の10月まで約3年間、Vagrant + Chefで構築した開発環境を使ってきました。(詳しくはこちら)
その開発環境は、僕が2人目のエンジニアとして入社するタイミングで、チームで開発を始めるために用意してくれていたものでした。
当時、Chefなど触ったこともなかった僕は、誰のPCでもコマンド1発で全く同じ環境を立ち上げられることに感動した記憶があります。
現在も、ProductionとStaging環境は、Amazon OpsWorksとChefでサーバーの構成管理をしています。
Vagrant + Chefの課題
VagrantとChefを導入しただけでもかなり便利だったのですが、システムが大きくなるにつれて、いろいろな課題が出てきました。
プロビジョンに時間がかかる
初めてVMを立ち上げるときは、Chefのレシピを基にディレクトリやユーザーを作成したり必要なアプリケーションをインストールするので、初回は結構時間がかかります。
例えば、Rubyのビルドだけで10分以上かかり、長い場合はプロビジョンが完了するのに数十分かかるものもありました。
ホストマシンとVMの間でファイルシステムが独立している
ホストマシンとVMはそれぞれ独立したファイルシステムを持っています。
VagrantにはSynced Foldersというファイル同期の機能もありますが、遅くてあまり使い物にならなかったので、ファイルの変更を反映するためにrsyncで同期していました。
ホストマシンの消費リソースが大きい
ホストOSとゲストOS(VMのOS)は独立しているため、ファイルシステムやメモリ管理も当然独立していて、1つのVMを立ち上げるだけでも数GBのディスク容量を消費します。
また、メモリの消費も大きく、メモリ8GBのMacBookProでVMを3つほど立ち上げると、フリーズすることが良くありました。
Vagrantのバージョンによっては環境に差異が生じる
Vagrantのバージョンが違うとプロビジョンに失敗することがたまにあり、完全に同じ環境を再現できるわけではありませんでした。
このような課題もあり、管理するシステムが増えるにつれてVagrant環境で開発を続けることに限界が近づいてきたので、まずは開発環境からDockerに移行することにしました。
Dockerに移行したメリット
開発環境をDockerに移行してからは、Vagrantが抱えていた多くの問題が解決され、とても快適になりました。
起動が爆速
初回の起動時はDockerイメージをローカルにダウンロードするので数分かかりますが、2回目からは起動がものすごく速いです。
VagrantのVMを起動するのは1分以上かかっていましたが、Dockerでは5秒ほどで必要な全てのコンテナが起動します。(弊社APIサーバーでの比較)
VM (VirtualBox) ではゲストOSを起動するので時間がかかりますが、DockerはホストOSの中でプロセスを立ち上げるようなものなので、すごく速いです。
新メンバーが最初に開発環境をセットアップするときも、VagrantだとVMを4つくらいプロビジョンするのに数時間かかっていましたが、Dockerだと数分で完了します。
ホストOSとコンテナの間でファイルシステムを共有できる
DockerコンテナはホストOSの中で動くので、ホストとファイルシステムを共有できます。
VMを使っていたときは、Gulpでファイルをウォッチしてrsyncでファイルを転送していましたが、そんなことをする必要はなくなりました。
ホストマシンの消費リソースが少ない
Dockerコンテナは、ホストOSにプロセスを立ち上げるようなものなので、メモリやディスク容量の消費も小さいです。
Nginx, PHP-FPM, MySQL, Redis, キューのワーカープロセスなど、7つほどのコンテナを立ち上げても400MB弱のメモリしか消費しません。
Vagrantでは、DBやWebサーバー用のVMを立ち上げると、合計で3GBほどのメモリを消費していました。
グローバルにインストールするものが減った
Dockerを導入する前は、Node.jsやComposerなどのツールは、ホストマシンにグローバルにインストールして使っていたため、人によってインストールしているバージョンが異なり、うまく動かないことがありました。
インストールの仕方やバージョンを統一するのは難しいですが、Dockerを使い始めてからは、各種ツールの公式Dockerイメージを使って、コンテナ内でコマンドを実行するようにしました。
例えば、Yarnを実行するために以下のaliasを登録して、yarnコマンドを打てばDockerコンテナ内でyarnが実行されるようにしています。
alias yarn='docker run -it --rm -v $PWD:/usr/src/app -v ~/.gitconfig:/root/.gitconfig -v ~/Library/Caches/Yarn:/usr/local/share/.cache/yarn -w /usr/src/app node:6.11 yarn'
Dockerのおかげで、ホストマシンにインストールするツールが減り、環境による差異も限りなく無くすことができました。
Dockerに移行して見えてきた課題
Dockerの良いことばかり書いてきましたが、使い始めて分かった課題もいくつかあります。
デフォルトの設定だとCPU使用率が急激に上がった
これは僕達のチーム固有の問題だと思いますが、Docker Composeで複数コンテナを立ち上げたときに、DockerのプロセスだけでCPU使用率が100%を超えて、Macが熱を持ってシュンシュン鳴り始めました。
キューをウォッチしているコンテナが最もCPUを使っていたのですが、docker-compose.yml の volumes
ブロックに cached
オプションを付けることで解消されました。
このオプションをつけると、ホストでのファイル変更がコンテナに反映されるまでに若干ディレイが発生するみたいですが、今のところ特に問題は起きていません。
参照:Performance tuning for volume mounts
学習コスト
用意されているDockerfileやdocker-compose.ymlを使うだけなら簡単なんですが、自分でDockerfileを書いたりするにはそれなりに勉強が必要でした。(Chefも学習コスト高いですが)
また、開発環境で使うハードルは低いですが、本番環境で運用するためには開発環境とは異なる知見が多く必要で、まだまだハードルが高いと感じました。
今後のこと
開発環境はDocker化することができましたが、ProductionとStaging環境については、現在Dockerに移行するための作業を進めているところです。
Kubernetesでデプロイすることも検討したのですが、AWS上でKubernetesを動かすには手動での煩雑なセットアップが必要だったので、まずは簡単に導入できる Elastic Beanstalk でデプロイすることにしました。
AWSでKubernetesを実行できる Amazon EKS のプレビュー版が発表されたり、Docker for MacがKubernetesをサポートするというニュースもあったので、動向をウォッチしながらKubernetesも試してみたいと思っています。
最後に
今、僕たちは新しいECプラットフォームを一緒に作っていける仲間を探しています。
技術を追求しながら、ライフスタイルも充実させ、最高のチームを作っていきたいと思っています。
興味がある方はぜひ一度、オフィスに遊びに来てみてください!