Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
GitOpsに潜む競合を、構造から見直す
Search
g0xu
September 04, 2026
240
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
GitOpsに潜む競合を、構造から見直す
g0xu
September 04, 2026
More Decks by g0xu
See All by g0xu
Kubernetesの「隠れメモリ消費」によるNode共倒れと、Request適正化という処方箋
g0xu
0
260
Featured
See All Featured
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
35
2.6k
Paper Plane (Part 1)
katiecoart
PRO
2
11k
Measuring & Analyzing Core Web Vitals
bluesmoon
9
1k
What Being in a Rock Band Can Teach Us About Real World SEO
427marketing
0
1.1k
Lightning Talk: Beautiful Slides for Beginners
inesmontani
PRO
2
710
The Curse of the Amulet
leimatthew05
3
15k
Are puppies a ranking factor?
jonoalderson
2
4k
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
123
22k
Primal Persuasion: How to Engage the Brain for Learning That Lasts
tmiket
0
490
Mozcon NYC 2025: Stop Losing SEO Traffic
samtorres
1
570
Evolving SEO for Evolving Search Engines
ryanjones
0
300
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
56
3.5k
Transcript
に潜む競合を、構造から見直す GitOps 〜症状ではなく、根本原因に向き合う〜 1
私たちのこと スリーシェイクは、クライアントへの SRE 支援を行っています。 今日お話しするのは、あるサービスの GKE 基盤で起きた、リリース時の競合 を「根本から直そうとした」話で す。 環境:
GKE でマイクロサービスを運用 Istio サービスメッシュ(サイドカーパターン) ArgoCD(GitOps) で宣言的にデプロイ GKE / Istio / Argo CD 2
今日話すこと 前提 — GitOps と proto descriptor、そしてこの構成 2. 事象 —
リリースの「順序」で不具合が起きた 3. その場しのぎをやめる — なぜこの構成なのかを辿る 4. 構造で解く — 根本原因と責任境界の見極め 5. 学び 1. 3
1. 前提 4
前提① GitOps / ArgoCD を単一の情報源(source of truth)にして、宣言的にクラスタを同期する運用モデル。 ArgoCD が Git
の状態を検知し、クラスタへ自動同期する 同期の単位は Application(=「この Git のこのパスを、このクラスタへ」) リポジトリを更新すれば、対応する Application が自動で同期される ポイント:「何を1つの Application にまとめるか」が、後々の挙動を左右する GitOps = Git 参考: Argo CD 公式ドキュメント / Core Concepts (Application) / OpenGitOps(GitOps 原則) 5
ArgoCD の Application リソース(例) apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name:
api namespace: argocd spec: project: default source: # ← 何を repoURL: https://github.com/xxx/k8s-manifest.git path: app/helm/api # この「1つのパス」を配信 targetRevision: main helm: valueFiles: [values/prd.yaml] destination: # ← どこへ server: https://kubernetes.default.svc namespace: api syncPolicy: automated: # ← Git 変更を自動で同期 prune: true selfHeal: true 6
前提② proto descriptor とは にデプロイされている api は gRPC サービス。しかしクライアントは HTTP/JSON
で叩きたい。 Istio のサイドカー(Envoy)の grpc_json_transcoder が、HTTP/JSON ⇄ gRPC を相互変換 その変換に必要な「API 定義の辞書」が proto descriptor(pb) GKE ⇒ pb(辞書)と image(API 実装)は、常に互いに整合している必要がある ずれると transcoder がサービスを解決できず、機能不整合が起きる gRPC-JSON transcoding: HTTP/JSON リクエストを、descriptor を辞書に gRPC 呼び出しへ変換する Envoy の機能 参考: Envoy gRPC-JSON Transcoder / Istio EnvoyFilter / Protocol Buffers 7
前提② proto descriptor とは 8
前提③ 対象システムの構成 今回の api は、2つの ArgoCD Application で構成されている。 api Application
… アプリ本体(Rollout)を配信 config Application … proto descriptor(pb)を ConfigMap として配信 api の Istio サイドカー(Envoy)がマウントして使う この pb は api + もう1つのワークロードから参照される(1対2) リリースの流れ: アプリのリリースで、CI が1コミットで imageTag(api) と pb(config) を同時更新 → ArgoCD が api / config それぞれの Application を「独立に」同期する image と pb は「1リリースで一緒に変わる」 。しかし同期するのは別々の Application。 9
2. 事象 10
事象:リリース時の競合 api のリリースで、Pod のロールアウトと proto descriptor(pb)の更新の競合が発生。 正しい順序は pb(config)を先に更新 → その後に
api の Pod をロールアウト しかし両者は別 Application で、この順序が保証されない api が先にロールアウトすると、新 Pod が「古い pb」を掴む → 今後も再発しうる 「たまたま順番が合えば動く」状態になっていた。 11
何が起きるのか pb (辞書)と image(実装)がずれると: 古い辞書で変換され 機能不整合(サービスは在るが descriptor の中身が古い) →502 エラー(アプリチームからの報告)
本来は pb を先に更新しておく必要があるのに、api が先行すると、新しい Pod が「古い pb」を掴んで起動する ——これが競合の正体。 12
3. その場しのぎをやめる 13
その場しのぎの誘惑 「すぐ塞ぐ手」はいくつもありました。 pb と image を別々にリリースする Application 間の同期順序を制御する Argo CD
の機能を使う でも——「なぜこの構成なのか」を問わずに塞ぐと、別の形でまた牙をむく。 まず根本原因にたどり着くことにしました。 14
配送の流れを辿る Git 上は1コミット(一致したペア)。しかしクラスタへは2経路で独立配送される。 本来は config(pb)を先に同期 → その後 api をロールアウト、が望ましい。しかし独立同期のため、この順序を保証できない。 15
根本原因 と pb は、別々の Application(api / config)に分かれて独立同期される → 2つの Application
間に、同期順序を保証する仕組みがない image 壊れているのは「リリースフロー(source)」ではなく、「どう Application に分けたか」。 16
なぜ、こう分かれたのか(歴史を辿る) 時期 内容 当時の課題 pb は 複数のワークロードから参照される(1対多)のに、各自が別々に管理。重複・不統一が課題だった 対応 pb を
専用の config Application に集約(DRY・単一フロー化) 。当時としては妥当な判断 副作用 pb が api 本体と別の Application に切り離され、独立同期で順序保証のない競合を生んだ 今回向き合っているのは、この 副作用 です。 17
トレードオフの表面化 当時の判断は「間違い」ではない。 当時は 重複排除(DRY) を優先するのが妥当だった その代償として、pb とワークロードが別 Application に分かれ、 独立配送による順序リスク(=今回の競合)を抱えることになった
設計を「正解/不正解」ではなく「トレードオフ」で捉える。 誰かのミスではなく、前提が時間とともに変わった、と読む。 18
ここまでのまとめ 事象:リリース時、Pod ロールアウトと pb 更新が競合する 本質:pb(辞書)と image(実装)がずれると機能不整合 原因:pb と image
が別 Application で独立配送され順序保証がない = リリースフローではなく Application の分け方 に起因 背景:過去の DRY 一元化のトレードオフが表面化した ここから「では、どう直すか」へ。 19
4. 構造で解く 20
解決策の検討 案 概要 評価 リリース PR 分割 pb と image
の PR を分ける ✕ CI 再設計・人手依存で形骸化 ArgoCD 順序制御(Beta) Application 群の同期順を制御 ✕ Beta・自動同期を無効化・目的外の流用 同期待ちの hook 先に config を確認してから api △ GA だが自作物の保守・SPOF 化 構造で解く(本命) Application の分け方そのものを見直す ◎ 競合が構造的に消える 21
本命:構造で解く 症状(順序)を抑えるのではなく、「別 Application に分かれた」構造を解消する。 方針:pb を、それを使うサービスの配送単位(Application)に置く 転機:もう一方のワークロードが GKE から外れることになり、pb 参照は
api のみ(1対2 → 1対1) → pb を api の Application に一本化(再統合) image と pb が同じ App で同期 → 順序が保証される 22
解決後の構造 pb を「元の配送単位」へ戻すだけで、競合が構造的に消える。 23
「どこで・誰が直すべきか」 責任境界の見極めが、この対応の肝でした。 リリースフロー(アプリ/BE 側)は妥当 → 触らない 競合は infra 側の Application
の分け方が原因 → infra 側で直すのが正しいスコープ ただし pb の配送元(CI)に手が入るため、実装は アプリ/BE 側と連携して進める 「自分たちの都合で、健全な他チームのフローを変えさせない」 原因のある場所で、責任を持って直す。 24
5. 学び 25
今回の学び 症状ではなく、構造を直す。 対症療法的なパッチは、根本原因(Application の分け方)を隠すことがあ る。 過去の設計は「トレードオフ」で捉える。 誰かのミスにせず、前提の変化として読む。 「どこで・誰が直すか」責任境界を見極める。 原因のある場所で直す。 ご清聴ありがとうございました。
26