Introduction
To customize error messages for upstream services in a Consul Service Mesh using Envoy involves leveraging EnvoyExtensions and Envoy's rich error handling capabilities. Envoy is a powerful proxy that can be configured to handle HTTP responses, including error codes, and allow customization of error messages for various scenarios such as 503 Service Unavailable, 404 Not Found, or 502 Bad Gateway errors.
With EnvoyExtension, the user can modify the behaviour of Envoy at runtime without modifying the core Consul or Envoy configurations directly. This makes it flexible and suitable for service mesh environments like Consul where service traffic is routed via Envoy proxies.
Expected Outcome
The expected outcome to customize error messages for any upstream service is that when an upstream service is unavailable (or any other error condition occurs), the Envoy proxy (which acts as a gateway or sidecar in Consul's service mesh) will return a custom error message instead of the default HTTP error page or message. Specifically, the user can modify the response body, the status code, or the response headers.
Example:
Let’s say if the user tries to customize the response body while hitting API GW endpoint for upstream service which is either unreachable or stopped.
Without Customization (default 503 message):
curl -i http://your-api-gateway/your-endpoint
HTTP/1.1 503 Service Unavailable
Date: Mon, 01 Jan 2024 12:00:00 GMT
Content-Type: text/html
Content-Length: 42
Connection: close
Service Temporarily Unavailable
With Lua Customization (custom 503 message):
curl -i http://your-api-gateway/your-endpoint
HTTP/1.1 503 Service Unavailable
Date: Mon, 01 Jan 2024 12:00:00 GMT
Content-Type: application/json
Content-Length: 77
Connection: close
{
"message": "Service temporarily unavailable. Please try again later."
}
Prerequisites (if applicable)
-
Ensure that the Consul is installed and running in your environment. User can either run it on-premises, in a cloud VM, or within a Kubernetes cluster.
-
User may follow any of the below guides to setup Consul on K8s cluster and provide or control access to services inside the mesh.
Configure Terminating Gateways for Consul on Kubernetes | Consul | HashiCorp Developer
Control access into the service mesh with Consul API gateway | Consul | HashiCorp Developer
Procedure
Step 1: Write a Lua Script for Custom Error Messages
Using Lua Envoy Extension document examples, the user would be creating one ProxyDefaults
CRD to pass the following Lua script to customize the message body for a URI or page/endpoint which doesn’t exist.
proxy_default_envoy_extension_custom_response.yaml
apiVersion: consul.hashicorp.com/v1alpha1
kind: ProxyDefaults
metadata:
name: global
spec:
config:
protocol: http
envoyExtensions:
- name: "builtin/lua"
required: true
arguments:
proxyType: "connect-proxy"
listener: "outbound"
script: |-
function envoy_on_response(response_handle)
if response_handle:headers():get(":status") == "404" then
response_handle:headers():replace(":status", "404")
response_handle:body():setBytes("Please check whether page or URI is configured correctly or not.")
end
end
In the above Lua script the user has modified the response body for 404
error code (where he would be hitting a non-existent page as it would be an outbound connection).
Step 2: Apply the ProxyDefault with EnvoyExtension to the cluster
% kubectl apply -f proxy_default_envoy_extension_custom_response.yaml
proxydefaults.consul.hashicorp.com/global configured
Step3: Connect to the downstream service and try to hit a non-existent page to test the customization
Once the above changes are applied, the user may exec to any downstream service and try to hit the upstream service by appending any non-existent page in the URI. Then he will get the following results in the output to validate the response body consists of the customized error message which he passed through EnvoyExtension reference.
% curl --header "Host: jsonplaceholder.typicodes.com" http://localhost:1234/non-existent-page
Please check whether page or URI is configured correctly or not.#
In absence of the customization, the screen would display output with 404 Not Found
error.
Step4: Other Customizations
You can modify the Lua script to handle other error codes, such as 503 Service Unavailable, 502 Bad Gateway, 504 Gateway Timeout, or even 404 Not Found. An example is given below to customize for 503 Service Unavailable
error message.
apiVersion: consul.hashicorp.com/v1alpha1
kind: ProxyDefaults
metadata:
name: global
spec:
config:
protocol: http
envoyExtensions:
- name: "builtin/lua"
required: true
arguments:
proxyType: "connect-proxy"
listener: "outbound"
script: |-
function envoy_on_response(response_handle)
if response_handle:headers():get(":status") == "503" then
response_handle:headers():replace(":status", "503")
response_handle:body():setBytes("Please ensure upstream service is running and reachable")
end
end
Conclusion
By using Lua filters in an EnvoyExtension within Consul, the user can customize the error messages that clients receive when an upstream service fails or returns an error. This allows to:
-
Provide clear, user-friendly messages for clients instead of generic error responses.
-
Customize status codes, response headers, and response bodies based on specific conditions.
-
Dynamically adjust the error messages based on the service that failed, or other request-related details.
Additional Information
Lua Envoy Extension | Consul | HashiCorp Developer
Envoy Proxy Configuration | Service Mesh | Consul | HashiCorp Developer