---
# System prepended metadata

title: Istio Compression

---

Istio Compression
==

## 前置作業
* 確認 ServiceMesh 所需的四個 Operator 存在

| Operator 名稱            | Namespace                     | 用途      |
| ---------------------- | ----------------------------- | ------- |
| Elasticsearch Operator | openshift-operators-redhat    | 日誌索引    |
| Jaeger Operator        | openshift-distributed-tracing | 分散追蹤    |
| Kiali Operator         | openshift-distributed-tracing | 可視化流量監控 |
| Service Mesh Operator  | openshift-operators           | 主體控制元件  |

```shell=
oc get operators | egrep 'servicemesh|kiali|elasticsearch|jaeger'

elasticsearch-operator.openshift-operators-redhat                 2y123d
jaeger-product.openshift-distributed-tracing                      2y123d
kiali-ossm.kiali                                                  74d
kiali-ossm.olm-test                                               74d
kiali-ossm.openshift-operators                                    2y123d
servicemeshoperator.olm-test                                      74d
servicemeshoperator.openshift-operators                           2y123d
servicemeshoperator3.openshift-operators                          74d
```

## 安裝 Istio
### 建立 SMCP / SMMR
### SMCP
```yaml=
apiVersion: maistra.io/v2
kind: ServiceMeshControlPlane
metadata:
  name: basic
  namespace: servicemesh
spec:
  version: v2.5
  tracing:
    type: Jaeger
  addons:
    kiali:
      enabled: true
  security:
    controlPlane:
      mtls: true
  gateways:
    ingress:
      enabled: true
      runtime:
        container:
          resources:
            requests:
              cpu: 100m
              memory: 128Mi
        deployment:
          autoScaling:
            enabled: false
      service:
        type: ClusterIP
```
### SMMR
#### 【SMMR】 - 透過 Namespace 選擇
```yaml=
apiVersion: maistra.io/v1
kind: ServiceMeshMemberRoll
metadata:
  name: default
  namespace: servicemesh   # ← 必須與 SMCP 同命名空間
spec:
  members:
    - alex-test-1     # 這種做法是透過 member selector 直接選 namespace
```
#### 【SMMR】 - 透過 Label 選擇
```yaml=
apiVersion: maistra.io/v1
kind: ServiceMeshMemberRoll
metadata:
  name: default
  namespace: servicemesh   # ← 必須與 SMCP 同命名空間
spec:
  memberSelectors:
    - matchLabels:
        istio-injection: "enabled"
```

### 確認 Istio 狀態
* 看 ServiceMesh Control Planes 建立狀態
* 確認在 `servicemesh` 中建立出 control planes
    ```shell=
    oc get servicemeshcontrolplanes -n servicemesh
    
    NAME    READY   STATUS            PROFILES      VERSION   AGE
    basic   9/9     ComponentsReady   ["default"]   2.5.2     2d20h
    ```
* 看 ServiceMesh Member Roll
    ```shell=
    oc get smmr -n servicemesh
    
    NAME      READY   STATUS       AGE
    default   4/4     Configured   24h
    ```

### 建立被監控 Workload
* 建立新的 project
* 切換指令預設 ns
* 將 ns 標上 `istio-injection=enabled`
```shell=
oc new-project alex-test-1
oc project alex-test-1

oc label namespace alex-test-1 istio-injection=enabled --overwrite
oc 
```
 
### 建立 nginx server / `nginx-deployment.yaml`
* 在剛建立的 project 中，建立 Nginx
```yaml=
apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-dep
  namespace: alex-test-1
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx-dep
  template:
    metadata:
      labels:
        app: nginx-dep
    spec:
      containers:
      - name: nginx-dep
        image: quay.kyndryl.tw/alex/nginx-unprivileged:1.25.3
        ports:
        - containerPort: 8080
        resources:
          requests:
            cpu: 50m
            memory: 64Mi
          limits:
            cpu: 200m
            memory: 128Mi
---
apiVersion: v1
kind: Service
metadata:
  name: nginx-service-2
  namespace: alex-test-1
spec:
  type: ClusterIP
  ports:
  - port: 80
    targetPort: 8080
    protocol: TCP
    name: http
  selector:
    app: nginx-dep
---
apiVersion: route.openshift.io/v1
kind: Route
metadata:
  name: nginx-route-2
spec:
  to:
    kind: Service
    name: nginx-service-2
    weight: 100
  port:
    targetPort: http
  tls:
    insecureEdgeTerminationPolicy: Redirect
    termination: edge
  wildcardPolicy: None
```
## 建立 Istio 入口
### VitualService / Gateway
* 建立 gateway 並引導流量
* 用 `oc get pods --show-labels` 
    ```yaml=
    oc get pod -n servicemesh --show-labels | grep ingress;
    ```
* Label 也可以用指令確認
```shell=
oc get deployment -n servicemesh istio-ingressgateway -o jsonpath='{.spec.template.metadata.labels}{"\n"}'

# 輸出結果
{"app":"istio-ingressgateway","istio":"ingressgateway","istio.io/rev":"basic","maistra-control-plane":"servicemesh","maistra.io/gateway":"istio-ingressgateway.servicemesh","service.istio.io/canonical-name":"istio-ingressgateway","service.istio.io/canonical-revision":"basic","sidecar.istio.io/inject":"false"}
```

```yaml=
apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:
  name: nginx-gateway            # 幫 gateway 取名字
  namespace: alex-test-1      # 放置的 ns
spec:
  selector:
    istio: ingressgateway        # 要跟 istio 的 ingressgateway Pod label 一致
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - alex-nginx-istio.apps.thsr.kyndryl.tw   # 綁定你的外部域名
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: nginx
  namespace: alex-test-1      # 要跟 GW 放在一起
spec:
  hosts:
  - alex-nginx-istio.apps.thsr.kyndryl.tw     # 與 Gateway 一致
  gateways:
  - nginx-gateway
  http:
  - route:
    - destination:
        host: nginx-service.alex-test-1.svc.cluster.local  # 寫「K8s Service 名稱」-> svc名稱.ns名稱.svc.cluster.local
        port:
          number: 80
```

## Check Point 1
* 先確認服務可以分別從下方兩路進行連線
    * 不透過 Istio 進入
        * https://nginx-route-2-alex-test-1.apps.thsr.kyndryl.tw/
    * 透過 Istio 的入口連入
        * http://alex-nginx-istio.apps.thsr.kyndryl.tw/
### 如果沒有成功注入...
* 在 Deployment 加入下列 annotation
    ```shell=
    oc patch deploy nginx-dep -n alex-test-1 \
      -p '{
      "spec": {
        "template": {
          "metadata": {
            "annotations": {
              "sidecar.istio.io/inject": "true"
            }
          }
        }
      }
    }'
    deployment.apps/nginx-dep patched
    ```
    > 如果一開始沒有使用 Sidecar 且初次啟用 Sidecar，則必定會重啟 Pods
    > 若需避免服務中斷，則需透過 
    > `oc rollout restart deployment nginx-dep -n alex-test-1`
    > Pods 會以 Rollout 方式重啟 / 服務不中斷但會觸發告警



## 啟用 Gzip
### EnvoyFilter 的設定
```yaml=
# EnvoyFilter: 對應 alex-test-1/nginx-gateway listener 啟用 gzip 壓縮
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: enable-gzip-nginx
  namespace: servicemesh
spec:
  workloadSelector:
    labels:
      app: istio-ingressgateway
  configPatches:
    - applyTo: HTTP_FILTER
      match:
        context: GATEWAY
        listener:
          filterChain:
            filter:
              name: envoy.filters.network.http_connection_manager
              subFilter:
                name: envoy.filters.http.router
          listenerFilterChain:
            filter:
              name: "envoy.filters.network.http_connection_manager"
      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: gzip
              typed_config:
                "@type": type.googleapis.com/envoy.extensions.compression.gzip.compressor.v3.Gzip
                memory_level: 9
                compression_level: BEST_COMPRESSION
                compression_strategy: DEFAULT_STRATEGY
            response_direction_config:
              common_config:
                min_content_length: 100    # 壓縮太小的，省不了傳輸量，還耗費 CPU 意義不大
                content_type:
                  - text/html
                  - text/plain
                  - text/css
                  - application/javascript
                  - application/json
```

### 確認修改 EnvoyFilter 不會重啟 Pod
    ```shell=
    ❯ oc get pods
    NAME                        READY   STATUS    RESTARTS   AGE
    nginx-689dd8dfb9-j52x6      2/2     Running   0          74m
    nginx-dep-6dc797957-skpv9   2/2     Running   0          56m
    ```

### 驗證壓縮功能
* GET `envoyfilter`
    ```shell=
    ❯ oc get envoyfilter -n servicemesh

    NAME                              AGE
    enable-gzip-nginx                 20s
    metadata-exchange-1.6-basic       7d10h
    stats-filter-1.6-basic            7d10h
    tcp-metadata-exchange-1.6-basic   7d10h
    tcp-stats-filter-1.6-basic        7d10h
    ```
* curl 請求，發現 `vary: Accept-Encoding`
    ```shell=
    # 測試指令
    HOST=alex-nginx-istio.apps.thsr.kyndryl.tw
    curl -sS -D - -o /dev/null -H 'Accept-Encoding: gzip' "http://$HOST/"

    # 結果如下
    HTTP/1.1 200 OK
    server: istio-envoy
    date: Tue, 25 Nov 2025 17:17:21 GMT
    content-type: text/html
    last-modified: Tue, 24 Oct 2023 13:46:47 GMT
    accept-ranges: bytes
    x-envoy-upstream-service-time: 2
    content-encoding: gzip
    vary: Accept-Encoding
    transfer-encoding: chunked
    set-cookie: 8163d0087b0b21765b4a8ecc72ffb1ac=3e288abbac618d5602454d79f23c0816; path=/; HttpOnly
    cache-control: private
    ```
    * 預期結果如果有 `content-encoding: gzip` 表示傳輸有被壓縮
    * `envoy.filters.http.compressor` 預設只壓縮超過 min_content_length 的 Content-Type
    * min_content_length 先前給了 100，上述 `content-length: 615`， 615 > 100 所以會觸發壓縮
    ![image](https://hackmd.io/_uploads/r1mt90h6xl.png)

## 測試
* 找出入口 ... 在 `alex-nginx-istio.apps.thsr.kyndryl.tw`
    ```shell=
    oc get routes -n servicemesh
    NAME                                         HOST/PORT                                               PATH   SERVICES               PORT          TERMINATION          WILDCARD
    alex-test-1-nginx-gateway-4897fe2ae11e0c79   alex-nginx-istio.apps.thsr.kyndryl.tw                          istio-ingressgateway   http2                              None
    grafana                                      grafana-servicemesh.apps.thsr.kyndryl.tw                       grafana                <all>         reencrypt/Redirect   None
    istio-ingressgateway                         istio-ingressgateway-servicemesh.apps.thsr.kyndryl.tw          istio-ingressgateway   8080                               None
    jaeger                                       jaeger-servicemesh.apps.thsr.kyndryl.tw                        jaeger-query           https-query   reencrypt            None
    kiali                                        kiali-servicemesh.apps.thsr.kyndryl.tw                         kiali                  20001         reencrypt/Redirect   None
    prometheus                                   prometheus-servicemesh.apps.thsr.kyndryl.tw                    prometheus             <all>         reencrypt/Redirect   None
    ```

* 每秒 100 次請求為例
```shell=
#!/usr/bin/env bash

HOST=alex-nginx-istio.apps.thsr.kyndryl.tw
echo "Target Host: $HOST"
echo "Press Ctrl+C to stop."

while true; do
  for i in {1..100}; do
    curl -s -o /dev/null -H 'Accept-Encoding: gzip' "http://$HOST/" &
  done
  wait
  sleep 1
done
```
* 在 Kalia 觀測
![image](https://hackmd.io/_uploads/B1UQcyapex.png)


## 效能檢查
* 在 Kiali/Prometheus 觀察 istio-proxy 的 CPU、延遲。壓縮會增加 CPU。
* 用 envoy admin（localhost:15000/config_dump）確認 filter 已插入（在 router 之前）。

## Ref
* https://imroc.cc/istio/usage/enable-gzip 
* https://access.redhat.com/articles/6972785

