Can you expose your microservices with an API gateway in Kubernetes?
December 2019
Welcome to Bite-sized Kubernetes learning — a regular column on the most interesting questions that we see online and during our workshops answered by a Kubernetes expert.
Today's answers are curated by Daniele Polencic. Daniele is an instructor and software engineer at Learnk8s.
If you wish to have your question featured on the next episode, please get in touch via email or you can tweet us at @learnk8s.
Did you miss the previous episodes? You can find them here.
Can you expose your microservices with an API gateway in Kubernetes?
TL;DR: yes, you can. Have a look at the Kong, Ambassador and Gloo Ingress controllers. You can also use service meshes such as Istio API gateways, but you should be careful.
Table of content:
- The king of API Gateways: Kong
- Ambassador, the modern API gateway
- Gloo things together
- Istio as an API gateway
In Kubernetes, an Ingress is a component that routes the traffic from outside the cluster to your services and Pods inside the cluster.
In simple terms, the Ingress works as a reverse proxy or a load balancer: all external traffic is routed to the Ingress and then is routed to the other components.
While the most popular ingress is the ingress-nginx project, there are several other options when it comes to selecting and using an Ingress.
You can choose from Ingress controllers that:
- handle HTTP traffic such as Contour or Treafik Ingress
- support UDP and TCP traffic such as Citrix Ingress
- support Websockets such as HAProxy Ingress
There are also other hybrid Ingress controllers that can integrate with existing cloud providers such as Zalando's Skipper Ingress.
When it comes to API gateways in Kubernetes, there are a few popular choices to select from.
The king of API Gateways: Kong
If you are building an API, you might be interested in what Kong Ingress has to offer.
Kong is an API gateway built on top of Nginx.
Kong is focused on API management and offers features such as authentication, rate limiting, retries, circuit breakers and more.
What's interesting about Kong is that it comes packaged as a Kubernetes Ingress.
So it could be used in your cluster as a gateway between your users and your backend services.
You can expose your API to external traffic with the standard Ingress object:
ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
spec:
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80
But there's more.
As part of the installation process, Kong's controller registers Custom Resource Definitions (CRDs).
One of these custom extensions is related to Kong's plugins.
If you wish to limit the requests to your Ingress by IP address, you can create a definition for the limit with:
limit-by-ip.yaml
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
name: rl-by-ip
config:
hour: 100
limit_by: ip
second: 10
plugin: rate-limiting
And you can reference the limit with an annotation in your ingress with:
ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
annotations:
plugins.konghq.com: rl-by-ip
spec:
rules:
- host: example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: api-service
port:
number: 80
You can explore the Custom Resource Definitions (CRDs) for Kong on the official documentation.
But Kong isn't the only choice.
Ambassador, the modern API gateway
Ambassador is another Kubernetes Ingress built on top of Envoy that offers a robust API Gateway.
The Ambassador Ingress is a modern take on Kubernetes Ingress controllers, which offers robust protocol support as well as rate-limiting, an authentication API and observability integrations.
The main difference between Ambassador and Kong is that Ambassador is built for Kubernetes and integrates nicely with it.
Kong was open-sourced in 2015 when the Kubernetes ingress controllers weren't so advanced.
Even if Ambassador is designed with Kubernetes in mind, it doesn't leverage the familiar Kubernetes Ingress.
Instead, services are exposed to the outside world using annotations:
service.yaml
apiVersion: v1
kind: Service
metadata:
labels:
service: api-service
name: api-service
annotations:
getambassador.io/config: |
---
apiVersion: ambassador/v0
kind: Mapping
name: example_mapping
prefix: /
service: example.com:80
host_rewrite: example.com
spec:
type: LoadBalancer
ports:
- port: 80
targetPort: 80
selector:
service: api-backend
The novel approach is convenient because, in a single place, you can define all the routing for your Deployments and Pods.
However, having YAML as free text within an annotation could lead to errors and confusion.
It's hard to get the formatting right in standard YAML, let alone as a string inside more YAML.
If you wish to apply rate-limiting to your API, this is what it looks like in Ambassador.
You have a RateLimiting object that defines the requirements:
rate-limit.yaml
apiVersion: getambassador.io/v1beta1
kind: RateLimit
metadata:
name: basic-rate-limit
spec:
domain: ambassador
limits:
- pattern: [{x_limited_user: "false"}, {generic_key: "qotm"}]
rate: 5
unit: minute
- pattern: [{x_limited_user: "true"}, {generic_key: "qotm"}]
rate: 5
unit: minute
You can reference the rate limit in your Service with:
service.yaml
apiVersion: v1
kind: Service
metadata:
name: api-service
annotations:
getambassador.io/config: |
---
apiVersion: ambassador/v1
kind: RateLimitService
name: basic-rate-limit
service: "api-service:5000"
spec:
type: ClusterIP
selector:
app: api-service
ports:
- port: 5000
targetPort: http-api
Ambassador has an excellent tutorial about rate limiting, so if you are interested in using that feature, you can head over to Ambassador's official documentation.
You can extend Ambassador with custom filters for routing, but it doesn't offer a vibrant plugin ecosystem as Kong.
Gloo things together
Ambassador is not the only Envoy-powered ingress which can be used as API Gateway.
Gloo is a Kubernetes Ingress that is also an API gateway. It is capable of providing rate limiting, circuit breaking, retries, caching, external authentication and authorisation, transformation, service-mesh integration and security.
The selling point for Gloo is that it is capable of auto-discovering API endpoints for your application and automatically understands arguments and parameters.
It might be hard to believe (and sometimes their documentation doesn't help either), so here's an example.
Imagine you have a REST API for an address book.
The app exposes the following endpoints:
GET /users/{id}
, get the profile for a userGET /users
, get all usersPOST /users/find
, find a particular user
If your API is developed using standard tools such as the OpenAPI, then Gloo automatically uses the OpenAPI definition to introspect your API and store the three endpoints.
If you list all the endpoint served by Gloo after the discovery phase, this is what you see:
gloo
upstreamSpec:
kube:
selector:
app: addressbook
serviceName: addressbook
serviceNamespace: default
servicePort: 8080
serviceSpec:
rest:
swaggerInfo:
url: http://addressbook.default.svc.cluster.local:8080/swagger.json
transformations:
findUserById:
body:
text: '{"id": {{ default(id, "") }}}'
headers:
:method:
text: POST
:path:
text: /users/find
content-type:
text: application/json
getUser:
body: {}
headers:
:method:
text: GET
:path:
text: /user/{{ default(id, "") }}
content-length:
text: '0'
content-type: {}
transfer-encoding: {}
getUsers:
body: {}
headers:
:method:
text: GET
:path:
text: /users
content-length:
text: '0'
content-type: {}
transfer-encoding: {}
Once Gloo has a list of endpoints, you can use that list to apply transformations to the incoming requests before they reach the backend.
As an example, you may want to collect all the headers from the incoming requests and add them to the JSON payload before the request reaches the app.
Or you could expose a JSON API and let Gloo apply a transformation to render the message as SOAP before it reaches a legacy component.
Being able to discover APIs and apply transformations makes Gloo particularly suitable for an environment with diverse technologies — or when you're in the middle of a migration from an old legacy system to a newer stack.
Gloo can discover other kinds of endpoints such as AWS Lambdas.
Which makes it the perfect companion when you wish to mix and match Kubernetes and serverless.
I've heard I could use Istio as an API gateway
What's the difference between an API gateway and a service mesh?
Aren't both doing the same thing?
Both offer:
- traffic routing
- authentication such as OAuth, JWT, etc.
- rate-limiting
- circuit breakers
- retries
- etc.
However, there's a distinction.
API gateways such as Kong and Ambassador are mostly focussed on handling external traffic and routing it inside the cluster.
External traffic is quite a broad label that includes things such as:
- slow and fast clients and
- well behaved and malicious users
In other words, API gateways are designed to protect your apps from the outside world.
Service meshes, instead, are mostly used to observe and secure applications within your infrastructure.
Typical uses of service meshes include:
- monitoring and observing requests between apps
- securing the connection between services using encryption (mutual TLS)
- improving resiliency with circuit breakers, retries, etc.
Since service meshes are deployed alongside your apps, they benefit from:
- low latency and high bandwidth
- unlikely to be targeted for misuse by bad actors
In other words, a service mesh's primary purpose is to manage internal service-to-service communication, while an API Gateway is primarily meant for external client-to-service communication.
API gateway | Service mesh |
---|---|
Exposes internal services to external clients | Manages and controls the traffic inside the network |
Maps external traffic to internal resources | Focuses on brokering internal resources |
But that doesn't mean that you can't use Istio as an API gateway.
What might stop you, though, is the fact that Istio's priority isn't to handle external traffic.
Let's have a look at an example.
It's common practice to secure your API calls behind an API gateway with JWT or OAuth authentication.
Istio offers JWT, but you have to inject custom code in Lua to make it work with OAuth.
On the other hand, Kong offers a plugin for that as this is a common request.
Enterprise API gateways such as Google Apigee include billing capabilities.
It's unlikely that those features will be replicated in a service mesh because the focus isn't on managing APIs.
What if you don't care about billing, can you still use a service mesh as an API gateway?
Yes, you can, and there's something else that you should know.
A general note on API gateways and service meshes
Depending on what you are trying to achieve, service meshes and API gateways could overlap significantly in functionality.
They might overlap even more in the future since every major API gateway vendor is expanding into service meshes.
- Kong announced Kuma a service mesh that can integrate with Kong or Istio
- Solo.io announced a service mesh that integrates with Gloo called SuperGloo
- Containous announced Maesh a service mesh that integrates with Traefik
And it would not be surprising to see more service meshes deciding to launch an API gateway as Istio did.
Recap
If you had to pick an API gateway for Kubernetes, which one should you use?
- If you want a battle-tested API gateway, Kong is still your best option. It might not be shiniest but the documentation is excellent with plenty of resources online. It also has the most production mileage than any other gateway.
- If you need a flexible API gateway that can play nicely with new and old infrastructure, you should have a look at Gloo. The ability to auto-discover APIs and transform requests is compelling.
- If you want the simplicity of setting all the networking in your Services, you should consider Ambassador. It has excellent tutorials and documentation to get started. Be aware of the YAML indentation as a free string.
If you had to pick an API gateway or a service mesh, which one should you use?
Starting with an API gateway is still the best choice to secure your internal apps from external clients.
As the number of apps grow in size, you could explore how to leverage a service mesh to observe, monitor and secure the traffic between them.
More options
If neither Ambassador, Kong or Gloo is suitable for the API gateway that you had in mind, you should check out the following alternatives:
- Tyk is an open-source API gateway which can be deployed as an Ingress.
- You could build your API gateway Ingress using Ballerina — a Cloud-Native programming language
That's all folks
Do you have any recommendation when it comes to API Gateways on Kubernetes?
Let us know in an email or tweet us @learnk8s.
A special thank you goes to Irakli Natsvlishvili who offered some invaluable feedback and helped me put together the above table. Also, thanks to:
- Idit Levine and Scott Weiss from the Solo.io team for answering my questions about the Gloo Ingress controller
- Daniel Bryant from Datawire who kindly helped me understand Ambassador better
- Marco Palladino from Kong Inc. for offering some detailed feedback about the article
If you enjoyed this article, you might find the following articles interesting:
- Scaling Microservices with Message Queues, Spring Boot and Kubernetes. You should design your service so that even if it is subject to intermittent heavy loads, it continues to operate reliably. But how do you build such applications? And how do you deploy an application that scales dynamically?
- Boosting your kubectl productivity. If you work with Kubernetes, then kubectl is probably one of your most-used tools. Whenever you spend a lot of time working with a specific tool, it is worth to get to know it very well and learn how to use it efficiently.
Don't miss the next article!
Be the first to be notified when a new article or Kubernetes experiment is published.
*We'll never share your email address, and you can opt-out at any time.