有名テック企業の技術ブログを、ひとつのフィードで。
フィード
35件
はじめに こんにちは。WEARバックエンド部SREブロックの春日です。普段はWEARというサービスのSREとして開発・運用に携わっています。 本記事では、WEARのハイブリッド検索のリリースに伴い刷新した検索インデクシングシステム(以下、インデクサー)について、OpenSearch Ingestionを採用しようとした際にハマったポイントや、ベクトル検索のためのインデクサーを設計する上で工夫した点を中心に紹介します。 目次 はじめに 目次 背景 既存のインデクサーと刷新の動機 ベクトルデータの保持方法の検討 インデクサーの構成方針 BigQuery → S3 のデータ連携 日次更新の設計 差分更新の設計 初期設計:OpenSearch Ingestion+Lambdaプロセッサでのベクトル化とインデクシング 1万件の差分更新で表面化した問題 再設計:ベクトル化Lambdaを前段に出す 最終設計:S3+SQS+Lambdaで非同期にベクトル化とインデクシング ベクトル化Lambdaでの工夫 Bedrockのリージョン分散 1ファイル単位の処理量を制御する 出力形式と後処理 OpenSearch投入Lambdaでの工夫 external versionで古いデータで新しいデータを上書きすることを防止 処理完了後のファイル削除 Lambdaエラー時のファイル退避 非同期処理の完了待機 既存データに対する初回ベクトル化 結果 まとめ 背景 WEARでは、検索基盤としてAmazon OpenSearch Service(以下、OpenSearch)を利用しています1。これまでフリーワード検索ではタグマッチングを主軸としていましたが、タグが付与されていない検索ワードに対する検索結果の質と量に課題がありました。 これを改善するため、ベクトル検索と全文検索を組み合わせたハイブリッド検索(WEARではあいまい検索と呼んでいるため、以下「あいまい検索」と表記)をリリースすることになりました2。 あいまい検索のためにベクトル検索を導入するには、検索対象の各documentに対して、タイトル・説明文・タグなどを連結したテキストをベクトル化したフィールドを持たせる必要があります。しかしながら、既存のインデクサーでこのフローを実現するのは難しく、インデクサー自体を刷新することになりました。本記事ではその刷新の過程と、設計時に行った工夫を紹介します。 既存のインデクサーと刷新の動機 WEARではOpenSearchへのインデクシングをEmbulkを用いて行っていました。 embulk-input-bigqueryとembulk-output-elasticsearchなどを組み合わせ、BigQueryからOpenSearchへデータを連携する構成です。EmbulkのジョブはDigdagのworkflowで管理し、Amazon EKS(以下、EKS)上のJobとして実行していました3。インデクサーには差分更新と日次更新の2種類があり、それぞれ次の役割を持っていました。 差分更新:10分間隔で実行。直近で新規投稿・更新documentをインデクシングし、削除された投稿をindexから削除 日次更新:1日1回、新しいindexを作成して全件をインデクシングし、Blue/Greenでエイリアスを切り替える形で全件更新する。統計データなどの日次で更新すべき値はこのタイミングで反映 しかし、ベクトル検索の導入を検討するにあたり、この構成にはいくつかの課題がありました。 WEARで一番大きいコーディネートのindexは大量のdocumentを持っており、これらを毎日ベクトル化するのはコストと処理時間の両面で非現実的 BigQueryからOpenSearchへの連携中にベクトル化の処理を挟むのが困難 本対応の検討時点でEmbulkはすでにメンテナンスがされていない状態であり、長期的な保守性に不安 これらを踏まえ、ベクトル検索対応に必要な機能と、長期的な保守性の両方を満たす構成へとインデクサーを刷新する方針を決めました。 ベクトルデータの保持方法の検討 最初に取り組んだのが、ベクトルデータをどこに、どのタイミングで持たせるかという検討です。 既存の日次更新では新しいindexを毎日作成して全件インデクシングしていましたが、大量のデータを毎日全件ベクトル化するのは非現実的なため、ベクトルデータを別ストレージに保存しておく案を検討しました。しかし、ベクトル取得時のパフォーマンスやコスト面で見合わないと判断し、最終的には日次での全件更新そのものを廃止する方針を取りました。 毎日indexを全件更新するメリットの1つとして、indexの不整合が発生した場合に、日次での全件更新によって整合性を保つことができるという点がありました。これは例として、差分更新の失敗時のリトライで、古いデータで新しいデータが上書きされてしまうといった状況が挙げられます。全件更新を廃止するにあたり、この点をどう担保するのかが課題でしたが、後述する方法でdocumentのバージョニングを行うことで、不整合が発生しないようにしました。 新しい設計では、ベクトル化は差分更新のみで行い、日次更新では同じindexに対して日次で更新すべき値のみを上書きするように責務を分けました。これにより、ベクトル化を投稿の追加・更新時のみに限定でき、ベクトル化コストと処理時間の問題を回避できるようになりました。 インデクサーの構成方針 インデクサー刷新にあたって、ベクトル化を含む新しい構成として複数の選択肢を検討しましたが、OpenSearch Ingestionを軸とする構成を採用しました。判断のポイントは以下の通りです。 自前で運用する外部ツールは最小限にしたい(Embulkのように追加でメンテナンスが必要なツールを増やしたくない) データ抽出のSQLはバックエンドエンジニア、インデクサーのインフラ構築・運用はSREという責務分離を維持し、両者を疎結合にしたい AWS公式のLambdaプロセッサでベクトル化するパターンを参考にすれば、ベクトル化部分をLambdaへ切り出して柔軟に構成できそう これらを総合的に考慮し、Amazon S3(以下、S3)を起点としたAWS Lambda(以下、Lambda)の構成を方針として進めることになりました。 BigQuery → S3 のデータ連携 WEARではMicrosoft SQL ServerからBigQueryへリアルタイム連携をしており、インデクサー側もBigQueryからデータを取得しています。前述の通り、インデクサーはS3を起点としてデータを処理する設計を取っているため、BigQueryから取得したデータをS3に連携する必要があります。BigQueryから直接S3へ出力する機能はないため、いったんCloud Storage(以下、GCS)へ出力してからS3へ転送する形を取りました。 GCSへの出力にはBigQueryのEXPORT DATA文を利用しています。差分更新・日次更新いずれもJSON Lines形式でGCSへ出力するように記述しており、以下に差分更新を例にしたものを記載します。 EXPORT DATA OPTIONS( uri='gs://GCS_BUCKET/coordinates/diff/raw-data/YYYY/MM/DD/HH/mm/data_*.jsonl', format='JSON', overwrite=true ) AS -- 対象データを取得するクエリ ... uriにワイルドカード(*)を含めることで、BigQueryが出力サイズに応じて自動的に複数ファイルへ分割します。出力フォーマットはJSONを指定するとJSON Lines形式になります。 GCSからS3への転送方法は、差分更新と日次更新で異なるツールを使い分けています。 差分更新:rclone 日次更新:AWS DataSync(以下、DataSync) DataSyncは大量データの高速転送に適していますが、タスクの起動・実行に約5分かかります。差分更新は10分間隔で実行する上、ベクトル化のような時間のかかる処理も挟まるため、起動に時間のかかるDataSyncは許容できませんでした。差分更新ではデータ量がそこまで多くないこともあり、rcloneを採用しています。 日次更新の設計 日次更新では、もともとEmbulkで実装されていた全件更新を廃止し、差分更新と同じindexに対して統計データなどの日次で更新すべき値のみを上書きする方式に変更しました。日次更新の構成は以下の通りです。 日次更新はOpenSearch Ingestionを採用しており、S3に格納された全件データに対してS3 scanでOpenSearchへbulkでupsertしています。OpenSearch Ingestionのパイプライン定義の例は以下のとおりです。 version: 2 coordinates-daily-indexer: source: s3: acknowledgments: true delete_s3_objects_on_read: true scan: buckets: - bucket: name: ${BUCKET_NAME} filter: include_prefix: ["coordinates/daily/raw-data/"] aws: region: ap-northeast-1 sts_role_arn: ${STS_ROLE_ARN} codec: ndjson: {} processor: - delete_entries: with_keys: <s
はじめに こんにちは。プラットフォームSREブロックの酒部・高塚・亀井です。私たちは2026年5月14日〜15日に名古屋で開催された「クラウドネイティブ会議」に参加してきました。本記事では印象に残ったセッションをご紹介します! はじめに クラウドネイティブ会議とは セッションレポート キーノート:老舗IoTクラウドサービス組織の変革 -クラウドネイティブをはじめよう- GameDay:チームで挑むリアルな障害対応 100マイクロサービスのTerraform/Kubernetes管理地獄から抜け出すためのAI活用術 巨大組織の認知負荷をどう下げるか?ソフトバンクが描くCNAP×Backstageによるクラウドネイティブの新時代 生成AI時代に信頼性をどう保ち続けるか - Policy as Codeの実践 おわりに クラウドネイティブ会議とは クラウドネイティブ会議は、CloudNative Days、Platform Engineering Kaigi、SRE Kaigiという3つの大規模テックイベントで合同開催されたカンファレンスです。現地参加とオンライン参加のハイブリッド形式で開催され、会場の名古屋・中日ホール&カンファレンスには約1,000人が集まりました。 当日の様子は公式のXのポストまとめで見ることができます。現地の雰囲気を感じることができるので、ぜひご覧ください。 posfie.com セッションレポート ここからは各メンバーからのセッション紹介をお届けします。 キーノート:老舗IoTクラウドサービス組織の変革 -クラウドネイティブをはじめよう- kaigi.cloudnativedays.jp 高塚です。1日目のキーノートでは、パナソニックさんの事例として、巨大なモノリスだった老舗IoTサービスをマイクロサービス化した熱い話を聞くことができました。 見切り発車でマイクロサービス化を始めたものの、最初は問題が山積みだったとのことです。 老舗IoTクラウドサービス組織の変革 -クラウドネイティブをはじめよう- アーカイブ動画 6:19 より引用 かなり昔からあるAWSアカウントでしか見られない「ap-northeast-1b」アベイラビリティゾーンがあった話では会場もざわざわしていました。 老舗IoTクラウドサービス組織の変革 -クラウドネイティブをはじめよう- アーカイブ動画 7:00 より引用 GitLabの導入は、社内から「Gitを使うなんて危険だ、けしからん」という声も上がるなど「正直ここが一番しんどかった部分」だったそうです。しかし、そういった意見を軽々しく否定せず、既存のシステムがお客様に価値を提供してきたことに敬意を持ちながらクラウドネイティブ化を進めたそうです。 老舗IoTクラウドサービス組織の変革 -クラウドネイティブをはじめよう- アーカイブ動画 8:22 より引用 その結果、無事に本番稼働させることができました。 老舗IoTクラウドサービス組織の変革 -クラウドネイティブをはじめよう- アーカイブ動画 15:26 より引用 後半ではIoT特有のE2Eトレーシングについて紹介がありました。 組み込みデバイスはCPU・メモリが限られており、スパン送信による性能劣化を避けるため、OpenTelemetry SDKは利用せずにトレーシングを自前実装したとのことです。 老舗IoTクラウドサービス組織の変革 -クラウドネイティブをはじめよう- アーカイブ動画 23:45 より引用 また、IoTデバイスはネットワークやOSなどの問題が障害の原因になりやすいため、eBPFでカーネルイベントもスパンにしたそうです。 老舗IoTクラウドサービス組織の変革 -クラウドネイティブをはじめよう- アーカイブ動画 24:45 より引用 約30分の発表はとても濃い内容で、大変勉強になりました。また私もZOZOTOWNのマイクロサービス化を長年担当しているため、発表で赤裸々に語られる苦労話には「わかりみが深い〜」と100回くらい頷いていました。 本記事では主に技術的な話をご紹介しましたが、組織の文化を醸成する話や「これからクラウドネイティブをはじめる方へのメッセージ」などとても学びになる内容が盛りだくさんですので、ぜひアーカイブ動画をご覧ください。 GameDay:チームで挑むリアルな障害対応 酒部です。GameDayはKubernetes環境上で発生するさまざまな障害シナリオに対して、チームで協力して原因を特定し、復旧させるという内容でした。参加者にはKubernetes上で稼働するアプリケーション環境が提供され、その環境にはあらかじめ障害が仕込まれており、クエスト形式で出題される問題を解きながら、システムを正常な状態に復旧させていくという形式でした。 形式は約2時間のチーム対抗戦で、Kubernetes初心者から経験者まで幅広い層が集まっていました。ルールはシンプルで、障害を復旧することでスコアが加算され、最終的にチーム単位で順位が決まる仕組みです。 困ったときに相談できるメンターがサポートしてくれる体制に加え、行き詰まっても段階的なヒントで前に進める仕組みも用意されており、勝負というよりもチームで協力して問題に取り組む過程が重視されているように感じました。 題材として用意されていたのは、OpenTelemetry DemoをベースとしたECサイトのマイクロサービス構成です。各チームにCode Server、Grafana、Jaeger、Argo CD、GitHubリポジトリが一式与えられました。基本フローは障害を発見 → GitHub上で修正 → commit & push → Argo CDが自動同期 → Verifierによって各問題の合否判定する流れです。 問題の内容や解説は下記の公式記事に解説があるため、そちらをご覧ください。 kaigi.cloudnativedays.jp 結果としては、最後の問題だけ時間内に解くことができませんでした。ただ、作問者が解かせるつもりで作っていないと言うほどの難問で、ほとんどのチームが解けていなかったので、終了後残り時間で会場でも簡単な解説をしていただきました。解説後、会場のあちこちから「そういうことだったのか」「やられた」といった声が漏れ、参加者全員が思わず唸ってしまうような巧妙な問題設計だったことが印象に残っています。 観察・操作系のチュートリアル問題も用意されていて、Kubernetesに触り始めたばかりの方でも問題なく楽しめる内容で、自信を持っておすすめできるプログラムでした。 100マイクロサービスのTerraform/Kubernetes管理地獄から抜け出すためのAI活用術 kaigi.cloudnativedays.jp speakerdeck.com 酒部です。このセッションでは膨大なTerraformやKubernetesマニフェストファイルを扱う構成において、日々の運用をAIエージェントでどう解決するかがテーマでした。 セッションは大きく4パートで構成されており、以下のトピックが扱われました。 Linear × Codexで全マイクロサービスのTerraform / K8s manifest更新を効率化 AIによるレビューで200 PR/dayの50%を自動化 問い合わせ・トラブルシューティングをAIに任せる試み Production Readiness Check(PRC)のEvidence確認もAIにやってもらう 特に、2と4は弊チームと似た取り組みも紹介されており大変興味深い内容でした。 まず、PRレビューへのAI活用について、Notionに整理されたガイドラインがあるのに、サービス・人数の増加で存在を知らない人が増え、結果としてガイドラインが守られないという課題がありました。 解決アプローチはガイドラインをAIエージェントが利用できる形でリポジトリに降ろすというものです。Notionは引き続きSoT(Source of Truth)として残しつつ、AIレビュー用のコンテキストはリポジトリに固定する設計としました。 紹介されていた実例では、Codex ReviewがIAM設定の重複を「社内ガイドライン違反」として指摘し、参照したガイドラインのファイルパスまで引用していました。一般論ではなく、社内ルールに照らした具体的な指摘ができている点が印象的でした。AIに指摘されない部分こそが暗黙知であるという気づきから、「AIが指摘してこない部分」を観察することで、ドキュメント化されていない暗黙知が浮かび上がってくる、というメタな視点が学びになりました。 本番リリース前のProduction Readiness Check(PRC)の自動化ですが、開発者はEvidenceを集め、SREはその妥当性をチェックするという、両者にとって骨の折れるプロセスがあるそうです。ここで、いきなりAIに丸投げするのではなく、AIに任せるべき項目を選定したり、Code化できる項目はCIで自動チェックしたりするなど工夫されていました。 また、AIに任せるためフォーマットを整理する過程で、以前はやや解釈が難しいPRC項目もあったが、自動化に向けて解釈がブレないようにしたという副次効果も語られていました。AI活用のためのドキュメント整備が、人間にとっても理解しやすいドキュメント整備につながるとい
はじめに こんにちは、WEAR開発部SREブロックの木内です。普段はWEARのSREとして開発、運用に携わっています。 WEARは2013年にサービスを開始し長年オンプレミスで運用されてきましたが、過去にクラウド(AWS)へのシステムリプレイスを実施しています。その際にWebアプリのCDNとしてFastlyを採用し、オンプレミスからクラウドへの段階的な移行を実現しました。 採用の決め手は主に以下の点です。 パスベースのルーティングが可能(パスごとにオンプレミスとクラウドのオリジンを切り替えられる) ネイキッドドメインへの対応 設定変更の即時反映による迅速なロールバック リプレイスの詳細については、以下の記事をご参照ください。 techblog.zozo.com Fastlyを用いた構成はサービスを止めずに安全なリプレイスを実現するうえで大きく貢献しました。一方で、リプレイスが完了しFastlyを導入した当初の目的を達成した後も残り続けたことで、運用負荷やコストといった課題が顕在化してきました。 本記事では、過渡期の構成を整理し、CDNをFastlyからAmazon CloudFront(以下、CloudFront)へ移行してAWSに統一した取り組みを紹介します。 目次 はじめに 目次 移行の背景・課題 運用負荷 コスト 移行後の構成 移行方法 1. LP・アセットの切り替え 2. 動的コンテンツ・認証処理の切り替え 3. VCLの処理をCloudFront Functionsへ移行 4. DNS切り替え WAFの移行タイミング 設計のポイント 移行期間中のリクエスト CloudFront Functionsを用いたリダイレクト・リライト カスタムエラーレスポンス 得られた成果 運用のシンプル化 インフラコストの削減 まとめ 移行の背景・課題 移行前の構成は以下の通りです。 Fastlyをフロントに置き、バックエンドにALBとS3が2つずつ、計4つのオリジンを持つ構成です。 ALBは動的コンテンツの配信や認証処理を担っており、S3はLPやアセットなどの静的コンテンツを配信しています。S3の前段にはそれぞれ個別のCloudFrontを使用しています。 また、FastlyではVCL1を用いてCDN以外の多くの処理も担っていました。 パスごとのオリジン振り分け 各種ブロック(IP / ASN / リファラ など) Basic認証 メンテナンスモード リダイレクト / リライト 前述の通り、リプレイス時にFastlyを採用したことで安全にリプレイスを進めることができましたが、リプレイス完了後に以下のような課題が残りました。 運用負荷 AWSとFastlyの二重管理が運用負荷に繋がっていました。 WEARの大部分はすでにCloudFrontを使用しており、2つのCDNそれぞれでキャッチアップが必要だった AWSとFastlyそれぞれでユーザーやリソースの管理も必要だった 設定変更をWebチームとSREチームで担っていたため、Fastly専用のインフラリポジトリを別途設けており、CIの整備やレビューフローの維持など、リポジトリが増えることに伴う管理コストが発生していた コスト FastlyをAWSの前段に置く構成であるため、大きく分けて2種類のコストが発生していました。 Fastlyがユーザーへ配信するコスト AWSがFastlyへ配信するコスト また、LPやアセットはすでにCloudFrontを使用していたため、FastlyとCloudFront両方のCDNコストが発生していた点も見過ごせません。 これらの課題を解消するために、CDNをCloudFrontへ移行し、配信基盤をAWSへ統一する方針を取りました。 移行後の構成 移行後の構成は以下の通りです。 移行後は、ALB・S3など全てのバックエンドの前段に1つのCloudFrontを配置しています。 また、FastlyのVCLで実施していた処理はそれぞれ対応するAWSサービスへ移行しました。 処理 Fastly AWS CDN・配信 Fastly CDN CloudFront パスごとのオリジン振り分け VCL CloudFront(Cache Behavior) 各種ブロック(IP / ASN / リファラ など) VCL AWS WAF Basic認証 VCL AWS WAF メンテナンスモード VCL AWS WAF リダイレクト / リライト VCL CloudFront Functions Basic認証・メンテナンスモードはAWS WAF(以下、WAF)のカスタムレスポンス機能を利用して実装しています。WAFのルールにマッチしたリクエストに対して、任意のHTTPステータスコード・レスポンスヘッダー・レスポンスボディを返せる機能です。 セキュリティ関連の処理をWAFに集約することで一元管理できることに加え、CloudFront Functionsのコードサイズや実行時間の制限2を避けられる点も採用の理由です。 リダイレクト・リライトの実装にあたり、Lambda@EdgeとCloudFront Functionsを比較検討しました。Lambda@Edgeは複雑な処理や長時間実行に向いている一方、今回のような軽量なリダイレクト・リライト処理にはCloudFront Functionsが適しています3。加えてスケール量・リクエスト料金の面でも有利なため採用しました。 さらに、リダイレクト・リライトはルール数が多いため、jsをビルドしminify化しながらCloudFront Functionsのコードサイズ制限を超過しないよう工夫しています。CloudFront KeyValueStoreを使用したサイズ圧縮も検討しましたが、フロントとインフラ間の依存関係の簡素化や認知負荷の低減を優先したかったからです。 これらの設計を経て、FastlyのVCLに分散していたエッジ処理をAWS WAFとCloudFront Functionsに集約し、CDNレイヤーの機能をすべてAWS上で完結させる構成になりました。 移行方法 今回のCDN切り替えはフェーズを分けて段階的に実施しました。このCDNはPC・SP全体のトラフィックを受けているため、問題が発生すれば多くのユーザーへ影響が出てしまいます。そのため、いかにユーザー影響を出さず安全に移行するかが本プロジェクトの鍵でした。 具体的なフェーズは以下の通りです。Fastlyの後段にCloudFrontを配置し、影響範囲が小さいものから順にCloudFront経由へ切り替えていきました。 1. LP・アセットの切り替え 最初はS3で配信しているLPとアセットの切り替えです。静的コンテンツは影響範囲が限定的で切り戻しもしやすいため、最初の移行対象としました。 切り替えにあたっては全パスを網羅するURLリストを用意してスクリプトで動作確認を行い、移行前後の挙動に差異がないことを確認しながら実施しました。 2. 動的コンテンツ・認証処理の切り替え 次に動的コンテンツの配信や認証処理を担うALBの切り替えです。動的コンテンツの配信や認証処理を担っているため、CDN切り替えによるヘッダーやキャッシュの挙動の変化が配信や認証に影響を与えるリスクがありました。 影響範囲を抑えるためにALBは1台ずつ切り替え、バックエンドチームにも協力してもらい機能リグレッションがないことを確認しながら進めました。 加えて、ダークカナリアリリース(ユーザーには見えない形で一部のトラフィックを新しい構成に流し、本番環境で検証する手法)でCloudFront経由に流し、環境差異による不具合がないかも検証しました。 3. VCLの処理をCloudFront Functionsへ移行 続いてVCLのリダイレクト・リライト処理を移行しました。VCLの処理の中にはリクエスト元の国別判定をした上でリダイレクトをする処理もあり、障害につながりやすい部分であったため、切り戻しやすさを考慮して2段階に分けて対応しました。 動作確認はFastlyで実施していたリダイレクト・リライト処理を網羅的に検証できるスクリプトをWebチームが作成してくれており、そちらを活用し移行前後の挙動に差異がないことを確認しながら進めました。 スクリプトはDenoのテストフレームワークで書かれており、各パスへのリクエストに対してステータスコード・リダイレクト先・レスポンスヘッダーを検証します。さらにHTMLレスポンス内のJS・CSSアセットも正常に取得できるかまで確認しており、移行後の挙動を一通りカバーしています。 また、VCLの移行はオリジンの切り替えと異なり、パスごとに挙動が細かく異なります。そのため追加のスクリプトも作成し、リダイレクト・リライト対象外のパスへの影響がないか、Serverヘッダーでオリジンが意図した経路を通っているかを、1パスずつ地道に確認していきました。 4. DNS切り替え 最後にDNSを切り替えてFastlyからCloudFrontへ完全移行しました。 WEARはDNSにAkamaiを使用しています。今回、AkamaiのChange Listを活用し、ダウンタイムなしで切り替えを実現しました。 CloudFrontのIPアドレスは固定されていないため、FastlyのIPを登録していたAレコードからCloudFrontのドメインを指定するCNAMEへの変更が必要でした。しかしAレコードとCNAMEは共存できないため、削除と追加を別々に適用すると瞬断のリスクがありました。Change ListはDNSレコードの変更をまとめてアトミックに適用できる機能で、これを活用することでダウンタイムなしでの切り替えを可能にしています。切り替えは有事の際に素早く切り戻せるよう、事前にTTLを60秒に下げた上で実施しました。 また、次のセクションで詳しく説明しますが、ブロックやBasic認証等のWAF切り替えもこのタイミングで同時に実施しています。 WAFの移行タイミング WAFはIP・国・ASNなどの判定を、送信元IPまたはX-Forwarded-For(XFF)ヘッダーのIPアドレスを基に行います。 DNS切り替え前はFastlyがリクエストを受け取るため、AWS WAFから見るとアクセス元のIPがFastlyのIPになります。この状態でWAFを先に切り替えると、ブロックルールがFastlyのIPに対して適用され、意図しないブロックや、本来ブロックすべきリクエストが通過してしまうリスクがありました。 XFFを参照することでクライアントIPに基づく判定も可能ですが、以下の理由から採用しませんでした。 Fastlyの判定ロジックが送信元IPを利用しており、仕様を変えたくなかった DNS切り替え前後でXFFの内容が変わるため、切り替えのタイミングで挙動が変わることを避けたかった そのため、DNS切り替えまでの間はFastly側のブロック設定を残し、WAFの切り替えはDNS切り替えと同時に行いました。 なお、事前の動作確認はCloudFrontのFQDNに直接curlでアクセスして行いました。DNS切り替え前はFastlyがエンドポイントのため、CloudFrontのFQDNに対してアクセスする必要があります。CloudFrontはHTTPS接続時にHostヘッダーの値でSSL証明書を選択するため、Hostヘッダーにドメインを指定することで正しく証明書検証が行えます。 CloudFront FunctionsについてもDNS切り替え前はリクエストがFastlyを経由するため、リクエスト元の国別判定で同様の問題がありました。 こちらはWebチームが解決策を検討・実装してくれました。DNS切り替え前の移行期間中に限り、Fastly側でCloudFrontの仕様に準ずるヘッダーを付与しました。CloudFront Functions側でもそのヘッダーを参照することで、正しく地域判定が行える構成にしています。 設計のポイント ここまで移行の手順を紹介しました。次に、移行にあたって設計上特に考慮が必要だったCloudFrontのビヘイビア設計について紹介します。 CloudFrontでは、リクエストのURIパターンに応じて処理方法を定義
はじめに こんにちは、SREブロックの岩切です。普段はZOZOTOWN Yahoo!店の連携基盤のリプレイスを担当しています。 ZOZOTOWN Yahoo!店では、FTPによるデータ連携の遅延をSplunkアラートで検知し、PagerDutyにインシデントを作成して運用しています。しかし、遅延が解消してもインシデントは自動でResolveされず、手動で対応する必要がありました。 Splunk × PagerDutyの運用では、「アラートは自動だがResolveは手動」という課題に悩まされがちです。本記事では、追加のミドルウェアなしでインシデントを自動Resolveする実装パターンを紹介します。 目次 はじめに 目次 この記事で得られる知見 背景・課題 自動Resolveの要件整理 解決策の検討 アプローチ1:Splunk Add-onのparam.dedup_keyを使う アプローチ2:Events API v2統合を使う アプローチ3:Event Transformer統合 + Service Event Orchestration(採用) 全体のアーキテクチャ インシデント作成(遅延発生時) インシデント自動Resolve(遅延解消時) 設定の詳細 Splunk側の設定 トリガーアラート(既存設定の変更) 解消アラート(新規作成) PagerDuty側の設定 Event Transformer統合(新規作成) Service Event Orchestration 動作シナリオ 正常時(遅延なし) 遅延発生から解消までの流れ まとめ この記事で得られる知見 Splunk Add-on for PagerDutyの制約と、その回避方法 PagerDutyのdedup_keyを活用したインシデントのライフサイクル管理 「検索結果が0件のときだけアラートを発火する」SPLテクニック 背景・課題 ZOZOTOWN Yahoo!店では、商品情報などのデータをFTPで連携しています。FTPによるデータ反映が一定時間遅れると、Splunkのアラートが発火し、PagerDutyのインシデントが作成されます。 しかし、遅延が解消してもインシデントは自動Resolveされず、毎回オンコール担当者が手動でResolveしていました。この手動対応が繰り返され、運用上の負担になっていました。 手動Resolveの課題は以下のとおりです。 対応コスト:遅延解消を確認し、PagerDutyを開いてResolveする作業が都度発生する Resolve忘れのリスク:インシデントが残り続けると、新たなアラートとの区別がつきにくくなる オンコール負荷:深夜・休日に遅延が解消しても、Resolveのためだけに対応が必要になる場合がある 自動Resolveの要件整理 PagerDutyのインシデントを自動Resolveするには、以下の2つを満たす必要があります。 インシデント作成時と同じdedup_keyでresolveイベントを送ること イベントのevent_actionがresolveであること dedup_keyとは、PagerDutyがイベントをインシデントに紐づけるための一意キーです。同じdedup_keyを持つイベントは同一インシデントとして扱われ、重複排除やResolveの対象になります。 要件自体はシンプルに見えますが、Splunk Add-on for PagerDutyにはresolveイベントを直接送信する機能がありません。そのため、Splunk側とPagerDuty側の両方に工夫が必要でした。 解決策の検討 最終的な設計に至るまで、いくつかのアプローチを検討・検証しました。 各アプローチの説明へ入る前に、本記事で登場するPagerDutyの主要な概念を整理します。 Event Transformer統合:Splunkなどの外部ツールからイベントを受け取り、PagerDuty形式に変換する統合タイプ。incident_keyの設定により、受信したイベントのどのフィールドをdedup_keyとして使うかを決定する Service Event Orchestration:サービスに届いたイベントをルールベースで加工する機能。条件に応じてevent_actionの変更、優先度の設定などが可能 アプローチ1:Splunk Add-onのparam.dedup_keyを使う Splunk Add-onのparam.dedup_keyパラメータでdedup_keyを明示的に指定する方法です。しかし、Event Transformer統合はincident_key設定に基づいてdedup_keyを自動生成するため、Splunk側のparam.dedup_keyは無視されます。この方法では意図したdedup_keyを指定できず、採用を見送りました。 アプローチ2:Events API v2統合を使う Events API v2統合であれば、ペイロードのdedup_keyをそのまま使えます。しかし、Splunk Add-onはSplunk固有のペイロード形式で送信するため、Events API v2統合ではペイロードを解釈できず、インシデントが作成されませんでした。 アプローチ3:Event Transformer統合 + Service Event Orchestration(採用) 新しいEvent Transformer統合を作成し、incident_key=sourceに設定します。SPLにeval source="yshp-ftp-delay-warning"を追加することで、トリガーと解消で同じdedup_keyを生成します。そのうえで、Service Event Orchestrationでresolveに変換します。 検討した3つのアプローチの比較 全体のアーキテクチャ 自動Resolveの仕組みは、インシデント作成とインシデント自動Resolveの2つのフローで構成されます。設計のポイントは以下の2点です。 dedup_keyをSPL側で強制的に統一する:eval source="yshp-ftp-delay-warning"でトリガーと解消に同じ値を付与 resolveはPagerDuty側で変換する:Splunkからはtriggerとして送り、Orchestrationでresolveに変換 自動Resolveの全体アーキテクチャ インシデント作成(遅延発生時) Splunk:「Yahoo!FTPデータ反映遅延警告」アラートが遅延ファイルを検出して発火 SPL:末尾のeval source="yshp-ftp-delay-warning"により結果にsourceフィールドを付与 Event Transformer:incident_key=sourceの設定によりdedup_key="yshp-ftp-delay-warning"を生成 Service Event Orchestration:event.summaryに「解消」を含まないため、そのまま通過(trigger)。なお、Splunkのsearch_name(アラート名)はPagerDutyではevent.summaryとして受信される 結果:インシデント作成(同一dedup_keyなら重複排除) インシデント自動Resolve(遅延解消時) Splunk:「Yahoo!FTP遅延解消チェック」アラートが遅延ファイル0件を検出して発火 SPL:| stats count | where count = 0 | eval source="yshp-ftp-delay-warning"で遅延ファイルが0件のときだけ結果を返す Event Transformer:dedup_key="yshp-ftp-delay-warning"(トリガーと同一キー) Service Event Orchestration:event.summaryに「解消」を含むため、event_actionをresolveに変換 結果:同一dedup_keyのインシデントを自動Resolve 以上の仕組みで解決した技術的課題をまとめます。 課題 解決方法 Splunk Add-onはresolveを送れない Service Event Orchestrationでtrigger→resolveに変換 trigger/resolveのインシデント紐づけ SPLにeval source="yshp-ftp-delay-warning"を追加し、Event Transformerのincident_key=sourceで同一dedup_keyを生成 解消イベントの識別 event.summaryに「解消」を含めてOrchestrationルールで判別 既存統合のincident_key=search_nameではdedup_key不一致 FTP遅延専用のEvent Transformer統合を新規作成しincident_key=sourceに設定 設定の詳細 Splunk側の設定 トリガーアラート(既存設定の変更) 「Yahoo!FTPデータ反映遅延警告」アラートに以下の変更を加えました。 integration_key/urlを新しいEvent Transformer統合に変更 SPL末尾に| eval source="yshp-ftp-delay-warning"を追加 発火条件・スケジュールは変更なし 解消アラート(新規作成) 「Yahoo!FTP遅延解消チェック」アラートを新規作成しました。 解消アラートの設定画面 設定項目 値 備考 SPLクエリ トリガーと同一ベース + | stats count | where count = 0 | eval source="yshp-ftp-delay-warning" 遅延ファイル0件のときのみ結果を返す counttype number of events <td style="text-align:l