はじめに
こちらの記事は以前に公開した "wasme を利用した Wasm Filter 開発と Istio の Envoy にデプロイするまでの流れ" の続編となります。
前回の記事では wasme という CLI を利用することで Envoy の Wasm Filter の開発とデプロイを簡単に行えることを紹介しましたが、wasme 自体は Wasm Filter の開発やテストで利用することが想定されているもので、本番環境の Kubernetes クラスタで稼働する Envoy へのデプロイは Wasme Operator を利用して Custom Resource で宣言的に管理することが推奨されています。
Wasme Operator について
引用: Declarative WebAssembly deployment for Istio
Wasme Operator は、WebAssembly Hub などのレジストリから Wasm Filter イメージをダウンロードして Node にキャッシュする wasme-cache
と、Wasm Filter を Envoy にデプロイする wasme-operator
の2つのコンポーネントで構成されており、各コンポーネントはデフォルトで wasme
ネームスペースで稼働する仕様になっています。
各コンポーネントのソースコードは solo-io/wasm の tools/wasme ディレクトリ で管理されており、wasme-cache
は wasme の cache サブコマンドで、wasme-operator
は operator サブコマンドで起動されています。
現時点では Wasme Operator がサポートするデプロイ対象は Istio のみとなっており、Kubernetes クラスタに Istio(具体的には EnvoyFilter
リソース)がインストールされていない場合は処理が失敗するので注意してください。
Wasme Operator が稼働している状態で FilterDeployment
リソース(CRD は こちら, Spec/Status の詳細は こちら)を Kubernetes クラスタに作成することで、自動で Istio 内の Envoy に Wasm Filter がデプロイすることが可能になります。
それでは実際に動かしてみて Wasme Operator がどのように機能するのかを見ていきます。
実際に動かしてみる
Wasme Operator は2020年10月29日時点での最新バージョン v0.0.28
を利用します。
Istio がインストールされた Kuberntes クラスタの作成
Kubernetes クラスタ 1.18.0 を作成します。
minikube start --kubernetes-version v1.18.0
Istio 1.5.6 をインストールします。今回デプロイする Wasm Filter が 1.5.x に互換性があるものなので少々古いバージョンとなりますが 1.5.6 を利用しています。
istioctl manifest apply --set profile=demo
バージョンを確認します。
$ kubectl version --short
Client Version: v1.19.0
Server Version: v1.18.0
$ istioctl version
client version: 1.5.6
control plane version: 1.5.6
data plane version: 1.5.6 (3 proxies)
Wasme Operator のインストール
FilterDeployment
リソースの CRD をインストールします。
kubectl apply -f https://github.com/solo-io/wasm/releases/download/v0.0.28/wasme.io_v1_crds.yaml
Wasme Operator をインストールします。
kubectl apply -f https://github.com/solo-io/wasm/releases/download/v0.0.28/wasme-default.yaml
wasme-cache
は DaemonSet で wasme-operator
は Deployment でデプロイされます。
$ kubectl get all -n wasme
NAME READY STATUS RESTARTS AGE
pod/wasme-cache-drjbd 1/1 Running 0 50s
pod/wasme-operator-7b9c77976b-zlmv8 1/1 Running 0 50s
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
daemonset.apps/wasme-cache 1 1 1 1 1 <none> 50s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/wasme-operator 1/1 1 1 50s
NAME DESIRED CURRENT READY AGE
replicaset.apps/wasme-operator-7b9c77976b 1 1 1 50s
サンプルアプリのデプロイ
Wasm Filter のデプロイ対象のサンプルアプリとして Bookinfo(solo-io/wasm の e2e テスト用のマニフェストを利用)をデプロイします。
kubectl create ns bookinfo
kubectl label namespace bookinfo istio-injection=enabled --overwrite
kubectl apply -n bookinfo -f https://raw.githubusercontent.com/solo-io/wasm/v0.0.28/tools/wasme/cli/test/e2e/operator/bookinfo.yaml
Bookinfo のアプリ内の Envoy へのリクエスト方法は以下となります。
kubectl exec -ti -n bookinfo deploy/productpage-v1 -c istio-proxy -- curl -I http://details.bookinfo:9080/details/123
この時点での HTTP レスポンスヘッダーは以下となります。
$ kubectl exec -ti -n bookinfo deploy/productpage-v1 -c istio-proxy -- curl -I http://details.bookinfo:9080/details/123
HTTP/1.1 200 OK
content-type: application/json
server: istio-envoy
date: Thu, 29 Oct 2020 09:40:51 GMT
content-length: 180
x-envoy-upstream-service-time: 1
x-envoy-peer-metadata: Ch0KDElOU1RBTkNFX0lQUxINGgsxNzIuMTcuMC4xMwrVAQoGTEFCRUxTEsoBKscBChAKA2FwcBIJGgdkZXRhaWxzCiEKEXBvZC10ZW1wbGF0ZS1oYXNoEgwaCjZmYzU1ZDY1YzkKJAoZc2VjdXJpdHkuaXN0aW8uaW8vdGxzTW9kZRIHGgVpc3RpbwosCh9zZXJ2aWNlLmlzdGlvLmlvL2Nhbm9uaWNhbC1uYW1lEgkaB2RldGFpbHMKKwojc2VydmljZS5pc3Rpby5pby9jYW5vbmljYWwtcmV2aXNpb24SBBoCdjEKDwoHdmVyc2lvbhIEGgJ2MQoaCgdNRVNIX0lEEg8aDWNsdXN0ZXIubG9jYWwKJQoETkFNRRIdGhtkZXRhaWxzLXYxLTZmYzU1ZDY1YzkteHBoemwKFwoJTkFNRVNQQUNFEgoaCGJvb2tpbmZvCk8KBU9XTkVSEkYaRGt1YmVybmV0ZXM6Ly9hcGlzL2FwcHMvdjEvbmFtZXNwYWNlcy9ib29raW5mby9kZXBsb3ltZW50cy9kZXRhaWxzLXYxCiUKD1NFUlZJQ0VfQUNDT1VOVBISGhBib29raW5mby1kZXRhaWxzCh0KDVdPUktMT0FEX05BTUUSDBoKZGV0YWlscy12MQ==
x-envoy-peer-metadata-id: sidecar~172.17.0.13~details-v1-6fc55d65c9-xphzl.bookinfo~bookinfo.svc.cluster.local
x-envoy-decorator-operation: details.bookinfo.svc.cluster.local:9080/*
Wasm Filter のデプロイ
今回は前回の記事で開発した HTTP レスポンスに hello
というヘッダーを追加する Wasm Filter である webassemblyhub.io/ryysud/custom-header:v0.1 を Istio 内の Envoy にデプロイしていきます。
FilterDeployment
リソースは以下のようになります。
apiVersion: wasme.io/v1
kind: FilterDeployment
metadata:
name: bookinfo-custom-filter
namespace: bookinfo
spec:
deployment:
istio:
kind: Deployment
filter:
image: webassemblyhub.io/ryysud/custom-header:v0.1
上記のリソースを作成します。
cat << EOF | kubectl apply -f -
apiVersion: wasme.io/v1
kind: FilterDeployment
metadata:
name: bookinfo-custom-filter
namespace: bookinfo
spec:
deployment:
istio:
kind: Deployment
filter:
image: webassemblyhub.io/ryysud/custom-header:v0.1
EOF
リソースが作成されると wasme-cache
による Wasm Filter イメージのキャッシュが完了した後に、wasme-operator
による Envoy への Wasm Filter のデプロイが開始されます。
Wasm Filter のデプロイは、Node にキャッシュされたイメージを Envoy コンテナに hostPath でマウントするために Istio 仕様の Annotation である sidecar.istio.io/userVolume と sidecar.istio.io/userVolumeMount をアプリの Deployment マニフェストに追加(このタイミングでアプリの Pod がローリングアップデートする)して、Wasm Filter を Envoy で使用する設定を定義した EnvoyFilter
リソースを子リソースとして作成するという流れになります。
以下は FilterDeployment
リソースの子リソースとして作成された EnvoyFilter
リソースとなります。Spec から Wasm Filter が Envoy に設定されることがわかります。
$ kubectl tree -n bookinfo filterdeployment bookinfo-custom-filter
NAMESPACE NAME READY REASON AGE
bookinfo FilterDeployment/bookinfo-custom-filter - 5m54s
bookinfo ├─EnvoyFilter/details-v1-bookinfo-custom-filter.bookinfo - 5m24s
bookinfo └─EnvoyFilter/productpage-v1-bookinfo-custom-filter.bookinfo - 5m24s
$ kubectl get envoyfilters.networking.istio.io -n bookinfo
NAME AGE
details-v1-bookinfo-custom-filter.bookinfo 3m12s
productpage-v1-bookinfo-custom-filter.bookinfo 3m12s
$ kubectl get envoyfilters.networking.istio.io -n bookinfo details-v1-bookinfo-custom-filter.bookinfo -o yaml | kubectl neat
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
name: details-v1-bookinfo-custom-filter.bookinfo
namespace: bookinfo
spec:
configPatches:
- applyTo: HTTP_FILTER
match:
context: SIDECAR_INBOUND
listener:
filterChain:
filter:
name: envoy.http_connection_manager
subFilter:
name: envoy.router
patch:
operation: INSERT_BEFORE
value:
config:
config:
name: bookinfo-custom-filter.bookinfo
rootId: add_header
vmConfig:
code:
local:
filename: /var/local/lib/wasme-cache/a515a5d244b021c753f2e36c744e03a109cff6f5988e34714dbe725c904fa917
runtime: envoy.wasm.runtime.v8
vmId: bookinfo-custom-filter.bookinfo
name: envoy.filters.http.wasm
workloadSelector:
labels:
app: details
version: v1
また、Wasm Filter のデプロイ状況は作成した FilterDeployment
リソースの Status からも確認できます。
# 余計な情報は削除しています
$ kubectl get filterdeployments.wasme.io -n bookinfo -o yaml bookinfo-custom-filter
apiVersion: wasme.io/v1
kind: FilterDeployment
metadata:
name: bookinfo-custom-filter
namespace: bookinfo
spec:
deployment:
istio:
kind: Deployment
filter:
image: webassemblyhub.io/ryysud/custom-header:v0.1
status:
observedGeneration: "1"
workloads:
details-v1:
state: Succeeded
productpage-v1:
state: Succeeded
最後に Wasm Filter がデプロイされたかを確認します。
$ kubectl exec -ti -n bookinfo deploy/productpage-v1 -c istio-proxy -- curl -I http://details.bookinfo:9080/details/123
HTTP/1.1 200 OK
content-type: application/json
server: istio-envoy
date: Thu, 29 Oct 2020 09:55:32 GMT
content-length: 180
x-envoy-upstream-service-time: 1
hello: world! # <----- Wasm Filter によって `hello` ヘッダーが追加されている
x-envoy-peer-metadata: Ch0KDElOU1RBTkNFX0lQUxINGgsxNzIuMTcuMC4xNwrVAQoGTEFCRUxTEsoBKscBChAKA2FwcBIJGgdkZXRhaWxzCiEKEXBvZC10ZW1wbGF0ZS1oYXNoEgwaCjdiYjg0Njk5YjQKJAoZc2VjdXJpdHkuaXN0aW8uaW8vdGxzTW9kZRIHGgVpc3RpbwosCh9zZXJ2aWNlLmlzdGlvLmlvL2Nhbm9uaWNhbC1uYW1lEgkaB2RldGFpbHMKKwojc2VydmljZS5pc3Rpby5pby9jYW5vbmljYWwtcmV2aXNpb24SBBoCdjEKDwoHdmVyc2lvbhIEGgJ2MQoaCgdNRVNIX0lEEg8aDWNsdXN0ZXIubG9jYWwKJQoETkFNRRIdGhtkZXRhaWxzLXYxLTdiYjg0Njk5YjQtNzdqN2YKFwoJTkFNRVNQQUNFEgoaCGJvb2tpbmZvCk8KBU9XTkVSEkYaRGt1YmVybmV0ZXM6Ly9hcGlzL2FwcHMvdjEvbmFtZXNwYWNlcy9ib29raW5mby9kZXBsb3ltZW50cy9kZXRhaWxzLXYxCiUKD1NFUlZJQ0VfQUNDT1VOVBISGhBib29raW5mby1kZXRhaWxzCh0KDVdPUktMT0FEX05BTUUSDBoKZGV0YWlscy12MQ==
x-envoy-peer-metadata-id: sidecar~172.17.0.17~details-v1-7bb84699b4-77j7f.bookinfo~bookinfo.svc.cluster.local
x-envoy-decorator-operation: details.bookinfo.svc.cluster.local:9080/*
レスポンスを見てみると hello
ヘッダーが追加されていることから、Wasm Filter が正常にデプロイできたことが確認できました。
さいごに
今回は Wasme Operator を利用して Kubernetes クラスタへの Wasm Filter のデプロイを Custom Resource で宣言的に管理する方法を紹介しました。Wasm Filter の本番運用を検討している場合には Wasme Operator の導入を検討すると良いでしょう。