News KrakenD Enterprise v2.6 released with OpenTelemetry, FIPS-140, gRPC server and more

Enterprise Documentation

Recent changes

You are viewing a previous version of KrakenD Enterprise Edition (v2.4) , go to the latest version

Extended Flexible Configuration

Document updated on Aug 23, 2023

Extended Flexible Configuration

The Extended Flexible Configuration allows you to express your KrakenD configuration using multiple files, reusing code blocks, and introduces a templates system. It is called “Extended” because it uses an engine more capable than its open source alternative, but it remains 100% compatible.

In its simplest form, you can do things like:

{
    "version": 3,
    "extra_config": {
        "$ref": "./service/extra_config.json"
    }
}

As you can guess, in the example above, the $ref is replaced by the content of the external file, much like it works in the JSON Schema specification.

You may need this feature when you have different environments with slight differences, work with a group of people, or avoid copying and pasting configurations in the various endpoints.

There are also what we call settings, files with your custom data structures that you can access in a variable tree. For instance, if you have a student.json or student.yaml with the content:

name: john

Then you could access its attributes like this:

{
    "version": 3,
    "extra_config": {
        "$ref": "{{ .student.name }}/service/extra_config.json"
    }
}

As you can see from the example above, we have introduced the concept of templates now, a very simple one. We are loading the extra_config.json file from a dynamic location that is dictated by a file student.yaml, in this case from john/service/extra_config.json.

But templates can get very complex. You can use the syntax of the Go templates, which opens the door to much more flexible configurations. Here’s another example:

{
    "version": 3
    {{ if .student }}
    ,{{ template "service/components.tmpl" .student }}
    {{ end }}
}

The example above is a template with a conditional, rendering into a JSON file, but you can encode your configuration files in any of the supported formats (json, yaml, toml, etc.), as the template engine is agnostic of its contents.

See in the following sections how to work with templates.

Configuration

Activating the Extended Flexible Configuration requires creating a behavioural file that defines how the engine parses the injected content. This file sets things like the paths to your content or options to parse it.

Copy and paste the following JSON file and save it with any name, for instance flexible_config.json:

 {
    "settings": {
        "paths": ["settings"],
        "allow_overwrite": true,
        "dir_field_prefix": "",
        "allowed_suffixes": [
            ".yaml",
            ".json"
        ]
    },
    "partials": {
        "paths": ["partials"]
    },
    "templates": {
        "paths": ["templates"]
    },
    "out": "result.json"
}

Create an initial directory structure to support what you defined in the paths above:

Template boilerplate 
$mkdir -p {partials,settings,templates}

Now you can run the software using krakend run or krakend check and pass the environment variable FC_CONFIG=flexible.config.json (pointing to the filename you chose). If you come from the open-source version of the flexible configuration, you can delete any previous FC_ environment variables.

For instance, if your configuration is in a krakend.tmpl file:

Execute a simple template 
$docker run --rm -v "$PWD:/etc/krakend/" -e "FC_CONFIG=/etc/krakend/flexible_config.json" krakend/krakend-ee check -c krakend.tmpl
Parsing configuration file: krakend.tmpl
Syntax OK!

Finally, you can debug the hierarchy of the settings tree by passing an environment variable FC_DEBUG=true.

This is all you need to start using the Extended flexible configuration.

The behavior file

The Extended Flexible Configuration behaves according to its configuration file. As you have seen above, you must express it in JSON format.

The structure of this file represents the following:

  • settings defines where are your data sources and several options to parse them.
  • partials defines from where to load snippets of text that don’t evaluate.
  • templates defines from where to load the Go templates.
  • out sets the filename that saves the resulting configuration after rendering the template.

Settings

Settings are files expressed in JSON, YAML, ENV, TOML, INI or properties files (Java). Their expected extensions are .json, .yaml, .env, .yml, .toml, .ini, .prop, .properties, or .props.

Settings option paths

The paths attribute in settings defines the list of all data sources, and they can be absolute directories (e.g.: /etc/krakend/settings), relative to the working dir (e.g., ./settings) or individual files (e.g.,: ./override.yaml). Directories are included recursively, with all the contents of subfolders. For instance, you could have:

{
    "settings": {
        "paths": [
            "./settings/common",
            "./settings/production",
            "override.yaml"
        ]
    }
}

When all directories and files are parsed, you can access them in the templates using the dot notation .. It means that if you, for instance, have a file under ./settings/production/a/b/c/file.json and you defined the paths as above, you can access its contents in the templates as {{ .a.b.c.file }} (notice the starting dot). All contents under the paths you defined are placed at the root level of the settings tree.

You can add multiple files and directories in the paths. The engine will load recursively and, in the order defined, all files and subdirectories you have specified in the paths. Their content is merged if you have repeated file names with different extensions (e.g.: file.yaml and file.json).

Settings option allow_overwrite

If there are conflicts when converting directories and file contents into the settings tree (they use the same name path), the allow_overwrite flag lets you define what you want to do. When overwrite is allowed, the last parsed file replaces any conflicting variables in the tree.

There might also be directory names that clash with file names or keys inside the data structures. For instance, you have ./settings/foo.json and ./settings/foo/common.json. This would resolve to {{ .foo }} and {{ .foo.common }}. The last one could replace a key common if it exists in foo.json.

Settings option dir_field_prefix

You have the opportunity to rename the paths of directories with a prefix. For instance, if you use "dir_field_prefix": "dir_", then the same scenario would resolve to {{ .foo }} and {{ .dir_foo.common }} which gives no room to conflict.

Settings option allowed_suffixes

And finally, you can have more files in the settings directories than the flexible configuration will load. To filter which extensions or ending paths you want to load, you can use the allowed_suffixes list. For instance:

{
    "settings": {
    "allowed_suffixes": [
            ".yaml",
            ".prod.json"
        ]
    }
}

The example above would only load YAML files or that end in .prod.json.

Partials

The partials are treated as raw text files, and they are inserted in the placeholder “as is”, and no template evaluation of its content is performed.

The paths list accepts one single directory because, unlike settings and templates, you specify the full relative path when invoked. E.g.: {{ include "dir1/dir2/file.txt" }}

{
    "partials": {
        "paths": [
            "./partials"
        ]
    }
}

Templates

When you start KrakenD, the configuration file passed with the -c flag is treated as the base Go template (documentation), and you can make use of all the power the template engine brings.

The templates attribute in the behavior configuration defines from where to load Go templates that are compiled into the final configuration file.

You must add a paths entry inside the templates setting. It is also a list that defines multiple directories or individual template files. For instance:

{
    "templates": {
        "paths": [
            "templates",
            "some_file.tmpl"
        ]
    }
}

In the example above, we pass a templates folder and an individual template file some_file.tmpl.

All paths are traversed recursively, meaning that all insider templates are also available if there are subfolders. The relative path is removed from the template name when there are subdirectories.

For instance, a directory structure like dir1/dir2/file.tmpl lets you load the template as {{ template "file.tmpl" }}, and as you can see, there is no dir1 or dir2 when you reference it.

When there are conflicts (you have the same filename in different folders), you will see a warning in the logs, and the engine will rename the template to {{ template "dir2_file.tmpl"}}, using the last directory name as a prefix. If there was also a conflict, you would have {{ template "dir1_dir2_file.tmpl"}}, and so on. But unless there are conflicts, the template base name is all you need.

To start working with templates, read Flexible Configuration Templates

Out file

Our final attribute of the behavior file is the out. It specifies a filename where the result of compiling the templates is stored. The directory and the filename you use must be writeable by the KrakenD process. It let’s you see the resulting file after rendering all the templates. It has no other purpose than debugging the resulting template.

For instance:

{
    "out": "result.json"
}

$ref: Reference external files

One of the main differences between the Extended Flexible Configuration and the open source one is that you can reference other configuration files using a reference, even if you don’t want to use Go templates.

The $ref keyword will inject the content of the referenced file, allowing you to work with non-template files (but the templates are welcome, too!). It does not matter if you have the configuration in YAML, INI, or JSON. For instance, when you add a $ref keyword, the content of the referenced file will replace the $ref block.

For instance, given that you have a websockets.json as follows:

{
    "url_pattern": "/ws/{room}",
    "disable_host_sanitize": true,
    "host": [ "ws://chat:8888" ]
}

You can include it in the configuration as follows:

{
  "endpoint": "/chat/{room}",
  "backend": [
    { "$ref": "./backends/websockets.json" }
  ]
}

And KrakenD resolves this to:

{
  "endpoint": "/chat/{room}",
  "backend": [
    {
        "url_pattern": "/ws/{room}",
        "disable_host_sanitize": true,
        "host": [ "ws://chat:8888" ]
    }
  ]
}

In addition, you can also use data pointers, so you can use # to traverse a specific route inside the referenced file. For instance:

{
  "endpoint": "/chat/{room}",
  "backend": [
    {
        "url_pattern": "/ws/{room}",
        "disable_host_sanitize": true,
        "host": { "$ref": "./backends/websockets.json#host" }
    }
  ]
}

In the example above, we import just one field from the referenced file.

Using $ref compared to template syntax is better for maintenance because the complexity is much lower.

Testing the configuration

We recommend using a Docker compose file to work faster with flexible configuration.

Save the following docker-compose.yml and do a docker-compose up. This setup with the :watch image will allow you to work locally with the latest version of KrakenD and apply the changes automatically whenever you change a source file.

version: "3"
services:
  krakend:
    image: krakend/krakend-ee:watch
    volumes:
      - "./:/etc/krakend/"
    environment:
      - FC_CONFIG=flexible_config.json
      - FC_DEBUG=true
    command: ["run","-dc","krakend.tmpl"]

As the flexible configuration is composed of several pieces, it’s easy to make a mistake at some point. Test the syntax of all the files with the krakend check command and pay attention to the output to verify there aren’t any errors. When there are errors, the output contains information to help you resolve it, e.g.:

ERROR parsing the configuration file: loading flexible-config settings:
- backends.json: invalid character '}' looking for beginning of object key string

The setting out in the behavior file (flexible_config.json above) writes the content of the final file in a known path, so you can check its contents at any time.

If you don’t use docker-compose, you can also use flexible configuration as follows:

Checking the configuration 
$FC_CONFIG=flexible_config.json \
FC_DEBUG=true \
krakend check -t -d -c "$PWD/krakend.tmpl"
Scarf

Unresolved issues?

The documentation is only a piece of the help you can get! Whether you are looking for Open Source or Enterprise support, see more support channels that can help you.