Skip to content

Simple REST endpoint to determine existence of Kubernetes Ingress "host" presence (or lack thereof) in a k8s cluster.

Notifications You must be signed in to change notification settings

bitsofinfo/kubernetes-ingress-info

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

23 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

kubernetes-ingress-info

This project provides a simple REST service that can be deployed to any Kubernetes cluster that reports whether or not a host exists in any Ingress deployed to that cluster.

Its important that this API does not report on the health of any given Ingress host but specifically whether or not ANY Ingress currently exists on the cluster where kubernetes-ingress-info is deployed, regardless of if its backend is actually up. It is intended to be a very lightweight and open endpoint to interrogate for this status.

This tool was specifically developed to serve as a endpoint for various cloud load-balancers and DNS services to be able to auto-detect which Kubernetes clusters are valid for a specific host FQDN. This can aid in workload migration across various clusters or just enable workloads to be deployed to subsets of clusters out of many organizational clusters, while letting upstream DNS and or glsb based devices react accordingly as many of these platforms rely on simple HTTP 200 OK type of "checks".

Use case:

This tool was specifically developed to serve as a endpoint for various cloud load-balancers and DNS services to be able to auto-detect which Kubernetes clusters are valid for a specific host FQDN.

Lets say you have two apps available at a.b.com and x.y.com and you have 3 available Kubernetes it could potentially be deployed on, clusterA, clusterB and clusterC. Generally upstream from your cluster LoadBalancers you will have another cloud load balancer device or you are just using some sort of DNS device to control what cluster LoadBalancer IPs are relevant for each application at any given time. So what you can do in this case is list all possible cluster IPs as possible targets for those FQDNs hostname, but enable/disable them based on calls to kubernetes-ingress-info which resides on all clusters. For this to work, you should ensure each possible target cluster Ingress Controller that is behind a LoadBalancer has kubernetes-ingress-info accessible via its own unique Ingress.

diag

Install/Setup

Helm chart:
https://github.com/boarder981/k8s-ingress-info

Run via Docker:
https://hub.docker.com/r/bitsofinfo/kubernetes-ingress-info

Otherwise:

Python 3.6+

Kubernetes version 1.19+

Dependencies: See Dockerfile

When deploying to a Kubernetes cluster the Pod that kubernetes-ingress-info is deployed as needs to run as a serviceAccount with (at a minimum) a binding to a [Cluster]Role with the following RBAC permissions:

...
rules:
- apiGroups: ["networking.k8s.io"]
  resources: ["ingresses"]
  verbs: ["list"]

Example:

This example will install kubernetes-ingress-info onto a Kubernetes cluster. The example.yaml creates a Namespace, ServiceAccount with RBAC bindings, a Deployment, Service and an Ingress bound to host: kubernetes-ingress-info.local.

The ServiceAccount has the ability to list all ingresses on a cluster. You can modify and install to your cluster however you see fit.

kubectl apply -f examples/example.yaml

Once installed, you will need a /etc/hosts entry or DNS setup for kubernetes-ingress-info.local to point to the LoadBalancer configured for whatever IngressController consumed the example Ingress in example.yaml

Let's hit the root to get a list of all Ingress "hosts" on the cluster.

curl http://kubernetes-ingress-info.local

[
  "kubernetes-ingress-info.local",
  ....
]

Validate the existence of a single host, will return a 200

curl http://kubernetes-ingress-info.local/kubernetes-ingress-info.local

{
  "info": "'kubernetes-ingress-info.local' found"
}

How about one that does not exist? (returns a 404)

curl http://kubernetes-ingress-info.local/non-existant-host.com

{
  "error": "'non-existant-host.com' 404 not found"
}

Cleanup:

kubectl delete -f examples/example.yaml

API:

The API is as follows:

GET all Ingress Hosts on the cluster:

curl -X GET http[s]://[kubernetes-ingress-info]

GET a specific host. Returns 200 if host exists, or a 404 if non-existant

curl -X GET http[s]://[kubernetes-ingress-info]/[host]

Note that if you startup info.py with the --host-match-on-header <headername> value, the named HTTP request header will be checked for a host. This host name will then be used if the /<path> host is not found

GET a specific host (via custom header). Returns 200 if host exists, or a 404 if non-existant

curl -X GET http[s]://[kubernetes-ingress-info]/anything -H '<--host-match-on-header header name>: [host]'

Caching:

If you enable caching w/ --enable-cache the internal Ingress database that is constructed after fetching all available Ingress from Kubernetes (and applying all specified selectors) is cached to disk. The cache structure is a single key that stores the entire dictionary to local disk. If running in a container this should have minimal storage requirements and does not necessitate a dedicated volume.

We currently use the https://github.com/grantjenks/python-diskcache library due to its get speed and active project activity.

Usage:

bash-4.4$ python3 info.py -h

usage: info.py [-h] [-r LOAD_CONFIG_MODE] [-i INCLUDE_LABEL_SELECTORS]
               [-x EXCLUDE_LABEL_SELECTORS] [-n NAMESPACES]
               [-m HOST_MATCH_ON_HEADER] [-p LISTEN_PORT] [-c]
               [-e CACHE_TTL_SECONDS] [-d CACHE_DIR] [-l LOG_LEVEL]
               [-b LOG_FILE]

optional arguments:
  -h, --help            show this help message and exit
  -r LOAD_CONFIG_MODE, --load-config-mode LOAD_CONFIG_MODE
                        How the target k8s cluster config will be loaded,
                        'local' will leverage the current kubectl context from
                        '~/.kube/config', while 'cluster' will talk direct to
                        the cluster the process is executing in using the
                        Pod's configured serviceAccount which needs read
                        access to all objects of type Ingress. Default 'local'
  -i INCLUDE_LABEL_SELECTORS, --include-label-selectors INCLUDE_LABEL_SELECTORS
                        Optional comma delimited of Ingress
                        label1=value,label2=value pairs that will be used to
                        build the database of IngressInfo objects available to
                        be fetched. If specified, ONLY Ingress objects having
                        ALL specified labels will be retrieved. If not
                        specified, ALL available Ingress objects will be
                        retrieved from k8s. Excludes take precendence over
                        includes.
  -x EXCLUDE_LABEL_SELECTORS, --exclude-label-selectors EXCLUDE_LABEL_SELECTORS
                        Optional comma delimited of Ingress
                        label1=value,label2=value pairs that will be used to
                        restrict the database of IngressInfo objects available
                        to be fetched. If specified, ONLY Ingress objects NOT
                        having ANY of the specified labels will be retrieved.
                        If not specified, ALL available Ingress objects will
                        be retrieved from k8s. Excludes take precendence over
                        includes.
  -n NAMESPACES, --namespace NAMESPACES
                        Optional comma delimited of Namespaces to scope
                        Ingress fetch within
  -m HOST_MATCH_ON_HEADER, --host-match-on-header HOST_MATCH_ON_HEADER
                        Optional name of HTTP Request header who's value will
                        be inspected for an Ingress host match, should the
                        default path based /[host] not find a match.
  -p LISTEN_PORT, --listen-port LISTEN_PORT
                        Port to listen on, default 8081
  -c, --enable-cache    Optional, enabling caching (uses
                        https://github.com/grantjenks/python-diskcache)
  -e CACHE_TTL_SECONDS, --cache-ttl-seconds CACHE_TTL_SECONDS
                        Optional, cache TTL in seconds
  -d CACHE_DIR, --cache-dir CACHE_DIR
                        Optional, cache dir, default /opt/kubernetes-ingress-
                        info/cache
  -l LOG_LEVEL, --log-level LOG_LEVEL
                        log level, default DEBUG
  -b LOG_FILE, --log-file LOG_FILE
                        Path to log file, default None, STDOUT