💡

Kubernetesで稼働するRedashのWorkerにLivenessProbeを実装してみる

に公開

課題

RedashのWorker(GenericWorker/AdhocWorker/ScheduledWorker)が、Redisにrq:workersとして登録されない、稼働中にステータスが無効になることでJobを処理できない状態が発生していました。
Workerにはデフォルトで各Probeが実装されておらず、Workerのコンテナは起動中のため、パット見では異常には見えません。
調査したところ、一時的な例外でWorkerプロセスが落ちてしまったり、Worker起動時にRedisとコネクション接続に失敗したりなどいくつか原因はありそうでした。
しかし継続調査が難航、かつ再起動で解決できる事象だったため、暫定処置としてWorker側が当該事象を検知して自動復旧できる仕組みを検討したのでメモです。

環境

解決方法

WorkerにLivenessProbeを実装します(デフォルトなし)。
Redash公式イメージにはPythonとrq/redisライブラリが同梱されているため、Pythonのスクリプトを実行する形式です。

LivenessProbeで実行するスクリプト

import sys
from redis import Redis
from rq import Worker
import os, socket
from redis.exceptions import ConnectionError

def main():
    try:
        r = Redis(
            host=os.getenv('REDASH_REDIS_HOSTNAME', 'localhost'),
            port=int(os.getenv('REDASH_REDIS_PORT', 6379)),
            password=os.getenv('REDASH_REDIS_PASSWORD')
        )

        # 自身のPod名を取得
        hostname = socket.gethostname()

        # Redisに登録されている有効なWorkerリストを取得
        workers = Worker.all(connection=r)

        for w in workers:
            # 自身のPodが登録されていれば問題なし(1podで複数Workerプロセスが登録されていますが1プロセスでも確認できればOKとします)
            if w.hostname == hostname:
                sys.exit(0)
        # 自身のPodが登録されていない場合はWorkerがJobを裁けない状態になっているので異常終了してPodを再起動します
        sys.exit(1)
    except ConnectionError as e:
        print('Redis connection failed:', e)
        sys.exit(1)

if __name__ == "__main__":
    main()

WorkerのDeploymentに設定するLivenessProbe

livenessProbe:
  exec:
    command: ["python", "/app/scripts/health_check.py"]
  initialDelaySeconds: 60
  timeoutSeconds: 3
  failureThreshold: 3
  periodSeconds: 60

メモ

これは安定稼働のベストプラクティスではなく、暫定処置としてのアイデアです。
この設定だと3回連続で異常を検知すると(最大3分)Podが再起動される挙動になるので、Probeの間隔などを短くする、StartupProbeを実装するなど改善の余地があります。
起動プロセスの時間を加味して、initialDelaySecondsは60sにしています。

Discussion