Daniele Polencic
Daniele Polencic

Can you expose your microservices with an API gateway in Kubernetes?

Published in April 2019

Updated in December 2019


Can you expose your microservices with an API gateway in Kubernetes?

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:

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.

Ingress as a load balancer

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:

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:

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:

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:

In other words, API gateways are designed to protect your apps from the outside world.

API gateways focus on handling external traffic

Service meshes, instead, are mostly used to observe and secure applications within your infrastructure.

Typical uses of service meshes include:

Since service meshes are deployed alongside your apps, they benefit from:

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.

Service meshes focus on internal service-to-service communitcation
API gatewayService mesh
Exposes internal services to external clientsManages and controls the traffic inside the network
Maps external traffic to internal resourcesFocuses 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.

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 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:

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:

If you enjoyed this article, you might find the following articles interesting:

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.