Ingress
A Layer-7 Load-Balancer built in to tk8s cluster.
Can be built like any other object in k8s - with a yaml file!
The Ingress does need to be exposed to the world, published with a NodePort or with a Cloud-Native LoadBalancer.
Ingress helps with load-balancing, auth, ssl, url-based routing config on the ingress controller.
Without ingress, a reverse-proxy might be useful as a type of "ingress controller" to configure them to route traffic based on urls.
- Ingress
Ingress Requires 2 Things: Rules and A Controller
With Ingress, 2 parts are required. A Controller/reverse-proxy like nginx, haproxy or traefik. Configuration, aka "ingress rules", is also required.
K8s Clusters Require a 3rd-Party Ingress Controller
K8s does not come with an Ingress controller by default.
Ingress Resources will not work without this controller.
Try nginx as a first implementaiton.
Roles of the Controller
A Load-Balancer.
Additional details, "intelligence", to monitor the cluster for new definitions or new ingress resources.
Options for the Controllers
A number of solutions exist:
- GCE
- Nginx
- Contour
- HaProxy
- Traefik
- Istio
Per K8s Docs, "Kubernetes as a project supports and maintains AWS, GCE and nginx ingress controllers.".
Ingress Controller as Another Object In the Cluster
Configuration Requirements
A few things are required:
- A ConfigMap, full of env vars - storing config vars in a configMap allows for toggling congif vars only in this configMap file, not deep in some other pod or deployment def file
- path to store logs
- session timeouts
- keep-alive threshold
- .... more config vars are available
- A Deployment Definition file, describing the deployment of the nginx-ingress pod
- Env Vars passed to the def file: the pod name and the namespace that it is deployed to
- Ports used by the ingress controller, here 80 (http) and 443 (https)
- A Service To Expose the Ingress Controller, a NodePort service linking this service to the ingress pod deployment
- A Service Account with permissions for the ingress controller to do its job
Deployment Config File
Here, a yaml for an nginx ingress controller. Here, the image is specially built for k8s.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-ingress-controller
spec:
replicas: 1
selector:
matchLabels:
name: nginx-ingress
template:
# deployment metadata
metadata:
labels:
name: nginx-ingress
spec:
containers:
- name: nginx-ingress-controller
image: controller/nginx-ingress-controller:0.21.0
args:
# the path where the nginx controller lives in the docker image
- /nginx-ingress-controller
# configmap through cli params
- --configmap=$(POD_NAMESPACE)/nginx-configuration
# pod name + namespace for nginx to read config data from within the pod
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
# ports used by this ingress controller
ports:
- name: http
containerPort: 80
- name: https
containerPort: 443
ConfigMap Object
apiVersion: v1
kind: ConfigMap
metadata:
name: nginx-config
Service Exposing Ingress Controller to the World
Exposing this new ingress object to the world with a NodePort Service:
apiVersion: v1
kind: Service
metadata:
name: nginx-ingress
spec:
type: NodePort
ports:
- name: http
protocol: http
port: 80
targetPort: 80
- name: https
protocol: https
port: 443
targetPort: 443
selector:
# matches the deployment metadata.name field in ingress deployment config file - above
name: nginx-ingress
Service Account Config
The Ingress controllers have intelligence.
The Ingress controllers monitor the K8s cluster for ingress resources.
The Ingress controllers configure the underlying nginx server when something changes.
The ingress controller requires a service account with "correct" permissions.
apiVersion: v1
kind: ServiceAccount
metadata:
name: nginx-ingress-serviceaccount
Ingress Resources
Rules + Config on the Ingress Controller: route traffic to different apps (pods) based on urls, and/or domain doman.
A Workflow for Exposing a Project to the world
- Create a Deployment
kubectl create deployment.... etc...
- Create A ClusterIP Service to expose the deployment
kubectl create service clusterip ...
- Create an Ingress Resource to expose the project to the world
- this one can get started with something like
kubectl create ingress projectingress --rule="theurl.com/aPath*=<the-service-name>:<a-port-to-expose!>"
- this one can get started with something like
A Trivial Ingress definition File
Here, an ingress resource def file:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-wear-app
spec:
# where traffic gets routed to
backend:
serviceName: wear-service
servicePort: 80
Rules
Rules are explicit to deal with routing.
Domain Or HostName
Traffic can be dealt with by domain or host:
- home.store.com
- learn.store.com
All paths for each domain get routed to the same service, perhaps a single-page app or something like that!
A Domain-Name Config File:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-wear-app
spec:
rules:
# two hosts, 1 service per host
- host: watch.store.com
http:
paths:
- backend:
service:
name: watch-service
port:
number: 80
- host: learn.store.com
http:
paths:
- backend:
service:
name: learn-service
port:
number: 80
Path
- store.com/watch
- store.com/cart
A look at an ingress def file with rules.
NOTE: No host field in the rules - this applies to all "*" host paths.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-wear-app
spec:
rules:
- http:
# path-based routing
paths:
# each path gets its own backend section
- path: /watch
pathType: Prefix
backend:
service:
name: watch-service
port:
number: 80
- path: /learn
pathType: Prefix
backend:
service:
name: learn-service
port:
number: 80
Inspect these with kubectl describe ingress instress-wear-app
. Notice a "default backend"! Deploy that one, default-http-backend or whatever it is called.
Consider Re-Writing Urls
Useful Commands & References
See k8s ingress docs.
See Kubectl Commands Docs for more, but here's a short list:
# create an ingress
# kubectl create ingress <ing-name> --rule="host/path=service:port"
kubectl create ingress ing-test --rule="learn.store.com/videos*=videos-service:80"
# create a "catch-all", perhoaps for error handling
kubectl create ingress all-else --class=otheringress --rule="/path=error-service:80"
Things To Be Able To Do
- Inspect a k8s setup
- kk get namespaces, find a bunch of namespaces
- get deployments across namespaces
kkg deployments.app --all-namespaces -o wide
- know that ingress might use a Deployment object
- figure out what namespace...
- an ingress controller is deployed to
- a bunch of pods/apps are deployed to
- an ingress resource is deployed to
- Which namespace is an ingress resource deployed in
kkg ingress --all-namespaces
- which hosts are configured on an ingress resource
- whats the name of an ingress resource
- what is the backend of an ingress resource
kkd -n <the-namespace> ingress <the-ingress-name>
- what paths are each service available on
- what services are available at what path
- what service(s) are served on requests to funky backends
- Change an ingress config, serve a service from another route
- get ingress config into yaml
- edit yaml per requirement
- kk delete current ingress -n namespace
- kk apply -f ingress-def-file.yaml
- create a namespace
- for nginx ingress controller: create a configmap and assign it to a namespace
- for nginx ingress controller: create a service-account and assign it to a namespace
- create a service that...
- lives in a specified namespace
- exposes a deployment by name
- named "ingress"
- exposes port 80 from the pod port 80
- is of type NodePort for public accessibility
kk -n ingress-space expose deployment ingress-controller --name ingress --port=80 --target-port=80 --type=NodePort --dry-run=client -o yaml > svc.yaml