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:
Where to listen: The port (e.g.,
8080
) and protocol (e.g., HTTP or HTTPS).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