This the multi-page printable view of this section. Click here to print.
Origins
1 - Rule Backend
The Rule Backend is not really a true Backend; it only routes inbound requests to other configured Backends, based on how they match against the Rule’s cases.
A Rule is a single inspection operation performed against a single component of an inbound request, which determines the Next Backend to send the request to. The Next Backend can also be a rule Backend, so as to route requests through multiple Rules before arriving at a true Backend destination.
A rule can optionally rewrite multiple portions of the request before, during and after rule matching, by using request rewriters, which allows for powerful and limitless combinations of request rewriting and routing.
Rule Parts
A rule has several required parts, as follows:
Required Rule Parts
input_source
- The part of the Request the Rule inspectsinput_type
- The source data typeoperation
- The operation taken on the input sourcenext_route
- The Backend Name indicating the default next route for the Rule if no matching cases. Not required ifredirect_url
is provided.redirect_url
- The fully-qualified URL to issue as a 302 redirect to the client in the default case. Not required ifnext_route
is provided.
Optional Rule Parts
input_key
- case-sensitive lookup key; required when the source isheader
or URLparam
input_encoding
- the encoding of the input, which is decoded prior to performing the operationinput_index
- when > -1, the source is split into parts and the input is extracted from parts[input_index]input-delimiter
- when input_index > -1, this delimiter is used to split the source into parts, and defaults to a standard space (' ‘)ingress_req_rewriter name
- provides the name of a Request Rewriter to operate on the Request before rule execution.egress_req_rewriter name
- provides the name of a Request Rewriter to operate on the Request after rule execution.nomatch_req_rewriter name
- provides the name of a Request Rewriter to operate on the Request after rule execution if the request did not match any cases.max_rule_executions
- limits the number of rules a Request is passed through, and aborts with a 400 status code when exceeded. Default is 16.
input_source permitted values
source name | example extracted value |
---|---|
url | https://example.com:8480/path1/path2?param1=value |
url_no_params | https://example.com:8480/path1/path2 |
scheme | https |
host | example.com:8480 |
hostname | example.com |
port | 8480 (inferred from scheme when no port is provided) |
path | /path1/path2 |
params | ?param1=value |
param | (must be used with input_key as described below) |
header | (must be used with input_key as described below) |
input_type permitted values and operations
type name | permitted operations |
---|---|
string (default) | prefix, suffix, contains, eq, md5, sha1, modulo, rmatch |
num | eq, le, ge, gt, lt, modulo |
bool | eq |
Rule Cases
Rule cases define the possible values are able to alter the Request and change the next route.
Case Parts
Required Case Parts
matches
- A string list of values applicable to this case.next_route
- The Backend Name indicating the next route for the Rule when a request matches this Case. Not required ifredirect_url
is provided.redirect_url
- The fully-qualified URL to issue as a 302 redirect to the client when the Request matches this Case. Not required ifnext_route
is provided.
Optional Case Parts
req_rewriter name
- provides the name of a Request Rewriter to operate on the Request when this case is matched.
Example Rule - Route Request by Basic Auth Username
In this example config, requests routed through the /example
path will be compared against the rules and routed to either the Reader cluster or the Writer cluster. Curling http://trickster-host/example/path
would route to the reader or writer cluster based on a provided Authorization header.
rules:
example-user-router:
# default route is reader cluster
next_route: example-reader-cluster
input_source: header
input_key: Authorization
input_type: string
input_encoding: base64 # Authorization: Basic <base64string>
input_index: 1 # Field 1 is the <base64string>
input_delimiter: ' ' # Authorization Header field is space-delimited
operation: prefix # Basic Auth credentials are formatted as user:pass,
# so we can check if it is prefixed with $user:
cases:
writers:
matches: # route johndoe and janedoe users to writer cluster
- 'johndoe:'
- 'janedoe:'
next_route: example-writer-cluster
backends:
example:
provider: rule
rule_name: example-user-router
example-reader-cluster:
provider: rpc
origin_url: 'http://reader-cluster.example.com'
example-writer-cluster:
provider: rpc
origin_url: 'http://writer-cluster.example.com'
path_routing_disabled: true # restrict routing to this backend via rule only, so
# users cannot directly access via /example-writer-cluster/
Example Rule - Route Request by Path Regex
In this example config, requests routed through the /example
path will be compared against the rules and routed to either the Reader cluster or the Writer cluster. Curling http://trickster-host/example/reader
and http://trickster-host/example/writer
would route to the reader or writer cluster by matching the path.
rules:
example-user-router:
# default route is reader cluster
next_route: example-reader-cluster
input_source: path
input_type: string
operation: rmatch # perform regex match against the path to see if it matches 'writer
operation_arg: '^.*\/writer.*$'
cases:
rmatch-true:
matches: [ 'true' ] # rmatch returns true when the input matches the regex; update next_route
next_route: example-writer-cluster
backends:
example:
provider: rule
rule_name: example-user-router
example-reader-cluster:
provider: rpc
origin_url: 'http://reader-cluster.example.com'
example-writer-cluster:
provider: rpc
origin_url: 'http://writer-cluster.example.com'
path_routing_disabled: true # restrict routing to this backend via rule only, so
# users cannot directly access via /example-writer-cluster/
2 - Supported Providers
Trickster currently supports the following providers:
Generic HTTP Reverse Proxy Cache
Trickster operates as a fully-featured and highly-customizable reverse proxy cache, designed to accelerate and scale upstream endpoints like API services and other simple http services. Specify 'reverseproxycache'
or just 'rpc'
as the Provider when configuring Trickster.
Time Series Databases
Prometheus
Trickster fully supports the Prometheus HTTP API (v1). Specify 'prometheus'
as the Provider when configuring Trickster. Trickster supports label injection for Prometheus.
InfluxDB
Trickster supports for InfluxDB. Specify 'influxdb'
as the Provider when configuring Trickster.
See the InfluxDB Support Document for more information.
ClickHouse
Trickster supports accelerating ClickHouse time series. Specify 'clickhouse'
as the Provider when configuring Trickster.
See the ClickHouse Support Document for more information.
Circonus IRONdb
Support has been included for the Circonus IRONdb time-series database. If Grafana is used for visualizations, the Circonus IRONdb data source plug-in for Grafana can be configured to use Trickster as its data source. All IRONdb data retrieval operations, including CAQL queries, are supported.
When configuring an IRONdb backend, specify 'irondb'
as the provider in the Trickster configuration. The host
value can be set directly to the address and port of an IRONdb node, but it is recommended to use the Circonus API proxy service. When using the proxy service, set the host
value to the address and port of the proxy service, and set the api_path
value to 'irondb'
.
3 - Timeseries Request Sharding
Overview
A shard means “a small part of a whole,” and Trickster 2.0 supports the sharding of upstream HTTP requests when retrieving timeseries data. When configured for a given time series backend, Trickster will shard eligible requests by inspecting the time ranges needed from origin and subdividing them into smaller ranges that conform to the backend’s sharding configuration. Sharded requests are sent to the origin concurrently, and their responses are reconstituted back into a single dataset by Trickster after they’ve all been returned.
Mechanisms
Trickster support three main mechanisms for sharding:
- Maximum Timestamps Per Shard: Trickster calculates the number of expected unique timestamps in the response by dividing the requested time range size by the step cadence, and then subdivides the time ranges so that each sharded request’s time range will return no more timestamps than the configured maximum.
- Maximum Time Range Width Per Shard: Trickster inspects each needed time range, and subdivides them such that each sharded request’s time range duration is no larger than the configured maximum.
- Epoch-Aligned Maximum Time Range Width Per Shard: Trickster inspects each needed time range, and subdivides them such that each sharded request’s time range duration is no larger than the configured maximum, while also ensuring that each shard’s time boundaries are aligned to the Epoch based on the configured shard step size.
Configuring
Maximum Unique Timestamp Count Per Shard
In the Trickster configuration, use the shard_max_size_points
configuration to shard requests by limiting the maximum number of unique timestamps in each sharded response.
backends:
example:
provider: prometheus
origin_url: http://prometheus:9090
shard_max_size_points: 10999
Maximum Time Range Width Per Shard
In the Trickster configuration, use the shard_max_size_ms
configuration to shard requests by limiting the maximum width of each sharded request’s time range.
backends:
example:
provider: 'prometheus'
origin_url: http://prometheus:9090
shard_max_size_ms: 7200000
Epoch-Aligned Maximum Time Range Width Per Shard
In the Trickster configuration, use the shard_step_ms
configuration to shard requests by limiting the maximum width of each sharded request’s time range, while ensuring shards align with the epoch on the configured cadence. This is useful for aligning shard boundaries with an upstream database’s partition boundaries, ensuring that sharded requests have as little partition overlap as possible.
backends:
example:
provider: 'prometheus'
origin_url: http://prometheus:9090
shard_step_ms: 7200000
shard_step_ms
can be used in conjunction with shard_max_size_ms
, so long as shard_max_size_ms
is perfectly divisible by shard_step_ms
. This combination configuration will align shards against the configured shard step, while sizing each shard’s time range to be multiple shard steps wide.
backends:
example:
provider: 'prometheus'
origin_url: http://prometheus:9090
shard_step_ms: 7200000
shard_size_ms: 14400000
Neither shard_step_ms
or shard_max_size_ms
can be used in conjunction with shard_max_size_points
.
4 - TLS Support
Basics
To enable the TLS server, you must specify the tls_listen_port
, and optionally, the tls_listen_address
in the frontend
section of your config file. For example:
frontend:
listen_port: 8480
tls_listen_port: 8483
Note, Trickster only starts listening on the TLS port if at least one origin has a valid certificate and key configured.
Each origin section of a Trickster config file can be augmented with the optional tls
section to modify TLS behavior for front-end and back-end requests. For example:
backends:
example: # example backend
tls: # TLS settings for example backend
# server configs
full_chain_cert_path: '/path/to/my/cert.pem'
private_key_path: '/path/to/my/key.pem'
# back-end configs
insecure_skip_verify: true
certificate_authority_paths: [ '/path/to/ca1.pem', '/path/to/ca2.pem' ]
client_cert_path: '/path/to/client/cert.pem'
client_key_path: '/path/to/client/key.pem'
Server Configuration when responding to clients
Each backend can handle encryption with exactly 1 certificate and key pair, as configured in the TLS section of the backend config (demonstrated above).
If the path to any configured Certificate or Key file is unreachable or unparsable, Trickster will exit upon startup with an error providing reasonable context.
You may use the same TLS certificate and key for multiple backends, depending upon how your Trickster configurations are laid out. Any certificates configured by Trickster must match the hostname header of the inbound http request (exactly, or by wildcard interpolation), or clients will likely reject the certificate for security issues.
Client Configs when proxying to an origin
Each backend’s TLS configuration can also configure the https client used for making requests against the origin as demonstrated above.
insecure_skip_verify
will instruct the http client to ignore hostname verification issues with the upstream origin’s certificate, and process the request anyway. This is analogous to -k | --insecure
in curl.
certificate_authority_paths
will provide the http client with a list of certificate authorities (used in addition to any OS-provided root CA’s) to use when determining the trust of an upstream origin’s TLS certificate. In all cases, the Root CA’s installed to the operating system on which Trickster is running are used for trust by the client.
To use Mutual Authentication with an upstream origin server, configure Trickster with Client Certificates using client_cert_path
and client_key_path
parameters, as shown above. You will likely need to also configure a custom CA in certificate_authority_paths
to represent your certificate signer, unless it has been added to the underlying Operating System’s CA list.
5 - Using Multiple Backends
Trickster supports proxying to multiple backends in a single Trickster instance, by examining the inbound request and using a multiplexer to direct the proxied request to the correct upstream origin, in the same way that web servers support virtual hosting.
There are 2 ways to route to multiple backends.
- HTTP Pathing
- DNS Aliasing
Basic Usage
To utilize multiple backends, you must craft a Trickster configuration file to be read when Trickster starts up - operating with environment variables or command line arguments only supports accelerating a single backend. The example.full.yaml provides good documentation and commented sections demonstrating multiple backends. The config file should be placed in /etc/trickster/trickster.yaml
unless you specify a different path when starting Trickster with the -config
command line argument.
Each backend that your Trickster instance supports must be explicitly enumerated in the configuration file. Trickster does not support open proxying.
Example backend configuration:
backends:
my-backend-01: # routed via http://trickster:8480/my-backend-01/
provider: prometheus
origin_url: http://my-origin-01.example.com
my-backend-02: # routed via http://trickster:8480/my-backend-02/
hosts: [ my-fqdn-02.example.com ] # or http://my-fqdn-02.example.com:8480/
provider: prometheus
origin_url: http://my-origin-02.example.com
my-backend-03:
path_routing_disabled: true # only routable via Host header, an ALB, or a Rule
hosts: [ my-fqdn-03.example.com ] # or http://my-fqdn-03.example.com:8480/
provider: prometheus
origin_url: http://my-origin-02.example.com
Default Backend
Whether proxying to one or more upstreams, Trickster has the concept of a “default” backend, which means it does not require a specific DNS hostname in the request, or a specific URL path, in order to proxy the request to a known backend. When a default backend is configured, if the inbound request does not match any mapped backends by path or FQDN, the request will automatically be routed through the default backend. You are probably familiar with this behavior from when you first tried out Trickster with the using command line arguments.
Here’s an example: if you have Trickster configured with an backend named foo
that proxies to http://foo/
and is configured as the default backend, then requesting http://trickster/image.jpg
will initiate a proxy request to http://foo/image.jpg
, without requiring the path be prefixed with /foo
. But requesting to http://trickster/foo/image.jpg
would also work.
The default backend can be configured by setting is_default: true
for the backend you have elected to make the default. Having a default backend is optional. In a single-backend configuration, Trickster will automatically set the sole backend as is_default: true
unless you explicitly set is_default: false
in the configuration file. If you have multiple backends, and don’t wish to have a default backend, you can just omit the value for all backends. If you set is_default: true
for more than one backend, Trickster will exit with a fatal error on startup.
Path-based Routing Configurations
In this mode, Trickster will use a single FQDN but still map to multiple upstream backends by path. This is the simplest setup and requires the least amount of work. The client will indicate which backend is desired in URL Path for the request.
Example Path-based Configuration with Multiple Backends:
backends:
# backend1 backend
backend1:
origin_url: 'http://prometheus.example.com:9090'
provider: prometheus
cache_name: default
is_default: true
# "foo" backend
foo:
origin_url: 'http://influxdb-foo.example.com:9090'
provider: influxdb
cache_name: default
# "bar" backend
bar:
origin_url: 'http://prometheus-bar.example.com:9090'
provider: prometheus
cache_name: default
Using HTTP Path as the Backend Routing Indicator
The client prefixes the Trickster request path with the Backend Name.
This is the recommended method for integrating with applications like Grafana.
Example Client Request URLs:
To Request from Origin
foo
: http://trickster.example.com:8480/foo/query?query=xxxTo Request from Origin
bar
: http://trickster.example.com:8480/bar/query?query=xxxTo Request from Origin
backend1
as default: http://trickster.example.com:8480/query?query=xxxTo Request from Origin
backend1
(Method 2, with Origin Name): http://trickster.example.com:8480/backend1/query?query=xxxConfiguring Grafana to request from backend
foo
via Trickster:
DNS Alias Configuration
In this mode, multiple DNS records point to a single Trickster instance. The FQDN used by the client to reach Trickster is mapped to specific backend configurations using the hosts
list. In this mode, the URL Path is not considered during Backend Selection.
Example DNS-based Backend Configuration:
backends:
# backend1 backend
backend1:
hosts: # users can route to this backend via these FQDNs, or via `/backend1`
- 1.example.com
- 2.example.com
origin_url: 'http://prometheus.example.com:9090'
provider: prometheus
cache_name: default
is_default: true
# "foo" backend
foo:
hosts: # users can route to this backend via these FQDNs, or via `/foo`
- trickster-foo.example.com
origin_url: 'http://prometheus-foo.example.com:9090'
provider: prometheus
cache_name: default
# "bar" backend
bar:
hosts: # users can route to this backend via these FQDNs, or via `/bar`
- trickster-bar.example.com
origin_url: 'http://prometheus-bar.example.com:9090'
provider: prometheus
cache_name: default
Example Client Request URLs:
To Request from Origin
foo
: http://trickster-foo.example.com:8480/query?query=xxxTo Request from Origin
bar
: http://trickster-bar.example.com:8480/query?query=xxxTo Request from Origin
backend1
as default: http://trickster.example.com:8480/query?query=xxxTo Request from Origin
backend1
(Method 2, via FQDN): http://backend1.example.com:8480/query?query=xxx
Note: It is currently possible to specify the same FQDN in multiple backend configurations. You should not do this (obviously). A future enhancement will cause Trickster to exit fatally upon detection at startup.
Disabling Path-based Routing for a Backend
You may wish for a backend to be inaccessible via the /backend_name/
path, and only by Hostname or as the target of a rule or ALB. You can disable path routing by setting path_routing_disabled: true
for the backend, as in this example, which requires the Request’s Host header match 1.example.com
or 2.example.com
in order to be routed to the backend:
backends:
backend1:
hosts:
- 1.example.com
- 2.example.com
origin_url: 'http://prometheus.example.com:9090'
provider: prometheus
cache_name: default
is_default: false
path_routing_disabled: true # this will disable routing through /backend1