「北欧、暮らしの道具店」のシステムリニューアルと新メンバー参加に向けて整えた開発環境

エンジニア 濱崎
「北欧、暮らしの道具店」のシステムリニューアルと新メンバー参加に向けて整えた開発環境

こんにちは、エンジニアの落合です。
クラシコムが運営するECサイト「北欧、暮らしの道具店」は、2016年5月にそれまで使っていたASPサービスを離脱し、フルスクラッチで開発したオリジナルのシステムにリニューアルしました。

(その経緯についてはこちら

今回は、リニューアルプロジェクトが始まる際に、少ないリソースで効率良く仕事をするために整えた開発環境についてお伝えします。

 

たった1人でのスタート

oliver-san

2015年1月にリニューアルプロジェクトが始まる前、クラシコムにいたエンジニアは、現在ノルウェーからサポートしてくれている、スウェーデン人のオリバーたった1人でした。

プロジェクトが始まるタイミングで、現リードエンジニアの濱崎が入社するのに合わせて、エンジニアが増えてもスムーズに開発できるように、オリバーが3ヶ月かけて現在の開発環境・開発フローを構築しました。

このブログを書くことが決まった時に、当時どんな思いでプロジェクトをスタートしたのか、オリバーに聞いてみました。


私が入社する前のクラシコムでは、WordPressを使った読みものコンテンツをさくらVPSで稼働させ、ASPのECサービスを使ってECサイトを運用していました。さくらVPSでの運用には限界があったので、私が入社したときに、読みものコンテンツをAmazon EC2に移行しました。

はじめは、それぞれのEC2インスタンスにSSHでログインして、各インスタンスをマニュアルでセットアップしていました。しかし、マニュアルでの作業は時間がかかる上に、ミスをする危険もあり、スケーラビリティに欠けていました。後にECサイトのリニューアルも控えていたので、より柔軟でスケーラブルに対応できるインフラのオーケストレーション方法を考えました。

その当時、Docker はまだ本番導入できる段階のものではなかったため、 Puppet と Chef を検討していました。当時からChef はコミュニティが活発で、かつ AWS でも Chef をサポートしているサービス(Amazon OpsWorks)があったので、 最終的には Chef を採用。代表の青木に掛け合い、3ヶ月間、新規機能の開発を全てストップして Chef および Amazon OpsWorks の導入に費やしました。

そして、 Vagrant + Chef で開発環境構築の負担をなくし、新たに加入してくるエンジニアが簡単にスタートできるように、Shellで独自のコマンドツールを作成。
また、ユニットテストを導入し、バグ修正のオーバーヘッドを最小限に抑えて開発スピードを保ちつつ、リニューアル開発の生産性と機能性を高めていきました。

これにより、開発者は既存の機能が動作しなくなったとしても、何が原因なのかをすぐに発見することができ、より迅速かつ確実に開発することができるようになりました。


経験上、ドキュメントがあったとしても、個々のマシンによってはセットアップに違いがでてくることもあり、環境構築にはいつも苦労させられるイメージがありました。
私にとって、Chefを使った環境構築は初めてでしたが、問題なく構築ができ、スムーズに開発に入っていくことができました。

また、当時ECシステムのリニューアル以外にもやりたいことがたくさんあったはずなのに、 3ヶ月間全ての開発を止めて、環境を整えることに集中させてくれた青木の決断にも驚かされました。
「システムのことは分からないけど、、」と言いながらも、私たちエンジニアがやりやすい環境を一緒に考えてくれているので、良いコミュニケーションがとれていると感じます。

 

開発中のストレスをなくす

development

Vagrant + Chefを採用することで、開発環境を構築する負担は大幅に減りましたが、まだマニュアルでやらなければならない面倒な作業が多くありました。

開発中は、無用なストレスから開放されてコーディングに集中したいので、GulpやShellスクリプトで作業をできるだけ自動化しています。

1. VMの操作をもっと簡単に

VagrantでVMを起動したりChef Cookbookを使ってプロビジョンするためには、いくつかのvagrantコマンドを使ったり、VMのIDを確認したりする必要があります。

こういったVMの操作をもっと簡単にするために、vagrantコマンド等をラップした “vm” というShellコマンドを作りました。

例えば、”vm provision app_api” というコマンドを実行すると、VMを新規作成して “app_api” という名前のChef Cookbookを使ってVMをプロビジョンします。

このCookbookにはプロビジョン用のレシピとデプロイ用のレシピが含まれているので、プロビジョンが完了したら、アプリケーションのソースコードがGitHubからVMにデプロイされ、すぐにアプリケーションを動かすことができます。

2. VMとのファイル同期・テスト実行・Asset PipelineをGulpタスク化

Vagrant (VirtualBox) は、ローカルのファイルシステムと同期されていないので、rsyncで同期する必要があります。VagrantにはSynced Foldersというファイル同期の機能もありますが、遅くて使い物になりませんでした。

また、ファイルを修正して保存する度に、VMでテストを実行したりSassなどのアセットをコンパイルする必要もあります。

これらの作業をGulpタスク化して、ファイルを保存する度に自動で実行されるようにしています。大きく分けて以下の3種類のGulpタスクを使っています。

・sync
ローカル・VM間のファイル同期用タスク。ローカルのファイル変更をウォッチして、rsyncでVMに転送する。

・test
VMでテストを実行するためのタスク。VMでのファイル変更をウォッチして、phpcsfixer, phpunitを実行。(PHPアプリケーションの場合)

・assets
SassやJSなどのAsset Pipeline用のタスク。VMでのファイル変更をウォッチして、Sassのコンパイル・ファイル圧縮・ファイル名にハッシュ付与・ローカルへのファイル転送を実行。

3. Gulpタスクの実行やログのtailをShellで自動化

Gulpタスクを用意したとしても、それらを実行するためには、タスクごとにターミナルのタブを開き、ローカルやVMでgulpfile.jsが置かれているディレクトリまで移動してタスクを実行しないといけません。これも地味に面倒です。

また、開発中はアプリケーションのログを確認することが頻繁にあるので、常にtailしておきたいです。

クラシコムでは、これらの作業を1発で行ってくれるShellコマンドを作って、開発を始める前にそれを1度だけ実行すれば良いようにしています。

develop_shop


より迅速かつ確実にデプロイする

EC2へのアプリケーションのデプロイは、以下のフローで行っています。

GitHub → CircleCI → Amazon OpsWorks → Amazon EC2

deploy

このようなフローにした理由は、エンジニアが3人しかいないため余計な手間は省きたいのと、必ず全テストを通すことでソースコードの品質を担保し、迅速かつ確実にデプロイするためです。

Stagingブランチは、CircleCIでのテストをパスしたらAmazon OpsWorksの deploy コマンドを実行し、EC2 に自動デプロイします。

本来であれば、Production も Staging のように自動デプロイで済ませたかったのですが、一部のアプリケーションでCircleCIでのテストに時間がかかり断念。
迅速にデプロイできることを優先しているため、現状は Amazon OpsWorks からマニュアルで deploy コマンドを実行しています。
最近CircleCIでのテストの高速化に成功したので、ProductionもCircleCIからの自動デプロイを検討しているところです。

数あるCIツールの中から CircleCI を採用したのは、比較検討していた TravisCI より月額のコストが安かったことと、 Privateリポジトリの制限がなかったからです。当時から複数のリポジトリを管理していたので、今後のことも踏まえ Privateリポジトリの制限がないことを優先しました。

 

課題と今後の展望

docker

当時は Docker があまり普及していなかったので、Vagrant + Chef の組み合わせを選択しましたが、2年半使ってみて不便なところもでてきました。

例えば、Vagrant のファイル共有(rsync, nfsなど)がうまく機能しないことがありましたが、Docker ではローカルのファイルシステムと共有できるため、ファイルが共有できないという心配はありません。

他にもいくつか課題がありますが、今なら Docker で解決できると考えているので、現在、Docker 導入のため検証を行っています。

 

クラシコムでは、これからのECを一緒に作っていってくれるエンジニアを随時募集していますので、興味がある方はぜひ一度オフィスに遊びに来てください!

▼クラシコムでは現在エンジニアを募集しています。