有名テック企業の技術ブログを、ひとつのフィードで。
フィード
912件
社内 IT の部署であるGYOMUハックでマネージャーをやっている kumataro です。私たちの取り組みから実感している次の時代のソフトウェアエンジニア像のひとつについて書いてみました。 2025年から2026年にかけて、Coding Agent が爆発的に進化しました。Claude Code や Codex、GitHub Copilot Agent など、コードを書くだけならAIが人間よりも高速かつ正確にこなせる時代が現実のものになりつつあります。 最近は、自分で1行もコードを書いていないという話も聞くようになってきました。 そんな環境ですので「AIに仕事を奪われるのではないか」という不安を抱いているソフトウェアエンジニアの方も多いのではないでしょうか。 「コードを書くことそのもの」に強いやりがいを感じているエンジニアにとっては、大きな変化に戸惑う側面もあるかもしれません。しかし「課題を解決すること」が目的であるエンジニアにとって、AI はこれ以上ない強力な武器です。私たちはこの変化を、エンジニアという職種がより本質的な価値へと回帰するチャンスだと捉えています。 Coding Agent 時代に陥りやすい罠 私たちは社内のバックオフィスの生産性を向上させるためのエンジニアチームです。Claude Code を用い、実装の速度が増したことにより、寄せられる要望に対応できる能力も高まっています。 同時に、ここには罠が存在することにも気づきました。それは、開発速度が増したことにより、寄せられた要望に素早く対応するだけの存在に陥ってしまいやすいということです。対応は感謝されるだけに、すぐに要望を実現したい気持ちはエンジニアにとっても、とても強いものです。 しかし、この先に待ち受けているのは、部門、業務ごとに個別最適化された処理やデータの乱立です。一見、業務は最適化されているように見えますが、全体的な視点では業務の重複による一貫性のなさや、データの散在が起こり、連携が困難な状況が急速に拡大するのが目に見えています。 実際に freee のバックオフィス内でも、従業員数の予測値について、労務と社内IT、財務の間でそれぞれの課題感から別々に算出している事例がありました。このような組織横断的な不整合の解決は個別の部署の業務改善では実現できません。 こうした「部分最適の罠」を回避し、AI を真の武器として活かすためには、単なる「対応力」を超えた、より戦略的なアプローチが不可欠です。そこで私たちが今改めて立ち返ったのが BPR と FDE というふたつのキーワードです。 道を切り開くふたつのキーワード、BPR と FDE BPR(Business Process Re-engineering): 既存の業務プロセスをそのままシステム化するのではなく、プロセスそのものを根本から再設計すること。 FDE(Forward Deployed Engineer): 本社のオフィスで仕様調整を待つのではなく、現場に入り込み、業務を観察し、課題を発見し、動くものを作って解決する「前線配備エンジニア」。 FDE は米国 Palantir 社などが先駆けて導入し有名になったポジションですが、これが「今の時代」に特にもてはやされているのには、明確な技術的・ビジネス的な背景があります。 freee でも社内のバックオフィスでは、ドッグフーディング的に自社プロダクトを利用しています。そういった環境での業務改善において、パッケージ化された SaaS をそのまま導入するだけでは解決できない企業固有の複雑な課題は残るのが現実です。 SaaS のデータと社内独自のデータの統合: 業務活動ではデータ分析の要求は常にあります。しかし、SaaS 内のデータと SaaS 外のデータを統合して扱うのは簡単なことではありません。また同じ元データのはずのものが部署毎の処理の中で異なる数字になって出てくることもあります。 スピード感: フィードバックは SaaS プロダクトに届けることができます。しかし、開発優先度の問題や SaaS としての全体最適化の中で、対応スピードは思うように上がりません。 個別最適化: SaaS という性質上、個社別の環境に最適化するわけには行かないため、個別の事情にピッタリマッチする改善はできないのが現実です。 こういった課題に対して、FDE は現場で活動している強みで、自ら解決策を提示し、導入、運用まで進めることができる役割となっています。 私たちのチームは社内における FDE として、業務をハックするエンジニアチームです。私たちが取り組んでいるのは、まさにこの FDE の動きを通じた BPR の実践です。 ミッションとバリュー では、ふたつのキーワードと陥りやすい罠を避けるために、どのようなマインドセットを持って業務に取り組めば良いと考えているのか紹介してみます。 私たちのミッションは「テクノロジーと対話を通じて、バックオフィスの生産性を最大化し、全従業員がより創造的な業務に集中できる環境を創り出す」ことです。このミッションを実現するために、以下の4つのバリューを大切にしています。 Why First(なぜ?から始める) 私たちは、表面的な要望の奥にある本質的な課題を探求することを常に最優先します。依頼された解決策をそのまま実装するのではなく「その業務はそもそも必要なのか?」「理想の状態は何か?」という問いから始めます。必要であれば「開発しない(業務自体をなくす)」という選択すら積極的に行います。 Be a Partner(最高のパートナーであれ) 私たちは、依頼者を「お客様」ではなく「課題解決のパートナー」と捉え、共に考え、共に成功を目指します。依頼者と対話し、業務のAs-Is/To-Beを描きながら、現場の泥臭い課題を共に解きほぐしていきます。 Impact Driven(インパクトで動く) 私たちは、取り組むべき改善を、そのインパクト(効果)の大きさによって判断します。 Go Simple(シンプルを追求する) 私たちは、複雑な問題を、誰もが使い続けられるシンプルで持続可能な解決策へと導きます。 私たちが目指すシステム全体像 こういった理想を実現するため、現場の課題に寄り添いながら、同時にそれを支える強固な技術基盤も並行して構築しています。現在、私たちが構築しているシステム全体のイメージ図を共有します。 開発中の基盤の全体像 Cadiz: OneLogin × AWS Cognito × Cerbosを組み合わせ、行・列レベルの認可制御を一元化した社内アプリ開発基盤。社内業務で用いる社員のセンシティブなデータも適切に守る。 Service Data Pipeline: AWS EKS 上で構築した自前のデータ連携基盤。複数の SaaS やデータソース間を柔軟に連携。 データ分析基盤: Google Cloud(BigQuery)/ Looker Cloud Core / Looker Studio Pro で構築したバックオフィスデータマネジメントを支えるデータ活用基盤。局所最適化された自動化でデータの分断が起こらないように一元化。 これらは単なるツールではなく、バックオフィスという複雑な領域を、他社にも誇れる「ショーケース」に変えるための重要なパーツです。これらの技術選定の裏側や、なぜその構成を選んだのかというトレードオフについても、また別の機会に詳しく共有していきたいと考えています。 まだまだ道半ば ここまで「FDE 的な動き」や「強固な基盤」について書いてきましたが、正直に言えば私たちはまだ、目的を成し遂げるための努力が必要な「発展途上」の段階です。 バックオフィスの現場には、未解決の複雑な業務フローや、解決すべきレガシーな仕組みが山ほど残っています。しかし、だからこそ面白い。 完成されたシステムを保守するのではなく、業務の現場に深く入り込み、技術の力で泥臭い課題を一つずつ解きほぐし、組織のあり方そのものを変えていく。この「変化のプロセス」こそが、私たちがエンジニアリングを通じて体験できる最大の醍醐味です。 これらの状況は、程度の差こそあれ、どのような会社にも存在するものではないでしょうか。 Coding Agent が強力になる中で、これからのエンジニアに必要なスキルセットは現場の深い理解(ドメイン知識)と、それを技術で最適化するアーキテクチャ設計能力の掛け合わせではないか、というのをひとつの答えとして提示してみました。 最後に GYOMUハックは、AIを武器に変え、バックオフィスの「前線」で挑戦を続ける仲間を募集しています。 「技術を使って組織を強くしたい」「コードを書く以上に、本質的な課題解決をしたい」と考えているエンジニアの方、ぜひ私たちと一緒にバックオフィスの新しいあり方を創りませんか? hire.wantedly.com
【デジカルチーム ブログリレー 2 日目】 クラウド型電子カルテデジカルチームの井上 (@wtr_in) です。 言いたいことはタイトルでほぼ言い切ってしまいましたが、先日 BigQuery 上のデータをうっかり消してしまいそうになる事件がありました。原因はテーブルコピーに関する細かい仕様の勘違いだったのですが、もしかすると今後同じようにハマる人もいるかもしれないので、せっかくなので書き残しておきます。 BigQuery に関する前提知識 1. BigQuery のテーブル有効期限機能 2. 今や bq cp で異なるリージョンにもテーブルコピーできる 本題: テーブルコピーでの有効期限の引き継ぎに気をつけろ! 有効期限以外の違いはあるか? まとめ We are Hiring! BigQuery に関する前提知識 本題に入る前に、BigQuery についての前提知識をおさらいします。BigQuery に詳しい方は 本題 まで飛ばしていただいて問題ありません。 1. BigQuery のテーブル有効期限機能 BigQuery にはテーブル単位で有効期限を設定する機能があります。有効期限を設定した場合、期限を過ぎるとテーブルが自動削除されます。 docs.cloud.google.com 例えば、日次でテーブルを作っていて、1 ヶ月前までのテーブルは取っておきたいが、それ以前のものは不要なので削除したい、というケースを考えます。この場合、テーブル作成時に有効期限を 1 ヶ月後に設定してあげれば、わざわざ利用者側で定期削除などを行わなくて良いので便利です。 2. 今や bq cp で異なるリージョンにもテーブルコピーできる BigQuery では長年、リージョン(ロケーション)が異なる複数のデータセットを扱う場合に様々な制約がありましたが、近年のアップデートによって、その制約が解消されつつあります。 代表的な例として、リージョンが異なるデータセットにまたがって直接 JOIN などのクエリを実行できない、というのが長年の BigQuery の常識だったのですが、今年プレビュー提供が開始されたグローバルクエリ機能を使うと、直接クロスリージョンでクエリが実行できるようになりました*1。 またもう一つの例として、リージョンの異なるデータセット間でテーブルをコピーするのも、かつては GCS を経由したり、Data Transfer Service を使ったりとひと手間かかっていました。しかしこちらも、2023 年に bq cp コマンドでのリージョン間テーブルコピー 機能がプレビュー提供開始されたことで、割と気軽にコピーができるようになりました*2。 本題: テーブルコピーでの有効期限の引き継ぎに気をつけろ! さて、前提がおさらいできたところで本題です。 通常、テーブル単位での有効期限が設定されたテーブルを bq cp や各言語の SDK でコピーした場合、有効期限は引き継がれません*3。試してみるなら以下のような感じになります。 PROJECT_ID=<YOUR_PROJECT_ID> bq mk --dataset --location=US ${PROJECT_ID}:test_dataset_us # 1 時間後期限のテーブルを作成 bq mk --table --expiration 3600 ${PROJECT_ID}:test_dataset_us.source_table name:STRING,value:INTEGER bq show --format=prettyjson ${PROJECT_ID}:test_dataset_us.source_table | grep -A1 expirationTime => # 期限が設定されている "expirationTime": "1781233620000", "id": "${PROJECT_ID}:test_dataset_us.source_table", # テーブルをコピー bq cp ${PROJECT_ID}:test_dataset_us.source_table ${PROJECT_ID}:test_dataset_us.dest_table bq show --format=prettyjson ${PROJECT_ID}:test_dataset_us.dest_table | grep -A1 expirationTime => # 期限は引き継がれていないので何も出ない ところが、これを リージョンをまたいで bq cp した場合には、通常のリージョン内でのコピーと異なり コピー元テーブルで設定されていたテーブル有効期限が引き継がれる という挙動になります!*4 PROJECT_ID=<YOUR_PROJECT_ID> # test_dataset_us は最初の例で作成済みの前提(未作成の場合は最初の例を参照) bq mk --dataset --location=asia-northeast1 ${PROJECT_ID}:test_dataset_jp # 1 時間後期限のテーブルを作成 bq mk --table --expiration 3600 ${PROJECT_ID}:test_dataset_jp.source_table name:STRING,value:INTEGER bq show --format=prettyjson ${PROJECT_ID}:test_dataset_jp.source_table | grep -A1 expirationTime => # 期限が設定されている "expirationTime": "1781233624000", "id": "${PROJECT_ID}:test_dataset_jp.source_table", # テーブルをコピー(クロスリージョンコピーの警告が出る) bq cp ${PROJECT_ID}:test_dataset_jp.source_table ${PROJECT_ID}:test_dataset_us.dest_table_from_jp **** NOTE! **** Warning: This operation is a cross-region copy operation. This may incur additional charges and take a long time to complete. This command is running in sync mode. It is recommended to use async mode (-sync=false) for cross-region copy operation. cp: Proceed with cross-region copy of ${PROJECT_ID}:test_dataset_jp.source_table? [y/N]: y Waiting on bqjob_r405771497b263f8f_0000019eb9956f0e_1 ... (9s) Current status: DONE Table '${PROJECT_ID}:test_dataset_jp.source_table' successfully copied to '${PROJECT_ID}:test_dataset_us.dest_table_from_jp' bq show --format=prettyjson ${PROJECT_ID}:test_dataset_us.dest_table_from_jp | grep -A1 expirationTime => # source_table と同じ期限が設定されている! "expirationTime": "1781233624000", "id": "${PROJECT_ID}:test_dataset_us.dest_table_from_jp", 通常のリージョン内でのテーブルコピーとはかなり異なる仕組みでコピーされていることが推測されるので、それに起因する仕様の違いだとは思うのですが、そこそこ BigQuery を触っていて、有効期限は引き継がれないと思い込んでいると逆にハマってしまう罠です。 なお、この有効期限の引き継ぎについて公式ドキュメントのテーブルコピーの制限事項も確認してみましたが、明確な記載は見当たりませんでした(2026 年 6 月時点)。ドキュメント化されていない挙動のようなので、将来変わる可能性がある点にもご注意ください。 もしリージョン内コピーの挙動に合わせてコピー先のテーブルで期限を削除したい場合は、コピー後に明示的に期限を削除すれば OK です。 bq update --expiration 0 ${PROJECT_ID}:test_dataset_us.dest_table_from_jp bq show --format=prettyjson ${PROJECT_ID}:test_dataset_us.dest_table_from_jp | grep -A1 expirationTime => # 期限は消えたので何も出ない 有効期限以外の違いはあるか? おまけですが、テーブルの有効期限以外で挙動の違いはあるのかも気になったので確認してみました。 結論としては、リージョン内コピーとクロスリージョンコピーで挙動が変わるのは、テーブル有効期限だけでした。 設定項目 リージョン内コピー クロスリージョンコピー テーブル有効期限 ✕ 引き継がれない 〇 引き継がれる パーティション有効期限 〇 引き継がれる 〇 引き継がれる パーティション設定 〇 引き継がれる 〇 引き継がれる クラスタリング 〇 引き継がれる 〇 引き継がれる テーブル / カラムの description 〇 引き継がれる 〇 引き継がれる ラベル 〇 引き継がれる 〇 引き継がれる こう見ると、リージョン内でテーブルの有効期限が引き継がれないのがどちらかといえば例外的な挙動ではあるようです。 まとめ クロスリージョンでの bq cp では、リージョン内コピーと異なり、コピー元テーブルの有効期限がそのまま引き継がれる 引き継がれた有効期限が不要な場合は、コピー後に bq update --expiration 0 で削除すれば OK 有効期限以外の主要な設定は、リージョン内・クロスリージョンのどちらのコピーでも同様に引き継がれる bq cp でのクロスリージョンコピーは便利な機能ですが、テーブル有効期限を使っている場合は気をつけましょう。 We are Hiring! エムスリーでは、クラウド型電子カルテを開発したい方はもちろん、BigQuery などを使ったデータエンジニアリングが好きな方も絶賛募集中です! 興味を持っていただけた方、カジュアル面談や採用へのご応募をお待ちしています。 jobs.m3.com *1:追加料金がかかるなど、注意事項はあるので、利用の際は公式ドキュメントを参照ください。 *2:こちらも追加料金がかかるので、利用の際はドキュメントを確認ください。 *3:なお、コピー先データセットにデフォルトのテーブル有効期限が設定されている場合は、コピー元の有効期限の有無に関わらず、そのデフォルト有効期限がコピー先テーブルに適用されます。 *4:こちらはコピー先データセットにデフォルトのテーブル有効期限が設定されていても、それは無視されてコピー元の有効期限がそのまま引き継がれます。逆にコピー元に有効期限がない場合は、コピー先データセットのデフォルト有効期限も適用されず、有効期限なしのテーブルが作成されます。
はじめに こんにちは、MA部SREブロックの片桐です。MA部ではメルマガやLINE、アプリプッシュ通知を配信するためのマーケティングオートメーションシステムを開発・運用しています。 MA部ではDBとして主にCloud SQL for MySQLを利用しており、調査や不具合対応のために開発メンバーがDBにログインして各種SQLを実行する場面があります。 このとき、共用の特権DBユーザーとパスワード認証を利用していました。しかし、この方式ではパスワード管理が必要になるほか、DB上のログイン主体も個人に紐づけにくい状態でした。 これらの課題を解決するために、人間によるDBへのログイン方式を、共用の特権DBユーザーとパスワード認証から個人のGoogle Cloudアカウントを使ったIAM認証へ移行しました。 あわせて、IAM認証でログインする各ユーザーには通常時は参照権限のみを付与し、書込系権限が必要な場合だけGitHub Actionsの承認付きワークフローから一時付与する運用にしました。 本記事では、共用DBユーザーによる運用から個人のIAM認証を使った運用へ移行した背景と、MySQLロールの一時付与を実現するための構成例を紹介します。 目次 はじめに 目次 従来の運用の課題 強い権限が常時使える 個人単位で追跡できない 目指した状態 全体構成 IAM認証で個人ログインにする IAM認証の有効化 IAMデータベースユーザーの作成 Cloud SQLへのログイン権限の付与 MySQLロールでDB内権限を分ける 通常時と一時付与用のロール ロールの作成 参照用ロールの付与 GitHub Actionsを承認ゲートにして書込系ロールを一時付与する GitHub Environmentで申請者以外の承認を必須にする 権限操作用サービスアカウントの作成 ワークフロー設定例 一時付与した書込系ロールを剥奪する 手動でロールを剥奪する 定期実行でロールを剥奪する 運用上の注意点と今後の改善 一時付与したロールを使うときの注意 ワークフロー入力値の検証 SQL本文のレビューと監査 一時付与した権限の失効タイミングの厳密化 MySQLロールの粒度 おわりに 従来の運用の課題 従来の構成ではデータベース操作用の共用特権DBユーザーを作成し、パスワード認証でCloud SQL for MySQLへログインしていました。 構成としては次のとおりです。 ここで利用しているCloud SQL Studioは、Google Cloudコンソール上からCloud SQLへ接続してSQLを実行できるWebベースの画面です。 この運用では、複数人が同じDBユーザーを使ってログインします。そのため、主に次のような課題がありました。 強い権限が常時使える 日常運用におけるデータ調査であれば、多くの場合はSELECTを実行できれば十分です。 しかし、共用の特権DBユーザーを使うと、参照だけで済む作業時でも特権によりデータ変更やDDL操作まで実行できてしまいます。 強い権限を持った状態でSQLを実行すると、誤操作時に本来不要だったデータ更新やスキーマ変更まで起きてしまう可能性があります。そのため、通常時は参照のみを許可し、必要なときだけ書込系権限を一時的に付与する運用にしたいと考えました。 個人単位で追跡できない 共用ユーザーでログインするため、データベースから見ると誰が操作しても同じユーザーに見えます。 そのため、DB上のログイン主体を開発メンバー個人のGoogle Cloudアカウントと結びつけにくい状態でした。 人間のDBログインを個人のIAM認証に寄せることで、少なくともDBへのログイン主体は個人単位で扱えるようになります。 目指した状態 共用特権DBユーザーの課題を踏まえ、今回の移行では次の状態を目指しました。 人間によるDBへのログインを、共用ユーザーではなく個人のGoogle Cloudアカウントに紐づける 通常時は参照権限のみを付与する 書込系権限は常時付与せず、必要なときだけ一時的に付与する 書込系権限の付与申請を簡単に行えるようにする 書込系権限の付与には、申請者以外の承認を必須にする 付与した書込系権限は、作業後または定期実行で剥奪する 今回の構成では、Cloud SQLへのログインにはIAM認証を利用します。一方で、ログイン後にどのSQLを実行できるかはMySQL側の権限で制御します。 さらに、書込系権限は常時付与せず、必要なときだけ承認付きで一時付与して、作業後または定期実行で権限を剥奪します。 そのため、今回の構成ではログイン可否、DB内権限、権限の一時付与、付与後の剥奪を次のように分けて考えました。 項目 役割 利用する仕組み 認証 誰がCloud SQLへログインできるかを制御する Cloud SQL IAM認証 認可 ログイン後に何を実行できるかを制御する MySQLロール 一時付与 必要時だけ書込系権限を付与する GitHub Actionsの承認付きワークフロー 剥奪 一時付与した権限を戻す 手動または定期実行のREVOKEワークフロー この構成により、通常時は参照権限のみを使い、書込系権限が必要な場合だけ承認付きで一時的に付与する運用にしました。 全体構成 今回構築した仕組みは、通常時のログイン経路、必要時における書込系権限の一時付与フロー、一時付与した権限の剥奪フローに分かれます。 通常時は、開発メンバーがCloud SQL Studioから自分のGoogle CloudアカウントでCloud SQL for MySQLへログインします。 本記事ではCloud SQL Studioから接続する例で説明しますが、接続元はこれに限りません。IAM認証に対応した接続方式であれば、同じ考え方を適用できます。 Cloud SQLへのログイン可否はIAMで制御し、ログイン後に実行できるSQLはMySQLロールで制御します。通常時は、開発メンバーに参照用のMySQLロールのみを付与します。 IAM認証へ移行した後の通常時の構成は次のとおりです。 この状態では、開発メンバーはCloud SQL StudioからSELECTを実行できます。一方で、書込系権限は通常時には付与しません。 データ修正などで書込系権限が必要な場合は、GitHub Actionsの手動ワークフローを実行します。ワークフローはGitHub Environmentの承認待ちになり、申請者以外のメンバーが承認すると、対象ユーザーに書込系のMySQLロールを一時的に付与します。 書込系権限を一時付与する流れは次のとおりです。 一時付与した書込系ロールは、作業後の手動実行または定期実行で剥奪します。剥奪の流れは次のとおりです。 剥奪は権限を戻す操作であるため、今回の例では付与時のような承認ゲートは設けていません。手動実行または定期実行でGitHub ActionsからSQL実行基盤を起動し、MySQLロールのREVOKEを実行します。 以降のコード例では、次のプレースホルダーを使います。 プレースホルダー 意味 YOUR_PROJECT_ID Google CloudプロジェクトID YOUR_PROJECT_NUMBER Google Cloudプロジェクト番号 YOUR_MEMBER_NAME 開発メンバーのメールアドレスの@より前の部分 YOUR_MEMBER_DOMAIN 開発メンバーのメールアドレスのドメイン YOUR_SA_NAME 権限操作用サービスアカウント名 YOUR_DB_NAME 対象のデータベース名 YOUR_TABLE_NAME 対象のテーブル名 YOUR_COLUMN_NAME 対象のカラム名 YOUR_WIF_POOL Workload Identity Pool名 YOUR_WIF_PROVIDER Workload Identity Provider名 YOUR_GITHUB_ENVIRONMENT_NAME 承認ゲートとして利用するGitHubのEnvironment名 IAM認証で個人ログインにする まず、個人のGoogle CloudアカウントでCloud SQL for MySQLへログインできる状態を作ります。 Cloud SQL for MySQLでIAM認証を利用するため、主に次の項目を設定しました。 Cloud SQLインスタンスでIAM認証を有効化する 開発メンバーごとのIAMデータベースユーザーを作成する Cloud SQLへログインするためのIAMロールを付与する Cloud SQL Studioを利用するためのIAMロールを付与する これらの設定は、Google Cloudコンソール、gcloud CLI、Terraformなどで行えます。MA部ではインフラ設定をTerraformで管理しているため、以降ではTerraformでの設定例を示します。 IAM認証の有効化 Cloud SQL for MySQLでIAM認証を有効化するには、インスタンスのデータベースフラグcloudsql_iam_authenticationを有効にします。 resource "google_sql_database_instance" "main" { # name, database_version, region などは省略しています settings { database_flags { name = "cloudsql_iam_authentication" value = "on" } } } IAMデータベースユーザーの作成 次に、開発メンバーをIAMデータベースユーザーとして作成します。 人間のGoogle CloudアカウントをIAMデータベースユーザーとして作成する場合は、typeにCLOUD_IAM_USERを指定します。 re
この記事は、Sansan Data Intelligence開発Unit ブログリレーの最終回(Vol.17)です。 Data Intelligence Engineering Unitの部長を務める多賀谷洋一です。 データクオリティマネジメント「Sansan Data Intelligence」をリリースして、半年が経ちました。半年間を通じて確信したのは、このプロダクトは変化の激しいAI時代の勝負どころに立っているということです。NVIDIA CEOのJensen Huang氏が「経済価値が生まれる場所」と呼ぶアプリケーションレイヤー、ここで勝つ条件は、独自データ・ドメイン知識・顧客基盤の3つ。Sansanはその3つを揃え、今まさに最前線に立っています。リリースから半年で事業は急速に立ち上がり、チームには確かな手応えが生まれています。今回はブログリレー最終回として、今このモーメンタムの中で働く魅力をお伝えします。 AI時代の「勝負どころ」に立つプロダクト Jensen Huang氏は、AI産業を5層のレイヤー構造として描いています。下からエネルギー、チップ、インフラ、ファウンデーションモデル、そして一番上にはアプリケーション。 下の4つのレイヤーはいずれも、参入に莫大な投資を要します。年間60兆円超が動くAIデータセンター、数千億円規模の学習コスト——資本の規模がそのまま競争力になる世界です。今から新たなプレイヤーが競争優位を築くのは困難です。 しかし、アプリケーションレイヤーは違います。顧客への価値を決めるのは資本の大きさではなく、独自のデータとドメイン知識です。 ただし、ここにも落とし穴があります。 Anthropicは今、ファウンデーションモデルを提供するだけでなく、Claude CodeやCoworkなどアプリケーション層へと大胆に事業を拡大しつつあります。つまり「単なるエージェント」を作るだけでは、モデルプロバイダー自体がとてつもなく強い競合になります。 Sequoia CapitalのJulien Bek氏は、この構造を次のように捉えています。 If you sell the tool, you're in a race against the model. But if you sell the work, every improvement in the model makes your service faster, cheaper, and harder to compete with. Services: The New Software By Julien Bek - Published March 5, 2026 (翻訳)ツールを売るなら、モデルとの競争を余儀なくされる。しかし仕事の成果を売るなら、モデルが進化するたびにあなたのサービスは速く、安く、競合に強くなる。 顧客に価値を届け続けるには、ツールではなく成果を提供できる立場に立つこと。そのためには、代替不可能な土台が必要です。 その条件は3つに収束します。独自データ(他社が真似できない独自のデータベース)、ドメイン知識(業界・業務の深い理解を体現したプロダクト)、そして顧客基盤(提供した成果に対して価値あるフィードバックして共創してくださる顧客)。 Sansanには、この3つが揃っています。そしてSansan Data Intelligenceは、まさにAI時代に顧客へ真の価値を届けていくプロダクトだと言えます。 なぜなら、AIエージェントがアプリケーション層で真の価値を生むには、自律的に判断・行動できる状態が必要であり、そのためには常に正しい情報を参照できる状態が不可欠だからです。 しかし、企業のデータ管理の現実はこうです。企業は数十のシステムにまたがるデータを保有し、同じ取引先を「A株式会社」「A(株)」「A社」と別々の名前や異なるIDで参照しています。AIエージェントが「A社の与信状況を確認して」と指示されても、同一企業を正確に結びつけられなければ、エージェントは間違った判断を下します。どれだけ高度なモデルを使っていても、データが正しくなければ正しい結果は出ません。 この問題を解決するのが、企業や事業所を一意の識別子(SOC: Sansan Organization Code)で管理し、常に正確で最新の状態に保つSansan Data Intelligenceです。このプロダクトは、その基盤となるマスターデータにおいてあらゆる企業や事業所に識別子であるSOCを付与します。個人に対するマイナンバーがあることで行政システムが連携して個人へのサービスを提供できるように、SOCがあることで複数システムを跨いで正しく企業や事業所を特定して連携させることができます。これにより、AIエージェントが目的とする企業や事業所を異なるシステムにおいて正確に特定し、そのリッチデータを取得し、正しく判断して自律的に業務を実行できます。 このように、Sansan Data Intelligenceは、Sansanだからこそつくることができる「AI時代の基盤」となるのです。 データクオリティマネジメント「Sansan Data Intelligence」 Sansan Data Intelligenceは、2025年12月にリリースされた「データクオリティマネジメント」サービスです。Sansanとして約4年ぶりの新規プロダクトで、構想からリリースまでわずか半年で実現しました。 企業が抱える取引先データの品質問題は深刻です。「重複・表記ゆれ・更新漏れ」を経験している企業は約8割にのぼります。(*1) この問題は、近年急速に広がるAI活用にも直撃しています。AI導入企業の約9割が「期待通りの精度が出ない」と報告していますが、その根本にあるのがGarbage In, Garbage Out——質の低いデータを入力すれば、出力も質の低いものになるという原則です。 具体的には、営業担当者の手入力による「株式会社」と「(株)」の表記ゆれ、企業の移転・合併情報の更新放置、市場全体の未取引企業が可視化されていない状態などが挙げられます。これらはいずれも、誤った情報を元にしたアプローチや商談機会の損失に直結します。 こうした問題は、社員が主導する一時的な名寄せプロジェクトでは解決できません。手作業では対応しきれない量とスピードで、データの劣化は常に進んでいるからです。必要なのは、構造的・継続的なデータ品質の維持です。 Sansan Data Intelligenceは、企業のCRM/SFAや基幹システムに蓄積された取引先データを、Sansanの企業データベース(事業所データ1000万件超)と照合し、4つの価値を継続的に提供します。 識別・正規化:表記ゆれや重複を含むデータを一意に識別して、正しい企業・事業所単位に統合 最新化:移転や合併、社名変更などの情報を自動検知し、常に最新のマスターデータを維持 リッチ化:業種、売上高、従業員数、系列情報など、営業戦略に必要な属性情報を付与 ホワイトスペース可視化:自社データにはない、市場の未接触企業(ホワイトスペース)を可視化し、ターゲティングリストとして提供 これを支えるのが、企業・事業所の識別子であるSOCです。Sansanは10年以上の名寄せ技術の蓄積を経て、この識別子を大規模データに付与する技術を磨いてきました。SOC v2では従来のRDB(Relational Database)型から時系列グラフモデルへと全面移行しました。Entity(Node)とRelationship(Edge)で構成し、全Edgeが有効期間を保持します。最新のスナップショットだけでなく、「2020年4月1日時点ではA社はB社の子会社だった」といった過去時点の関係性まで扱う高い表現力を持つアーキテクチャへと根本から設計し直しました。 既存プロダクト「Sansan Data Hub」が名刺情報を起点としていたのに対し、Sansan Data Intelligenceは企業・事業所のマスターデータを起点としています。名刺がない企業、一度も会ったことのない取引先まで含めて、企業のデータ資産全体を統合管理できます。将来的にはリスクチェック、APIによるあらゆるシステムとの連携強化、グローバル展開へとプラットフォームを拡張していく見込みです。 (参照:Sansan Data Intelligenceリリースに寄せて) 技術的な挑戦と成長環境 Sansan Data Intelligenceを構成する技術スタックは、モダンかつSansanだからこそプロダクション利用できる要素もあり、エンジニアにとって貴重な経験ができる構成になっています。コアデータモデルの設計から、Google Cloudを活用したインフラ、Go言語とそのエコシステムを採用したバックエンド、Next.js(App Router)とTypeScriptを採用したフロントエンド、AIを活用した開発手法まで、各領域に技術的な挑戦や成長環境があります。 コアデータモデル:SOC v2 (参照:ブログリレーVol.03) Sansan Data Intelligenceのデータモデルの中心にあるのは、驚くほどシンプルな構造です。それは、Entity(Node)とRelationship(Edge)、から構成されるグラフモデルです。Sansanではこの新しいデータモデル、そしてそれに基づく識別子をSOC v2(Sansan Organization Code Version 2)と呼んでいます。 企業はNode、企業同士の関係はEdge。「A社はB社の子会社である」「A社はC拠点に所在する」「A社とD社は合併した」——現実世界の複雑な企業情報が、すべてこの2つのプリミティブで表現できます。 さらにこのモデルが強力なのは、全Edgeが有効期間を持つという点です。Edgeは「いつからいつまでその関係が成立していたか」を保持します。つまりこのグラフは現時点のスナップショットだけではなく、時間軸を含んだ企業変遷の完全な記録となります。「2025年3月1日時点でA社はB社の子会社だったか」「この合併はいつ発生したか」——任意の時点の状態を、任意の時点でグラフから取り出すことができます。 名寄せとは集合論的にはEquivalence Classを求めることであり、Graph的に表現することが自然である。 Vol.03 SOCv2: MasterData as a Service (MDaaS) 10年もののSystemを作り替える 集合論に基づいたこのモデルは、Sansanを代表するエンジニアのMakoto Nagaiが設計しました。その設計ドキュメント (Design Doc) を読んだ時に、「NodeとEdge、有効期間のみでこれだけのことが表現できるのか」という驚きと静かな興奮があったことを覚えています。10年以上にわたって企業データの名寄せと向き合い続けたSansanが、最終的にたどり着いたシンプルな構造。複雑な現実を、最小限のプリミティブで過不足なく記述できる。真に良い設計はシンプルで美しい——そう確信させてくれる設計です。 グラフデータベース:Spanner Graph (参照:ブログリレーVol.09) Spanner Graphは Google Cloud Spannerの機能の1つで、グラフ構造のデータに対して専用のクエリ言語(GQL: Graph Query Language)でクエリできます。 「合併・移転・親子関係のつながりを辿る」という、SOC v2に基づくデータ取得はグラフ探索そのものです。だからこそ、Spanner Graphとの相性は必然でした。 通常のSQLではグラフチェーンを辿るクエリは複雑になります。一方でGQLでは、例えば -[:edge]->{0,100} という1行で「エッジを0〜100回辿る」ことを表現できます。「合併や分割というイベントを何段辿っても対象企業を特定する」という処理は、まさにこのGQLが力を発揮する問題です。 ところが、プロダクションの企業データで検証を進めるうちに、Spanner Graphを使い倒しているからこそ気づく特性が見えてきました。Sansanのエンジニアの滑川が突き止めたのは「パフォーマンスの支配的要因はグラフの経路数であって、パスの長さや幅ではない」というものです。実際に検証すると、パスの長さや幅はパフォーマンスへの影響は軽微だったのに対し、経路数は次の表のようにパフォーマンスに大きな影響を与えました。 経路数 応答時間 1,024 355ms 2,048 696ms 32,768 13,733ms さらに、同一経路数であってもグラフの形状によって実行速度が約10倍違うケースがあることも突き止めました。 現在1000万件を超える企業・事業所データ、複雑な資本関係、合併の連鎖。Sansan Data Intelligenceだからこそこの特性の理解が重要です。この検証のような経路数が爆発する企業が出てきた場合には、適度なクエリ分割やSQLとのハイブリッドな運用、ショートカットを作る設計などが求められることになります。 Spanner Graphをこの深さまで実運用で検証しているのはSansanだからこそです。しかも2026年5月末時点では、Spanner GraphはEnterpriseエディションまたはEnterprise Plusエディションでしか使うことができません。Sansanでしか経験できない技術チャレンジはたくさんあり、Spanner Graphはその一つです。 モダンな技術スタック (参照:ブログリレーVol.01, Vol.03, Vol.14) 次の3つの主要システムともにGoogle Cloud上で稼働し、モダンな技術スタックを採用しています。これにより、エンジニアは顧客価値を生むためのシステム設計やプロダクト開発に注力できます。 MasterData System: 組織と組織間の関係性を表す時系列グラフモデル(SOC v2)によるマスターデータ基盤 Application: ユーザー向けのユースケースを提供するフロントエンドとバックエンドマイクロサービス Data Hub: データの識別・統合処理を行うデータパイプライン インフラ GKE(Google Kubernetes Engine)Autopilotベースの社内共通プラットフォーム Orbit を採用。開発・ステージング・本番環境のマニフェスト定義、Secret Manager統合、ArgoCDによるデプロイ管理などを担い、インフラの認知負荷を大幅に削減 Terraformによるインフラ管理(IaC:Infrastructure as Code) Argo CDとGitHub ActionsでCI/CDを整備 Observabilityは OpenTelemetry + Cloud Monitoring / Cloud Trace / Cloud Loggingを採用 認証は社内共通基盤 Auth Oneを採用 データ基盤 メインデータベースにCloud Spannerを採用。前述のように、グラフデータベースもSpanner GraphによりCloud Spannerで完結 MasterData SystemのデータパイプラインはDataflow with Apache Beamで構築し、バッチとストリーミングを透過的に実装可能 バックエンド・API バックエンドにはGo言語を採用。goroutineによる軽量な並行処理がデータパイプラインと高い相性。MasterData SystemとData Hubで言語を統一しており、人材の流動性を高めている バックエンドとフロントエンドのAPI通信は <a href="https://connectrpc.com
はじめに こんにちは、データ基盤ブロックの平本(@cisetn)です。 本記事では、ZOZOTOWNのリアルタイムデータ連携基盤の中核であるETL層を作り直した事例を紹介します。対象はオンプレミスのSQL ServerからBigQueryへリアルタイムにデータを連携する基盤です。そのETL層をGoで実装したプラグイン(実行基盤はFluent Bit)で再設計しました。 ZOZOのリアルタイム連携基盤は2020年に一度紹介記事を公開していますが、それ以降、段階的にアーキテクチャを見直してきました。本記事はその中でもETL層の再設計にフォーカスします。 想定読者は、リアルタイム連携基盤やストリーミング処理基盤の設計・運用に関わる方です。 本記事で扱うこと、扱わないことは次のとおりです。 扱う:ZOZOのリアルタイム連携の全体像、今回リプレイスした基盤の背景・設計・実装 扱わない:BigQuery側のテーブル設計、SQL Server側のChange Tracking設定、利用側(BI・分析クエリ等) 目次 はじめに 目次 ZOZOのリアルタイムデータ連携の全体像 これまでの変遷 リプレイスに至った背景 顕在化してきた課題 新基盤アーキテクチャ 設計の軸 技術選定:Fluent Bit + Goプラグイン 全体構成 大量のデータをリアルタイムで捌くために考えたこと 新基盤の構成 INPUT内部:取得とエンコードを分けた OUTPUT内部:送信とACK確認を分けた 結果 今後の展望:Change Data Captureへの移行 まとめ ZOZOのリアルタイムデータ連携の全体像 本題の前に、ZOZOにおけるリアルタイム連携の全体像を軽く俯瞰しておきます。本記事のテーマがあくまで「その中のひとつ」であることを共有するためです。 ZOZOではデータソースが多岐にわたります。オンプレミスのものもあれば、クラウド上のものもあり、MySQL、SQL Server、DynamoDBなどさまざまです。当然、差分を検知する手段もソースに応じて変わりますし、連携の実現方式も1つではありません。 マネージド / SaaSで済むケース:例えばMySQL → BigQueryであればDatastreamを利用する 専用のパイプラインを組む必要があるケース:例えばDynamoDB → BigQueryのように、対応するマネージドサービスがない場合は、別途データ連携のパイプラインを構築する必要がある 結果として、ZOZOのリアルタイム連携基盤は複数系統に分かれて共存しています。本記事で扱うのは、そのうちオンプレ SQL Server → BigQueryの系統です。本番環境(prd)で約400のテーブルを連携対象としており、新規の連携依頼も日々発生するため、データ基盤の運用において比重の大きな系統となっています。SQL ServerのChange Tracking機能で変更を検知し、プラグインで取得したレコードをPub/Sub経由でBigQueryに流しています。 これまでの変遷 実は、本記事で扱う系統は今回が初めてのリプレイスではありません。以下の変遷を経ています。 時期 アーキテクチャ 主目的 2020 Qlik Replicate→ fluentd + Dataflow→ BigQuery 安定性向上 + コスト削減 2024 fluentd + BigQuery Subscription(Dataflow を廃止) コスト削減 2025 プラグインによる ETL 層の再設計+ BigQuery Subscription 効率改善(メモリ・スループット・コスト) 2024年には、ストリーム処理層のDataflowを廃止し、Pub/SubのBigQuery Subscriptionに置き換えるリプレイスが行われました。このフェーズの主目的はコスト削減です。 そして今回、ETL層をプラグインで再設計したのが本記事のテーマです。詳細な背景と目標は次章で述べますが、結果として、コスト削減・メモリ効率の改善・スループット向上・運用課題の解消といった効果につながりました(数値は末尾)。 リプレイスに至った背景 誤解のないよう先に述べておくと、旧基盤の設計が「悪かった」わけではありません。2020年当時、ZOZOのデータ基盤はまさに拡大していくフェーズにあり、リアルタイム連携の需要も増え始めたばかりでした。そうした状況では、プラグインが豊富なfluentdとDataflowのように既存のツールを組み合わせて素早く構築できる構成は合理的な選択だったかと思います。実際、信頼性(データ欠損が起きないこと)はチェックポイント機構などによって担保できており、長く運用されてきました。チェックポイント機構は、処理済みのChange TrackingバージョンをBigQueryに保持する仕組みです。Pod再起動時はそこから再開できます。 顕在化してきた課題 一方で、運用を続け、データ量や利用要件が増えていく中で、効率の側面でいくつかの課題が徐々に顕在化してきました。 メモリ効率:結果セットを一括でメモリに載せる実装のため、メモリ使用量がデータ量に比例して増加する構造でした。大量更新時のOOMを避けるためには「ピーク時のデータ量」を見越した大きなメモリを常時確保しておく必要があり、データ量が増えるにつれてリソース見積もりの難しさが目立つようになってきました。 コスト:上記のメモリ確保がそのままコストに直結します。メモリがトランザクション単位のデータ量に比例する構造であるかぎり、「ピーク時のデータ量」の見積もりを下回るとOOM直行となります。そのため運用上の工夫(時間帯別のスケーリング等)では本質的な改善が難しく、リソースの常時確保によるコスト増を抱え続けるしかありませんでした。 性能:逐次処理ベースの実装のため、1トランザクションあたりの規模が大きいテーブルでは、リアルタイム性を保ちにくい場面もありました。 運用:依存していたコンテナイメージがEOLを迎えており、継続利用にリスクがありました。加えて、内部状態の可視性が低く、障害発生時の原因特定にも時間がかかる状況でした。 一言でまとめると、各所でガタが出始めており、信頼性を維持したまま効率(メモリ・スループット・コスト)の側面を改善するため、リプレイスを検討するタイミングに来ていた、ということです。 新基盤アーキテクチャ 設計の軸 新基盤の設計指針はシンプルで、キャパシティプランニングの軸を「ピーク時のデータ量」から「単位時間あたりの処理量」に変えることに尽きます。信頼性(データ欠損が起きないこと)は旧基盤からチェックポイント機構によって担保されており、新基盤でもそのまま引き継いでいます。そのため本記事のテーマは信頼性を維持したまま、効率(メモリ・スループット・コスト)をどう改善したかです。 技術選定:Fluent Bit + Goプラグイン 今回のリプレイスは、前フェーズ(2024年のDataflow撤廃 + BigQuery Subscriptionへの切り替え)の延長線上にあります。前フェーズでDataflow関連の費用がまるごと不要になり大きなコスト削減は既に達成済みで、下流(Pub/Sub HubとBigQuery Subscription)も整理されている状態でした。一方でETL層はfluentdベースのまま残っており、メモリ効率とスループットの面で課題が顕在化していたため、今回はその続きとしてETL 層の中身を作り直すことにしました。下流はそのまま踏襲し、ソース側(Change Tracking設定)にも手を加えません。 このスコープと、既存のPub/Sub Hub構成・BigQueryテーブル設計を維持する制約のもとで、マネージドCDCサービスやOSSのCDCミドルウェアの活用も検討しました。ただし我々のケースでは、既存テーブル設計とPub/Sub Hubへの直接出力をそのまま組み合わせ続けられる選択肢を見つけられず、プラグインとして実装する形に決めました。 採用したのはFluent Bit + Goプラグインです。決め手は次のとおりでした。 既存基盤がfluentdベースで運用されていたため、Fluent Bitへの移行が素直:プラグインモデル・設定構造・デプロイ手順といった運用ノウハウがそのまま活きる INPUT(Change Tracking取得)とOUTPUT(Pub/Sub送信)の挙動を自分たちで細かく調整できる。後述の非同期ACK並列確認のような最適化も、プラグインとして自前で書いているからこそ仕込める Fluent BitのBuffer・バックプレッシャー機構をそのまま活用できる Goプラグイン公式サポートにより、後述する並列処理をgoroutineとchannelで素直に書ける 全体構成 以下の図は主要コンポーネントのみを示した簡略図です。 ETL層(Fluent Bit + Goプラグイン)はGKE上で動作します。プラグインはデータ取得(INPUT)とPub/Subへの送信(OUTPUT)の2つで構成されており、それぞれの実装の詳細は次章で扱います。 大量のデータをリアルタイムで捌くために考えたこと 新基盤の設計で常に意識していたのは、「大量のデータをいかにリアルタイムで捌くか」という問いでした。データ量が増えてもパイプラインが詰まらず、メモリ消費がデータ量に比例しない構造をどう実装するかを検討しました。前章で述べた「単位時間あたりの処理量を軸にする」方針を、Fluent Bitのパイプライン上に乗せて具体化していった話を、本章で紹介します。 なお、Fluent Bitのパイプライン構造の全体像については、公式ドキュメントもあわせてご覧ください。 新基盤の構成 Fluent Bitのパイプライン構造はINPUT → Filter → Buffer → Router → OUTPUTという形です。新基盤ではこのうちINPUTとOUTPUTをGoプラグインで実装しました。チャンク単位の処理やバックプレッシャーといったBuffer周りの機構はFluent Bit Engineが標準で備えています。そのためプラグイン側はINPUTとOUTPUTの"箱の中"の設計に集中できました。 設計の出発点として、データ取得から送信までの各処理を「どこがボトルネックになるか」で整理し、並列化方針を決めました。 処理 特性 並列化方針 CT取得(クエリ → カーソル) I/O bound(DB側) 単一スレッド(DBがボトルネック) エンコード CPU bound Worker数で並列化 Pub/Sub Publish I/O bound(NW) 非同期APIで並列化 ACK確認 I/O bound(NW待ち) 別Workerプールで並列化 CPU boundとI/O boundを別レーンに分け、それぞれを独立した並列度で動かす設計です。以下、INPUT内部・OUTPUT内部の順で紹介します。 INPUT内部:取得とエンコードを分けた INPUT内部の設計では、メモリとCPUを独立した軸として扱えるようにしました。 メモリの設計:結果セット全体を展開せず、カーソルで小分けに読み進める方式を採用。1回のクエリで読むレコード数 RecordsPerChunk をプラグインの設定で指定でき、本番では10,000件/チャンク CPUの設計:取得処理とエンコード処理を別レーンに分け、エンコードは複数のWorkerで並列実行 取得とエンコードの間に中間キュー(jobs queue)を挟むことで、取得側はエンコードの完了を待たずに次のチャンクを先行投入できます。キュー容量がゼロだと直列に戻ってしまうため、本実装ではjobs queueの容量をWorker数の5倍に設定しています。 この構造のもとで、同時にレコード形式でメモリに乗るチャンク数はNumWorkers × 6個で頭打ちになります。内訳は「jobs queue上の最大NumWorkers × 5個 + 各Workerが処理中の1個」です。 同時メモリ上のレコード数 = RecordsPerChunk × (jobs queue + 処理中 Worker) = RecordsPerChunk × (NumWorkers × 5 + NumWorkers) = RecordsPerChunk × NumWorkers × 6 = 10,000 × NumWorkers × 6 例えばNumWorkers = 2なら、データ量に関わらず常に約12万レコード分のメモリしか確保しなくて済みます。100万件規模のトランザクションが流れてきても、結果セット全体を一括ロードしてしまう旧基盤と違ってOOMにはなりません。 なお、Fluent Bit上でカーソル方式を実装するときには工夫が必要でした。Fluent BitはINPUTに対して定期的に「データをちょうだい」と呼び出してくる構造になっており、素朴に書くと毎回新規にクエリを発行してしまいます。それでは結果セットが毎回頭から読み直されてしまうため、カーソル状態をプラグイン側に持ち越し、呼び出しごとに「続きから」読み進めるようにしました。 OUTPUT内部:送信とACK確認を分けた OUTPUT内部では、送信処理とACK確認処理を別レーンに分離しました。Pub/SubのPublishは同期的に書くと「送信 → ACK待ち → 次へ」と直列化してしまい、ACK待ちのネットワークI/Oが支配的になります。これだとスループットがACKレイテンシに律速されてしまうため、両者を分離して並列化する方針を取りました。 送信側:非同期APIを呼んで即座にFuture相当の結果を受け取り、次へ進む。送信そのものは止まらない 確認側:受け取ったFutureのACK確認専用のWorkerプールを設け、複数並列で確認する 各メッセージが独立したACKタイムアウトを持つようになり、1件の遅延が後続全
こんにちは。タイミーのデータエンジニアリング部 DSグループでMLOpsを担当しているYukitomoです。 私たちのチームでは多くのPythonアプリをモノレポで管理していますが、Dependabotによる依存関係更新PRが多すぎることが運用課題でした。本記事では、Renovateへの移行によって「更新PRの粒度と数をコントロールできる運用」を実現するまでの設計判断と、Python + uv環境特有の注意点を共有します。 この記事の想定読者 Pythonのモノレポ環境で、複数のアプリケーションやライブラリを運用している方 Dependabotが生成する大量の更新PRの対応に疲弊しており、運用を効率化したい方 Renovateへの移行を検討している、または導入したが設定(packageRules)のベストプラクティスに悩んでいる方 パッケージマネージャーに uv を採用している(または検討している)方 要約(TL;DR:この記事でわかること) 本記事では、Python + uv環境でRenovateを運用する際の課題とその解決策(新しすぎるパッケージの除外設定、Google Cloud WIFにおけるブランチ名の文字数制限の回避など)を整理し、実践的なrenovate.json5の設定ノウハウを解説します。 背景 近年はサプライチェーン攻撃が現実的なリスクになっており、Trivyの侵害以降も Python モジュールや JS ライブラリを狙った攻撃が継続して観測されています。PyPI など外部エコシステムに依存する以上、これまで以上に「依存関係をどう安全に運用するか」を真面目に考える必要があります。 一方で、依存関係を「安全に」保つには、継続的にアップデートを回し続ける必要があります。ここで次の課題になるのが、運用対象が増えたときに更新対応のコストがスケールしてしまう点です。 私たちもDependabot運用の効率化を進めてきましたが*1、アプリごとにパッケージ管理へ移行した結果、モノレポ内のpyproject.tomlが増えました。2026年5月時点では、DSグループだけでも約70のPythonアプリケーション/ライブラリを扱っています。Dependabotは脆弱性の検知とPR作成を行ってくれる一方で、依存関係ごとにPRが分割されます。そのため、対象が増えるほど対応コストが急増します。 そこでこの課題を解決するため、Renovateを導入し「更新をまとめて扱える運用」へ切り替える方針にしました。本記事では、公式ドキュメントや公開されている設定例を参考にしつつ、私たちが重視した設定ポイントを整理します。 この記事の前提 言語: Python 依存関係ファイル: pyproject.toml / uv.lock 動作環境: GitHub & Google Cloud 目的: Renovateで「脆弱性対応」と「定常アップデート」を破綻なく回す(PRの数と粒度をコントロールする) 設定ファイル(.renovaterc.json5) 設計方針 私たちが設定で重視したのは以下の3点です。 PRの粒度をコントロールする — patch / minor / vulnerability を適切にグルーピングし、PRの本数を削減する サプライチェーンリスクを軽減する — 公開直後のバージョンを即座に採用しない 小さく始める — まず許可リスト方式で必要な更新だけを有効化し、段階的に広げる 全体像 以下が設定ファイルの抜粋です(各設定の詳細は後述)。 // .renovaterc.json5 より一部抜粋 { extends: ["config:best-practices"], minimumReleaseAge: "N days", lockFileMaintenance: { enabled: true, branchTopic: "lfm", // GCP WIF 127-byte limitに対応するためブランチ名を省略 minimumReleaseAgeBehaviour: "timestamp-optional" // 一時的な対応 }, vulnerabilityAlerts: { groupName: "maintenance", groupSlug: "maint", minimumReleaseAge: "14 days", }, packageRules: [ // packageFileDirをブランチ名に含めつつGCP WIF 127-byte limitに対応するためブランチ名を省略 { matchFileNames: ["base_containers/base/**"], additionalBranchPrefix: "{{{replace 'base_containers/base/' 'b_b/' packageFileDir}}}/", }, // packageRuleを一旦無効化 { matchPackageNames: ["**"], enabled: false }, // グルーピング ---------------------------------------------------- // ルール 1: { matchUpdateTypes: ["patch"], enabled: true, groupName: "maintenance", groupSlug: "maint", }, // ルール 2: { matchUpdateTypes: ["minor"], matchJsonata: ["isVulnerabilityAlert = false"] enabled: true, groupName: "minor updates", groupSlug: "minor", dependencyDashboardApproval: true }, // ルール 3: { matchPackageNames: ["**"], matchJsonata: ["isVulnerabilityAlert = true"] enabled: true, // この2つは vulnerabilityAlerts で設定した値で上書きされます groupName: "maintenance", groupSlug: "maint", }, // マイナーレベルでの破壊的な更新の抑制 ただし脆弱性対応を除く { matchJsonata: ["isBreaking = true and not(isVulnerabilityAlert)"], enabled: false, }, ], // バージョンの更新 bumpVersions: [ { bumpType: "patch", filePatterns: ["{{packageFileDir}}/pyproject.toml"], matchStrings: ["version\\s*=\\s*\"(?<version>[^\"]+)\""] }, { bumpType: "patch", filePatterns: ["{{packageFileDir}}/uv.lock"], matchStrings: ["name = \"[^\"]+\"\\nversion = \"(?<version>[^\"]+)\"\\nsource = \\{ (?:editable|virtual) = \"\\.\" \\}"] } ] } 設定項目の説明 <h3 id="configbest-practices-を土台にす
2026年4月22日〜24日に開催されたGoogle Cloud Next '26へ参加してきました。昨年に引き続きアメリカ・ラスベガスで開催され、弊社からはMA部の平井・林・木野、AI事業戦略部の川田・桜井の5名が参加しました。なお、昨年参加した様子は以下の記事で紹介しています。 techblog.zozo.com 今年はAIエージェントを『実戦』に投入し、いかに賢く、安全に使うのかに焦点を当てたセッションが多い印象でした。本記事では、現地での様子と特に興味深かったセッションをピックアップして紹介します。 また、Recapのオンラインイベント「Google Cloud Next 2026 Recap in ZOZO」を2026年5月18日に開催しました。このイベントでは、Google Cloud Next '26について、今回のテックブログで紹介できなかった内容など、より詳細に共有しております。 現地の様子 私たちは会期の前々日にラスベガスの空港に到着したのですが、空港内にはさっそくGoogle Cloud Nextの広告が流れており、イベントに向けた熱意が一気に高まりました。 Google Cloud Nextの広告を見かけたハリー・リード国際空港の様子 昨年に引き続き会場は、ラスベガスのマンダレイ・ベイホテル コンベンションセンター。非常に盛り上がっており、特に各セッションや展示ブースでのデモでは参加者から活発な質問が飛び交っていたのがとても印象的でした。 熱気に包まれる会場内の様子 以降では、現地に参加したメンバーが気になったセッションを紹介します。 セッション紹介 What's new in Cloud Run こんにちは、MA部配信基盤ブロックの木野です。私は通知系(LINE/Mail/アプリ)の開発をしています。 公開資料「What's new in Cloud Run」のP.1より引用 このセッションでは、Cloud Runが単なるWebアプリのデプロイ先ではなく、より幅広いワークロードを受ける汎用実行基盤へ広がっていることが紹介されていました。セッション全体のメッセージは、Cloud Runが「on-demand compute for everyone」であるという点に集約されており、Vibe Coded Apps、AI Agents、AI Models、Large Scale Appsという4つの観点から新機能が説明されていました。 冒頭では、AI Studioで生成したマルチプレイヤーゲームをそのままCloud Runに公開するデモが紹介されており、Cloud Runが「作ったものをすぐにクラウドへ出す」ための基盤として強く打ち出されていました。また、Cloud Run公式のFully managed MCP Serverも発表されており、人間が操作する実行基盤というだけでなく、AIエージェントから直接デプロイや管理の対象になる基盤へ寄ってきていることも印象的でした。 GA対応したCloud Run Worker Pools 私が特に興味を持ったのは、Cloud Run worker poolsのGAです。Worker poolsは、HTTPリクエストを受けることが本質ではない常駐workerやpull consumer、runnerのような処理に対して、Cloud Run上のより自然な置き場を与える機能だと感じました。 Cloud RunにはこれまでもServiceやJobがありましたが、Serviceはrequest-driven、Jobはrun-to-completionであり、そのどちらにもきれいに当てはまらない処理を表現しづらい場面がありました。セッションでも、Temporalのworkerのようなlong polling前提の処理がworker poolsに適している例が紹介されていました。 この点は、私たちの配信基盤にもそのままつながります。例えばPub/Subのpull consumerや、ループし続ける常駐worker、定期的に状態を見て後続処理を進めるfinalizerのような処理は、実態としてはHTTPエンドポイントを持つことが本質ではありません。それにもかかわらず、これまではCloud Run Serviceの形に寄せるためにヘルスチェックや待受用のコードを持たせていました。worker poolsが一般提供されたことで、こうした処理をより素直な形で実装でき、配信基盤の見通しや運用性を改善できる可能性があります。 Cloud Run Instancesとbuilt-in dev loop 公開資料「What's new in Cloud Run」のP.30より引用 もう1つ興味深かったのが、Cloud Run Instancesとbuilt-in dev loopの流れです。セッションでは「ローカルでクラウドをエミュレートしようと頑張るのではなく、Cloud Run上でそのまま開発する」というメッセージが明確に打ち出されていました。ローカルの変更をCloud Run instanceに同期し、そのままdev scriptをクラウド側で実行することで、pushしてデプロイを待つ前に即時検証できる世界観が示されていました。さらに、SSH supportも合わせて紹介されており、Cloud Runを本番の実行基盤として使うだけでなく、開発や調査の場としても扱う方向性が見えてきたと感じました。 これは、複数サービスをまたぐ検証が多い配信基盤の開発体験にとって特に大きい変化だと思います。現在でもローカルでの統合テストやcontainer_testのような仕組みは有効ですが、実サービス依存に近い確認をしたい場合は、どうしてもdev環境への反映待ちや、共有環境ゆえの状態差分が問題になります。もしbuilt-in dev loopが成熟すれば、各開発者が自分の変更をCloud Run側へすぐに反映し、実サービス依存に近い状態で軽く検証を回せるようになります。さらに、人間が行う確認フローとPR後のE2EやCIの構成も近づけられる可能性があり、複数サービスをまたぐ開発・検証体験を大きく変えるアップデートだと感じました。 加えて、このセッションはCloud Runの新機能を個別に列挙するだけでなく、「Cloud Runはどこまで守備範囲を広げようとしているのか」という観点で見ると、とても示唆が多い内容でした。これまではHTTPサービスをスケールさせるためのプロダクトという見方が中心だったと思いますが、今回の発表では、AIエージェントの実行基盤、長時間動くworkerの置き場、さらにはCloud Run上での開発ループまで含めて整理されていました。配信基盤のように非同期処理、複数サービス連携、運用時の可観測性が重要なシステムにとっては、単なる機能の追加以上に、Cloud Runをどう使うかの前提そのものが変わり始めていると感じています。 セッションを通しての感想 Cloud Runは長らく「HTTPサービスを手軽に動かす場所」という印象が強かったのですが、今回のセッションを通して、AIエージェント、常駐worker、開発ループまで含めたより広い実行基盤へ進化していることがよく分かりました。特に私たちのように、非同期処理や複数サービス連携を多く持つシステムにとっては、今後の設計や検証フローを見直すきっかけになるセッションでした。 What's new in AlloyDB: Scale PostgreSQL for agentic AI and hybrid clouds こんにちは、MA部MAシステム開発ブロックの平井です。私は自社マーケティングシステム「ZMP」の開発をしています。ZMPではユーザー毎に最適化された情報を配信するパーソナライズ配信機能があり、そのデータベースとしてGoogle CloudのAlloyDBを利用しています。そこで、私はAlloyDBに関するセッションを聴講しました。 「What's new in AlloyDB」セッション会場の様子 このセッションでは、AlloyDBのアップデートをエンタープライズ・分析機能の観点、AI関連機能の観点から説明していました。 エンタープライズ・分析機能に関するアップデート Hot Standby 公開資料「What’s new in AlloyDB: Scale PostgreSQL for agentic AI and hybrid clouds」のP.8より引用 Hot Standbyは、スタンバイ中のノードがWALを受け続けながらアクティブなインスタンスとして動く機能です。この機能によって、起動時間の短縮とプライマリー昇格の加速によるRTOの改善、メモリーキャッシュの暖気とフェイルオーバー後のパフォーマンス低下の抑制により一貫したパフォーマンスの維持が可能になります。 Read Pool Autoscaling 公開資料「What’s new in AlloyDB: Scale PostgreSQL for agentic AI and hybrid clouds」のP.9より引用 Read Pool Autoscalingは、読み取りインスタンスがワークロードに応じて自動でスケーリングする機能です。また、事前に決められたスケジュールでスケーリングすることも可能です。例えばサイバーマンデーやブラックフライデーなどあらかじめ高負荷が予想される場合にとても有効です。私たちのパーソナライズ配信システムでも読み取りインスタンスを利用していて、負荷がスパイクする傾向があるため、Read Pool Autoscalingが一般提供された際は、その効果を速やかに検証したいと考えています。 Transparent Query Forwarding 公開資料「What’s new in AlloyDB: Scale PostgreSQL for agentic AI and hybrid clouds」のP.11より引用 Transparent Query Forwardingは、プライマリーノードで受け付けた読み取りクエリを読み取りノードにフォワードする機能です。読み取りノードにクエリをフォワードすることでプライマリーノードの負荷を軽減し、クラスター全体のリソースを有効活用するために設計されました。アプリケーション側で必要だったライブラリを利用したプライマリノードと読み取りノードのコネクションの作成/クエリフォワード設定が不要になります。また、書き込みと読み込みの一貫性を担保しているため、アプリケーション側で古い情報を参照する心配がありません。 LakeHouse Federation for AlloyDB 公開資料「What’s new in AlloyDB: Scale PostgreSQL for agentic AI and hybrid clouds」のP.16より引用 Lakehouse Federation for AlloyDBは、AlloyDBからBigQueryやIcebergにあるデータを簡単にクエリできる機能です。AlloyDB上のトランザクションデータとBigQuery上の履歴データ、集
垣見です。 毎日AWSアップデートの漫画を生成してくれるSlackボットを作りました。 はじめに できたもの システム構成 プロンプト設計 Claude整形プロンプト(重要度判定機能付き) Vertex AI漫画生成プロンプト 実装上の工夫 1. Vertex AIとの連携アーキテクチャ 認証情報の管理 Vertex AI REST APIの直接呼び出し 参考画像のクロスクラウド共有 2. Slack直接画像投稿の実装 files_upload_v2 APIの活用 必要な権限設定 3. Step Functionsによる処理設計 4. JPEG圧縮による画像サイズの最適化 そのほか工夫 運用コ…
こんにちは。ファインディ株式会社でデータエンジニアをしている開です。 2026年4月28日(火)に、データソリューションチーム主催の採用イベント「事業成長に効かせるファインディ流データエンジニアリングの実践」を開催しました。 findy-inc.connpass.com この記事では、イベントを企画した背景と当日の3本のセッションを参加できなかった方にもイメージが伝わるようにまとめます。 イベント開催の背景 セッション1: ファインディの事業拡大を支える拡張可能なデータ基盤へのリアーキテクチャ セッション2: データモデリングを通して管理会計のオペレーションを再設計 セッション3: 社内で使われるLooker整備の進め方 まとめ イベント開催の背景 ファインディでは、既存4プロダクトに加えて、新たに4つのプロダクトをリリースし、エンジニアの皆さまへサービスを多角的に展開しています。会社規模の拡大とともに、扱うデータの量と種類は急速に広がってきました。 prtimes.jp 変化の激しい事業環境のなかで客観的な意思決定を支えるには、社内の情報流通をより活性化させる仕組みが欠かせません。私たちは、その土台を担うのがデータエンジニアリングだと考えています。 データソリューションチームは少数精鋭で推進してきましたが、事業成長のスピードに合わせてデータ基盤をさらにスケールさせるには、共に挑戦してくれる仲間の存在が不可欠です。今回のイベントは、ファインディがどのような課題に向き合い、どのような技術と組織で解いているかを直接お話しする機会としました。 セッションは3本立てで、データ基盤・データモデリング・BIの3つの観点からファインディのデータエンジニアリングをお話ししました。 セッション1: ファインディの事業拡大を支える拡張可能なデータ基盤へのリアーキテクチャ 登壇者: 開 speakerdeck.com 事業拡大に合わせてデータ基盤をどうリアーキテクチャしているかを紹介しました。直近1年でデータソースは10倍、Google Cloudプロジェクトは6倍に増える一方、データエンジニアは3名のままで、認知コストと運用負荷が膨らんでいました。 これまでは事業=ドメインとしたデータメッシュ的な構成で、技術選定も各チームに委ねていました。アジリティは出る一方で、ドメイン間の連携不足や技術のばらつき、作業重複が課題になっていました。 そこで、データメッシュの利点は残しつつ実装を見直し、Google Cloudプロジェクトの統合、IAMのデータセット単位での管理、dbt Platformへのオーケストレーション集約やマネージドサービスの活用を進めています。これによりマネージドサービスのAPIやMCPを用いてAIエージェントに運用を一部移譲することができています。作成したスキルやサブエージェントは以前テックブログで紹介したプラグインとしてチーム全体で使えるようにしています。 tech.findy.co.jp DataOpsの省力化が進む一方、コスト透明性の低下といった新しい課題も見え、FinOps体制の構築や、浮いた時間をデータ活用者との会話やイネーブリングに使っていくことを次のテーマにしています。 セッション2: データモデリングを通して管理会計のオペレーションを再設計 登壇者: 田頭さん speakerdeck.com 経営判断に直結する管理会計という業務領域に対して、データモデリングの観点からオペレーションを再設計した取り組みを紹介しました。 ファインディの管理会計は、長らくスプレッドシートを中心に回っていました。月次のたびに関数とピボットを手作業で組み直し、IMPORTRANGEやVLOOKUPで絡み合ったスプレッドシートのリネージは50件を超え、どこか1枚崩れると全体が連鎖して壊れる脆さを抱えていました。同じKPIが部署ごとに別ロジックで計算されて数字が合わない、月次締めに2〜3日かかって意思決定が後追いになる、といった状態も常態化していました。 再設計の起点に置いたのは、技術選定ではなく業務担当者へのヒアリングです。「計上組織」「補助科目」「配賦」「予算番号」といった専門用語が飛び交うなか、勘定元帳やマクロを眺めるだけでは掴めない集計粒度や分析軸を、経営管理部の担当者と何度もMTGを重ねて引き出していきました。書籍『アジャイルデータモデリング 組織にデータ分析を広めるためのテーブル設計ガイド』のBEAM✲を参考に、誰が・何を・いつ・どこで集計したいのかを対話から輪郭化し、総勘定元帳を起点に売上・費用・原価を月次粒度のファクトとして整理しています。 実装は、会計データソースをGoogle DriveにアップロードしてTROCCOで取り込み、dbtで集計してLookerやスプレッドシートから参照する構成に落としています。これにより、ワンボタンで月次の実績値が揃い、想定外の科目も自動で検出できるようになりました。「どの数字が正しいか」を議論する場面はなくなり、月次締めの所要時間と数字の信頼性が同時に改善しています。 今後は、実績ファクトと同じ粒度で予算・見通しを取り込んだ予実分析の自動化や、整備済みのファクトを起点にAIエージェントが自然言語で会計分析を行える基盤への展開を進めています。 セッション3: 社内で使われるLooker整備の進め方 登壇者: 出相さん speakerdeck.com 社内で実際に使われるBIにするためにLookerをどのように整備してきたかを紹介しました。「ダッシュボードを作った瞬間がピークになって使われなくなる」「事業部からはデータ活用の入口が見えない」「スプレッドシート運用が属人化して限界が見えている」といった、よくある課題を出発点にしています。 ファインディでは、Lookerを意思決定にひも付くダッシュボードを定常的に見る場としてだけでなく、Exploreや会話分析でデータそのものを探索する場にすることを目指しています。ただし、最初はLookerを見に行く習慣もExploreの操作にも慣れていないため、進め方の工夫が欠かせません。 そこで、ヒアリングで課題を引き出す → 最低限の機能に絞って最初のダッシュボードを素早く提供する → 共有MTGで一緒に触りながら改善ループを回す → 利用が定着してからディメンショナルモデルやメタデータを整える、という4ステップで価値を積み上げてきました。完璧な設計よりも早い体験提供を優先し、苦労していたことから先に解消していくことを大切にしています。詳しい進め方は以前のテックブログでも紹介しています。 tech.findy.co.jp その結果、MAUは2026年1月から4月途中で約1.5倍、WAUは1月中旬から4月中旬で約2.6倍に成長しました。経営管理部からも「BigQueryやLookerを駆使したモニタリングが事業拡大に不可欠」というコメントが届くなど、Lookerが信頼できるデータソースとして社内に定着してきています。 まとめ 今回のイベントを通じて、ファインディがデータエンジニアリングをどのように事業に効かせようとしているかを、3つの異なる切り口でお伝えできたと思います。データ基盤・データモデリング・BIのいずれも、技術そのものよりも「事業や業務にどう接続するか」を軸に進めてきた取り組みです。 参加してくださった皆さん、ありがとうございました! ファインディでは、データエンジニアリングの力で事業成長を支える仲間を募集しています。今回のイベント内容に少しでも興味を持っていただけた方は、ぜひお気軽にカジュアル面談などでお話しできるとうれしいです。 herp.careers
こんにちは、Infrastructureチームの前多(@kencharos) です。AIの進化におびえながら、電気の資格の勉強でもしようかと考えている日々です。物理はいいですね。 さて、CloudSQLやAlloyDBで初回構築時に設定されるデフォルトユーザーをそのまま使っている方はいらっしゃいますか?いませんよね? 今回の話はAIネタではなくもっと地味なお話です。 データベースの権限設定のつらみ Terraform Postgres Provider の採用 パスワードの扱いについて CI/CDでの実行 1. Argo CD + k8s での Job実行 2. GitHub Actionsから踏み台サーバーに接続して実行する ownerの変更やowner指定には要注意 まとめ おまけ: 第三の選択肢、Crossplane データベースの権限設定のつらみ スキーマの設定を自動マイグレーションするサードパーティのサービスをそのまま使う場合ならともかく、 自分たちで開発しているサービスであれば、マイグレーションとアプリケーションの実行でDBユーザーの権限は分けた方が安全ですし、 複数サービスでDBを共有する場合なら、データベースやスキーマレベルで権限を分けたくなります。 また、AIツールがSQLを実行することも今後はあり得ると思います。 その場合もAIツールが勢い余ってすごいSQLを発行しても大丈夫なように権限を絞ったDBユーザーを使うようにしておきたいものです。 Google CloudのCloudSQLやAlloyDBではDBユーザーやIAMユーザーの作成はできます。 しかし、RDBMS内の権限付与(Grantなど)は結局RDBMSにログインしてSQLを実行する必要があります。 この手のSQLはどうやって管理しているでしょうか? prismaなどのアプリケーションのスキーママイグレーションで管理するのも手段の1つです。 ですが最初にマイグレーション用の権限を持つユーザーは作っておく必要があります。 また何らかの理由で開発サイクルとは別のサイクルでDBユーザーを追加、修正することは多々あります。 レプリケーション用のユーザーが欲しいとか、新しいメンバーが参加したからそのIAMユーザーを追加したいとか、要はスキーマ定義とは独立して管理したいわけです。 筆者らは、このような権限付与を手順書にSQLを書いて手動で実行していました。 苦痛を伴う作業と認識しながら、よい代替手段が当時は思いつきませんでした。 これにはいくつか問題があります。 複数環境で繰り返し実行が必要 変更の都度、現状の状態から細かいGrantやRevokeが必要 手順書の修正などで過去の権限付与の内容の修正などが面倒 などの理由から、微妙に権限付与の内容が環境ごとに異なってしまうことがあります。 意図した通りに権限付与ができているのかが把握しづらくなります。 サービスの拡大に伴ってデータベースの数も増えてきたこともありどうにかしなきゃと思い、解決策を探し始めました。 Terraform Postgres Provider の採用 権限管理のツール化を行うにあたり、要件は次の3つです。 手動ではなくCICDなどから実行して作業を自動化できること 宣言的に権限付与を管理できること PostgreSQLの様々な機能(extension, database, schema, grant, default_privileges, replication slotなど)に対応できること 当初はYAMLに権限付与設定を書いて、自作しようかと思っていましたが、terraform の postgresql provider を見つけたのでこれでいいやとなりました。 ただし、posgresql providerはサードパーティのプラグインですので、扱いには気をつけてください。 要件と概ね一致していましたし、筆者らはTerraformを常用しています。 hclファイルで宣言的に権限設定を管理できるのが大きな理由でした。 (欲を言えば、hclよりも読みやすいフォーマットの方がよかったのですが、それも今ならClaudeなどでサマリできそうだし、まあいいやとなっています) これを使って、以下のような権限設定を作成します。 ownerとなるmigration user、アプリケーション実行用のapplication userを作成する database, schemaは独自のものを作る application userにschema, tableへのgrantとdefault privilegesを設定する。 上記をhclで表現したものが次の通りです。 terraform { required_version = "1.10.5" backend "local" { path = "sample.state" } required_providers { postgresql = { source = "cyrilgdn/postgresql" version = "1.26.0" } } } // プロバイダの設定。ここではデフォルトユーザーやadminユーザーを指定する provider "postgresql" { host = "x.x.x.x" port = 5432 database = "postgres" username = "postgres" password = var.admin_password sslmode = "disable" connect_timeout = 15 } // userの作成 resource "postgresql_role" "migration" { name = "migration" login = true # password_woはstateにパスワードを記録しない。パスワードを変更したい場合は password_wo_versionを変更する password_wo = var.migration_password password_wo_version = "1" bypass_row_level_security = true } resource "postgresql_role" "application" { name = "application" login = true password_wo = var.application_password password_wo_version = "1" } // databaseの作成 resource "postgresql_database" "app_db" { name = "app_db" owner = postgresql_role.migration.name allow_connections = true } // schemaの作成 resource "postgresql_schema" "schema" { name = "app" owner = postgresql_role.migration.name } resource "postgresql_grant" "grant_to_schema" { database = postgresql_database.app_db.name role = postgresql_role.application.name schema = postgresql_schema.schema.name object_type = "schema" privileges = ["USAGE"] } # grant role to table resource "postgresql_grant" "grant_to_application" { database = postgresql_database.app_db.name role = postgresql_role.application.name schema = postgresql_schema.schema.name object_type = "table" # objectsが空の場合は all # objects = [] # privileges は明示する。ここに無いものは revoke 対象になる。 privileges = ["SELECT", "INSERT", "UPDATE", "DELETE", "REFERENCES", "TRIGGER", "TRUNCATE"] } # default privileges を指定して、application userに対して新規テーブルの権限を付与する resource "postgresql_default_privileges" "default_privs" { role = postgresql_role.application.name database = postgresql_database.app_db.name schema = postgresql_schema.schema.name owner = postgresql_role.migration.name objec
こんにちは、Infrastructure Teamの宮本(@m1yam0t0)と申します。 本記事では、キャディの権限昇格システムの取り組みを紹介します。 目次 目次 はじめに 内製システムから Google Cloud PAM への移行 PAM の利用資格の設定 PAM の運用で工夫していること Slack 通知機能の実装 Devin による利用資格設定の自動化 まとめ はじめに みなさんは、パブリッククラウドの権限はどのように管理されていますか? IAMでメンバーに必要な権限を付与していますでしょうか?TerraformでIaC管理されていますでしょうか? キャディでは、最小権限の原則に従って、開発者には閲覧系の必要最低限の権限のみを付与しています。*1 開発・運用で追加の権限が必要になった場合は、Just-In-Time(JIT) Accessの仕組みで一定期間だけ権限昇格できるようになっています。 開発者が権限を申請し、承認者が承認してはじめて権限が付与されます。 最小権限の原則を徹底することで、昨今利用が広がっているAIエージェントを活用した場合にも、本番環境の権限を持っていないため、誤って操作してしまうリスクを低減できます。 本記事ではこのJIT Access Systemを内製システムからGoogle Cloud Priviledged Access Manager(PAM)に移行したお話を紹介いたします。 内製システムから Google Cloud PAM への移行 キャディでは、2022年より内製のJIT Access Systemを運用しておりました。 しかし、この内製のJIT Access Systemについて、認可制御に課題があったため、IAM Condition を組み合わせて権限が付与できるように改修を検討していました。 そんな中、Google Cloud PAM のアップデートで、権限のスコープが設定可能になったことを知り、検証をしてみたところ、内製のシステムを改修しづつけるより、効率良く目的を達成できることがわかりました。 IAM release notes | Identity and Access Management (IAM) | Google Cloud Documentation 上記を踏まえて、以下の理由から、キャディのJIT Access SystemをGoogle Cloud PAMへ移行する価値があると判断し、移行を実施いたしました。 権限のスコープを細かく設定でき、取得する権限を必要最小限に抑えられる Cloud Loggingに監査ログが残るため、通知や監査に活用できる Google Cloudマネージドのサービスであるためメンテナンス不要 PAM の利用資格の設定 Google Cloud PAMでは、取得したい権限のセットを利用資格として定義し、必要な権限に対応する利用資格を選択して申請します。 Terraform Provider が公式で提供されているため、IaCで管理できます。 利用資格はユースケースごとに複数作成するため、 以下のようなTerraform moduleを定義し、変数を入力することで容易に設定できるようにします。 resource "google_privileged_access_manager_entitlement" "entitlement" { provider = google-beta entitlement_id = var.entitlement_id location = var.location parent = var.parent max_request_duration = var.max_request_duration eligible_users { principals = var.eligible_users } privileged_access { gcp_iam_access { resource_type = var.resource_type resource = var.resource dynamic "role_bindings" { for_each = toset(var.roles) content { role = role_bindings.value } } } } approval_workflow { manual_approvals { require_approver_justification = var.require_approver_justification steps { approvers { principals = var.approvers } approvals_needed = var.approvals_needed approver_email_recipients = var.approver_email_recipients } } } additional_notification_targets { admin_email_recipients = var.notification_emails } requester_justification_config { unstructured {} } } 実際に利用する箇所では以下のようにTerraform moduleを呼び出して定義しています。 申請・承認するユーザを設定できるため、チームによって申請可能な利用資格を設定できます。 module "pam_org_gcs_bucket_read_access" { source = "../../modules/pam" # 利用資格名 entitlement_id = "gcs-bucket-read-access" # Organization, Folder, Project 単位で指定可能 parent = "organizations/${local.organization_id}" location = "global" resource_type = "cloudresourcemanager.googleapis.com/Organization" resource = "//cloudresourcemanager.googleapis.com/organizations/${local.organization_id}" # 取得したい role を定義 roles = [ "roles/storage.bucketViewer", "roles/storage.objectViewer", ] # 申請可能なユーザ eligible_users = [ "group:users@caddi.com", ] # 承認可能なユーザ approvers = [ "group:approvers@caddi.com", ] # 最大の申請期間 max_request_duration = "14400s" # 必要な承認の数 approvals_needed = 1 } PAM の運用で工夫していること Slack 通知機能の実装 PAMの通知機能はメール通知のみでSlackへの通知には標準では対応していません。 しかし、既存のJIT Access SystemではSlack通知するようにしていたため、利用者体験が変わらないようにする必要がありました。 そこで、PAMの監査ログの内容をパースしてSlack通知するAPIを実装しました。 以下のような仕組みで動作しています。 Pub/Subを経由して、実装したSlack通知APIに送信 Cloud Loggingに保存されているPAMの監査ログをLog routerでPub/Subに転送 Pub/Subの Push Subscription を使ってCloud Runで動作しているSlack通知APIにHTTP POST 実際の構成図は以下です。 PAM通知機能の構成図 上記のSlack通知APIを利用して、既存システムの使用感はそのままに、SlackでPAMの申請・承認を通知できるようにしました。 PAMのSlack通知 Slack通知の内容についても、利便性を上げるために様々な改善をしています。 承認結果のメッセージを申請したメッセージのスレッドに紐づけて投稿 申請内容に不備がある場合は、申請内容の修正を促すように警告文を自動で投稿 申請のステータスによって、SlackのAttachmentの色を変更 Devin による利用資格設定の自動化 PAMの利用資格の中に取得したい権限が存在しない場合、利用資格を修正する必要があります。 PAMの移行当初は取得できる権限が不足しており、利用者から多く依頼を受けていました。 その度にTerraformの定義を修正しレビューするのは大変です。 そこで、Devinを使って、Terraformの修正からPRの作成を自動でしてもらうようにしました。 Devin Playbook で利用資格を修正するPR作成作業を定型化しています。 利用者がSlack Workflowで追加してほしい権限を入力するとDevinが呼び出され自動でPRを作成します。 あとは、チームメンバーがPRをレビュー
はじめに こんにちは。メルカリのAI Securityエンジニアの@hi120kiです。 メルカリでは、AI AgentサービスDevinを社内の複数チームに展開しています。Devinは自律的にコードの調査・作成・PR提出までをこなせるサービスですが、組織として運用するうえでは管理上の課題がいくつかあります。 本記事ではAI SecurityチームがAI Agent Platformチームと協力し、Devin Enterprise APIを活用したカスタムTerraformプロバイダーと自動管理ツール群を自作しました。これにより、メンバーと権限の管理・シークレットローテーション・APIキーのライフサイクル管理・監査の仕組みを構築した取り組みについて紹介します。 Enterprise運用の課題 メルカリではDevinのEnterpriseプランを採用しています。Remote環境で動作するAI Agentを組織的に運用するためにOktaによるSSO、監査ログ、権限の管理、チームごとの環境分離が必須要件であり、これらを満たすために選定しました。 Devin EnterpriseではCoreプランやTeamプランのように1つのOrganizationを共有するのではなく、Enterpriseという管理基盤から複数のOrganizationを一元管理します。メルカリには複数のビジネス領域にまたがる多数のチームがあり、各チームが扱う情報を分離して保護する必要があります。そのためチームや目的に応じてOrganizationを割り当てています。 ただし、10以上のOrganizationと多数の利用者を抱える環境では、次の課題が生じます。 権限管理の課題 メンバーのOrganizationへのアサインが手動操作に依存 「誰がどのOrganizationに所属しているか」の状態管理が困難 シークレット管理の課題 各Organizationにサードパーティサービスごとの認証情報を個別に設定する必要 シークレットを手動で一斉ローテーションする手間 アクセス権の課題 Devin APIキーの有効期限管理が標準機能として提供されておらず、各Organization内に長期間未ローテーションのAPIキーが残存するリスク Devinの活用が広がるほど管理するOrganizationも増え、これらの課題の負担は拡大します。以前はWeb UIでの手作業に頼っていましたが、2025年末以降DevinがEnterprise向けAPIをv2からv3へ拡充したことで、ほとんどの管理操作をAPI経由で自動化できるようになりました。これを受け、Go言語とGitHub Actionsを用いた管理基盤を内製しています。 Devin APIの概要 Devinはv3 として最新のEnterprise管理向けAPIを提供しています。Enterprise・Organization単位のMember・Role管理や、各OrganizationのSecret・Knowledgeを操作できます。v3 APIで以下の自動管理機能を実現しました。 カスタムTerraformプロバイダー シークレットの一斉ローテーション Google Cloudサービスアカウントキーのローテーション セキュリティ管理基盤との連携 APIキー管理のみv2 APIを使用しています。v2 APIでは複数OrganizationにまたがるAPIキーの作成・取得・削除が可能で、以下を実施しています。 利用者が発行したAPIキーの定期無効化 社内AgentのDevin Wiki利用向けAPIキー管理 これらのAPI仕様はREST形式のAPIとしてDevinの公式ドキュメントにリクエストおよびレスポンスの詳細な仕様とともにドキュメント化されており、一般的なREST APIクライアントを実装することでそれぞれの機能を呼び出すことができます。今回これらのREST APIクライアントは、メルカリ社内で広く用いられているGo言語を用いてそれぞれのAPIが関数に対応するように実装し再利用しやすいように整備しました。 以下の章からそれぞれの管理機能の詳細を紹介します。 1. カスタムTerraformプロバイダー 管理基盤の中核は、Terraform Plugin Frameworkで構築したカスタムTerraformプロバイダーによるOrganizationおよびメンバー管理です。 メルカリではGoogle Cloudをはじめリソース管理にTerraformを広く利用しており、エンジニアが日常的に扱っている点から採用しました。DevinをInfrastructure as Codeで管理すると、メンバー追加や権限変更にPRレビューを挟める・Organizationやメンバーの状態をコードで把握できるようになります。公式のTerraformプロバイダーは現時点で提供されていないため自作しました。 利用者や管理者は各チーム用のOrganizationをTerraformで定義します。ACU(Agent Compute Unit)上限もここで設定し、チームごとの利用量を制御します。max_cycle_acu_limit はOrganization全体のACU上限、max_session_acu_limit は1セッションあたりの上限で、想定外のコスト超過を防ぎます。 resource "devin_organization" "mercari_example_team" { name = "mercari-example-team" max_cycle_acu_limit = 500 max_session_acu_limit = 250 } またメンバーのOrganizationへのアサインもTerraformで宣言的に管理します。 # メンバー定義(メールアドレスで参照) data "devin_member" "mercari_example_team" { for_each = toset([ "user-1@example.com", "user-2@example.com", "user-3@example.com", ]) email = each.value } # Organizationへのアサイン resource "devin_organization_member" "mercari_example_team" { for_each = data.devin_member.mercari_example_team user_id = each.value.user_id org_id = devin_organization.mercari_example_team.org_id org_role_id = "mercari_org_member" } Organizationの追加やACU上限の変更、メンバーの追加・削除は、Terraformコードの変更→PRレビュー→マージという通常の開発フローで行います。terraform plan の出力で「誰がどのOrganizationに追加/削除されるか」が明確にわかり、意図しない権限変更を防げます。 このTerraformプロバイダーではDevin Knowledgeも管理できます。KnowledgeはDevinにおけるAgent Skillのような存在です。メルカリのDevin環境では各チームが別々のOrganizationに分かれており、互いの利用状況を閲覧できません。セキュリティ面では望ましい分離ですが、活用ノウハウの共有が難しくなります。Knowledgeをプロバイダーで管理できるようにし、チーム間での活用ノウハウの配布を可能にしました。 2. シークレットの一斉ローテーション DevinはSessionごとに独立した仮想マシンを起動するため、初期状態ではGitHub等ソースコード管理サービスへの権限しか持ちません。クラウド環境やチケット管理サービスなどへ接続するには、APIキー等の認証情報を個別に設定する必要があります。 一方、DevinはAI Agentとして与えられたAPIキーを自由に扱えるうえ、Organization内のメンバーはSession内部のファイルシステムやシェルにアクセスできるため認証情報の取り扱いには注意が必要です。そこでメルカリでは、Devinに設定するAPIキー群を管理者が一元管理し、短い間隔で定期ローテーションすることで、長期間有効な認証情報がDevin上に残らないようにしています。 ただし手動でのローテーションは負担が大きく、以前は多数のOrganizationの複数Secretをローテーションするだけでかなりの時間を要していました。しかしDevinが2026年1月にSecret管理機能をv3 APIへ追加したことで、これらの操作を自動化できるようになりました。現在のローテーション手順は以下のとおりです。 Devin管理者がそれぞれのサービスで認証情報をローテーションする 新しい認証情報を事前に作成済みのGoogle Cloud Secret Managerに追加する 自動化をGitHub Actions経由で起動する ローテーションが実行され、Secret Managerから各Organizationに配布される これにより、最小限の作業で10以上のOrganizationのシークレットを一斉ローテーションできるようになりました。 3. Google Cloudサービスアカウントキーのローテーション メルカリでは主にGoogle Cloudを利用しておりライブラリの取得やテスト環境との接続にはGoogle Cloudの権限をDevinに付与する必要があります。しかしDevinは現在Workload Identity Federationに対応できるようなOIDCトークン発行機能がないため、サービスアカウントキーを用いる必要があります。 しかし前提として、メルカリではGoogle Cloud公式のベストプラクティスに従い、Organization Policyでサービスアカウントキーの発行を一律禁止しています。このためDevin専用のGoogle Cloud Projectを設け、さらにiam.serviceAccountKeyExpiryHoursを追加のOrganization Policyとして設定しました。これにより、自動化が停止した場合でもサービスアカウントキーは一定期間で無効化されます。 この仕組みのうえで、Organizationごとに個別のサービスアカウントキーを定期ローテーションしながら付与しています。 4. セキュリティ管理基盤との連携 Devin Enterprise採用の要件の一つに監査ログがあります。メルカリではAI Security およびThreat Detection and ResponseチームのAnnaがDevin v3 APIを通じて内製セキュリティ監視プラットフォームとの連携を構築しました。 この連携では、Admin権限を持つEnterprise Service UserとEnterprise Audit Logsエンドポイントを利用しています。これはv2 APIにおけるエンドポイントとは異なりページネーションがあるため、すべての監査ログを正確に取得することができます。これによりGoogle CloudのCloud Run Job を使って5分おきにAPIを取得し、前回取り込んだ最後の監査ログのタイムスタンプ以降の新規監査ログをすべて取得したうえでGoogle CloudのPubSubトピックへと転送しています。そして転送された監査ログはセキュリティ調査のためのBigQueryに保存されます。 5. 利用者が発行したAPIキーの定期無効化 Enterprise全体のAPIキーを全件取得し、作成から一定期間が経過したキーを自動で無効化します。Devinの標準機能にはないセキュリティポリシーを、APIで独自に実装しました。 これらのAPIキーは主にDevin MCPの接続に用いられます。APIキー経由で間接的にソースコードを取得できるため、厳格な管理が求められます。AI Agentを複数利用する開発環境では、使わなくなったAgentの設定ファイルに認証情報が残る・個人のAPIキーを複数人が利用する自作Agentに設定して社内公開してしまう、といった事態が起こりえます。 一定期間経過したAPIキーを自動無効化することで、利用中のAgentだけがAPIキーを保持する状態を維持し、複数人で共有するAgentには、次章で紹介するGoogle Cloud Secret Manager経由のAPIキーを利用させることで、Agentが持つ権限の可視化も実現しました。 6. 社内AgentのDevin Wiki利用向けAPIキー管理 メルカリでは各チームの開発用Organizationとは別に、Devin Wiki用のOrganizationを運用しています。Devin WikiはDevin MCP経由でリポジトリの内容を取得したり、自然言語で検索したりできます。 ソースコードの探索をAI Agentが直接行うとコンテキストを大量に消費します。ソースコード調査が必要な場面ではDevinに処理を委託することで、コンテキスト消費を抑えられます。 ただしDevin MCPの利用にはAPIキーが必要で、前章のとおり一定期間で自動無効化されます。例外となるAPIキーを設けることもできますが、目的外利用を完全には防げません。そこでAPIキーを短い間隔で定期的に再作成し、Google Cloud Secret Managerに保存する自動化を構築しました。 これにより、Devin MCPを利用するAI AgentのサービスアカウントをTerraform上で一元管理し利用状況を可視化するとともに、APIキーの定期再作成による目的外利用の防止も実現しました。 resource "google_secret_manager_secret" "shared_wiki_api_key" { secret_id = "shared-wiki-api-key" } resource "google_secret_manager_secret_iam_member" "shared_wiki_api_key" { for_each = toset(local.accessor_service_accounts_shared_wiki_api_key) secret_id = google_secret_manager_secret.shared_wiki_api_key.secret_id role = "roles/secretmanager.secretAccessor" member = "serviceAccount:${each.value}" } locals { accessor_service_accounts_shared_wiki_api_key = [ "agent-1@---.iam.gserviceaccount.com", "agent-2@---.iam.gserviceaccount.com", ] } 管理操作を動かすCIパイプライン これらの管理操作はすべてGitHub Actionsで自動化しています。SaaS管理向けに独自管理ツールを作る場合、長期的なメンテナンスが避けられません。組織変更時の引き継ぎも考慮すると、依存関係を小さく保ち、メンテナンスしやすい技術・プラットフォームを選ぶ必要があります。 Secret ManagerやサービスアカウントはGoogle Cloud上に置きつつも、処理の実行にはGitHub Actionsを選びました。リポジトリ内の自動化がデプロイなしで直接動作するためメンテナンスの手間が減り、不要なクラウドリソースを持たないことでコストと管理・引き継ぎ時の認知負荷も抑えられます。また定期実行に加え手動トリガー(workflow_dispatch)にも対応しており、緊急時のシークレットローテーションを即座に実行できます。 一方、GitHub Actionsは自由に実行できてしまうため、権限管理や<a href="https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-rulese
こんにちは。データエンジニアの田頭(@tagasyksk)です。 ファインディのデータ基盤は、CTO室データソリューションチームが事業部横断で開発・運用を担っています。事業の拡大に伴ってプロダクト数が急増し、当初採用していたデータメッシュのアーキテクチャでは管理コストの増大やサイロ化といった課題が顕在化してきました。 本記事では、Google Cloudプロジェクトの統合や共通化と分権のバランス再設計など、データ基盤をプラットフォームへと進化させている途上の取り組みについてご紹介します。まだ道半ばではありますが、同様の課題に向き合っている方の参考になれば幸いです。 これまでのデータ基盤のあゆみ データメッシュの採用 責任分界点の設計 事業拡大で直面した課題 プロダクトの急増 Google Cloudプロジェクトの増殖 技術選定のサイロ化 プロジェクト間データ連携の複雑化 どう解決したか データメッシュの再解釈とプロジェクト統合 フェデレーテッド・ガバナンスの確立 dbtランタイムの共通化 Lookerによる事業部横断の指標管理 今後の展望 終わりに これまでのデータ基盤のあゆみ データメッシュの採用 ファインディのデータ基盤は、分散型のデータウェアハウスアーキテクチャであるデータメッシュを採用していました。 データメッシュは、各事業部がデータの所有権を持ち自律的にデータを管理するアーキテクチャです。ファインディでは次のような方針で運用してきました。 事業部ごとにGoogle Cloudプロジェクト及びBigQueryを分離 各事業部がそれぞれのデータを管理し、アクセス権を事業部単位で制御 事業部間のデータ共有にはBigQuery Sharingを利用 責任分界点の設計 データチームでは、レイヤーごとに責任分界点を定め、各チームが自律的にデータを活用できる体制を整えていました。データチームはソースデータの取り込みや共通のデータモデルを整備し、各事業部はその上に独自の分析用モデルを構築する形です。 データメッシュの運用については、過去に別の登壇でも発表しています。 事業拡大で直面した課題 プロダクトの急増 ファインディでは2026年に「生成AI時代の事業戦略2026」として、Findy InsightsやFindy AI+など4つの新規AI事業を同時に発表しました。 prtimes.jp これにより、当初の設計で前提としていた「プロダクト数がある程度限られている」状態が崩れ、いくつかの課題が表面化しました。 Google Cloudプロジェクトの増殖 当初の設計思想に則り、プロダクトごとにGoogle Cloudプロジェクトを分離していたため、プロダクトが増えるたびにプロジェクトも増え続ける構造になっていました。IAM、予算、リソースの管理がプロジェクトの数に比例して煩雑になり、新しいプロダクトが追加されるたびに同じようなインフラ構築作業が発生していました。 技術選定のサイロ化 データメッシュではデータに関わる技術選定も各事業部に委ねていたため、ツールや実行環境が事業部ごとにバラバラになっていました。データ変換にはdbtとDataformが混在し、BIもスプレッドシートとLooker Studioが併存、dbtの実行環境もDocker・GitHub Actions・ローカル実行と統一されていない状態でした。中央で統制しづらく、会社として共通のノウハウを蓄積しにくいことが課題になっていました。 プロジェクト間データ連携の複雑化 事業部横断でのデータ活用ニーズも増えてきました。各プロダクトのCRMに蓄積された顧客情報をBigQueryに集約した「共通企業マスタ」の構築や、MCPとAIエージェントを組み合わせたSlackからの横断検索など、プロダクトを跨いだデータ連携の取り組みが広がっています。 tech.findy.co.jp しかし、プロジェクトが分離された構成のままでは、プロダクトが増えるたびに連携先も倍々で増加し、管理が追いつかなくなることが見えていました。 どう解決したか データメッシュの再解釈とプロジェクト統合 方針転換の核となったのは、「データメッシュにおけるドメイン分離の単位をプロジェクトからデータセットに変える」という判断です。 Google Cloudプロジェクトを一つに統合し、BigQueryのデータセット単位でドメインを分離する構成に移行しました。これにより、プロジェクト管理のオーバーヘッドを大幅に削減しつつ、ドメインごとのデータの独立性は維持しています。 フェデレーテッド・ガバナンスの確立 フェデレーテッド・ガバナンスとは、全社共通で統制すべきルールと各事業部に委ねるルールを明確に分け、中央集権と分権を両立させるガバナンスモデルです。プロジェクト統合に伴い、このモデルに沿ってガバナンスの境界を整理しました。 IAM管理、Cloud DLP、BigQuery Policy Tagなどのセキュリティ・コンプライアンス領域は元々共通化していたものです。事業拡大を機に、CI検査項目、Formatter・Linter、dbtの実行環境(ランタイム)を新たに標準化しました。一方で、事業ドメイン、ビジネスイベント、データモデリングといったビジネスに近い領域は引き続き各事業部に委譲しています。 共通化すべきものと分権すべきものの線引きが明確になったことで、データチームと事業部チームの双方が迷いなく動けるようになりました。 dbtランタイムの共通化 バラバラだったdbtの実行環境をDockerに統一しました。共通のDockerイメージをArtifact Registryで管理し、各リポジトリはGitHub Reusable Workflowを通じて共通のワークフローを呼び出す形にしています。 jobs: dbt-build: uses: org/shared-workflows/.github/workflows/dbt.yml@main with: image_tag: "0.0.0" mount_path: "." dbt_args: "build --target prod" また、ローカル開発時の共通コマンドにはTaskfileのincludes機能を活用しています。各リポジトリは共通Taskfileを参照するだけで、lint、test、buildなどの操作を統一されたインターフェースで実行できます。 includes: common: taskfile: ./path/to/shared/Taskfile.yml tasks: lint: cmds: - task: common:lint test: cmds: - task: common:test 新しいプロダクトが追加された場合も、共通のワークフローとTaskfileを参照するだけでdbt環境が整うため、立ち上げのリードタイムが大きく下がりました。バージョンアップやdependabotへの対応も、事業部の数だけ必要だったものが共通イメージ1つの更新で済むようになっています。 Lookerによる事業部横断の指標管理 データ基盤のリアーキテクチャとあわせて、BIツールの見直しも行いました。これまで事業部ごとにスプレッドシートやLooker Studioで管理していた指標を、Lookerに集約しています。 Lookerのセマンティックレイヤーを活用することで、全社で共通のビジネスロジックを定義し、指標の一貫性を担保できるようになりました。一方で、指標の定義そのものは各事業部に委譲しています。実際に、全体のダッシュボードの68%がデータエンジニア以外のメンバーによって作成されており、中央に寄せつつも現場のデータ活用はむしろ活発になっています。Looker導入の詳細については次の記事で紹介しています。 tech.findy.co.jp 今後の展望 プラットフォーム化の取り組みはまだ道半ばです。今後は次の2つの方向で進化を続けていきます。 1つ目は、セルフサービスかつAI Readyなデータ基盤です。事業部のメンバーやAIが自らデータを探索・分析できる仕組みをさらに拡充し、データチームへの依存を減らしていきたいと考えています。 2つ目は、メタデータの整備です。今後事業やプロダクトが増えても低コストでデータを探し利用できるようにし、事業や組織間のシナジーをデータで生み出していくことがチームのミッションとして求められています。 終わりに 本記事では、データメッシュからプラットフォームへとデータ基盤を進化させた取り組みについて紹介しました。 事業の成長フェーズによって、最適なアーキテクチャは変わります。ファインディでは、データメッシュの考え方自体を捨てたわけではなく、「プロジェクト分離」から「データセット分離」へとドメイン境界の粒度を見直すことで、スケーラビリティと自律性のバランスを取り直しました。 データ基盤は一度作って終わりではなく、事業の成長に合わせて進化し続けるものです。今回紹介したリアーキテクチャもまだ道半ばで、セルフサービス化やメタデータ整備など取り組むべきテーマは山積みです。この記事が、同様の課題に向き合っている方の参考になれば嬉しいです。 ファインディではこのデータ基盤を一緒に育てていくメンバーを募集しています。少しでも興味が湧いた方はカジュアル面談お待ちしております! <iframe src="https://hatenablog-parts.com/embed?url=https%3A%2F%2Fherp.careers%2Fv1%2Ffindy%2Frequisition-groups%2F14c4a661-5e48-40c5-99d0-ea657b8b4c04" title="プロダクト開発 / SRE / QA の求人一覧 - ファインディ株式会社" class="embed-card embed-webcard" scrolling="no" frameborder="0" style="display: block; width: 100%; height: 155px; max-width: 500px;