はじめに
こんにちは、University of British Columbia 学部4年の保井祐理です。
2026年4月3日から4月30日の1ヶ月間、CA Tech JOBに参加しました。
私は、バックエンドエンジニアとして極AIの開発チームに配属していただきました。
この記事では、インターンシップ期間中に私が取り組んだことと、その成果についてご紹介します。
背景
極AI開発チームについて
極予測AIというAIを使った広告クリエイティブに関するプロダクトがあります。
開発チームは、マルチメディアを取り扱う大規模なバッチ処理の開発・運用を行なっています。
元々のワークフロー
もともと、このパイプラインは以下のようなアーキテクチャでCloud Workflowsを使用して構成されていました。

課題
Cloud Run Jobs呼び出すたびに、その時点の最新のDockerイメージ(:latest)を取得します。そのため、ループをしながら同じ処理を呼び出したいケースでは、ループの途中で新しいバージョンがデプロイされると、同じワークフローの中で前半と後半で異なるバージョンのコードが動いてしまいます。

またそれだけでなく、Cloud Workflowsは失敗したステップからのリトライができないなど、ワークフローエンジンとしては機能が限られていました。パイプラインが大規模になってきたことで、より柔軟で機能豊富なArgo Workflowsへの移行を進めることになりました。
GKE(Google Kubernetes Engine)はGoogleが提供するKubernetesのマネージドサービスです。Kubernetesとは、複数のコンテナをまとめて管理・実行するためのプラットフォームで、GKEを使うことでKubernetesクラスターの構築・運用をGoogleに任せることができます。
Argo WorkflowsはKubernetes上で動作するワークフローエンジンです。各処理をコンテナとして定義し、それらの実行順序や依存関係を管理します。Cloud Workflowsと比較して、失敗したステップからのリトライや、GUIでの実行状況の視覚的な確認など、より豊富な機能を持っています。今回はこのGKE上にArgo Workflowsを構築し、移行先の実行基盤としました。
取り組んだタスクについて
こうした背景から、Cloud Workflowsで管理されていたワークフローをArgo Workflowsへ移行するというタスクに取り組みました。
1. データ変換・集計を担うジョブをArgo Workflowsに移行
最初に担当したのは、Cloud Workflowsで管理されていたデータ変換・集計ジョブをArgo Workflowsに移行するタスクです。
システム上でBigQuery上のデータを整形・集計するためのdbtジョブが複数動いており、それぞれCloud Workflows \+ Cloud Scheduler \+ Cloud Run Jobsで定期実行されていました。今回の移行では、これらのジョブをArgoのCronWorkflowとして再実装しました。
Argo Workflowsでは、処理の単位をWorkflowTemplateとして定義し、それを組み合わせて CronWorkflowを構成します。今回はdbtのビルドジョブをWorkflowTemplateとして切り出し、スケジュール実行の設定をCronWorkflowに記述する形で実装しました。
実装後はArgo WorkflowsのGUIを使って実行状況を確認しました。各ステップが視覚的にノードとして表示され、チェックマークで正常完了していることをひと目で確認できます。

このタスクを通じて、WorkflowTemplate・CronWorkflowといったArgoの基本的な構成要素を一通り実務で習得しました。
2. Slack通知の Argo Workflow 実装
2つ目のタスクは、Argo Workflowsでの共通Slack通知機能の実装です。
Cloud Workflows時代はLog Routerでログを検知しPub/Sub経由でCloud Run Functionを呼び出すという仕組みを取っていました。Argoへの移行に伴い、Argo Workflowsのexit hookを使い、全ワークフロー共通で完了・失敗時にSlackへ自動通知する仕組みを実装しました。
実装当初はSlack OAuthトークンを手動で設定する方法をとっていましたが、セキュリティと運用の観点から自動取得できる仕組みを検討しました。まず External Secrets Operator(ESO)を使う構成を検討しましたが、追加コンポーネントの管理コストが高いため採用を見送りました。
最終的には、プロジェクト内の別サービスPythonプロセス内でSecret Managerから直接取得するシステムを採用しました。Secret Manager へのアクセスに必要なライブラリを、ワークフロー内でスクリプトを実行するためのコンテナイメージに追加し、Workload Identity の権限を使ってトークンを取得する実装で、既存の設計パターンとの一貫性を保ちながらシンプルに実現できました。
3. PythonワークロードのArgo Workflow実装
3つ目のタスクは、広告クリエイティブのPythonワークロードのうちの一つの実行基盤をArgo Workflowsへ移行することです。
実装中、Terraformのapplyが失敗するという問題に直面しました。原因を調査した結果、デプロイの順序に依存関係があることが判明しました。今回の実装では、Argo Workflows用に新たにGCPサービスアカウントとKubernetesサービスアカウントを作成し、Workload Identityで紐付ける構成をとっています。GCPサービスアカウントとWorkload Identityのバインディングは 別モジュールで管理されており、後者は前者のサービスアカウントをメールアドレスの文字列として参照しています。そのためTerraformが依存関係を自動解決できず、サービスアカウントが存在しない状態で一括applyするとエラーになります。解決策として、まずサービスアカウントの変更を先にリリースし、その後でWorkload Identityバインディングを含む変更を適用するという順序を踏みました。インフラの変更はリソース間の依存関係を意識した上でリリース順序を設計することが重要だと学びました。

学んだこと
1. Argo Workflowsの実装、Terraformをゼロから習得
CronWorkflow / WorkflowTemplate / Kustomizeによる環境管理など、Kubernetes周りの知識も含めて実務を通じて習得しました。
2. Vibe Codingでは「背景の言語化」が品質を左右する
PythonワークロードのArgo移行のタスクを行なっていた際に、私は最初「既存のCloud Workflowsを CronWorkflow に変更してほしい」という内容のみで、Claudに指示出しをしていました。しかし実際には、Cloud Workflowsが呼び出しのたびに :latestイメージを取得するためバージョンが揃わないという課題を解決するための移行であり、その背景を伝えていませんでした。その結果、Dockerイメージのバージョン管理まで考慮した実装にならず、気づかないままPRを出してしまいました。移行の目的と背景を最初から指示に含めていれば、Claudeがバージョン管理の必要性まで踏まえた設計を提案でき、手戻りを避けられたはずです。
要件だけでなく「なぜそうしたいか」「既存の制約は何か」を自分の中で整理してから渡すことが、Vibe Codingを効果的に使う上で重要だと気づきました。
3. 問題の切り分けの大切さ
インフラ実装では、エラーメッセージだけでは原因が掴みにくい問題に直面することがありました。
実際に実装した範囲をリリースした際、本番環境では正常に動作しているにもかかわらず、ステージング環境と開発環境では動かないという状況が発生しました。まずどの環境で・何が・どのステップで失敗しているのか」を整理するところから始めました。ステージング環境を調査すると、そもそもCloud Buildによるビルド自体が失敗しておりデプロイまで到達できていないことがわかりました。一方、開発環境では、ビルドは成功しているものの全く別の原因で失敗していることが判明し、環境ごとに原因が異なっていました。
この経験を通じて、エラーに直面したときはまずどの環境で再現するか、どのステップまで正常に進んでいるかを切り分けることが、原因特定への最短経路だと学びました。
まとめ
1ヶ月のインターンシップを通じて、dbtの定期実行フローの移行、Slack通知の共通化、 PythonワークロードのArgo Workflows移行という3つのタスクを完遂しました。
技術面では、Argo WorkflowsやKubernetes周りの知識をゼロから実務を通じて習得したことが大きな収穫でした。また、Vibe Codingを実務で活用する中で、「要件だけでなく背景を言語化してから渡す」という気づきは、AIとの協働を今後さらに活かしていく上で自分の中に残る学びになりました。
短い期間ながら、トレーナーさん、メンターさんをはじめ、実際のプロダクト開発に深く関わらせていただいた極AIチームの皆さんに感謝します。1ヶ月間本当にありがとうございました!
