Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
5
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

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

概要

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を!!

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
5
Help us understand the problem. What are the problem?