Emissary Ingress : A Beginner's Guide

Emissary Ingress : A Beginner's Guide

Introduction

Emissary Ingress is an open source API gateway service incubated under CNCF. It is a very good example of a reverse proxy. It is used to manage external access to services running inside a Kubernetes cluster. It sits in front of your services in a Kubernetes cluster and handles all incoming requests from clients. In Emissary’s case the setup would be:

User -> Emissary Ingress -> Service

  • When a user wants to access a service (like a web application), their request goes to Emissary Ingress first.

  • Emissary Ingress then decides which service should handle the request and forwards it to that service.

  • The service processes the request and sends the response back to Emissary Ingress, which then sends it to the user.

This way, Emissary Ingress acts as a gatekeeper, managing and directing traffic to the right services while keeping the actual service addresses hidden from the users. This blog is a beginner-friendly guide to understanding and using Emissary Ingress. While this setup is simplified for local environments, the same principles apply to production-grade Kubernetes clusters. In a real-world production setup, additional configurations like DNS records, TLS termination, and multiple service routing would be used. Here, we focus on understanding Emissary Ingress basics using a local environment.

Components of Emissary Ingress

Listener

A Listener in Emissary Ingress is like a "gate" that decides how incoming traffic enters your Kubernetes cluster. It specifies:

  1. Where to listen: The port (e.g., 8080) and protocol (e.g., HTTP or HTTPS).

  2. Who to handle: Which namespaces or hostnames the Listener can respond to.

For example

apiVersion: getambassador.io/v3alpha1
kind: Listener
metadata:
  name: my-listener
  namespace: emissary
spec:
  protocol: HTTP
  port: 8080

This Listener listens for HTTP traffic on port 8080 and helps Emissary Ingress decide how to handle it.

Mappings

A Mapping in Emissary Ingress is like a "traffic map" that tells where incoming requests should go. It connects specific requests (like a URL path or hostname) to the right service in your Kubernetes cluster.

apiVersion: getambassador.io/v3alpha1
kind: Mapping
metadata:
  name: my-mapping
  namespace: emissary
spec:
  hostname: "example.com"
  prefix: /api/info
  service: api-service.default.svc.cluster.local:8080

This Mapping sends all requests to example.com/api/info to the api-service on port 8080.

Host

A Host in Emissary Ingress defines the domain name (hostname) that Emissary Ingress should respond to. It’s like a "signpost" that tells which domain traffic is allowed and how to handle it.

apiVersion: getambassador.io/v3alpha1
kind: Host
metadata:
  name: example-host
  namespace: emissary
spec:
  hostname: example.com
  acmeProvider:
    authority: none
  requestPolicy:
    insecure:
      action: Route

This Host ensures Emissary Ingress responds to requests for example.com, even if the connection is insecure (HTTP).

Hands-on

Vanilla Installation of Emissary Ingress

kubectl create namespace emissary
kubectl apply -f https://app.getambassador.io/yaml/emissary/3.9.1/emissary-crds.yaml
kubectl apply -f https://app.getambassador.io/yaml/emissary/3.9.1/emissary-emissaryns.yaml

Make sure all the pods are running properly. It may take a little time.

Setting up trial application

For this blog, we’ll use the standard devops application - podinfo. You can simply apply the deployment and service manifest from my gitlab link - LINK

# Run these commands one by one
git clone https://gitlab.com/tripathiayush23/podinfo
cd podinfo
kubectl apply -f deployments.yaml
kubectl apply -f services.yaml

Setting up the components

Setting up the host is not necessary for trial purposes but for the sake of this blog, we’ll setup all the components. Create different manifests in your machine to make the process simpler.

Listener

apiVersion: getambassador.io/v3alpha1
kind: Listener
metadata:
  name: blog-listener-http
  namespace: emissary
spec:
  protocol: HTTP
  port: 8080                
  securityModel: XFP          
  hostBinding:
    namespace:
      from: ALL
kubectl apply -f <your-file-name>.yaml

Mappings

apiVersion: getambassador.io/v3alpha1
kind: Mapping
metadata:
  name: blog-mapping-root
  namespace: emissary
spec:
  hostname: "podinfo.ayush"
  prefix: / 
  service: podinfo.default.svc.cluster.local:9898
  rewrite: /
---
apiVersion: getambassador.io/v3alpha1
kind: Mapping
metadata:
  name: blog-mapping-version
  namespace: emissary
spec:
  hostname: "podinfo.ayush"
  prefix: /version
  service: podinfo.default.svc.cluster.local:9898
  rewrite: /version
---
apiVersion: getambassador.io/v3alpha1
kind: Mapping
metadata:
  name: blog-mapping-healthz
  namespace: emissary
spec:
  hostname: "podinfo.ayush"
  prefix: /healthz
  service: podinfo.default.svc.cluster.local:9898
  rewrite: /healthz
---
apiVersion: getambassador.io/v3alpha1
kind: Mapping
metadata:
  name: blog-mapping-apiinfo
  namespace: emissary
spec:
  hostname: "podinfo.ayush"
  prefix: /api/info
  service: podinfo.default.svc.cluster.local:9898
  rewrite: /api/info
kubectl apply -f <your-file-name>.yaml

Host

apiVersion: getambassador.io/v3alpha1
kind: Host
metadata:
  name: podinfo-host
  namespace: emissary
spec:
  hostname: podinfo.ayush
  acmeProvider:
    authority: none
  requestPolicy:
    insecure:
      action: Route
kubectl apply -f <your-file-name>.yaml

For the host to function properly, we’ll have to map this hostname to our local IP by modifying the /etc/hosts file. In case of actual cloud setup, we do this using DNS records and Internal Load balancers for services. While modifying /etc/hosts is sufficient for a single service in a local environment, Emissary Ingress is designed for scalable, production-grade traffic management. This guide helps you understand its core components and functionality.

Testing our setup

# To generate an external IP - which is localhost IP on a local setup
minikube tunnel

Visit these URLs - you can that the endpoints mentioned here are the ones that we added in the mappings manifest. You will get JSON response for each endpoint.

http://podinfo.ayush:9898
http://podinfo.ayush:9898/healthz
http://podinfo.ayush:9898/version
http://podinfo.ayush:9898/api/info

Now that you’ve set up Emissary Ingress locally, try expanding the setup with multiple services, or deploy it in a cloud-based Kubernetes cluster for a more realistic scenario.
Connect with me: https://linktr.ee/ayusht02