IstioのEnvoyFilterでgzip圧縮をしていく

今回はIstioのEnvoyFilterでのgzip圧縮をしたのでそれを書いていきます。
gzip圧縮自体は Envoy が提供しているのでこれを使用するだけなのですが、EnvoyFilter を初めて使ったのでそれのメモがてらの記事でもあります。
https://www.envoyproxy.io/docs/envoy/latest/configuration/http/http_filters/compressor_filter

今回は2通りの方法を試しています。

  1. アプリケーションのサイドカーgzip 圧縮
  2. Istio Ingress Gatewayサイドカーgzip 圧縮

両者の違いとしては Filter をどこまで適用するかで、アプリケーション側で行う時は Filter はそのアプリケーションに対して適用されますが、 Istio Ingress Gateway の場合は複数のアプリケーションが紐づいている場合はそれらすべてに Filter が適用されるという認識です。

環境

  • Kubernetes: v1.18.14
  • Istio: v1.9.0
  • Envoy: 1.17.0
    • バージョンは kubectl exec -it [サイドカーが動いてるPod] -c istio-proxy -- pilot-agent request GET server_info | jq {version} で確認しました

アプリケーションのサイドカーgzip 圧縮

適用する EnvoyFilter の YAML ファイルは下記になります。

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: gzip
  namespace: sample-app
spec:
  workloadSelector:
    labels:
      # Podのラベル
      app: sample-app
  configPatches:
    - applyTo: HTTP_FILTER
      match:
        context: SIDECAR_INBOUND
        listener:
          filterChain:
            filter:
              name: envoy.filters.network.http_connection_manager
              subFilter:
                name: envoy.filters.http.router
        proxy:
          proxyVersion: ^1\.9.*
      patch:
        operation: INSERT_BEFORE
        value:
          name: envoy.filters.http.compressor
          typed_config:
            '@type': type.googleapis.com/envoy.extensions.filters.http.compressor.v3.Compressor
            compressor_library:
              name: for_response
              typed_config:
                '@type': type.googleapis.com/envoy.extensions.compression.gzip.compressor.v3.Gzip
                compression_level: "COMPRESSION_LEVEL_6"
            response_direction_config:
              common_config:
                content_type:
                  - text/html
                  - text/css
                  - application/javascript
              remove_accept_encoding_header: true
            request_direction_config:
              common_config:
                enabled:
                  default_value: false
                  runtime_key: request_compressor_enabled

gzip周りの設定は spec. configPatches[0].patch.value に書かれています。
各値に関しては公式のドキュメントを参照します。
ひとつ注意するところとしては今自分がどのバージョンの Envoy のドキュメントを見ているかは最初に確認します。
これをしないと設定できない項目を設定しようとして反映されない。。。なんでだろう。。。と悩むことになります。
www.envoyproxy.io

今回は Content-Type が text/html, text/css, application/javascript の時に gzip 圧縮を Envoy 側でかけるようにしています。

実際にこれが適用されるアプリケーションは spec.workloadSelector をみます。
ここに記載されている labels が Pod のラベルと照合されます。
EnvoyFilter は namespace ごとに配置されており今回は sample-app という namespace に適用します。
そのため、今回の gzip 圧縮は sample-app という namespace で istio-proxy がサイドカーとして動いている app: sample-app というラベルをもった Pod に適用されます。

適用自体は kubectl apply すると適用されます。

適用されたかの確認は kubectl exec -it [Pod名] -c istio-proxy -- curl -s localhost:15000/config_dump で確認することができます。
envoy.filters.http.compressorgrep とかすると設定した値が反映されている箇所が見つかるはずです。

設定に不備により適用されない時は kubectl apply 時に istiod のログをみると Proto constraint validation failed など原因が見つかるかもしれません。

Istio Ingress Gatewayサイドカーgzip 圧縮

Istio Ingress Gatewayサイドカーに適用する場合はアプリケーション側の YAML から大きな変更はなくて context を SIDECAR_INBOUND から GATEWAY に変更して namespace と label を Istio Ingress Gateway に合わせるだけです。

 kind: EnvoyFilter
 metadata:
   name: gzip
-  namespace: sample-app
+  namespace: istio-system
 spec:
   workloadSelector:
     labels:
       # Pod's Label
-      app: sample-app
+      app: istio-ingressgateway
   configPatches:
     - applyTo: HTTP_FILTER
       match:
-        context: SIDECAR_INBOUND
+        context: GATEWAY
         listener:
           filterChain:
             filter:

最後に

今回は EnvoyFilter を作ってみましたが、結構楽しいので色々試して活用していきたい。