食べチョク開発者ブログ

食べチョクエンジニアによるプロダクト開発ブログ

本番環境のデータをマスクしてステージング環境に同期する

こんにちは。エンジニアの西尾です。

食べチョクのステージング環境では、本番環境のデータを日次で同期して利用しています。 今回はステージング環境の役割と、どのようにデータ同期をしているのかについてご紹介いたします。

ステージング環境

食べチョクでは、手元のマシンでプログラムを修正しコードレビューを実施後、改修内容をステージング環境にデプロイしています。 ステージングは、本番へのリリース前に修正箇所の動作確認・検証する環境です。この環境で動作や性能に問題がないかを確認後、本番環境へのデプロイを実施しています。

ステージング環境には、本番と同等のデータが入っています。 リリース当初は、ステージング環境と本番環境のデータは同期しておらず、テスト用のダミーデータで動作確認を行っていました。 しかしダミーデータでの確認だと、

  • ダミーばかりが並んだサイトと本番環境では見た目や印象が違っていて、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を見てみてください。

github.com github.com

同期の方法

食べチョクでは、本番環境からステージング環境へのデータの同期は以下のようにして実施しています。

  1. 本番環境DBのdumpを取る
  2. 同期用のDBにリストアする
  3. 同期用DBからステージング環境にgammaでデータマスクしつつ差分同期する

f:id:vividgarden-tech:20181126210805p:plain

本番環境からステージングに同期するにあたり、同期用DBを用意しています。 本番DBから直接ステージングに差分同期すると、本番環境に余計な負荷がかかってしまう恐れがあります。そのため、一度別DBにリストアしてから差分同期しています。

おわりに

今回は食べチョクでのステージング環境の役割の紹介と、本番からステージングへのデータ同期の方法について紹介しました。

本番環境からのデータ同期は、個人情報などセンシティブなデータにはマスクを施すなど、細心の注意を払う必要があります。サイトや企業によっては、本番のデータを利用するのはなかなかハードルが高い可能性もあります。

食べチョクでは、ステージング環境に本番同等のデータがあることで動作検証が格段にやりやすくなりました。なにより本番同等のデータが入った環境でのテストは安心感があります。

みなさまも、もし可能ならば本番環境のデータをマスクしてステージング環境に同期してみてはどうでしょうか。