アプリケーションを開発している際や、既存のアプリケーションをkubernetes上で稼働できるように置き換えをしていく起動順序に他のアプリケーションとの兼ね合いで、Podが再起動を繰り返す(=CrashLoopBackOff)するケースがあります。そのようなケースには、InitContainerを使って解決するのが良いので、紹介します。

よくあるケース

アプリケーションの起動シーケンスでは、下記のようなことが多いかと思います。

  • DBアクセス(コネクション生成)
  • メッセージブローカ初期化 + コネクション生成
  • 他サービスとのコネクション生成

など、依存先のアプリケーションがすでに立ち上がっていることを前提にするケースが多いです。

postgresを例に具体的に考えてみる

下記例は、postgresをDBを生成するサービス、Statefullsets, Podのマニュフェスト例です。

apiVersion: v1
kind: Service
metadata:
  name: postgres-svc
spec:
  ports:
    - port: 5432
  selector:
    app: postgres
  clusterIP: None
---
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: postgres-sts
spec:
  serviceName: postgres-svc
  replicas: 1
  selector:
    matchLabels:
      app: postgres
  template:
    metadata:
      labels:
        app: postgres
    spec:
      containers:
        - name: postgres
          image: postgres:latest
          ports:
            - containerPort: 5432
          env:
            - name: POSTGRES_USER
              value: dmin
            - name: POSTGRES_PASSWORD
              value: admin
            - name: PGDATA
              value: /var/lib/postgresql/data/pgdata
            - name: POSTGRES_DB
              value: sample
          volumeMounts:
            - name: postgres-pvc
              mountPath: /var/lib/postgresql/data/pgdata
              subPath: postgres
  volumeClaimTemplates:
    - metadata:
        name: postgres-pvc
      spec:
        accessModes: [ "ReadWriteOnce" ]
        resources:
          requests:
            storage: 3Gi

StatefullsetsでPodを起動するケースは、起動に少し時間がかかります。下記のようなコンテナを同時に起動してまうと、“CrashLoopBackOff”を繰り返し、kubectl get pods等で確認するとRESTARTS回数が増えていきます。

apiVersion: v1
kind: Pod
metadata:
  name: sample-app
spec:
  containers:
  - image: xxxx:latest   # DBアクセスするアプリ
    name: sample

kubernetesには、Init Containersという仕組みがあります。このInit Containersは、Pod内でメインとなるコンテナを起動する前に別のコンテナを起動させる機能です。この機能を使うことで、DBアクセス可能になるまでまつことが可能になります。

apiVersion: v1
kind: Pod
metadata:
  name: sample-app
spec:
  initContainers:
  - name: check-db-ready
    image: postgres:latest
    command: ['sh', '-c', 
      'until pg_isready -h postgres-svc -p 5432; 
      do echo waiting for database; sleep 2; done;']
  containers:
  - image: xxxx:latest   # DBアクセスするアプリ
    name: nginx

このようにすることで、postgresが立ち上がって、通信できる状態になるまで待つことができます。initContainers自体、containersと同様、複数のPodを記載することができます。 他の利用方法としては、自動テストなどで利用するデータの投入処理なんかにも利用可能です。このようにすることで、メインのコンテナは、必要な処理だけ記載できます。 

今回は、kubernetes利用時によく出るエラー”CrashLoopBackOff”の対処方法の一つとして、initContainersを紹介しました。お疲れさまでした。