1. HOME
  2. ブログ
  3. 開発ノート
  4. マイクロサービス環境でのCI/CD構築開発ノート:Kubernetes導入から自動化パイプラインまで
BLOG

ブログ

開発ノート

マイクロサービス環境でのCI/CD構築開発ノート:Kubernetes導入から自動化パイプラインまで

背景とプロジェクト起動の経緯

私は大手製造業の社内SEチームに所属し、これまで社内向け業務システムはモノリシックなJava Spring Bootアプリで運用してきました。しかし、ビジネス拡大に伴い、複数の機能を独立サービスとしてスケールさせる必要性が生じ、マイクロサービス化を検討することになりました。そこで「システムの可用性向上」「開発スピードの向上」「障害時の影響範囲を限定したい」という3つの要件を掲げ、開発会社と協力してプロジェクトを立ち上げました。

当初、開発会社選びでは「Kubernetes導入実績」「CI/CD構築の経験」「予算感に合う見積」をポイントに複数社から相見積もりを取得しました。見積内容には、Kubernetesクラスタ構築、Dockerイメージ化、CI/CDパイプライン設定、E2Eテスト自動化、監視システム(Prometheus+Grafana)導入などが含まれ、総予算は約1,500万円(相場よりやや高め)となりました。予算内に収めるため、要件を優先順位で整理し、初回リリース時はユーザーモジュールと注文管理モジュールのみをマイクロサービス化するフェーズ1に集中することに決定しました。

発注前に行った準備として、まず現行モノリスアプリの業務フローをフローチャート化し、サービス分割案を策定。たとえば「商品カタログ」「在庫管理」「注文履歴」「ユーザー認証」の4つのドメインを想定し、初回はユーザー認証と注文履歴を分離することが最適と判断しました。そのうえで、発注書には「各サービスはDockerでコンテナ化し、Kubernetes上にデプロイ」「CI/CDはGitHub Actionsを利用」「ステージングと本番環境は別クラスタ」「予算内でインフラ利用料を抑える」といった具体的な要件を明記。開発会社は要件を受けて工数を算出し、私たちも相場感を把握したうえで工数×単価(1工数=30,000円)を確認し、発注を行いました。

初期Kubernetesクラスタ構築と苦戦ポイント

プロジェクト開始から最初の1か月は、Kubernetesクラスタ構築と開発環境自動化に集中しました。開発会社はAWS EKSを選び、インフラ構築から始めましたが、ここでいくつかの苦戦ポイントが発生しました。

  1. ネットワークポリシー設定の複雑さ
    最初にEKSを起動した際、各ポッド間の通信がデフォルトで許可される状態だったため、本来業務ドメインごとに限定したいサービス間通信がすべて可能となり、セキュリティ要件から外れていました。ネットワークポリシー設定に慣れていたエンジニアが少なく、開発会社のエンジニアが公式ドキュメントを読み解きながらcalicoプラグインを導入し、通信フィルタルールを定義。結果的に、**「注文履歴サービスはDBアクセスのみ許可」「ユーザー認証サービスは外部APIのみ許可」**といった細かいポリシーを適用できるようになりました。ただし、この対応には見積外の追加工数(約20工数、60万円相当)が発生し、開発会社との交渉で予算の一部を内部調整でまかなう形としました。

  2. 開発環境のローカル再現性
    本番環境ではEKSを使用しますが、ローカル開発はDocker DesktopのKubernetesを使っていました。ここで問題となったのが、**「本番EKSとDocker Desktopの挙動差異」**です。Ingressの動作、ストレージクラスの違い、LBプロビジョニングの手順などで動作が一致せず、開発環境で動いたコードがステージングでエラーになる事態が頻発しました。開発会社と協力し、Helmチャートのテンプレート化を進めてローカル・ステージング・本番で同じマニフェストを利用するアプローチを採用。これにより、Kustomizeを活用した環境別パラメータ差分管理を実現し、動作差異を最小限に抑えることができました。結果として切り替えテストの工数を当初計画より約30%削減でき、予算超過を防ぎつつ納期を守る形となりました。

  3. モニタリング基盤の要件定義不足
    初期要件では「PrometheusとGrafanaで監視基盤を構築する」と記載していましたが、どのメトリクスを取得し、閾値をどう設定するかが曖昧でした。そのため、開発会社がPrometheus Operatorを導入した後に、「CPU使用率が80%を超えたらアラート」「ポッド再起動回数が1日5回を超えたらアラート」というルールを設定する必要がありました。ここで私たちの社内SEチームから「要件定義が不十分だと保守運用で混乱する」とクレームが入り、再度要件を擦り合わせ。結果的に、**「各マイクロサービスごとにビジネスマトリクスを整理する」**という追加タスクを設け、注文履歴サービスであれば「1時間あたりの注文数」「DBクエリタイム」「エラーレート」などを定義したうえで、PrometheusにExporterを実装して取得。Grafanaダッシュボードをまとめる工数(約15工数、45万円相当)を追加発注し、結果的にSLI/SLOに基づいたアラート設計が完成しました。これにより障害時の初動対応が迅速化し、障害発生時のダウンタイムを平均30分→5分に短縮できました。

CI/CDパイプライン構築のトライアンドエラー

次に重点を置いたのが、CI/CDパイプライン構築です。モノリス時代は手動デプロイと手動テストが混在しており、安定リリースに時間がかかっていました。マイクロサービス化後は、GitOpsを取り入れ、コード変更から本番反映まで自動化を目指しました。以下に主な改善点と学びをまとめます。

  1. パイプライン全体の設計不足によるイテレーション遅延
    当初、CIパイプラインを「テスト→ビルド→デプロイ」の3ステージで組みましたが、ステージング環境へデプロイしたあとに手動で動作確認を挟むワークフローだったため、本番反映までに平均2日かかるボトルネックが残っていました。開発会社と再度設計を見直し、E2Eテスト→ステージング自動デプロイ→自動承認条件→本番デプロイというフローに変更。

    • E2Eテスト自動化:Cypressを採用し、GitHub Actions上でヘッドレスブラウザテストを実行。テストパラメータや環境変数はGitHub Secretsで管理し、成功時のみ次のステージに進むよう設定。

    • 自動承認条件:ステージング環境でのエンドツーエンドテストがすべて通過し、かつステージングDBのスキーマ変更がない場合に限り、GitHub ActionsのApprovalステップをスキップ。これにより、コードマージから本番リリースまでのリードタイムを平均2日→4時間に短縮しました。
      この改善で追加発注工数は約25工数(75万円相当)でしたが、開発会社選びでは「CI/CD構築実績」「テスト自動化のノウハウ」を重視するとスムーズに進みます。

  2. マルチマイクロサービス間の依存関係とDev環境の同期問題
    各マイクロサービスは独立して動作しますが、依存関係を持つケースがあり、ユーザー認証サービスがないと注文管理サービスが動かないといった問題が発生しました。当初、GitHub Actionsではそれぞれのサービスを個別にビルド・テストしていましたが、依存サービスのMockサーバーやテスト用DBを起動する必要があったため、ローカル開発とCI環境で挙動差異が発生しました。
    そこで、以下のアプローチを採用しました。

    • テスト用コンテナオーケストレーション:GitHub Actions Runner上でDocker Composeを利用し、依存マイクロサービスのMockイメージとテスト用PostgreSQLを同時に起動。各サービスのコンテナはDockerネットワークで接続し、統合テストを実施。

    • テストDBスキーマのバージョン管理:Flywayを導入し、マイグレーションスクリプトをGit管理。CIパイプラインでFlywayが自動実行されるため、DBスキーマの不整合によるテスト失敗を防ぎました。
      この対応により、ローカル開発環境とCI環境での不整合が解消され、毎回のビルドエラーを50%以上削減できました。開発会社との見積交渉では「Docker Compose設定工数:15工数(45万円)」「Flyway導入工数:10工数(30万円)」と明示し、発注しました。

  3. セキュリティスキャン統合と脆弱性対応
    CIパイプラインにおいて見落としがちなポイントとして、ソースコードの脆弱性や依存ライブラリの脆弱性があります。特にKubernetes環境では、イメージの脆弱性があると本番環境に致命的な問題を引き起こすため、スキャン自動化が必須です。
    初期パイプラインではテストとビルドのみだったため、開発会社と協議して以下を追加しました。

    • Rust側のCargo Audit:Rustプロジェクトにおいて、cargo auditコマンドをCIパイプラインに組み込み、依存クレートの脆弱性を検出。自動的にGitHub Actions上で脆弱性レポートを生成し、SQレベルの警告発生時はブロックする仕組みにしました。

    • Dockerイメージスキャン:GitHub ActionsのステップでTrivyを用い、ビルドしたDockerイメージをスキャン。脆弱性が高リスク(Critical/High)と判定された場合はCIを失敗させ、開発者にアラートを返却します。

    • Kubernetesマニフェスト検証kube-linterを用いてマニフェストのセキュリティルール(例:runAsNonRoot設定、readOnlyRootFilesystem指定など)を自動チェックし、ベストプラクティスに沿ったリソース定義を担保。
      これらのスキャン統合は追加工数(約20工数、60万円)でしたが、**開発会社選びでは「セキュリティ対応実績」「脆弱性診断の自動化ツール導入経験」**を要件にしておくと、リスクを大幅に低減できます。

リリース後の運用保守と継続的改善

CI/CDを本番環境へ適用後も、開発ノートとして留意すべき点が多数あります。ここでは、運用保守フェーズにおける具体的な教訓とノウハウを共有します。

  1. ローリングアップデートの失敗とロールバック対策
    初回リリース時、Actuator健康チェックを設定せずにEKSでローリングアップデートを行ったため、新バージョンのコンテナが正常化前にトラフィックを受け、ステージングで想定外のエラーが発生しました。結果として、本番環境で一時的にサービス停止が生じ、影響範囲は約1時間に及びました。
    この失敗を受け、次の対策を実施しました。

    • Readiness/Liveness Probe設定:各サービスに対して/healthエンドポイントを設置し、起動後に一定時間アイドル状態を監視してからトラフィックを流す設定を追加。これにより、稼働前のコンテナがトラフィックを受けるリスクを排除できました。

    • 自動ロールバック設定:EKSのデプロイ設定で、ヘルスチェックエラーが一定回数発生した場合、自動で旧バージョンへロールバックする機能を有効化。これにより、新リリースが不安定な状態では自動的に復旧し、ダウンタイムを最小化できるようになりました。
      これらの対応は開発会社との追加契約(約15工数、45万円)で実施し、結果として本番リリース時のダウンタイムを3カ月で0件にまで減少させ、運用コストを抑制しました。

  2. 可観測性向上の継続的取り組み
    リリース後、Prometheus/Grafanaだけではビジネス指標が見えにくいため、APM(Application Performance Monitoring)ツールとしてDatadogを導入し、エンドツーエンドのトレースを可視化することにしました。以下の点が学びとなりました。

    • トレースタグの設計:注文フローの各ステップ(リクエスト受信、DBクエリ、ビジネスロジック、レスポンス返却)に一意のトレースIDを付与し、Datadog APMで可視化。結果、特定APIのレスポンスタイムが突発的に増加する原因がキャッシュ無効化のタイミングであることを発見し、キャッシュTTLを調整して平均レスポンスタイムを200ms→50msに改善しました。

    • ログ構造の統一化:各マイクロサービスから出力されるログがバラバラだったため、ELKスタックを使ってJSON形式の構造化ログに統一。フィールドは「request_id」「service_name」「log_level」「timestamp」「message」とし、クエリ時に特定リクエストの関連ログを追跡しやすくしました。

    • アラートプレイブックの作成:障害発生時の初動手順をドキュメント化し、シナリオ別にチームメンバーへアラートを送るSlack連携を設定。たとえば「DB遅延時にはデータベースチームに通知」「APIエラー発生時は開発チームに通知」といったフローを自動化し、障害対応スピードを従来の平均1時間→平均10分に短縮しました。

  3. コスト最適化と予算レビュー
    運用開始から半年が経過した時点で、当初想定以上にAWSリソース利用料が増加していることが判明しました。特にEKSで使用するノード数やRDSのスケール設定が運用開始時のまま据え置かれていたため、不要なリソースが垂れ流されている状態でした。以下を実行してコスト削減を図りました。

    • ノードグループの最適化:EKSではマイクロサービスごとのPod数を調査し、オートスケーリングポリシーを見直して最小ノード数を1ノードから0ノードに変更。これにより、夜間や週末の利用が少ない時間帯にはノードをスケールインし、月額コストを約20%削減できました。

    • RDSインスタンスのリサイズ:ステージング環境でRDSのdb.t3.mediumインスタンスを使っていましたが、本番運用データは中程度の負荷だったため、db.t3.smallへリサイズ。ダウンタイムなしでリサイズを行い、月額費用を約5,000円削減しました。

    • S3データライフサイクル設定:ログやバックアップを保存するS3バケットで、90日以上経過したアーカイブをGlacier階層に移行するライフサイクルルールを設定。これにより、ストレージ費用を約30%削減しました。
      開発会社との保守契約時に「月次コストレビュー」「コスト最適化提案」をオプションとして盛り込んでおいたため、コスト削減策をスムーズに実施できました。

テスト戦略:ユニットテストからE2Eテストまで

マイクロサービス環境では、テスト戦略の策定が欠かせません。単体テスト、統合テスト、E2Eテストの三層構造をどのように組み合わせるかは、開発会社やチームによってばらつきがあります。私たちが辿った流れと学びを紹介します。

  1. ユニットテスト(各サービス内ロジック検証)
    Rustのテスト機能を使い、ビルドインテストフレームワークでビジネスロジックを検証します。たとえば、注文管理サービスでは「在庫引き当てロジック」「価格計算ロジック」などをモジュール単位でテストし、コードカバレッジを70%以上に維持。これにより、変更時に細かなバグを検出しやすくなるというメリットがありますが、テスト作成の工数(相場:サービスあたり20~30工数、40万円~60万円)がかかるため、予算を取る前に優先度を検討し、重要なビジネスロジックからコストをかけるようにしました。

  2. 統合テスト(サービス間連携検証)
    マイクロサービスの間でREST APIやgRPC通信が正しく動作するかを検証する統合テストでは、テスト用Docker Composeを使って依存サービスを一時起動。特定のユースケース(例:注文作成→在庫減算→請求レコード登録)が正常に完了するかを確認します。
    ここで失敗したポイントとして、テストDBと本番DBのマイグレーションツールのミスマッチがあり、スキーマ変更が同期されずにテストが落ちることがありました。対策として、統合テスト用のテストDBは自動マイグレーションを実行したうえで開始し、DBスキーマの不整合を防止しました。この対応は追加で10工数(30万円)かかりましたが、テストの安定性と信頼性が向上しました。

  3. E2Eテスト(ユーザー視点での機能検証)
    最もコストがかかるのがE2Eテストであり、Cypressを使ったブラウザテストPostmanを使ったAPIチェーンテストを組み合わせました。特に、注文フローでは「ユーザー登録→ログイン→商品検索→注文→決済」が正しく動作するかを検証します。
    ここで苦戦したのが「非同期処理によるテストタイミングずれ」です。注文後に在庫更新が非同期で行われるため、Cypressで次のアサーションを行う前に、適切に待機時間を挟む必要がありました。結果として、E2Eテスト全体を約5分以内に終わらせるために、cy.wait()を使わずに、特定DOMが表示されるまでcy.get().should('exist')を使う形に変更。これにより、テストの再現性が向上し、テスト実行コストを約30%削減できました。

  4. テスト自動化インフラの維持管理
    CI/CDでテストを実行する際、テスト環境構築に時間がかかるとパイプライン全体が遅延します。そこで、GitHub Actionsのキャッシュ機能を活用して、依存関係のダウンロード時間を短縮。また、Dockerイメージを予めビルドしておき、テスト実行時に再利用することで、テストリソースの使用量を最適化しました。
    これによって、1回のテスト実行に要する時間を30分→10分に短縮。開発会社や社内SEチームから「テスト待ちによる開発遅延がなくなった」「ビルドリソースの無駄遣いが減った」と好評でした。

コミュニケーションとベンダーマネジメントの工夫

いくら技術要件やテスト戦略をしっかり策定しても、開発会社(ベンダー)とのコミュニケーション不足により、想定外の追加費用や納期遅延が発生するケースが少なくありません。私たちが実践して効果があったマネジメント手法を共有します。

  1. デイリースタンドアップの徹底
    リモート中心の開発体制では、各サービスの進捗や障害、翌日の予定を毎朝15分程度のスタンドアップミーティングで共有。Zoomで開発会社のエンジニアも参加することで、タスクの見える化と情報共有を高速化し、要件のズレを早期に発見できました。また、タスク管理ツール(Jira)でストーリーポイントを設定し、バーンダウンチャートを毎週レビューすることで、工数遅れやリスクを事前に把握し、次週のリソース配分を調整しました。

  2. 要件凍結と変更管理ルール
    当初、要件定義書には「マイクロサービスごとのAPI契約書」「DBスキーマ設計書」「CI/CDパイプライン設計書」などを明記しましたが、その後「UX要件追加」「UIデザイン差し替え」などが頻発し、追加工数が膨らみました。これを防ぐために、**「要件凍結後の変更はTシャツサイズ(S/M/L)の見積もりを都度取得し、事前承認を得る」**ルールを制定。結果的に、追加要件発生時の工数予測精度が向上し、開発会社との予算交渉もスムーズになりました。

  3. 週次レビューとステークホルダー参加
    週次レビューでは、各マイクロサービスのデモを行い、ステークホルダー(事業部長やプロダクトオーナー)に進捗を確認してもらいました。特にビジネスロジックが正しく実装されているかを、実データを使って検証することで、要件理解の齟齬を早期に解消できました。これにより、修正フェーズでの手戻り工数を約40%削減することができ、予算内で開発を完了できました。

  4. 小規模リリースとフィードバックループの短縮
    当初は「1か月に1回まとめて大きくリリースする」計画でしたが、テスト環境と本番環境で問題が顕在化し、リリース作業に半日以上かかる状態でした。そこで、**「1週間に一度、小さな機能単位でリリースする」**アジャイル型リリースに切り替え。これにより、リリース時の障害発生リスクが低減し、必要に応じて素早くロールバックが可能になりました。

以上のコミュニケーションとベンダーマネジメントにより、開発遅延による追加費用発生を最小限に抑え、予算超過を防止できたことが最大の学びでした。

振り返りと今後の展望

本記事では、モノリシックからマイクロサービスへの移行プロジェクトにおけるKubernetes導入、CI/CD構築、テスト自動化、運用保守、コミュニケーションまでを一貫して開発ノートとしてまとめました。ここまでの振り返りポイントは以下の通りです。

  • 事前準備と要件定義の重要性

    • ドメイン分割案を策定し、Kubernetesクラスタ構築やCI/CDパイプラインなどの要件を明確化。これにより、発注時に優先順位をつけて開発会社と合意できた。

  • 追加工数と予算管理のバランス

    • ネットワークポリシー設定やモニタリング設計など、見積当初に想定していなかったタスクが発生したが、要件凍結ルールでコストをコントロール可能だった。

  • CI/CDパイプラインの自動化でリードタイム短縮

    • E2Eテスト自動化や統合テスト環境の整備で、本番リリースまでのリードタイムを大幅に短縮。開発スピード向上と品質担保を両立できた。

  • 運用保守とコスト最適化の継続的取り組み

    • オートスケーリング設定、バックアップライフサイクル設定、ログ集約などでランニングコストを約30%削減。

  • コミュニケーションによる顧客満足度向上

    • デイリースタンドアップや週次レビュー、小規模リリースなどの取り組みにより、ステークホルダーの信頼を獲得し、開発会社との関係性も強化できた。

今後は、サービスメッシュ(IstioやLinkerd)の導入検討や、GitOpsのさらなる推進サービス間コネクションのセキュリティ強化(mTLSなど)を検討しています。これにより、マイクロサービス間のトラフィック管理を強化し、運用自動化をさらに進化させる予定です。また、コスト最適化フレームワークを内製化し、クラウド請求書を自動で解析・レポーティングする仕組み(FinOps)も取り入れていきます。

これらの取り組みを通じて、開発会社選びや発注のノウハウ、予算管理の方法論を社内に蓄積し、次のプロジェクトでさらなるコスト削減と開発スピード向上を実現することを目指します。

新機能フェーズにおけるトラブルと改善策

前半ではマイクロサービスの構築からCI/CD自動化、運用保守までを解説しましたが、プロジェクトは常に一度リリースして終わりではありません。今回は、新機能追加フェーズで発生した具体的なトラブルと、その改善策を詳細にお伝えします。

開発会社との契約では「第2フェーズ以降は追加要件として都度見積もり」としていましたが、第2フェーズの初期において、以下の2つの機能追加が決まりました。

  1. リアルタイム在庫同期(サードパーティ倉庫システム連携)

  2. ユーザー行動解析ダッシュボード(BigQuery連携とカスタムメトリクス表示)

リアルタイム在庫同期機能の導入失敗例

先行して「リアルタイム在庫同期」を追加し、サードパーティ倉庫システムとKubernetes上の在庫管理マイクロサービスを連携する要件が発生しました。要件は以下のとおりです。

  • 倉庫から在庫変動のWebhook通知を受信し、Kubernetesクラスタ内の在庫管理サービスのRedisキャッシュを更新

  • 更新されたキャッシュ情報を基に注文受付システムで即時在庫チェックを行う

  • 万が一API連携に失敗した場合は、ローグバック用のキューにイベントを格納し、後続ジョブでリトライ

しかし、実装開始直後に以下の問題が頻発しました。

  1. Webhook受信エンドポイントのスケーリング不足
    開発会社が用意したIngressルールでは、コンテナにヘルスチェックを設定せず、最小レプリカ数を1としたままWebhook大量発行テストを行った結果、ポッドがスケールアウトするまでにタイムアウトが発生。これにより、ハンドシェイクがきれたWebhookが多数発生し、サードパーティ倉庫から一時的にリクエストが弾かれる事態が発生しました。

    • 改善策:Horizontal Pod Autoscaler(HPA)を導入し、CPU/メモリの使用率が50%を超えたら自動スケールアウトするよう設定。さらに、IngressのreadinessProbe/healthzエンドポイントに紐づけ、PodがReady状態になるまでIngressでトラフィックを流さない仕組みを実装しました。これにより、突発的なWebhookピークでもスケールアウトによるパフォーマンス低下を防止できるようになりました。

  2. リトライキューの永続化設計不足
    当初、リトライ用にKubernetesのCronJobとRabbitMQを組み合わせて一時的に再送処理を行う設計にしましたが、RabbitMQがPodリスタート時にキューの永続化を行っていなかったため、Pod再起動でキュー内のデータがすべて消失しました。結果として、在庫同期漏れが発生し、注文受付で在庫切れエラーが多発。

    • 改善策:RabbitMQのPersistent Volume(PV)を利用し、キューデータを永続ボリュームに保存するよう設定しました。また、CronJobによるリトライではなく、KubernetesのJobを利用し、リトライ回数とバックオフ戦略を明示する方式に変更しました。これにより、Pod障害時でもキューの再送タスクが保持され、在庫同期に一貫性が担保されました。

これらのトラブルは、要件定義段階で「Webhook頻度」「リトライ時のデータ永続化要件」を正確に提示していなかったことが原因です。開発会社選びの際には、要件定義の曖昧さを防ぐために事前ヒアリングを徹底し、追加費用の発生を最小限に抑えることが重要です。

ユーザー行動解析ダッシュボードの導入成功例と学び

次に、ユーザー行動解析ダッシュボードの開発経緯と成功要因を共有します。こちらはビジネス要件として「プロダクト利用状況をリアルタイムに可視化し、マーケチームが施策効果を即時把握できる」ことが目的でした。要件は以下の通りです。

  • フロントエンドで発行されるユーザーイベントをKafkaに送信

  • KafkaからBigQueryへバッチ連携し、リアルタイムではなく1分ごとに集計テーブルを更新

  • GrafanaとBigQueryの連携で、ダッシュボード表示を実装

成功要因1:データパイプラインを小規模に始めた

初回見積もりでは「Fluentd+Kafka+BigQuery連携」の全構成で約30工数(約90万円)の追加工数が発生。そのうえで、運用保守コストとして月額1万~2万円相当の追加費用が必要でした。そこで開発会社と相談し、まずはKafkaをAzure Event Hubsに置き換えて構成を簡易化するアプローチを採用。

  • Event Hubsならマネージドサービスであり、SparkジョブやDatabricksを使わずとも、Azure Functionsで1分ごとにEvent HubsからBigQueryにデータをエクスポートする仕組みが用意されていました。

  • これにより、Kafkaクラスタの運用コストと工数をカット。Azure Event Hubs導入とAzure Functions設定で約15工数(45万円)の追加費用で済み、本番運用を早期にスタートできました。

成功要因2:クエリ最適化でコストを大幅削減

BigQueryはクエリ実行量に応じた従量課金制であり、イベント集計クエリを逐次実行するとコストが膨らみます。初回10万行程度のイベントデータでテストした際、1時間の集計クエリ実行で約1,000円の費用が発生しました。これを本番環境規模に合わせて月間試算すると約3万円に到達する見込みでした。

  • 改善策:BigQueryのマテリアライズドビューを活用し、リアルタイムの集計処理を定期的に差分更新する方式に変更。これにより、フルテーブルスキャンを回避し、クエリ実行コストを従来の10分の1以下に抑制できました。たとえば、マテリアライズドビューの更新にかかる費用は月間数千円程度で済むようになりました。

  • 開発会社には、**「クエリチューニング工数:5工数(15万円)」「マテビュー設定工数:3工数(9万円)」**として追加発注し、合計で約24万円の追加費用で大幅なコスト削減を実現しました。

これらの成功事例からわかるのは、初期要件での予算相場を過度に見積もらず、小さく始めてから調整・最適化フェーズを設けることの有効性です。ユーザー行動解析は運用開始後に追加要件が増える可能性がありますが、小規模な構成でローンチし、本番利用状況を見ながらスケールさせることで、無駄な費用をかけずに安定した開発が可能になります。

共通ミドルウェアのアップグレードと依存関係管理

マイクロサービスが複数に分散すると、**共通ミドルウェア(認証、ログ、トレーシング)**をどのようにバージョン管理し、定期的にアップデートするかが重要になります。本プロジェクトでは以下を実施しました。

  1. 認証ミドルウェアのバージョンアップによる互換性トラブル
    初期フェーズでは、OAuth 2.0トークン発行ライブラリとしてKeycloakを利用し、各マイクロサービスはKeycloakの公開鍵を使ってJWTトークンを検証していました。しかし、Keycloakがメジャーバージョンアップした際、トークン生成ロジックが変更され、JWTのalgヘッダーがRS256からES256に切り替わりました。その結果、既存の検証ロジックでトークン署名検証が失敗し、認証エラーが頻発

    • 改善策:Keycloakのメジャーバージョンアップを検証環境で先行テストし、JWT検証ライブラリ(jsonwebtoken)をアップデート。同時に、トークン検証ロジックをalgフィールドに依存しない方式に書き換え、アルゴリズムの変化に強い実装に変更しました。これにより、リリース時に発生するダウンタイムを最小限に抑え、トラブルシュートにかかるコスト(約20工数・60万円相当)を予算に組み込むことで、本番障害を回避できました。

  2. 分散トレーシングの統合とバージョン整合性
    各マイクロサービスではOpenTelemetryを利用してトレースを収集し、Jaegerに送信していましたが、バージョン間の仕様変更でExporterのメトリクス名やタグ構造が変わり、既存のGrafanaダッシュボードで表示できなくなったことがありました。

    • 改善策:OpenTelemetryのバージョンを一度にすべてアップデートするのではなく、マイクロサービス単位で段階的にバージョンを合わせるアプローチをとりました。具体的には、各サービスのOpenTelemetry SDKを0.17.xに統一し、Jaeger Collectorのバージョンを1.36以降へアップグレード。併せて、Grafanaのダッシュボードもクエリ定義を修正し、タグ名の変更に対応しました。

    • この対応には、**調査+アップグレード工数:合計12工数(36万円)**がかかりましたが、トレーシング情報の信頼性を維持しつつ、問題発生からの復旧を即時行える体制を構築できました。

技術調査とPOCによるリスク低減の重要性

前述したトークン検証問題やOpenTelemetryの仕様変更問題は、発注段階での技術調査不足が原因です。本プロジェクトでは、以下の技術調査とPOC(Proof of Concept)を一部前倒しで実施することで、リスクを低減できると学びました。

  1. MVP(Minimum Viable Product)開発と早期フィードバック
    初期開発時に、各マイクロサービスのコア機能(ユーザー認証、注文管理、在庫同期、行動解析)をMVPバージョンとして1~2週間で作成。具体的には、Keycloakトークン発行とJWT検証、Redisキャッシュ挿入、BigQuery連携バッチジョブを小規模に構築し、全体の構成感を把握しました。これにより、将来的に起きそうな技術的リスク(トークン仕様変更、BigQueryコスト増)を事前に理解し、POC段階で必要なライブラリバージョンやクエリ最適化方法を確立できました。

  2. ベンチマークテストによる性能検証
    発注前に「Kubernetesクラスタ上で実際にPodを2ノード稼働させ、リアルタイム在庫同期のWebhook負荷テストを実施」。1秒間に500件のWebhookイベントを3分間継続し、Podのスケーリング挙動と処理遅延を測定。これにより、**HPAのスケール閾値設定(CPU60%超でスケールアウト、CPU30%未満でスケールイン)**が適切であることを確認し、発注時の運用設計に組み込みました。

  3. セキュリティ脆弱性検査の事前実施
    アプリケーションのDockerイメージをTrivyとAnchore Engineを使って脆弱性スキャンし、ライブラリ依存に深刻なCVEがある場合は事前にバージョンアップやライブラリ代替を検討しました。これにより、**CIパイプラインへのスキャン実装工数(約8工数、24万円)**を発注前に算定でき、セキュリティリスクを事前に低減できました。

これらの技術調査とPOCを発注前に組み込むことで、プロジェクト全体で発注(見積)時に含む工数を明確にし、予期しないトラブルによるコスト増を防ぎつつ、予算内での開発を実現できます。

開発会社との継続的協業とナレッジ共有

本プロジェクトは、フェーズ1からフェーズ3まで通算で約1億円超の予算規模となりました。その中で最も重要だったのが、開発会社との継続的な協業社内ナレッジの蓄積です。以下に、具体的に実施した取り組みを紹介します。

  1. Wikiと技術ドキュメントの整備

    • Confluenceを用いて「マイクロサービス構成図」「API仕様」「Kubernetesマニフェスト」「CI/CDパイプライン設計」「各種Terraformコード」などを社内ナレッジとして体系化。

    • 特に予算管理シートを公開し、各フェーズでの見積内訳(工数×単価、インフラ費用、ライセンス費用など)を透明化。これにより、経営陣への説明が容易になり、追加費用発生時の承認プロセスがスムーズになりました。

  2. 技術共有勉強会の定期開催

    • 社内SEチームと開発会社の合同で、月1回の振り返り+技術勉強会をオンラインで実施。テーマは「Kubernetes最新動向」「OpenTelemetryの活用」「Terraformスタイルガイド」など多岐にわたりました。

    • この勉強会により、開発会社エンジニアと社内エンジニアのスキルギャップを埋め、次期フェーズでの要件定義や設計品質が向上。結果として、要件もれによる手戻り工数を20%削減できました。

  3. ガバナンス設計とレビュー体制

    • GitHubのプルリクエストレビュー体制を厳格化し、「最低2名の承認必須」「コードスタイルチェック(rustfmt、golangci-lintなど)の自動化」「テストカバレッジ基準(ユニットテスト70%以上)」をマージ条件に設定。

    • これにより、バグ混入が大幅に減少し、リリース後の障害発生率をリリース前の10分の1以下に抑えられました。また、**レビュー工数(相場:50~60工数、150万~180万円)**を健康的に確保することで、品質向上にかかるコストを予算内に収められました。

  4. ラーニングレコードとベストプラクティス集

    • プロジェクトで得られたノウハウをナレッジサイトとしてまとめ、「Kubernetesトラブルシューティングガイド」「CI/CDパイプラインのベストプラクティス」「開発会社選びチェックリスト」などをコンポーネント化して蓄積。

    • これを次期プロジェクトで再利用することで、要件定義と見積もりの精度が向上し、初期段階での工数評価ミスを80%軽減できました。

プロジェクト評価:成果と課題

最終フェーズのリリース後、プロジェクト全体を振り返った定量評価定性評価をまとめます。

定量評価

  • 開発スピード向上:マイクロサービス化前は新機能リリースまで平均3~4か月要していましたが、マイクロサービス化後は平均1~2か月に短縮。特に、ユーザー行動解析機能はリリースからリードタイム0.5か月で運用開始。

  • システム可用性:リリース前は月間ダウンタイム合計が30分程度発生していましたが、マイクロサービス化とローリングアップデートの導入により、月間ダウンタイム0件を3か月間継続。

  • コスト削減:初期導入時の予算は約1,500万円でしたが、運用開始から半年間でクラウド費用を30%削減(月額約30万円→約21万円相当)に成功。スケール最適化とバックアップポリシー変更による成果。

定性評価

  • 社内SEチームのスキル向上:開発会社との共同作業を通じて、KubernetesやCI/CD、Terraformの運用ノウハウを蓄積。現在では社内SEだけでEKS上の小規模サービスを立ち上げられるようになり、外注依存度を10%程度低減

  • 開発会社との信頼関係構築:要件定義時に発生した追加工数やコスト交渉を透明なコミュニケーションで乗り切り、その結果、途中での発注範囲変更や追加要件にも柔軟に対応してもらえるようになりました。

  • ステークホルダー満足度:ビジネス部門や経営陣からは「要件変更に対する開発体制の適応力」「コスト意識を持った工数管理」「迅速な障害対応」に高評価を得ており、プロジェクト満足度は90%以上との回答を得ています。

一方で、以下の課題も顕在化しました。

  • ドキュメント更新の遅延:リリースサイクルが短くなったことで、ドキュメント整備が追いつかず、新規参入チームメンバーへのナレッジ共有に課題あり。現在は、ドキュメントレビューをリリースチェックリストに追加し、リリース直前に必ず最新化される仕組みを構築中です。

  • テストカバレッジのばらつき:重要機能は70%以上のカバレッジを確保している一方で、非機能部分(例:管理者向けメニューや旧機能)はカバレッジが30~40%に留まっているため、次期フェーズでは非機能部分のテスト強化を計画中です。

  • コスト増加のリスク管理:運用開始から約1年が経過し、ログ量やイベント量が増加しているため、BigQueryやGrafanaのランニングコストが予想以上に増加するリスクがあります。これに対し、データライフサイクルを改善し、旧データはCold Storageへアーカイブする方針を今後実施予定です。

次期フェーズへの提言と展望

本プロジェクトの教訓を踏まえ、次期フェーズで検討すべきポイントを以下に整理します。

  1. サービスメッシュ導入によるトラフィック管理
    現状は各マイクロサービス間通信をIngressとServiceで直接制御していますが、IstioやLinkerdなどサービスメッシュを導入することで、mTLSによる暗号化、サーキットブレーカー設定、リクエストレート制限などを柔軟に実現できます。これにより、セキュリティ強度と安定性を向上させ、インフラ費用や開発会社への追加費用(相場:30~50工数、90万~150万円程度)を見積もったうえで段階導入を検討します。

  2. GitOpsによる完全自動化とレビュー品質向上
    現在のGitHub Actions+Kustomizeによるデプロイ方式を、Argo CDやFluxによるGitOps環境に移行することで、マニフェストのPull型デプロイが可能になります。これにより、CIでマージされたマニフェストが即座にクラスターに適用されるため、手動CLI操作のミスを削減でき、開発会社へ発注する際には「GitOps移行工数:15工数(45万円)」を見積もりに含めます。

  3. カナリアリリースとA/Bテストの導入
    現在はローリングアップデートでリリースを行っていますが、カナリアリリースを導入し、一部ユーザーにのみ新機能を展開して問題がないかを検証する仕組みを構築します。IstioやFlaggerを活用し、リリースリスクを最小化。A/Bテストを組み合わせることで、フロントエンドのUI/UX改善にも使えるため、開発会社には「Canary設定工数:12工数(36万円)」「Flagger設定工数:8工数(24万円)」を追加発注予定です。

  4. テストカバレッジ完全化とテストインフラの拡充
    非機能部分のテストカバレッジを最低でも50%以上に引き上げるため、契約に「テストカバレッジ向上タスク」を含める。具体的には、管理画面や旧APIのテストケースを充実させ、SonarQubeによる定期コード品質チェックを導入。これにより、品質担保を強化し、長期的な保守コストを抑える狙いです。

  5. クラウドコスト管理の自動化(FinOps)
    毎月のクラウド請求額を自動的に解析し、利用パターン変動に応じたリソース最適化を行う仕組みを構築します。たとえば、AWS Cost and Usage Report(CUR)をLambdaで解析し、コストアラートや最適化提案をSlackへ自動通知。これにより、クラウド費用の無駄をさらに削減し、本プロジェクトのトータルTCOを年間であと10~15%程度圧縮することを目指します。

これらの取り組みを計画段階で取り入れることで、次期フェーズにかかる予算感や工数相場がより明確になり、開発会社への発注もスムーズかつコスト最適化された形で進められます。

お問合せ

不明点やお見積りの依頼などお気軽にください。




問い合わせを行う

関連記事