News Improving The Developer Experience of Your APIs

Canary releases with KrakenD: Safely roll out API changes

by Albert Lombarte

Jul 3, 2023

6 min read
post image

Canary release is a powerful technique that helps organizations deploy changes to their APIs in a controlled and gradual manner. Instead of publishing changes to receive the impact of all traffic when going live, you expose the changes to a small subset of the traffic. The Canary Release allows for thorough monitoring and validation, reducing the risk of potential issues affecting the entire system.

This blog post will explore three ways of implementing Canary Releases on KrakenD, ensuring smoother deployments and enhanced reliability.

Canary Releases to ensure safe API deployments

A Canary Release involves rolling out changes to a small portion of the user base before making them available to everyone. This controlled release allows organizations to closely monitor the impact of the changes and collect valuable metrics from a limited audience.

By controlling the exposure to new changes, organizations can mitigate risks, gather insights, and address potential issues proactively, ultimately leading to more reliable and stable API deployments.

Implementing Canary Releases with KrakenD

KrakenD offers capabilities for implementing Canary Releases in your API deployments using different techniques. Let’s walk through some examples of how you can achieve this using KrakenD.

We are going to refer through the examples to two different services or two different URLs:

  • Main: Represents your existing stable API version or URL. E.g., http://main, or http://localhost:8080/__echo/main
  • Canary: Represents the new version of your API that you want to test. E.g., http://canary, or http://localhost:8080/__echo/canary

Canary Releases using Load Balancing

The simplest strategy is when you use an egress strategy using the poor man’s weighted load balancing. This simple technique expresses the desired proportion of main vs. canary services in the host list responsible for load balancing.

For instance, you want to send 25% of the traffic to the canary service. You must add the following host list in your backend.

{
  "url_pattern": "/test",
  "host": [
    "https://main",
    "https://main",
    "https://main",
    "https://canary"
  ]
}

By repeating the hosts, the Canary will receive only 1 out of 4 hits (25%) when doing the Round-Robin. Remember that KrakenD does not have any penalty for the longitude of this list and that you don’t need to necessarily write these lines in the config but use a template to simplify this.

As you can see, this technique is effortless, but you cannot change the URL of the Canary release, only the host. To change the URL, see below.

Canary Releases using the Service Discovery

A similar way of implementing host-based Canary Releases is using your DNS SRVService Discovery.

An SRV entry is a custom DNS record that defines the locations and weights of services. Your Kubernetes or Consul service might offer this, for example.

If you use an "sd": "dns" entry in the configuration, when KrakenD needs to know the location and load balancing options of a specific service, it will fetch the DNS and take its content into account.

Here is an example of what this DNS looks like:

Querying a Google's SRV record 
$$ dig _sip._udp.sip.voice.google.com SRV +short
10 1 5060 sip-anycast-1.voice.google.com.
20 1 5060 sip-anycast-2.voice.google.com.

As you can see, every service has a priority (10 and 20) and weight (1 and 1). In the example above, KrakenD would balance the traffic to both services equally.

You can use the weight as an absolute weight or as a percentage, KrakenD compares each host weight to the sum of all the weights to determine its representation. For instance, the following DNS response would send 1% of the traffic to the canary:

Querying your SRV record 
$$ dig _sip._udp.sip.yourservice.com SRV +short
10 100 5060 main.youservice.com.
20 1 5060 canary.youservice.com.

Canary Releases using scripts

The more powerful option is adding a script that considers the logic behind Canary Release. A no-brainer is using Lua, so we are going to create a simple canary.lua file with our desired Canary configuration:

function canaryRelease( req, percentage, canary_url )
  if math.random(1, 100) <= percentage
  then
    req:url(canary_url)
  end
end

The script above is quite simple and reusable across all your backend definitions. For the current request, we get a random number up to 100, and if it is within the percentage you have set, it points the request to the Canary URL. For instance, canaryTesting(req, 5, 'http://canary/url' ) sends 5% of the traffic to http://canary/url.

As you can see, the setter req:url allows you to point to a different host and a path, and you have complete control of where the request goes.

Now, on KrakenD, you only need to call the Canary function. Here’s a complete working configuration you can copy/paste and test (do not forget copying the canary.lua too):

{
  "version": 3,
  "@comment": "Canary release",
  "$schema": "https://www.krakend.io/schema/krakend.json",
  "echo_endpoint": true,
  "endpoints": [
    {
      "endpoint": "/test",
      "backend": [
        {
          "host": ["http://localhost:8080"],
          "url_pattern": "/__echo/main",
          "allow": ["req_uri"],
          "extra_config": {
            "modifier/lua-backend": {
              "sources": ["canary.lua"],
              "pre": "canaryRelease(request.load(), 20, 'http://localhost:8080/__echo/canary')",
              "allow_open_libs": true
            }
          }
        }
      ]
    }
  ]
}

Notice that the stable main service is always in the backend entry. Here is an example log of this configuration sending 20% to the Canary release:

Canary Testing log

Suppose any issues arise during the canary testing phase, and the release is not working as you expected. In that case, you have two alternative options to quickly rollback the Canary Release:

  1. By setting the traffic weight to 100%
  2. By adding an @ before the Lua namespace (quicker than deleting the code block)

The two options (you need only one) are illustrated below:

{
    "@modifier/lua-backend": {
        "sources": ["Canary.lua"],
        "pre": "canaryTesting(request.load(), 100, 'http://localhost:8080/__echo/canary')",
        "allow_open_libs": true
    }
}

If everything goes well, you could gradually increase the traffic to the canary service over time by adjusting the weights using the same Lua script.

The Lua script is a simple but effective example that can evolve to a more complex setup if you need it, including checking the current date and time and shifting traffic gradually to the Canary without redeploying or considering multiple Canary entries.

Conclusion

In this article we have demonstrated three different ways to implement Canary Releases that you can even mix together.

By implementing Canary Releases with KrakenD, you can confidently introduce critical changes to your APIs while minimizing potential disruptions and ensuring a smooth user transition. This approach empowers organizations to maintain high availability and stability, delivering a seamless experience to their users.

Whatever logic you apply, constantly monitor its performance, error rates, latency, and other relevant metrics. Use this feedback to identify any potential issues or improvements. Monitoring the canary service’s performance and gathering feedback allows for proactive issue identification and resolution, leading to more stable and reliable API deployments.

Canary testing is a valuable technique for ensuring safe and reliable API deployments. By leveraging KrakenD, organizations can quickly implement canary testing and gradually roll out changes to a subset of users or infrastructure components.

Embrace canary testing with KrakenD to optimize your API release process and deliver exceptional user experiences.

Categories: Tutorials & How-Tos

Scarf
 Stay up to date with KrakenD releases and important updates