Kubernetes Ingress Path Override
Suppose we have an old website and page by page rewriting it to something new
- We have some project
demo.mac-blog.org.ua
- It has few endpoints:
/
/about/
/about/company/
/contacts/
Lets deploy old.yml
(simple deployment, nothing special)
---
apiVersion: v1
kind: ConfigMap
metadata:
name: old
data:
index.html: "HOME OLD\n"
about.html: "ABOUT OLD\n"
company.html: "ABOUT COMPANY OLD\n"
contacts.html: "CONTACTS OLD\n"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: old
labels:
app: old
spec:
selector:
matchLabels:
app: old
template:
metadata:
labels:
app: old
spec:
nodeSelector:
kubernetes.io/os: linux
containers:
- name: old
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
resources:
limits:
cpu: 500m
memory: 500Mi
requests:
cpu: 50m
memory: 100Mi
volumeMounts:
- name: old-home
mountPath: /usr/share/nginx/html
- name: old-about
mountPath: /usr/share/nginx/html/about
- name: old-about-company
mountPath: /usr/share/nginx/html/about/company
- name: old-contacts
mountPath: /usr/share/nginx/html/contacts
volumes:
- name: old-home
configMap:
name: old
items:
- key: index.html
path: index.html
- name: old-about
configMap:
name: old
items:
- key: about.html
path: index.html
- name: old-about-company
configMap:
name: old
items:
- key: company.html
path: index.html
- name: old-contacts
configMap:
name: old
items:
- key: contacts.html
path: index.html
---
apiVersion: v1
kind: Service
metadata:
name: old
spec:
type: ClusterIP
selector:
app: old
ports:
- protocol: TCP
port: 80
targetPort: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: old
spec:
ingressClassName: external
rules:
- host: demo.mac-blog.org.ua
http:
paths:
- backend:
service:
name: old
port:
number: 80
path: /
pathType: ImplementationSpecific
And check it inside our cluster
kubectl apply -f old.yml
kubectl get po -l app=old
curl --resolve demo.mac-blog.org.ua:80:20.13.179.68 http://demo.mac-blog.org.ua/
# HOME OLD
curl --resolve demo.mac-blog.org.ua:80:20.13.179.68 http://demo.mac-blog.org.ua/about/
# ABOUT OLD
curl --resolve demo.mac-blog.org.ua:80:20.13.179.68 http://demo.mac-blog.org.ua/about/company/
# ABOUT COMPANY OLD
curl --resolve demo.mac-blog.org.ua:80:20.13.179.68 http://demo.mac-blog.org.ua/contacts/
# CONTACTS OLD
Ingress allows us to override upstream services by url prefix
Lets imagine that our new version of web site has only "about" page ready
Deploy new.yml
(once again nothing fancy, usual deployment, BUT, it has the same domain as in old.yml
, and path is changed from /
to /about
)
---
apiVersion: v1
kind: ConfigMap
metadata:
name: new
data:
about.html: "ABOUT NEW\n"
company.html: "ABOUT COMPANY NEW\n"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: new
labels:
app: new
spec:
selector:
matchLabels:
app: new
template:
metadata:
labels:
app: new
spec:
nodeSelector:
kubernetes.io/os: linux
containers:
- name: new
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
resources:
limits:
cpu: 500m
memory: 500Mi
requests:
cpu: 50m
memory: 100Mi
volumeMounts:
- name: new-about
mountPath: /usr/share/nginx/html/about
- name: new-about-company
mountPath: /usr/share/nginx/html/about/company
volumes:
- name: new-about
configMap:
name: new
items:
- key: about.html
path: index.html
- name: new-about-company
configMap:
name: new
items:
- key: company.html
path: index.html
---
apiVersion: v1
kind: Service
metadata:
name: new
spec:
type: ClusterIP
selector:
app: new
ports:
- protocol: TCP
port: 80
targetPort: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: new
spec:
ingressClassName: external
rules:
# POI: DNS is the same
- host: demo.mac-blog.org.ua
http:
paths:
- backend:
service:
name: new
port:
number: 80
# POI: but path is different
path: /about
pathType: ImplementationSpecific
kubectl apply -f new.yml
kubectl get po -l app=new
kubectl get ing | grep -E "old|new"
curl --resolve demo.mac-blog.org.ua:80:20.13.179.68 http://demo.mac-blog.org.ua/
# HOME OLD <- still served by old service
curl --resolve demo.mac-blog.org.ua:80:20.13.179.68 http://demo.mac-blog.org.ua/about/
# ABOUT NEW <- served by new service
curl --resolve demo.mac-blog.org.ua:80:20.13.179.68 http://demo.mac-blog.org.ua/about/company/
# ABOUT COMPANY NEW <- served by new service
curl --resolve demo.mac-blog.org.ua:80:20.13.179.68 http://demo.mac-blog.org.ua/contacts/
# CONTACTS OLD <- still served by old service
If we do not want to serve all about sub routes, but only about page, for that we may change path type to exact, more details about this setting can be found here https://kubernetes.io/docs/concepts/services-networking/ingress/#path-types
Lets deploy next variation new2.yml
---
apiVersion: v1
kind: ConfigMap
metadata:
name: new
data:
about.html: "ABOUT NEW\n"
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: new
labels:
app: new
spec:
selector:
matchLabels:
app: new
template:
metadata:
labels:
app: new
spec:
nodeSelector:
kubernetes.io/os: linux
containers:
- name: new
image: nginx
imagePullPolicy: IfNotPresent
ports:
- containerPort: 80
resources:
limits:
cpu: 500m
memory: 500Mi
requests:
cpu: 50m
memory: 100Mi
volumeMounts:
- name: new-about
mountPath: /usr/share/nginx/html/about
volumes:
- name: new-about
configMap:
name: new
items:
- key: about.html
path: index.html
---
apiVersion: v1
kind: Service
metadata:
name: new
spec:
type: ClusterIP
selector:
app: new
ports:
- protocol: TCP
port: 80
targetPort: 80
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: new
spec:
ingressClassName: external
rules:
# POI: DNS is the same
- host: demo.mac-blog.org.ua
http:
paths:
- backend:
service:
name: new
port:
number: 80
# POI: but path is different
path: /about/
# POI: changed from "ImplementationSpecific" to "Exact"
pathType: Exact
kubectl apply -f new.yml
curl --resolve demo.mac-blog.org.ua:80:20.13.179.68 http://demo.mac-blog.org.ua/
# HOME OLD <- still served by old service, ok
curl --resolve demo.mac-blog.org.ua:80:20.13.179.68 http://demo.mac-blog.org.ua/about/
# ABOUT NEW <- served by new service, what we want
curl --resolve demo.mac-blog.org.ua:80:20.13.179.68 http://demo.mac-blog.org.ua/about/company/
# ABOUT COMPANY OLD <- what we wanted, only concrete endpoint is served by new service
curl --resolve demo.mac-blog.org.ua:80:20.13.179.68 http://demo.mac-blog.org.ua/contacts/
# CONTACTS OLD <- still served by old service
Note that if we delete this new ingress, requests will still work and will be served by old implementation
kubectl delete ing,svc,deployment new
curl --resolve demo.mac-blog.org.ua:80:20.13.179.68 http://demo.mac-blog.org.ua/about/
# ABOUT OLD <- expected, we have removed new.yml which did override that
To cleanup everything
kubectl delete ing,svc,deployment old
Ingress to AWS S3
Here is how we can create something similar to AWS S3 static site with help of Ingress, but even more, we are going to serve single file on main domain
# Note: our service points to another domain instead of pods
---
apiVersion: v1
kind: Service
metadata:
name: s3
spec:
type: ExternalName
externalName: s3.eu-central-1.amazonaws.com
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: s3
annotations:
# POI: rewrite target, can use regex, simplified for demo
nginx.ingress.kubernetes.io/rewrite-target: /static.mac-blog.org.ua/sitemap.xml
# POI: optional, because of host S3 works we override host as well
nginx.ingress.kubernetes.io/upstream-vhost: s3.eu-central-1.amazonaws.com
spec:
ingressClassName: external
rules:
# POI: main website
- host: mac-blog.org.ua
http:
paths:
- backend:
service:
name: s3
port:
number: 80
# POI: we want to serve only this path
path: /sitemap.xml
pathType: ImplementationSpecific
Ingress to external service
Also we may configure everything in a such a way so it does not matter if for example our old site is running outside Kubernetes
With all such approaches Ingress may become single entry point for everything which has its benefits, especially after tuning its compression