'Use Envoy for Blue/Green Deployment
I am trying to understand if it would be possible to use Envoy proxy to route traffic between services based on the custom logic.
In the example, I found: https://www.tetrate.io/blog/envoy-101-configuring-envoy-as-a-gateway/ Envoy has a defined config file to route the request to the right instance after performing certain filtering.
Would it be possible to write a custom javascript/python logic for the routing?
E.g. take param from the query string and lookup database mapping to make a decision where to route the request.
Solution 1:[1]
You can introduce custom logic with Lua filter, but not directly with pure Javascript or Python. Also, instead of Lua filter, maybe Wasm filter can suit your needs. I have not tested it and it's experimental, so I don't know if it works in your case.
Anyway, the following example is a base config to showcase what you can do with Lua filter (envoy.filters.http.lua
section). It:
- parses the
path
(something like/something?param=1&other=xxx
) - retrieves the
param
field - adds it in a header (
X-App
) used in the route matching (param=1
will redirect traffic to clusterfirst
andparam=2
will redirect traffic to clustersecond
; other values will redirect traffic to clusterfirst
by default)
Of course, here I have used a Lua filter to allow you to add some other custom logic.
static_resources:
listeners:
- address:
socket_address:
address: 0.0.0.0
port_value: 8080
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
codec_type: AUTO
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: backend
domains:
- "*"
routes:
- match:
prefix: "/"
headers:
- name: "X-App"
string_match: # with envoy < 1.22.0, use exact_match: "1" instead
exact: "1"
route:
cluster: first
- match:
prefix: "/"
headers:
- name: "X-App"
string_match: # with envoy < 1.22.0, use exact_match: "2" instead
exact: "2"
route:
cluster: second
- match: # default, if no headers
prefix: "/"
route:
cluster: first
http_filters:
- name: envoy.filters.http.lua
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua
inline_code: |
function envoy_on_request(request_handle)
path = request_handle:headers():get(":path")
param_value = string.match(path, '/.*[?&]param=([^&]+)')
if param_value then
request_handle:headers():add("X-App", param_value)
end
end
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
- name: first
connect_timeout: 5s
type: LOGICAL_DNS
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: first
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: first
port_value: 5000
- name: second
connect_timeout: 5s
type: LOGICAL_DNS
lb_policy: ROUND_ROBIN
load_assignment:
cluster_name: second
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: second
port_value: 5000
You can also do some canary traffic routing with a random number (here 50/50):
function envoy_on_request(request_handle)
math.randomseed(os.clock())
-- math.random() returns a number in [0;1)
if math.random() < 0.5 then
request_handle:headers():add("x-app", "1")
else
request_handle:headers():add("x-app", "2")
end
end
But note that Lua is very limited when used in Envoy filter (I'm not sure but it looks like you can't install external packages/modules), and you probably won't be able to query a database to make your routing decision. You should take a look at Wasm filter, it may work for this.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 |