How to add websocket support to an ingress resource in Kubernetes on IBM Bluemix? - nginx

When the client tries to connect our ingress defined endpoint via a wss:// request, the app returns 400 bad request, which according to socket.io docs is due to missing headers removed by load balancing proxies like nginx.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: my-ingress
annotations:
nginx.org/websocket-services: service-name
spec:
tls:
- hosts:
- www.myhost.com
rules:
- host: www.myhost.com
http:
paths:
- path: /
backend:
serviceName: service-name
servicePort: 80
From the logs in the IBM provided ingress controller it seems to be a fork of this nginx ingress controller. Which says that the annotation nginx.org/websocket-services adds support for websockets by adding directives to the generated nginx conf to pass the required headers. We have tried this as per above but to no avail.
Has anyone had any success making this annotation work?
Any workarounds for adding to the generated nginx conf?
Any IBM people know if this functionality was intentionally removed from the fork? And if there is any way to add support for websockets in the IBM version of Kubernetes?

Websockets is not currently supported, we are working on adding it and I will update here when it is available.
Thank you
Edit: Websocket support is available in all regions, the annotation for it is:
annotations:
ingress.bluemix.net/websocket-services: service-name

Related

Hostname (SNI) missing while using nginx ingress SSL Passtrough to underlying service

I'm trying to implement SSL Passtrough with nginx-ingress-controller. This is my Ingress Object:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/backend-protocol: HTTPS
nginx.ingress.kubernetes.io/ssl-passthrough: "true"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
labels:
my-label: example
name: example
namespace: example
spec:
rules:
- host: '*.example.com'
http:
paths:
- backend:
serviceName: example
servicePort: 8443
path: /
The --enable-ssl-passtrough flag is present in the controller args.
When request is coming trough ingress controller to my underlying service I'm trying to parse the SNI to find out what domain was used to find out the certificate I should present, but the service cannot find the SNI and returns this error:
{"level":"debug","ts":1592992137.1836417,"msg":"Error getting server name","error":"No hostname"}
Does nginx-ingress-controller remove the SNI when parsing? Or what may be the reason for such behavior?
Thanks in advance for help
I contacted nginx-ingress developers directly and I got information that the reason this is not working is the wildcard domain, which is not supported by nginx-ingress.
Everything else is configured correctly and when changing *.example.com into something specific (e.g. whatever.example.com) it works correctly.

Can you set backend-protocol per rule in k8s nginx ingress?

I have a kubernetes cluster setup with two services set up.
Service1 links to Deployment1 and Service2 links to Deployment2.
Deployment1 serves pods which can only be connected to using http.
Deployment2 serves pods which can only be connected to using https.
Using kubectl port-forward and exec'ing into pods I know the services and deployments are responding as they should, connectivity internally between the services is working fine.
I have an nginx ingress setup to allow external connections to both services. The services should only be connected to using https and any incoming connections that are http need to be redirected to https. Here is the ingress setup:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: master-ingress
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/ssl-redirect: "true"
cert-manager.io/cluster-issuer: "letsencrypt-production"
spec:
tls:
- secretName: tls-secret-one
hosts:
- service1.domain.com
- service2.domain.com
rules:
- host: "service1.domain.com"
http:
paths:
- path: /
backend:
serviceName: service1
servicePort: 60001
- host: "service2.domain.com"
http:
paths:
- path: /
backend:
serviceName: service2
servicePort: 60002
Here is the problem. With this yaml I can connect to service1 (http backend) with no issues but connecting to service2 (https backend) results in a 502 Bad Gateway.
If I add the annotation ' nginx.ingress.kubernetes.io/backend-protocol: "https" ' the connectivity switches. I can no longer connect to service1 (http backend) but can connect to service2 (https backend)
I can understand why the switch does this, but my question is:
Can you set the backend-protocol per rule in an nginx-ingress ?
It's not possible to set backend protocol per rule in a single ingress. To achieve what you want you can create two different ingress one for service1 and another one for service2 and annotate the ingress for service1 with http and ingress for service2 with https.

Nginx Ingress - how to set redirect to external site if there is no matching route?

beginner here. I am currently trying to configure Ingress to do two things - if the fibonacci route exists, redirect to the function and pass the parameter, if the route doesn't exist, redirect to another website and attach the input there.
So, for example, there are two basic scenarios.
https://xxx.amazonaws.com/fibonacci/10 -> calls fibonacci function with parameter 10 (that works)
https://xxx.amazonaws.com/users/jozef -> calls redirect function which redirects to https://api.github.com/users/jozef
I think the service doing the redirect is written correctly, it looks like this.
kind: Service
apiVersion: v1
metadata:
name: api-gateway-redirect-service
spec:
type: ExternalName
externalName: api.github.com
ports:
- protocol: TCP
targetPort: 443
port: 80 # Default port for image
This is how my Ingress looks like. Experimented with default-backend annotation as well as various placement of the default backend, nothing worked. When I try to curl https://xxx.amazonaws.com/users/jozef, I keep getting 301 message but the location is unchanged. The final output looks like this
HTTP/1.1 301 Moved Permanently
Server: openresty/1.15.8.2
Date: Wed, 13 Nov 2019 15:52:14 GMT
Content-Length: 0
Connection: keep-alive
Location: https://xxx.amazonaws.com/users/jozef
* Connection #0 to host xxx.amazonaws.com left intact
* Maximum (50) redirects followed
curl: (47) Maximum (50) redirects followed
Does someone have an idea what am I doing wrong? This is my Ingress. Also, if it helps, we use Kubernetes version 1.14.6. Thanks a million
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress-nginx
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "false"
nginx.ingress.kubernetes.io/force-ssl-redirect: "false"
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
rules:
- http:
paths:
- path: /fibonacci/(.*)
backend:
serviceName: fibonacci-k8s-service
servicePort: 80
- path: /(.*)
backend:
serviceName: api-gateway-redirect-service
servicePort: 80
The resolution to the problem was the addition of the 'Host: hostname' header in the curl command.
The service that was handling the request needed Host: hostname header to properly reply to this request. After the hostname header was provided the respond was correct.
Links:
Curl docs
Ingress docs
So I ve kept reading about this subject and it turns out that ingress controllers generally don't go through services but connect to pods directly (it looks up pods selected by the service and configures them into nginx), wich makes the use case here (connecting to the serice that isn't backed up by anypod) destined to fail.
HOWEVER, it looks like that in recent version this has been supported by nginx ingress controller with nginx+ ONLY so far.
references:
Support for Type ExternalName Services
Ingress uses Endpoints to configure PODs Ips in nginx config to load balance

Is it possible to rewrite HOST header in k8s Ingress Controller?

Due to some legacy application that relies on Host header to function correctly, I need to have an Ingress (proxy, etc) that capable of rewrite Host header and pass that to downstream (backend). Is there any Ingress Controller that supports this functionality?
Example:
End user access our website through foo.com/a for backend a and foo.com/b for backend b. But since a and b are legacy app, it only accept:
a accepts connection when Host: a.foo.com
b accepts connection when Host: b.foo.com
This can be done using this annotation: nginx.ingress.kubernetes.io/upstream-vhost: host.example.com
I'm not sure whether you can find appropriate annotation within NGINX Ingress Controller for Host header modification to match your requirement as well. However, you can consider using nginx.ingress.kubernetes.io/configuration-snippet annotation in order to append configuration snippet to the location block inside nginx.conf of the particular Nginx controller pod:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/configuration-snippet: |
proxy_set_header Host www.example-host.com;
name: my-app
spec:
rules:
- host: my-app.example.com
http:
paths:
- backend:
path: /app
serviceName: my-app
servicePort: http
We set here Host header www.example-host.com for target URL my-app.example.com.
I want to add my finding to this question of mine.
Although my solution is not using k8s Ingress Controller, our cluster is using Istio and Istio's VirtualService supports rewrite the uri and authority (Host header) as documented in this link: https://istio.io/docs/reference/config/istio.networking.v1alpha3/#HTTPRewrite
To know how I implement that in my case, you can take a look at this link: https://github.com/istio/istio/issues/11668
you can use ingress nginx controller on Kubernetes and set head and also transfer to backend and manage services connection from ingress objects.
here sharing link for rewrite target from header: https://kubernetes.github.io/ingress-nginx/examples/rewrite/
ingress nginx will be also good with SSL cert manager you can add it.
manage other thing using annotations of ingress.
check this out for ingress SSL setup you can modify it and per your need: https://www.digitalocean.com/community/tutorials/how-to-set-up-an-nginx-ingress-with-cert-manager-on-digitalocean-kubernetes
ingress will be like at last
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
tls:
- hosts:
- myapp.abc.com
secretName: ingress-tls
rules:
- host: myapp.abc.com
http:
paths:
- path: /my-service
backend:
serviceName: my-backend
servicePort: 80

kubernetes ingress controller clarification [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
I m bit new to Kubernetes and was going over "Ingress". after reading the k8 docs and googling , I summarised the following. Can somebody confirm/correct my understanding:
To understand Ingress, I divided it into 2 sections :
Cloud Infrastructure:
In this, there is in-built ingress controller which runs in the master node(but we can't see it when running kubectl get pods -n all). To configure , first create ur Deployment Pods and expose them through services (Service Type=NodePort must). Also, make sure to create default-backend-service. Then create ingress rules as follows:
kind: Ingress
metadata:
name: app-ingress
spec:
backend:
serviceName: default-svc
servicePort: 80
rules:
- host: api.foo.com
http:
paths:
- path: /v1/
backend:
serviceName: api-svc-v1
servicePort: 80
- path: /v2/
backend:
serviceName: api-svc-v2
servicePort: 80
Once you apply the ingress rules to the API server, ingress controller listens to the API and updates the /etc/nginx.conf. Also, after few mins, nginx controller creates an external Load balancer with an IP(lets say LB_IP)
now to test: from your browser, enter http://api.foo.com/(or http://) which will redirect to default service and http://api.foo.com/v1(or http:///v1) which will redirect it service api-svc-v1
Question:
how can I see /etc/nginx files since the ingress controller pod is not visible.
During the time, ingress rules are applied and an external LB_IP is getting created, does all the DNS servers of all registrars are updated with DNS entry "api.foo.com "
In-house kubernetes deployment using kubeadm:
In this, there is no external ingress controller and you need to install it manually. To configure, first create ur deployment pods and expose them through service (make sure that service Type=NodePort). Also, make sure to create default-backend-service.Create Ingress controller using the below yaml file:
spec:
containers:
-
args:
- /nginx-ingress-controller
- "--default-backend-service=\\$(POD_NAMESPACE)/default-backend"
image: "gcr.io/google_containers/nginx-ingress-controller:0.8.3"
imagePullPolicy: Always
livenessProbe:
httpGet:
path: /healthz
port: 10254
scheme: HTTP
initialDelaySeconds: 10
timeoutSeconds: 5
name: nginx-ingress-controller
readinessProbe:
httpGet:
path: /healthz
port: 10254
scheme: HTTP
we can see the ingress controller running in node3 using "kubectl get pods" and login to this pod, we can see /etc/nginx/nginx.conf
Now create the ingress rules as follows:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
ingress.kubernetes.io/rewrite-target: /
name: app-ingress
spec:
rules:
- host: testabc.com
http:
paths:
- backend:
serviceName: appsvc1
servicePort: 80
path: /app1
- backend:
serviceName: appsvc2
servicePort: 80
path: /app2
Once you apply the ingress rules to the API server, ingress controller listens to the API and updates the /etc/nginx.conf. But note that there is no Load balancer created . Instead when you do "kubectl get ingress", you get Host=testabc.com and IP=127.0.0.1. Now to expose this ingress-controller outside, I need to create a service with type=NodePort or type=Loadbalancer
kind: Service
metadata:
name: nginx-ingress
spec:
type: NodePort
ports:
- port: 80
nodePort: 33200
name: http
selector:
app: nginx-ingress-lb
After this, we will get an external IP(if type=Loadbalancer)
now to test: from your browser, enter http://testabc.com/(or http://) which will redirect to default service and http://testabc.com/v1(or http:///v1) which will redirect it service api-svc-v1
Question:
3.if the ingress-controller pod is running in node3, how it can listen to ingress api which is running in node1
Q.1 How can I see /etc/nginx files since the ingress controller pod is not visible?
Answer: Whenever you install an Nginx Ingress via Helm, it creates an entire Deployment for that Ingress. This deployment resides in Kube-System Namespace. All the pods bind to this deployment also resides in Kube-System Namespace. So, if you want to get attach to the container of this pod you need to get into that namespace and attache to it. Then you will be able to see the Pods in that namespace.
Here You can see the Namespace is Kube-System & the 1st deployment in the list is for Nginx Ingress.
Q.3 If the ingress-controller pod is running in node3, how it can listen to ingress api which is running in node1?
Answer: Entire Communication between the pods & nodes take place using the Services in Kubernetes. Service Exposes the pod to each & every node using a NodePort as well as Internal Endpoint & External Endpoint. This service is then attached to the deployment (ingress-deployment in this case) via Labels and is known through out the cluster for communication. I hope you know how to attach a service to a deployment. So even if the controller pod is running on node3, service knows this and transfer the incoming traffic to the pod.
Endpoints exposed to entire cluster, right above the curser.

Resources