Kubernetes nginx-Ingress reverse proxy some paths - kubernetes

i'm trying to reverse proxy using nginx-ingress.
but i cannot find a way to apply reverse proxy in only certain paths
for example, i want apply reverse proxy http://myservice.com/about/* from CDN static resources
and other paths serve my service (in example, it means 'my-service-web' service)
maybe in terms of k8s, CDN means "public external service"
in result,
http://myservice.com/about/* -> reverse proxy from CDN (external service)
http://myservice.com/* -> my-service-web (internal service)
here is my ingress.yaml file
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: my-service-web
namespace: my-service
annotations:
kubernetes.io/ingress.class: nginx-ingress
nginx.ingress.kubernetes.io/server-snippet: |
location ~ /about/(.*) {
proxy_pass https://CDN_URL/$1${is_args}${args};
......and other proxy settings
}
spec:
rules:
- host: myservice.com
http:
paths:
- path: /about
........how do i configuration this?
- path: /*
backend:
serviceName: my-service-web
servicePort: 80
how do i set rules and annotations?

You can create a service with externalName type that will point to your external service (CDN) and it's well explained in this blog post, for example:
apiVersion: v1
kind: Service
metadata:
name: my-service
namespace: my-service
spec:
type: ExternalName
externalName: FQDN
and then use it in your ingress rules by referring to the service name.

Related

K8s Ingress to Static Assets in DigitalOcean Bucket

I'm trying to use an Ingress and ExternalName Service in Kubernetes to route traffic to an external storage service (DigitalOcean Spaces) - but no matter what I try, I get some form of http error.
Things I've tried:
https://github.com/kubernetes/ingress-nginx/pull/629#issue-116679227 (Error: 404 Not Found, nginx)
https://github.com/kubernetes/ingress-nginx/issues/1809 (Error: 502 Bad Gateway, nginx)
A fair bit of other tinkering which has been lost to time.
How do I configure a K8s Ingress/Service to direct ingress requests from example.com/static to a storage bucket (e.g. <zone>.digitaloceanspaces.com/<bucket-name>/<path>/<object>)?
It looks like some of the resources I was able to find were simply outdated. The following solution works as of Kubernetes v1.21.4.
Important Notes:
All Ingress annotations are required:
kubernetes.io/ingress.class: nginx - necessary to engage Nginx ingress controller.
nginx.ingress.kubernetes.io/backend-protocol: HTTPS - necessary to maintain HTTPS traffic to service (this replaces /secure-backends in older versions).
nginx.ingress.kubernetes.io/upstream-vhost - must match service externalName, removes hostname from request path (e.g. if this is missing and being tested through localhost, will likely encounter error: "No such bucket: localhost").
nginx.ingress.kubernetes.io/rewrite-target - passes matched asset URL path through to service.
The path.service.port.number in the Ingress definition must match whatever port the ExternalName service expects (443 in the case of our HTTPS traffic).
apiVersion: v1
kind: Service
metadata:
name: do-bucket-service
spec:
type: ExternalName
externalName: <zone>.digitaloceanspaces.com
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: do-bucket-ingress
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/backend-protocol: HTTPS
nginx.ingress.kubernetes.io/rewrite-target: /<bucket>/$2
nginx.ingress.kubernetes.io/upstream-vhost: <zone>.digitaloceanspaces.com
spec:
rules:
- http:
paths:
- path: /path/to/static/assets(/|$)(.*)
pathType: Prefix
backend:
service:
name: do-bucket-service
port:
number: 443

Ingress on self-hosted Kubernetes on custom interface

I would like to deploy an ngingx-ingress controller on my self-hosted Kubernetes (microk8s) that is configurable to listen on one or more interfaces (external IPs).
Not even sure if that is easily possible and I should just switch to an external solution, such as HAProxy or an nginx.
Required behavior:
192.168.0.1-H"domain.com":443/frontend -> 192.168.0.1 (eth0) -> ingress -> service-frontend
192.168.0.1-H"domain.com":443/backend -> 192.168.0.1 (eth0) -> ingress -> service-backend
88.88.88.88-H"domain.com":443/frontend -> 88.88.88.88 (eth1) -> ? -> [403 or timeout]
88.88.88.88-H"domain.com":443/backend -> 88.88.88.88 (eth1) -> ? -> [403 or timeout]
And then later the eth1 interface should be able to be switched on, so that requests on that interface behave the same as on eth0.
I would like to be able to deploy multiple instances of services for load-balancing. I would like to keep the configuration in my namespace (if possible) so I can always delete and apply everything at once.
I'm using this guide as a reference: https://kubernetes.github.io/ingress-nginx/deploy/baremetal/
I was able to get something working with minikube, but obviously could not expose any external IPs and performance was quite bad. For that, I just configured a "kind: Ingress" and that was it.
So far, the ingress controller that's default on microk8s seems to listen on all interfaces and I can only configure it in its own namespace. Defining my own ingress seems to not have any effect.
I would like to deploy an ngingx-ingress controller on my self-hosted
Kubernetes (microk8s) that is configurable to listen on one or more
interfaces (external IPs).
For above scenario, you have to deploy the multiple ingress controller of Nginx ingress and keep the different class name in it.
Official document : https://kubernetes.github.io/ingress-nginx/user-guide/multiple-ingress/
So in this scenario, you have to create the Kubernetes service with Loadbalancer IP and each will point to the respective deployment and class will be used in the ingress object.
If you looking forward to use the multiple domains with a single ingress controller you can easily do it by mentioning the host into ingress.
Example for two domain :
bar.foo.dev
foo.bar.dev
YAML example
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: frontdoor-bar
annotations:
kubernetes.io/ingress.class: nginx
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/rewrite-target: /$1
nginx.ingress.kubernetes.io/use-regex: "true"
spec:
tls:
- hosts:
- bar.foo.dev
secretName: tls-secret-bar
rules:
- host: bar.foo.dev
http:
paths:
- backend:
serviceName: barfoo
servicePort: 80
path: /(.*)
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: frontdoor-foo
annotations:
kubernetes.io/ingress.class: nginx
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
tls:
- hosts:
- foo.bar.dev
secretName: tls-secret-foo
rules:
- host: foo.bar.dev
http:
paths:
- backend:
serviceName: foobar
servicePort: 9000
path: /(.*)
One potential fix was much simpler than anticipated, no messing with MetalLB needed or anything else.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
annotations:
kubernetes.io/ingress.class: "public"
nginx.ingress.kubernetes.io/whitelist-source-range: 192.168.0.0/24
...
This does not answer the question of splitting an Ingress across multiple interfaces, but it does solve the problem of restricting public access.
By default, bare-metal ingress will listen on all interfaces, which might be a security issue.
This solution works without enabling ingress on Microk8s:
install ingress controller : kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.34.1/deploy/static/provider/baremetal/deploy.yaml
create your deployment and service and add this Ingress resource (all in the one namespace):
kind: Ingress
metadata:
annotations:
ingress.kubernetes.io/service-upstream: 'true'
nginx.ingress.kubernetes.io/rewrite-target: "/$2"
name: ingress-resource
namespace: namespace-name
spec:
rules:
- http:
paths:
- backend:
service:
name: service-name
port:
number: service-port
path: /namespace-name/service-name(/|$)(.*)
pathType: Prefix
kubectl get svc -n ingress-nginx
now get either CLUSTER-IP or EXTERNAL-IP and :
curl ip/namespace-here/service-here

Can I point an Ingress controller to an external service like AWS S3

I want to have a setup where my dns points to my EKS cluster, and my EKS cluster points api.server.com/static
to files on S3 and api.server.com/api to my tomcat deployment.
I'm curious if and how this is possible.
Yes, you can add a service of "externalName" type pointing to an external domain name. This has to be a FQDN, not a URL though, you need to add routing logic to your ingress.
---
apiVersion: v1
kind: Service
metadata:
name: external
namespace: default
labels:
app: external
spec:
type: ExternalName # <-- this is the service type for external resources
externalName: s3.amazon.fqdn # <-- put your external domain here
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: external
namespace: default
nginx.ingress.kubernetes.io/rewrite-target: / # <-- your routing logic?
spec:
rules:
- http:
paths:
- path: /static # <-- your routing logic
backend:
serviceName: external # <-- your service name
servicePort: 80

Kubernetes Service pointing to External Resource

We have an existing website, lets say example.com, which is a CNAME for where.my.server.really.is.com.
We're now developing new services using Kubernetes. Our first service /login is ready to be deployed. Using a mock HTML server I've been able to deploy two pods with seperate services that map to example.com and example.com/login.
What I would like to do is get rid of my mock HTML server, and provide a service inside of the cluster, that points to our full website outside of the server. Then I can change the DNS for example.com to point to our kubernetes cluster and people will still get the main site from where.my.server.really.is.com.
We are using Traefik for ingress, and these are the changes I've made to the config for the website:
---
kind: Service
apiVersion: v1
metadata:
name: wordpress
spec:
type: ExternalName
externalName: where.my.server.really.is.com
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: wordpress
annotations:
kubernetes.io/ingress.class: traefik
spec:
backend:
serviceName: wordpress
servicePort: 80
rules:
- host: example.com
http:
paths:
- backend:
serviceName: wordpress
servicePort: 80
Unfortunately, when I visit example.com, rather than getting where.my.server.really.is.com, I get a 503 with the body "Service Unavailable". example.com/login works as expected
What have I missed?
Following traefik documentation on using ExternalName
When specifying an ExternalName, Træfik will forward requests to the given host accordingly and use HTTPS when the Service port matches 443.
This still requires setting up a proper port mapping on the Service from the Ingress port to the (external) Service port.
I believe you are missing the ports configuration of the Service. Something like
apiVersion: v1
kind: Service
metadata:
name: wordpress
spec:
ports:
- name: http
port: 80
type: ExternalName
externalName: where.my.server.really.is.com
You can see a full example in the docs.

Route traffic to a service in a different namespace with Traefik and Kubernetes

Using Traefik as an ingress controller (on a kube cluster in GCP).
Is it possible to create an ingress rule that uses a backend service from a different namespace?
We have a namespace for each of our "major" versions of code.
1-service.com -> 1-service.com ingress in the 1-service ns -> 1-service svc in the same ns
2-service.com -> 2-service.com ingress in the 2-service ns... and so on
I also would like another ingress rule in the "unversioned" namespace that will route traffic to one of the major releases.
service.com -> service.com ingress in the "service" ns -> X-service in the X-service namespace
I would like to keep major versions separate in k8s using versioned host names (1-service.com etc), but still have a "latest" that points to the latest of the releases.
I believe voyager can do cross namespace ingress -> svc. can Traefik do the same??
You can use a workaround like this:
Create a Service with type ExternalName in your namespace when you want to create an ingress:
apiVersion: v1
kind: Service
metadata:
name: service-1
namespace: unversioned
spec:
type: ExternalName
externalName: service-1.service-1-ns.svc.cluster.local
ports:
- name: http
port: 8080
protocol: TCP
Create an ingress that point to this service:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: traefik
name: ingress-to-other-ns
namespace: service-1-ns
spec:
rules:
- host: latest.example.com
http:
paths:
- backend:
serviceName: service-1
servicePort: 8080
path: /
Just tested with the following example on EKS. Traefik is deployed in default namespace. This is the config used for the k8s service:
---
apiVersion: v1
kind: Service
metadata:
name: 1-service
namespace: 1-service
labels:
app: 1-service
spec:
selector:
app: 1-service
ports:
- name: http
port: 80
targetPort: 80
And this is the config used for Traefik service that will send the request to different namespace:
services:
1-service:
loadBalancer:
servers:
- url: http://1-service.1-service.svc.cluster.local:80
# - url: http://1-service.1-service:80 # This should work perfectly as well, didn't test it explicitly
As you probably already get that, you can reference to services from different namespace by using SERVICE.NAMESPACE notation, instead of the SERVICE, which will automatically assume that you are referencing a service from the current namespace.