こんにちは。エンジニアの西尾です。
食べチョクのステージング環境では、本番環境のデータを日次で同期して利用しています。 今回はステージング環境の役割と、どのようにデータ同期をしているのかについてご紹介いたします。
ステージング環境
食べチョクでは、手元のマシンでプログラムを修正しコードレビューを実施後、改修内容をステージング環境にデプロイしています。 ステージングは、本番へのリリース前に修正箇所の動作確認・検証する環境です。この環境で動作や性能に問題がないかを確認後、本番環境へのデプロイを実施しています。
ステージング環境には、本番と同等のデータが入っています。 リリース当初は、ステージング環境と本番環境のデータは同期しておらず、テスト用のダミーデータで動作確認を行っていました。 しかしダミーデータでの確認だと、
- ダミーばかりが並んだサイトと本番環境では見た目や印象が違っていて、UIが最適なのか、操作しやすいのか、性能は問題ないか等の検証がしにくい
- 本番環境でしか再現しない、データに依存したバグに気がつかない恐れがある
という問題がありました。ステージングで動いたのに本番デプロイしたらエラーが発生した というリスクもできるかぎり下げたいものです。 そのため本番環境のデータをステージングに同期し、テストに利用することにしました。
データをマスクして同期する
食べチョクはECサイトであり、DBにはユーザーの個人情報(氏名、メールアドレス、住所等)が入っています。 本番環境のデータを利用するにあたり、センシティブなデータをマスクしないで同期してしまうと、思わぬ情報流出や事故につながる可能性があります。
特に怖いのがメールアドレスです。 ユーザーの操作やバッチ処理でメールを飛ばす処理はいたる所に存在しています。 テストのためにバッチを動かしたら、実際のユーザーさんにメールが飛んでしまった等といった事故を防ぐためにも、ステージング環境へはデータをマスクして同期する必要があります。
データ同期に必要なこと
本番データをステージングに同期するにあたり、以下を実現したいです。
- 個人情報やセンシティブな情報はマスクして同期したい
- ユーザー名、メールアドレス、住所 etc はマスクして同期
- データ同期はリアルタイムではなくてよい (1日1回 とか数回で問題ない)
また、食べチョクではデータベースへのマイグレーションはそこそこの頻度(週1,2回)で発生しています。 マイグレーション発生のたびに同期ツールの設定修正はできるかぎり行いたくはありません。 そのため、マイグレーションが発生してもいい感じにデータ同期してくれるツールが必要でした。
DB同期ツール Gamma
データの差分同期ができて、マスク処理も(Rubyで)簡単にかけて、DBのテーブルやカラムが増えても手がかからない、そんなツールが欲しかったです。 なかなか良さそうなものが見つからなかったので、自前でツールを作って対応しました。
https://github.com/nishio-dens/gamma というツールです。githubでも公開しています。
gammaでは、次のようなyaml形式の設定ファイルを作り、データ同期をします。
# data.yml # # 対象DBの ar_internal_metadata というテーブル以外をすべて差分同期する # updated_at カラムの値を見比べて、差分があるかを判断する - data: table: - "*" table_without: - "ar_internal_metadata" mode: "replace" delta_column: "updated_at"
あとはdatabaseの設定ファイル(settings.yml) が必要です。これらを用意して以下コマンドを実行すると差分同期ができます。
# settings.yml は DB設定ファイル(割愛) # data.yml は上記設定ファイル $ gamma apply --settings settings.yml --data data.yml
データをマスクする処理はrubyで記述できます。 例えば、usersテーブルのaddressという項目をマスクしたければ、次のような設定ファイルを書きます。
- data: table: - "users" mode: "replace" delta_column: "updated_at" hooks: - column: name: - "address" scripts: - "hooks/mask_address.rb"
hooks/mask_email.rb はマスク用のrubyスクリプトです。
# hooks/mask_email.rb のサンプル # 住所のうち、最初の3文字だけ残して残りはすべてマスク class MaskAddress def execute(apply, column, value) address = "#{value[0...3]}●●●●●●" address end end
詳しい使い方は割愛します。興味のある方は、以下repositoryのREADMEを見てみてください。
同期の方法
食べチョクでは、本番環境からステージング環境へのデータの同期は以下のようにして実施しています。
- 本番環境DBのdumpを取る
- 同期用のDBにリストアする
- 同期用DBからステージング環境にgammaでデータマスクしつつ差分同期する
本番環境からステージングに同期するにあたり、同期用DBを用意しています。 本番DBから直接ステージングに差分同期すると、本番環境に余計な負荷がかかってしまう恐れがあります。そのため、一度別DBにリストアしてから差分同期しています。
おわりに
今回は食べチョクでのステージング環境の役割の紹介と、本番からステージングへのデータ同期の方法について紹介しました。
本番環境からのデータ同期は、個人情報などセンシティブなデータにはマスクを施すなど、細心の注意を払う必要があります。サイトや企業によっては、本番のデータを利用するのはなかなかハードルが高い可能性もあります。
食べチョクでは、ステージング環境に本番同等のデータがあることで動作検証が格段にやりやすくなりました。なにより本番同等のデータが入った環境でのテストは安心感があります。
みなさまも、もし可能ならば本番環境のデータをマスクしてステージング環境に同期してみてはどうでしょうか。