May 24, 2021
Today we’re going to learn about how to combine Emissary ingress (formerly known as the Ambassador API Gateway) with Linkerd to build a scalable system that combines the context-aware routing of Emissary with the observability and security of Linkerd.
Emissary is a newly adopted CNCF project from the folks over at Ambassador Labs. It’s an ingress that combines standard ingress functionality with some features traditionally associated with an API gateway. Emissary is powerful, fast, and offers a ton of configuration options. It also shares an important property with Linkerd: it’s easy to learn and use.
By the end of this article you should:
For anyone who isn’t familiar with Linkerd, it’s a lightweight, simple, and Kubernetes-native service mesh. Linkerd provides users with security, observability, and reliability benefits by injecting a proxy that handles app-to-app communication. It is highly performant and allows platform owners to rapidly diagnose application issues and restore service when issues occur.
Emissary, a newly incubating CNCF project, aims to simplify the process of using and configuring Envoy. Emissary works as an ingress and API gateway with features targeted at microservice developers. Specifically, Emissary aims to deliver observability and reliability features that will allow developers to move faster and hit higher availability targets.
Both tools aim to solve similar problems for different audiences and their features are extremely complimentary. If you like Emissary but want easy to use end-to-end encryption, Linkerd can handle that. If you want to route users to different services based on user names, use Emissary to handle smarted routing at the ingress.
Now that you see the value in using Linkerd with Emissary, let’s dive into how this works.
For the purpose of this article, we’re going to deploy everything on a kind cluster. It’s important to understand that when dealing with an ingress we generally expect a Kubernetes service to have access to some kind of external load balancer. When working in a production, or production-like environment, you’ll want to use Emissary with a serviceType: LoadBalancer and integrate it with your DNS service. In our examples, we use localhost due to the constraints imposed on us by kind.
Before doing anything we need to deploy our kind cluster:
After that, we install the Emissary ingress.
Note: You’ll see a lot of references to Ambassador in this demo as what used to be called the Ambassador API gateway is being renamed to Emissary.
If you don’t already have Linkerd installed you can pull down the latest stable:
Then run the pre-check and install commands:
This will ensure your kind cluster can run linkerd, install the service mesh, and validate that the linkerd install is healthy.
If you want, you can add the Linkerd dashboard:
Once your mesh is up and running, you can integrate it with Emissary.
To do this, you must add the ambassador ingress itself. You can also optionally add the agent and Redis instances. I’ll add instructions for that at the end of this section.
We’re going to grab the ambassador deployment and add it to the mesh. You should note we use two flags to modify the standard injection annotations:
We deliberately skip the inbound ports 80 and 443 on the ingress. We do this for two reasons:
The Agent doesn’t require any special configuration. It serves traffic on port 8877 but it’s standard http traffic which Linkerd handles without issue:
Redis isn’t currently included in Linkerd’s default opaque ports so you’ll need to tell Linkerd to treat the Redis traffic as a TCP connection:
By adding the entirety of Ambassador’s control plane you’ll have more detailed information about how it works and simplify debugging issues as they come up.
Modules and mappings help you configure your Emissary instance and route traffic to applications.
Read the official docs for a more in depth explanation, but on a high-level, modules provide cluster-wide configuration. In our example, we use the following mapping to tell Emissary to forward Linkerd headers on all routes:
Mappings are route-specific rules, similar to an ingress object. They allow you to route traffic to a given application and provide Emissary specific logic to control things like circuit breaking or header based routing.
We will use the following mapping resource to route traffic to the Emojivoto application in the next section:
Now that we have Emissary and Linkerd installed, we can deploy Emojivoto and route some traffic to our ingress.
Start by deploying and injecting our app:
We can view the dashboard to check on the progress or use Linkerd check to test the proxy:
With that done, we configure Emissary and create our mapping. Save the following files and content:
linkerd_module.yaml
linkerd_mapping.yaml
Then apply them to your Kubernetes cluster:
With that done traffic should be able to flow from the ingress to Emojivoto. Let’s try it out! Forward traffic from port 8443 on your local machine to the Emissary ingress:
Then use a private window to browse to https://localhost:8443. You’ll see a warning like this:
At this point you should immediately shut down your computer and unplug your telephone lines to avoid any security problems. Just kidding! You can safely ignore the invalid certificate in this case as we deliberately avoided creating a real certificate for our ingress and aren’t using a DNS service to create an externally valid host entry.
After allowing your browser to continue you’ll see Emojivoto pop up. You can use the app normally and observe the traffic through the ingress via the Linkerd viz dashboard or the Linkerd CLI.
Congrats! You’re about done with setting up Linkerd with Emissary. By skipping inbound traffic on ports 80 and 443 you’ve ensured that Emissary will work as designed and you can enable more advanced routing rules like enabling web sockets. On that note, if you’re looking to route traffic to the Linkerd dashboard, you’ll want to set a couple things:
Here’s an example dashboard configuration
Emissary has a ton of functionality that is extremely valuable to developers and platform owners, as does Linkerd. While Emissary is focused on the ingress to your cluster, Linkerd is able to handle the inter-app communication within your cluster. When you pair them together they become more than the sum of their parts and are a key building block to making a developer focused Kubernetes platform.
I hope this has been useful, informative, and worth your time!