Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
突然のメモリ使用率上昇へ対応! k8sカスタムコントローラー開発事例
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
syossan27
April 30, 2025
550
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
突然のメモリ使用率上昇へ対応! k8sカスタムコントローラー開発事例
MIXI × ココナラのSRE改革大作戦 〜改善のその先へ〜 の資料です
https://mixi.connpass.com/event/352623/
syossan27
April 30, 2025
More Decks by syossan27
See All by syossan27
一人SREが歩んだPlatform Engineeringスモールスタート実践録 ~ クラウドネイティブ会議版 ~
syossan27
4
2k
プロポーザル サポートガイドを読み解いていこう!
syossan27
3
820
幻滅期を越える サイトリライアビリティ エンジニアリング
syossan27
1
230
一人SREが歩んだ Platform Engineering スモールスタート実践録
syossan27
2
1.8k
SREって何? 現場で学んだサイト信頼性の第一歩
syossan27
5
1.6k
知識0からカンファレンスやってみたらこうなった!
syossan27
5
710
監視 やばい
syossan27
12
11k
最先端を追う前に、まず広めよう! 〜AIツールの普及活動のすすめ〜
syossan27
2
1.6k
Fanstaの1年を大解剖! 一人SREはどこまでできるのか!?
syossan27
2
870
Featured
See All Featured
The State of eCommerce SEO: How to Win in Today's Products SERPs - #SEOweek
aleyda
2
11k
Music & Morning Musume
bryan
47
7.2k
KATA
mclloyd
PRO
35
15k
Reality Check: Gamification 10 Years Later
codingconduct
0
2.2k
SERP Conf. Vienna - Web Accessibility: Optimizing for Inclusivity and SEO
sarafernandez
2
1.5k
Designing Experiences People Love
moore
143
24k
Ten Tips & Tricks for a 🌱 transition
stuffmc
0
130
Believing is Seeing
oripsolob
1
140
Evolving SEO for Evolving Search Engines
ryanjones
0
210
We Have a Design System, Now What?
morganepeng
55
8.2k
The Art of Programming - Codeland 2020
erikaheidi
57
14k
エンジニアに許された特別な時間の終わり
watany
107
250k
Transcript
©MIXI 突然のメモリ使用率上昇へ対応! k8sカスタムコントローラー開発事 例 株式会社MIXI 井上 翔太
©MIXI 自己紹介 名前:しょっさん X(旧: Twitter)/ mixi2:@syossan27 所属:MIXI 活動: • SRE
Kaigi • SRE Magazine • ゆるSRE勉強会
©MIXI Fanstaのご紹介 • スポーツ観戦ができる飲食店に特化した検索サービス • スポーツ観戦できる飲食店をエリアやチーム、放映予定から検索し、予約できる • お店にとってはスポーツ観戦ができることを告知し、集客することができる • [New]
事前決済ができるようになりました! ©Fansta
©MIXI ある日のこと・・・
©MIXI ある日突然・・・ まぁもし、なにかが起こっても爆速で対処しますよ! 最近は昔に比べると、特にエラーも起こらず平和ですなぁ〜
©MIXI ある日突然・・・ まぁもし、なにかが起こっても爆速で対処しますよ! ハッハッハッ! 最近は昔に比べると、特にエラーも起こらず平和ですなぁ〜
©MIXI ある日突然・・・ まぁもし、なにかが起こっても爆速で対処しますよ! ハッハッハッ! 最近は昔に比べると、特にエラーも起こらず平和ですなぁ〜 やばい!
©MIXI 何が起こったのか? 起因は一部のGraphQLクエリの修正 • 修正したGraphQLクエリでは非常に大きいレスポンスを返すように なってしまっていた • 結果、メモリ使用量が急速に肥大化 • メモリがサチることでレイテンシの悪化につながった
• k8sを利用していたため、HPAでメモリ使用率がある一定を超えたら スケールするようにしていたが、スケール数も上限に達していた
©MIXI すぐに直したいが・・・
©MIXI ある日突然・・・ まぁもし、なにかが起こっても爆速で対処しますよ! 最近は昔に比べると、特にエラーも起こらず平和ですなぁ〜
©MIXI なんとかするっきゃねぇ!
©MIXI k8sカスタムコントローラー、作りました pre-oom-killer ※ GitHub - syossan27/pre-oom-killer : https://github.com/syossan27/pre-oom-killer
©MIXI 前提:k8sカスタムコントローラーとは? • k8sでは様々なリソースを管理するコントローラーが動いています ◦ Node ◦ Deployment ◦ ReplicaSet
◦ CronJob ◦ etc… ※ つくって学ぶkubebuilder - カスタムコントローラーの基礎 : https://zoetrope.github.io/kubebuilder-training/introduction/basics.html
©MIXI 前提:k8sカスタムコントローラーとは? • このコントローラーを自作することができる! • コントローラーを自作することで、独自のロジックをk8s内に持ち込むこと ができます • また、独自リソース(CR)を定義し、それを利用するためにカスタムコン トローラーを作成することもできます
• 有名なカスタムコントローラーだと ◦ cert-manager ◦ external-secrets ◦ などなど • とはいえ、きちんとk8sの内部処理を理解していかないといけないので、ち とハードルは高め
©MIXI カスタムコントローラーを作ってみよう やりたいこと:指定したメモリ使用率に達したらPodをevictする • evict(立ち退き)とは、Podに対して終了を要請すること • 当初調べた時に、 zapier/preoomkiller-controller というカスタムコン トローラーもあったが、こちらはメモリ使用量を指定するタイプで取
り回しが悪かった • やりたいことはほぼpreoomkiller-controllerが実現していたので、こ ちらを参考にする形で実装する
©MIXI カスタムコントローラーを作ってみよう - 処理イメージ
©MIXI カスタムコントローラーを作ってみよう - クライアント設定
©MIXI カスタムコントローラーを作ってみよう client-goを使い、k8sクライアントを作成 • kubernetes/client-go を利用して、 k8sクライアントを作成 • シグナルハンドラー、k8s APIやmetrics
API へ接続する設定を渡して作成します • 最後に、コントローラー構造体にそれらを 入れ、監視ループを走らせます config, err := clientcmd.BuildConfigFromFlags(masterUrl, kubeconfig) if err != nil { log.Fatal(err) } clientset, err := kubernetes.NewForConfig(config) if err != nil { log.Fatal(err) } metricsClientset, err := metrics.NewForConfig(config) if err != nil { log.Fatal(err) } ctx := SetupSignalHandler() controller := NewController(ctx, clientset, metricsClientset, time.Duration(interval)*time.Second) controller.Run()
©MIXI カスタムコントローラーを作ってみよう - Pod検出
©MIXI カスタムコントローラーを作ってみよう 監視ループを回し、対象Podを検出 • 対象となるannotationが付与されたPodを 検出します • annotationはdeploymentに以下のように設 定する ◦
pre-oom-killer.v1alpha1.k8s.io/target-container-name: "app" • ここで検出したPodで更に処理を行う podList, err := c.clientset.CoreV1().Pods("").List( c.context, metav1.ListOptions{ LabelSelector: PodLabelSelector, }, ) for _, pod := range podList.Items { podName, podNamespace := pod.ObjectMeta.Name, pod.ObjectMeta.Namespace podTargetContainer, ok := pod.ObjectMeta.Annotations[TargetContainerName] if !ok { log.WithFields(log.Fields{ "pod": podName, "namespace": podNamespace, }).Errorf("PodTargetContainerNameFetchError: %s", err) continue } // 後続処理は省略 }
©MIXI カスタムコントローラーを作ってみよう - Pod検出
©MIXI カスタムコントローラーを作ってみよう - メモリ使用率チェック メモリ使用率をチェックし、超過でevict • 対象となるPodで設定されているevictにす るメモリ使用率を取得する • メモリの最大値・使用量を取得する
podMemoryUsageThreshold, err := resource.ParseQuantity(pod.ObjectMeta.Annotations[MemoryUsa geThresholdAnnotation]) // メモリの最大値を取得 var containerLimitsMemory *resource.Quantity for _, container := range pod.Spec.Containers { containerLimitsMemory = container.Resources.Limits.Memory() } // メモリの使用量を取得 containerMemoryUsage := &resource.Quantity{} podMetrics, err := c.metricsClientset.MetricsV1beta1().PodMetricses(podNamespac e).Get(c.context, podName, metav1.GetOptions{}) for _, containerMetrics := range podMetrics.Containers { containerMemoryUsage = containerMetrics.Usage.Memory() }
©MIXI カスタムコントローラーを作ってみよう - メモリ使用率チェック メモリ使用率をチェックし、超過でevict • 対象となるPodで設定されているevictにす るメモリ使用率を取得する • メモリの最大値・使用量を取得する
• 最後に、メモリ使用率を取得し、超過した 場合にPodをevictさせる // メモリ使用率を算出 containerMemoryUsagePercentage := (float64(containerMemoryUsage.Value()) / float64(containerLimitsMemory.Value())) * 100 if containerMemoryUsagePercentage > float64(podMemoryUsageThreshold.Value()) { _, err := evictPod(c.context, c.clientset, podName, podNamespace, "v1", false) }
©MIXI カスタムコントローラーを作ってみよう - メモリ使用率チェック メモリ使用率をチェックし、超過でevict • 対象となるPodで設定されているevictにす るメモリ使用率を取得する • メモリの最大値・使用量を取得する
• メモリ使用率を取得し、超過した場合にPod をevictさせる • 最後に作成したクライアントを通して evictする eviction := &policy.Eviction{ TypeMeta: metav1.TypeMeta{ APIVersion: policyGroupVersion, Kind: EvictionKind, }, ObjectMeta: metav1.ObjectMeta{ Name: podName, Namespace: podNamespace, }, DeleteOptions: deleteOptions, } err := client.PolicyV1beta1().Evictions(eviction.Namespace).Evict(ctx, eviction)
©MIXI カスタムコントローラーを作ってみよう - Pod検出
©MIXI カスタムコントローラーを作ってみよう - 終了処理 シグナルをハンドリングし、終了させる • SIGTERMとSIGINTをハンドリングし、 キャッチしたら終了させる • シグナルハンドラを多重で呼び出さないよ
う、onlyOneSignalHandlerを作成 var onlyOneSignalHandler = make(chan struct{}) var shutdownSignals = []os.Signal{os.Interrupt, syscall.SIGTERM} func SetupSignalHandler() context.Context { close(onlyOneSignalHandler) c := make(chan os.Signal, 2) ctx, cancel := context.WithCancel(context.Background()) signal.Notify(c, shutdownSignals...) go func() { <-c cancel() <-c os.Exit(1) }() return ctx }
©MIXI 実装は以上! 思ったより簡単ですね
©MIXI カスタムコントローラーを作ってみると k8sの内部処理も併せて理解できるメリットも!
©MIXI 非常にお世話になった文献 ※ 実践入門 Kubernetes カスタムコントローラーへの道 : https://amzn.asia/d/8oIrthm • カスタムコントローラーについて、日本語
で体系的にまとまった文献が少ない中、内 部構造の説明から非常に分かりやすく書か れていました • ただ、本書内で使われているコマンド等は 使えなくなっている可能性が大なので、適 宜最新の内容に変えつつ読み進めていくの がよし
©MIXI 後日談
©MIXI pre-oom-killerを参考にカスタムコントロー ラーを作ってくれた方が! ※ GitHub - phamngocsonls/k8s-oom-killer : https://github.com/phamngocsonls/k8s-oom-killer
©MIXI ご清聴ありがとうございました