Dynamic modules (Rust HTTP filter)
This sandbox demonstrates a basic Envoy dynamic module written in Rust with the Rust SDK.
Dynamic modules are shared libraries that Envoy loads at runtime, and are the recommended way of extending Envoy with custom code without recompiling it.
In this example, the module is loaded by an HTTP filter which adds a header to, and appends some text to the body of, responses proxied by Envoy.
The module is built from source in the first stage of a
multi-stage Docker build, so no build tools are required on the host, and no prebuilt binaries are
shipped with the example.
Note
The Rust SDK is consumed as a git dependency on the Envoy repository,
pinned in the example’s Cargo.toml:
8[dependencies]
9# The SDK is consumed as a git dependency as it is not published to crates.io.
10#
11# The pinned revision should be kept in sync with the Envoy image used in
12# `Dockerfile-proxy` - ie the SDK version must match the ABI version of the
13# Envoy binary that loads the module.
14envoy-proxy-dynamic-modules-rust-sdk = { git = "https://github.com/envoyproxy/envoy", rev = "726d7acb73934085cbbccc83ea47fdd78b583d7e" }
15serde = { version = "1.0", features = ["derive"] }
The SDK version must match the ABI version of the Envoy binary that loads the module - the pinned
revision should be kept in sync with the Envoy image used in
Dockerfile-proxy.
Per the ABI compatibility policy, a module built with the SDK for a given Envoy version keeps working with later Envoy versions, but not necessarily with earlier ones.
Step 1: Start all of our containers
First lets start the containers - an Envoy proxy which loads the dynamic module, and a backend which echos back our request.
The module is compiled in the first stage of the proxy image build, which may take a few minutes the first time it is run.
Change to the dynamic-mod-rust directory, and start the composition:
$ pwd
examples/dynamic-mod-rust
$ docker compose pull
$ docker compose up --build -d
$ docker compose ps
NAME COMMAND SERVICE STATUS
dynamic-mod-rust-proxy-1 "/docker-entrypoint.…" proxy Up
dynamic-mod-rust-web_service-1 "/bin/echo-server" web_service Up
Step 2: Check web response
The module appends Hello from the Rust dynamic module to the body of every response from the
upstream service.
$ curl -s http://localhost:10000 | grep "Hello"
Hello from the Rust dynamic module
It also adds an x-dynamic-module header to the response.
$ curl -sI http://localhost:10000 | grep "x-dynamic-module"
x-dynamic-module: FOO
Both the header and the appended body text are set in the filter_config of the
envoy.yaml configuration, which Envoy passes to
the module as JSON:
27 - name: envoy.filters.http.dynamic_modules
28 typed_config:
29 "@type": type.googleapis.com/envoy.extensions.filters.http.dynamic_modules.v3.DynamicModuleFilter
30 dynamic_module_config:
31 # Loads `libdynamic_mod_rust.so` from `ENVOY_DYNAMIC_MODULES_SEARCH_PATH`.
32 name: dynamic_mod_rust
33 # The name of the filter to instantiate, as dispatched by the module's
34 # `new_http_filter_config_fn`.
35 filter_name: response_mutation
36 # The configuration passed to the filter - a `google.protobuf.Struct` is
37 # received by the module as JSON.
38 filter_config:
39 "@type": type.googleapis.com/google.protobuf.Struct
40 value:
41 response_header_name: x-dynamic-module
42 response_header_value: FOO
43 response_body_suffix: "Hello from the Rust dynamic module\n"
Step 3: Update the filter configuration
Stop the proxy server and change the value of the response_header_value in the filter_config
of envoy.yaml from FOO to BAR:
$ docker compose stop proxy
$ sed -i s/FOO/BAR/ envoy.yaml
Now, rebuild and start the proxy container:
$ docker compose up --build --force-recreate -d proxy
As the module itself is unchanged, its build is fully cached, and only the Envoy configuration is updated in the rebuilt image.
Step 4: Check the proxy has been updated
The response header set by the module should have changed:
$ curl -sI http://localhost:10000 | grep "x-dynamic-module"
x-dynamic-module: BAR
Tip
You can also change the behavior of the module itself by editing
src/lib.rs and rebuilding the proxy in the
same way - in this case the module is recompiled as part of the image build.
See also
- Dynamic modules
Overview of Envoy’s dynamic modules, including the ABI compatibility policy.
- Dynamic module HTTP filter API
The API for configuring HTTP filter dynamic modules.
- Rust SDK
The Rust SDK for Envoy dynamic modules.
- Dynamic modules examples
Further examples of Envoy dynamic modules.