制作環境

Published on 2017/10/23

Naokazu Terada

制作環境

2017/10/23

Naokazu Terada

今回はKARAPPOで普段行っている公開作業(デプロイ)の仕組みについて解説し、改めてどういう考えで今の形に落ち着いたのか整理してみようと思います。
この記事のメインターゲットは、受注案件メインの制作会社などで、公開作業を毎回手作業で行っているエンジニアの方々です。一括りに「ウェブエンジニア」といっても、ウェブアプリ開発系の現場ではデプロイ・ツールも充実していて、色々モダンな手法があると思います。しかし、その他のウェブ制作の現場では、実は意外と未だにFTPクライアントを使ったアップロードなどしているところもあるんじゃないか?と思い1、そういう人たち向けに書いてみます。比較的少ない投資ですぐ運用できるので2、もし気に入ったら詳しい使い方などはGitHubのドキュメントを読んでみて下さい。

drone-deploy の紹介

紹介するのは drone-deploy というシェルスクリプトで書かれたプログラムで、OSSのCIサービス DroneとGitHubなどのバージョン管理サービスと合わせて使います。gitのログを確認すると2014年8月から現在(2017年10月)まで、既に丸3年以上実戦で運用し、メンテナンスしてきた秘伝3のスクリプトです。

karappo/drone-deploy

全体をざっくり解説すると、下の図のようになります。

  1. ローカルでの開発
  2. GitHubにpush

ここまでが、ユーザーがやることで、あとはdrone-deployがやってくれます。

  1. Droneへのclone
  2. drone-deployからスクリプトを取得
  3. スクリプトの実行
    1. 前処理(環境毎の置換処理など ※)
    2. ファイルの転送
    3. 後処理(キャッシュの削除など ※)
  4. Slack等への通知(任意)

※ プロジェクト毎に自由にカスタマイズ可

以上、シンプルです。では、導入前の課題とそれが導入後どう解決されたかについて書いていきます。

開発から公開までのワークフローの一元化

せっかくgitでソースコード管理をしていても、デプロイを手作業で行っている限り、リポジトリのコードが最新である補償は残念ながらありません4。
そこで、Herokuのようにgit pushしたらあとは自動でやってくれるような仕組みにしたいと思いました。また、社内の全員が同じワークフローで仕事を行うことで、特定の個人に依存しない皆が使える環境を構築出来ました。例えばツールのアップデートも、皆が共通で使っているdockerイメージを更新すれば良いので簡単です。
また、ファイル数が多い場合など、単純に転送にかかる時間も長くなり、無駄なコストになります。rsync5を使えれば良いのですが、フロントエンドエンジニアにはちょっとハードルが高いです。ですが、こんな便利なものは誰でも気軽に利用できるようにするべきだと思っていました。ワークフローを統一したことで、それが実現できたのも大きなメリットでした。
また、branchで展開先を切り替えたり、pushしたら通知が来るまでは他の作業をしたりできるのは、実際かなりの負担軽減になっていると思います。

デプロイ作業のコード化

例えば、長く付き合いをさせていただいているお客さんから、久しぶりに改修やリニューアルなどというお話を頂くことがあります。久しぶりに作業すると、例えば既に作業マシンを新調していてサーバーの接続情報を調べるところから始めなければならないこともあります。また、それがもし緊急の要件で、さらに担当者以外の人間が対応をしなければならないとなると、手間取って非効率的ですし、精神的にも不安が残ります。
もしこの手続きがコード化されていれば、その辺の心配をせず安心して対応することができるようになります。例えば一番初歩的なところだと、Ignore fileの機能を使うことで、うっかりWordPressのuploadsフォルダを上書きしてしまうことを防止出来ます。プロジェクト毎にそうした手続きをしっかりとコード化できるので、いつ更新したかわからなかったり他人が読んだ時に不明な点が入り込む余地のある“秘伝のタレ”的手続書よりも、常に稼働してきたコードの方が信頼できますよね。

色んなサーバー環境への対応

制作会社では案件によって様々なサーバー環境に対応しなければなりません。何でもできるVPSやPaaS等で運用している案件もあれば、gitもrsyncも入っていないようなレンタルサーバーで運用している案件もあります。そのあたりに対応するために、転送にgitは使わず、rsyncとlftpを使います。FTP接続のみ(しかもSFTP非対応とかだったり…)のサーバーなどもたまにあるので、あまり好ましくはないですが、lftpで素のFTPプロトコルによる転送も選択可能にしています。
前章までの繰り返しになりますが、担当者が責任持って、望ましい転送方法をあらかじめ選択していれば、本来SFTPが使えるのに何故か特定の人だけFTPで転送している、などということも予め抑止できます(デプロイ作業のコード化)。また、ターゲットとなるサーバーが望ましいプロトコルに対応した際に、.drone.ymlをアップデートしさえすれば誰がやっても適切な転送方法が選択されます(ワークフローの一元化)。また副産物として、デプロイ用のサーバーが一箇所に集約するので、IP制限のあるサーバーに対して、出先からもデプロイすることができるようになりました。

環境毎の設定変更を自動化

ここまでに書いた問題点は、実はDroneのプラグイン機能を使って解決することもできそうなのですが、drone-deployを作ろうと思いたった、もう一つ重要な要件があります。それは環境毎の設定切替機能です。
例えば、WordPressのサイトでローカルとステージング、本番環境でそれぞれDBの設定を変えなければならない、ステージングサイトでは認証を追加したいなど、環境に合わせて変更したい部分があります。例えばRailsとかだと、環境変数をまとめた設定ファイルを置いて管理しますが、そのようなことができるといいなと思ったのです。
例を見てもらうと早いと思うので以下を御覧ください。WordPressのwp-config.php内のDBの設定部分の抜粋です。

ローカル開発時では、下記のような状態で開発をすすめ、deploy時にその下に示したように変換してくれるという機能です。

// Activate only in local environment
//DEP_REMOTE_RM /*
define('DB_NAME', 'LOCAL_DATABASE');
define('DB_USER', 'root');
define('DB_PASSWORD', 'root');
define('DB_HOST', 'localhost');
//DEP_REMOTE_RM */

// Activate only in master branch's deploy target
//DEP_MASTER_RM define('DB_NAME', 'PROD_DATABASE');
//DEP_MASTER_RM define('DB_USER', 'PROD_USER');
//DEP_MASTER_RM define('DB_PASSWORD', 'PROD_PASSWORD');
//DEP_MASTER_RM define('DB_HOST', 'PROD_HOST');

// Activate only in staging branch's deploy target
//DEP_STAGING_RM define('DB_NAME', 'STAGING_DATABASE');
//DEP_STAGING_RM define('DB_USER', 'STAGING_USER');
//DEP_STAGING_RM define('DB_PASSWORD', 'STAGING_PASSWORD');
//DEP_STAGING_RM define('DB_HOST', 'STAGING_HOST');

↓

// Activate only in local environment
/*
define('DB_NAME', 'LOCAL_DATABASE');
define('DB_USER', 'root');
define('DB_PASSWORD', 'root');
define('DB_HOST', 'localhost');
*/

// Activate only in master branch's deploy target
define('DB_NAME', 'PROD_DATABASE');
define('DB_USER', 'PROD_USER');
define('DB_PASSWORD', 'PROD_PASSWORD');
define('DB_HOST', 'PROD_HOST');

// Activate only in staging branch's deploy target
//DEP_STAGING_RM define('DB_NAME', 'STAGING_DATABASE');
//DEP_STAGING_RM define('DB_USER', 'STAGING_USER');
//DEP_STAGING_RM define('DB_PASSWORD', 'STAGING_PASSWORD');
//DEP_STAGING_RM define('DB_HOST', 'STAGING_HOST');

Railsのようにファイルで切り出すのではなく、コメントアウトを利用して同一コード内に記述するスタイルです。この例の場合、masterブランチにpushしている想定です。sed6を使って//DEP_REMOTE_RMや//DEP_MASTER_RMという文字列を削除しています。同じようにstagingブランチにpushすれば、//DEP_REMOTE_RMと//DEP_STAGING_RMが削除されるという具合です。必要なとこだけこの形式でコメント化しておけばよいという形です。詳しくはこちらを参照して下さい。
複数の環境設定をいちいちデプロイ時に、置換する手間がなくなるので、以前までと比べるとかなり効率化されます。個人的にはこれが一番のオシ機能です。

Droneを選んだ理由

CIのサービスはTravis CI や CircleCI など色んな選択肢がありますが、Droneを使うことにしました。その理由は、DroneはOSSでセルフホスティングが可能なため、機密情報の取扱など考えると都合が良かったからです。開発は今も結構盛んなので、まだしばらくは安心して使えそうです。dockerを使って簡単にインストールできるのも良くて、比較的に気軽にアップデートが出来ます(手順はQiitaにまとめてます)。昔VPSでGitlabをホスティングしていた頃の苦労を考えると、dockerベースの運用は隔世の感があります…。CIは最悪壊れても致命的ではないというのもありますが。

今後の展望

Droneにはプラグイン機能があるので、パッケージングしてみるのも面白そうです。その方が他の人も使ってもらいやすいかもしれないですよね。
プラグインはgoで書くのが基本だと思いますが、一応Bashでも作れるみたいなので、ちょっと迷います。シェルスクリプトは文法的なところで結構つまずくので、メンテのしやすい言語で書き直すのは良い気がしますが、逆に依存しすぎると今後移植性の面で不利になるかもしれません。悩ましいですね…。

おわりに

KARAPPOでは、作業負担の軽減や制作物のクオリティアップのために、エンジニアリングの力でできることが、まだまだたくさんあると思っています。そうした作業の手伝いや開発をしてくれる仲間がいると嬉しいです。


エンジニアを募集しています!


KARAPPOでは、エンジニアリング的視点から生まれる新しいアイデアや問題解決の提案、他の会社ではできないような面白いチャレンジをしていくために、今よりエンジニアの数を増やしたいと思っています。貢献したい/しても良いよという方は、ぜひこちらの募集要項をご覧になってご応募ください(この記事読んだよと書いてくださるとさらに喜びます)。よろしくお願いします!

  1. 実際KARAPPOも数年前はそんな状態でした
  2. Droneをホスティングするサーバー代だけす。DigitalOceanなら1分単位で借りられます
  3. 秘伝といいつつOSSですが
  4. 『直接サーバー上のコードを触るってこと?そんなバカな?!』と思われるかもしれませんが、コーディングからデプロイまでのしっかりとしたワークフローが整備されていないと、いつかそんな「バカ」なことが起こる可能性が残るので、これも精神衛生上よくありません…
  5. 差分符号化を使ってデータ転送量を最小化し、遠隔地間のファイルやディレクトリの同期を行うCLIツール
  6. テキスト変換をしてくれるコマンド