Help us understand the problem. What is going on with this article?

kubernetesでenvoy使ってgRPCしながら終了時にパケットロストしない方法

More than 1 year has passed since last update.

概要

kubernetesでmicroservicesアーキテクチャを採用している場合、envoyでgRPC通信するケースが多いかと思います。詳しくはこちらの記事を。
そんなときに瞬断の影響が大きいサービスを運用している場合、アプリをシャットダウンするタイミングで何も考えないで運用しているとパケットをロストします。

これは、serviceから切り離される前にPodが終了してしまうことや、Podに対して終了シグナルが送られた場合に、アプリより先にenvoyが終了しちゃう事などで発生します。
これはサイドカーしている他のコンテナでも同様のことが言えます。

対策

grpcはhttp2の通信なのでコネクションを永続化します。つまりserviceから張られていたコネクションは処理中のものも含めて切断されてしまいます。

それを避けるためには
① serviceから当該Podへの新規のコネクションを止める
② すべての処理が終わるまですべてのコンテナを落とさない
を行う必要があります。

しかしながら②を実現することは困難なので sleep 30 で妥協することにしました。
30秒程度あればすべての処理は終了するだろうという考えです。

事前準備

まず、複数のコンテナ間で状態を共有するためにunhealthyという名前の共有volumeを作成します。

これを各コンテナの /tmp にマウントしておきます。
ここに状態共有のための情報を書き込みます。

appコンテナの挙動

appコンテナはSIGTERMを受け取ると /tmpunhealthy というファイルを作成し30秒sleepします。

同時に unhealthy がある場合は readinessProbe を失敗させ、serviceから切り離します。

envoyはheadless servicesを利用してバランシングしているので、このPodに対して新しいコネクションは張られなくなります。

envoyコンテナの挙動

envoyコンテナはSIGTERMを受け取ると unhealthy ファイルを発見するまでループします。
これでappコンテナが終了するよりも前にenvoyコンテナが終了することを防ぎます。
unhealthy ファイルを発見したら、こちらも同様に30秒sleepします。

30秒後に両コンテナが完全に終了するという流れになります。

具体的には下記のようなyamlになります。

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: app
spec:
...
      containers:
      - name: sidecar-envoy
        image: envoyproxy/envoy:v1.7.0
...
        volumeMounts:
        - name: unhealthy
          mountPath: /tmp
          readOnly: true
        lifecycle:
          preStop:
            exec:
              command:
              - sh
              - -c
              - while (! test -e /tmp/unhealthy); do sleep 1; done; sleep 30
      - name: app
        image: path/to/app:latest
...
        readinessProbe:
          exec:
            command:
            - sh
            - -c
            - exit `! test -e /tmp/unhealthy; echo $?`
          initialDelaySeconds: 5
          timeoutSeconds : 3
          periodSeconds: 3
          failureThreshold: 1
        lifecycle:
          preStop:
            exec:
              command:
              - sh
              - -c
              - touch /tmp/unhealthy; sleep 30
      volumes:
      - name: unhealthy
        emptyDir: {}

initialDelaySeconds とか timeoutSeconds あたりは短めにしてるって程度で深い意味はありません!
これでHappy gRPC lifeを!!

cyberagent
サイバーエージェントは「21世紀を代表する会社を創る」をビジョンに掲げ、インターネットテレビ局「AbemaTV」の運営や国内トップシェアを誇るインターネット広告事業を展開しています。インターネット産業の変化に合わせ新規事業を生み出しながら事業拡大を続けています。
http://www.cyberagent.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away