0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

KubernetesでCrashLoopBackOffを意図的に発生させ、待機Podを自動スケールする方法【Flask + Python】

Last updated at Posted at 2025-05-17

この記事では、CrashLoopBackOff状態を再現する方法と、それをトリガーに待機していた別Podを自動でスケールアウト(replicas=1)する構成を、Python × Flask × Kubernetes環境で構築する手順をまとめます。

この仕組みは、障害発生時の自己復旧ロジックやフェイルオーバー実装のベースとしても活用できます。

🎯 目的

  • CrashLoopBackOffをテスト用トリガーとして確実に発生させる
  • Flaskアプリがクラッシュしたら、standby-app を自動で1レプリカ起動する
  • 障害検知から自己修復までの自動監視&スケーリングを組み込む

🧱 構成イメージ

  • crash-app(replicas:1、起動後30秒で強制終了→CrashLoopBackOff)
  • standby-app(replicas:0で待機)
  • crash-appのPodがCrashLoopBackOffになると、standby-appをreplicas=1で起動

本番環境を止めずに、予備Podへフェイルオーバーさせる簡易構成です。


1. CrashLoopBackOff発生用Flaskアプリ例

app.py

import os
import threading
import time
from flask import Flask

CRASH_DELAY = int(os.getenv("CRASH_DELAY", "30"))

app = Flask(__name__)

@app.route("/")
def index():
    return "Hello from crash-app!"

@app.route("/healthz")
def healthz():
    return "OK", 200

def crash_after():
    time.sleep(CRASH_DELAY)
    os._exit(1)  # 即時終了でCrashLoopBackOffを誘発

if __name__ == "__main__":
    threading.Thread(target=crash_after, daemon=True).start()
    app.run(host="0.0.0.0", port=5000)

ポイント:環境変数 CRASH_DELAY 秒後に os._exit(1) でコンテナを異常終了させ、CrashLoopBackOff状態を確実に作ります。


2. crash-app Deployment設定

apiVersion: apps/v1
kind: Deployment
metadata:
  name: crash-app
spec:
  replicas: 1
  selector:
    matchLabels:
      app: crash-app
  template:
    metadata:
      labels:
        app: crash-app
    spec:
      containers:
        - name: crash-app
          image: your-registry/crash-app:latest
          imagePullPolicy: IfNotPresent
          env:
            - name: CRASH_DELAY
              value: "30"
          ports:
            - containerPort: 5000
          livenessProbe:
            httpGet:
              path: /healthz
              port: 5000
            initialDelaySeconds: 10
            periodSeconds: 15
            failureThreshold: 1
  • livenessProbe/healthz に1回でも失敗すると再起動 → CrashLoopBackOffへ移行します。

3. standby-app Deployment設定

apiVersion: apps/v1
kind: Deployment
metadata:
  name: standby-app
spec:
  replicas: 0  # ← 初期は待機状態
  selector:
    matchLabels:
      app: standby-app
  template:
    metadata:
      labels:
        app: standby-app
    spec:
      containers:
        - name: standby-app
          image: your-registry/crash-app:latest
          imagePullPolicy: IfNotPresent
          env:
            - name: CRASH_DELAY
              value: "120"  # 長めに設定してCrashLoopBackOffになりにくく
          ports:
            - containerPort: 5000
          readinessProbe:
            httpGet:
              path: /healthz
              port: 5000
            initialDelaySeconds: 5
            periodSeconds: 10

replicas: 0 のまま待機し、必要に応じて監視スクリプトでスケールアウトします。


4. 監視&自動スケーリングロジック

scale.py

from kubernetes import client, config, watch

config.load_incluster_config()
apps_v1 = client.AppsV1Api()
core_v1 = client.CoreV1Api()

def scale_deployment(name: str, replicas: int, namespace: str = "default"):
    patch = {"spec": {"replicas": replicas}}
    apps_v1.patch_namespaced_deployment_scale(name, namespace, patch)
    print(f"{name}{replicas} レプリカにスケールしました")

def monitor_crash_app():
    w = watch.Watch()
    for event in w.stream(core_v1.list_namespaced_pod,
                          namespace="default",
                          label_selector="app=crash-app"):
        pod = event["object"]
        for cs in pod.status.container_statuses or []:
            if cs.state.waiting and cs.state.waiting.reason == "CrashLoopBackOff":
                scale_deployment("standby-app", 1)
                w.stop()
                return

if __name__ == "__main__":
    monitor_crash_app()
  • kubernetes-client の Watch 機能で crash-app PodのCrashLoopBackOffを検出
  • 検出時に standby-app を1レプリカにスケール

5. crash-app に監視スクリプトを組み込む

crash-app のPod内でSidecarとして動かす場合、以下のようにDeploymentへ追加します。

      containers:
        - name: crash-app
          # …(省略)…
        - name: crash-monitor
          image: your-registry/crash-monitor:latest
          command: ["python", "/opt/scale.py"]
      volumeMounts:
        - name: kube-config
          mountPath: /root/.kube
      volumes:
        - name: kube-config
          configMap:
            name: kube-config  # ServiceAccount不要でアクセス可能なら省略可

※上記は例です。別PodとしてデプロイしてもOKです。


6. RBAC設定

crash-monitor にDeploymentスケール権限を与えるRoleとRoleBindingを作成します。

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: deployment-scaler
  namespace: default
rules:
  - apiGroups: ["apps"]
    resources: ["deployments/scale"]
    verbs: ["get", "patch"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: bind-deployment-scaler
  namespace: default
subjects:
  - kind: ServiceAccount
    name: default
    namespace: default
roleRef:
  kind: Role
  name: deployment-scaler
  apiGroup: rbac.authorization.k8s.io

🔁 実行フローまとめ

  1. crash-app 起動 → 30秒後に os._exit(1) で異常終了
  2. KubernetesがCrashLoopBackOff判定
  3. crash-monitor (scale.py) が検知 → standby-app を1レプリカにスケール
  4. standby-appが立ち上がり、あとはモニタリング継続

✅ 補足:CPU飽和によるCrashLoopBackOff例

# cpu_burn.py
data = []
while True:
    data.extend([0] * 10**6)  # CPUとメモリを使い切る

Deploymentに組み込んで resources.limits.cpu: "100m" などを設定すると、CPU制限超過でOOMKilled → CrashLoopBackOff もテスト可能です。


✅ まとめ

方法 再現性 備考
os._exit(1) + threading 最も直接的で失敗率ゼロ
livenessProbe失敗 Probe 設定次第
CPU/メモリ負荷(OOM) リソース制限が必要

CrashLoopBackOffはトリガーとして活用し、自動スケールやフェイルオーバー機能のテストと設計に役立てましょう。
これにより、本番環境での高可用性・自己修復構成をシンプルに実現できます。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?