Accessing my nodejs/react site using the URL displays "Invalid Host header". Accessing it through the public IP displays "default backend - 404".
I am using Kubernetes nginx controller with Azure cloud and load balancer.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: myrule
namespace: mynamespace
annotations:
kubernetes.io/ingress.class: nginx
certmanager.k8s.io/cluster-issuer: letsencrypt-staging
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
tls:
- hosts:
- mysite.uknorth.cloudapp.azure.com
secretName: tls-secret
rules:
- host: mysite.uknorth.cloudapp.azure.com
http:
paths:
- backend:
serviceName: service-ui
servicePort: 8080
path: /
- backend:
serviceName: service-api
servicePort: 8999
path: /api
Any guidance appreciated.
So let's assume the SSL part is ok (link) since you can reach the nginx ingress controller.
Your rewrite annotation is not necessary for what you need. Take a look at these rules:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: myrule
namespace: mynamespace
annotations:
kubernetes.io/ingress.class: nginx
certmanager.k8s.io/cluster-issuer: letsencrypt-staging
spec:
tls:
- hosts:
- mysite.uknorth.cloudapp.azure.com
secretName: tls-secret
rules:
- host: mysite.uknorth.cloudapp.azure.com
http:
paths:
- backend:
serviceName: service-ui
servicePort: 8080
path: /
- backend:
serviceName: service-api
servicePort: 8999
path: /api
Whatever you send to /api/.* will be redirected to service-api. And whatever you send to / will be send to service-ui.
Thanks for your feedback. It turns out the problem was not with the ingress rule above. The service-ui was running the incorrect command parameters thus not acknowledging the request. I missed the fact that the service-api was responding correctly.
In short, check the endpoints and running services are configured correctly - more a lesson for me than anyone else. I received a response by curling the service locally but that didn't mean it could handle https requests over ingress as the service was configured incorrectly.
Also, another lesson for me, ask the developers if the correct image is being used for the build. And ask them again if they say yes.
Related
I'm new to Kubernetes and I'm trying to deploy a React app to my cluster. Here's the basic info:
Docker Desktop, single-node Kubernetes cluster
React development frontend, exposing port 3000
Node.js/Express backend, exposing port 8080
NGINX Ingress Controller, serving my React frontend on "localhost:3000" and routing my Fetch API requests (fetch("localhost:3000/api/...", OPTIONS)) to the backend (which works)
I am having an issue when opening the React app. The Ingress Controller correctly routes to the app but the 3 bundles (bundle.js, main.chink.js, the third one which I don't remember) aren't loaded. I get the following error:
GET http://localhost/static/js/main.chunk.js net::ERR_ABORTED 404 (Not Found) ingress (one example)
I understand why this error happens. The Ingress Controller correctly routes the traffic but only loads the index.html file. In this file, there are calls to 3 scripts (referring to the bundles) which aren't loaded. I understand the error, the files don't get sent to the browser so the index.html file can't load them in, but do not know how to fix it.
Does anyone have any suggestions? de and then pulled from Docker Hub. Does anybody know what a possible solution could be? For example, does deploying the build/ folder (built React app using "npm run build") fix this? Do I have to use nginx inside my Dockerfile to build the container?
Ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: titanic-ingress
#labels:
#name: titanic-ingress
spec:
ingressClassName: nginx
rules:
- host: localhost
http:
paths:
- path: /
pathType: Exact
backend:
service:
name: titanicfrontendservice
port:
number: 3000
- path: /api
pathType: Exact
backend:
service:
name: titanicbackendservice
port:
number: 8080
Ingress controller deployment yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-ingress
namespace: nginx-ingress
spec:
replicas: 1
selector:
matchLabels:
app: nginx-ingress
template:
metadata:
labels:
app: nginx-ingress
#annotations:
#prometheus.io/scrape: "true"
#prometheus.io/port: "9113"
spec:
serviceAccountName: nginx-ingress
containers:
- image: nginx/nginx-ingress:1.10.0
imagePullPolicy: IfNotPresent
name: nginx-ingress
ports:
- name: http
containerPort: 80
- name: https
containerPort: 443
- name: readiness-port
containerPort: 8081
#- name: prometheus
#containerPort: 9113
readinessProbe:
httpGet:
path: /nginx-ready
port: readiness-port
periodSeconds: 1
securityContext:
allowPrivilegeEscalation: true
runAsUser: 101 #nginx
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
env:
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
args:
- -nginx-configmaps=$(POD_NAMESPACE)/nginx-config
- -default-server-tls-secret=$(POD_NAMESPACE)/default-server-secret
#- -v=3 # Enables extensive logging. Useful for troubleshooting.
- -report-ingress-status
- -external-service=nginx-ingress
#- -enable-prometheus-metrics
#- -global-configuration=$(POD_NAMESPACE)/nginx-configuration
Ingress controller service yaml
apiVersion: v1
kind: Service
metadata:
name: nginx-ingress
namespace: nginx-ingress
spec:
externalTrafficPolicy: Local
type: LoadBalancer
ports:
- port: 3000
targetPort: 80
protocol: TCP
name: http
- port: 443
targetPort: 443
protocol: TCP
name: https
selector:
app: nginx-ingress
TL;DR
Switch your pathType in both /api and / path to Prefix.
I've included some explanation with fixed Ingress resource below.
For the reproduction purposes I used the titanic manifests that you provided in the another question:
Github.com: Strobosco: Titanicfullstack
The issue with your configuration is with: pathType.
Using your Ingress resource with pathType: Exact showed me blank page.
Modifying your Ingress resource with pathType: Prefix solved the issue.
Side note!
The message: "Would you have survived the sinking of the Titanic?" showed.
The exact Ingress configuration should be following:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: titanic-ingress
spec:
ingressClassName: nginx
rules:
- host: localhost
http:
paths:
- path: /
pathType: Prefix # <-- IMPORTANT
backend:
service:
name: titanicfrontendservice
port:
number: 3000
- path: /api
pathType: Prefix # <-- IMPORTANT
backend:
service:
name: titanicbackendservice
port:
number: 8080
Why I think it happened?
Citing the official documentation:
Path types
Each path in an Ingress is required to have a corresponding path type. Paths that do not include an explicit pathType will fail validation. There are three supported path types:
ImplementationSpecific: With this path type, matching is up to the IngressClass. Implementations can treat this as a separate pathType or treat it identically to Prefix or Exact path types.
Exact: Matches the URL path exactly and with case sensitivity.
Prefix: Matches based on a URL path prefix split by /. Matching is case sensitive and done on a path element by element basis. A path element refers to the list of labels in the path split by the / separator. A request is a match for path p if every p is an element-wise prefix of p of the request path.
-- Kubernetes.io: Docs: Concepts: Services networking: Ingress: Path types (there are some examples on how the path matching is handled)
Ingress controller is forced to match only the / path leaving rest of the dependencies (apart from the index.html) on other paths like /super.jpg and /folder/awesome.jpg to error with 404 code.
Side note!
You can test yourself this behavior by spawning an nginx Pod and placing example files in it. After applying the Ingress resource with / and pathType: Exact you won't be able to request it through the Ingress controller but you could access them within the cluster.
I encourage you to check the additional resources:
Kubernetes.io: Docs: Concepts: Services networking: Ingress
Kubernetes.github.io: Ingress nginx: User guide: Ingress path matching
The issue with your ingress.yaml is that the route for your ui should be /* and placed below the backend routing. Also, check your routing for APIs
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: titanic-ingress
#labels:
#name: titanic-ingress
spec:
ingressClassName: nginx
rules:
- host: localhost
http:
paths:
- path: /api/*
pathType: Exact
backend:
service:
name: titanicbackendservice
port:
number: 8080
- path: /*
pathType: Exact
backend:
service:
name: titanicfrontendservice
port:
number: 3000
I have a Mongo, Express, React Node app that is currently deployed in a microk8s pod. I am trying to setup Ingress for the app. The express server is setup to serve the react with express.static like below
app.use(express.static('DemoApp/build'));
app.get('*', function(req, res, next) {
res.sendFile(path.resolve(__dirname, 'DemoApp', 'build', 'index.html'));
});
Everything works fine when I navigate to the ip:port of the kubernetes cluster and even everything works fine when I navigate to the FQDN for the ingress host but as soon as I add a path to the ingress then the app only shows a white screen. One note, my kubernetes node and workstations are all running inside an internal private network. I am not trying to expose anything outside of that. I have tried to follow the step provided in this post (ReactJS app displays whitescreen using Kubernetes Ingress) but it has not fixed the issue. I have the built in ingress controller enabled for microk8s.
Below is the YAML I am using for ingress that doesnt work
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: demo-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
namespace: default
spec:
rules:
- host: apps.sst.com
http:
paths:
- path: /demo(/|$)(.*)
backend:
serviceName: mern-demo
servicePort: 4000
Here is the YAML for ingress that does work
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: demo-ingress
annotations:
namespace: default
spec:
rules:
- host: apps.sst.com
http:
paths:
- path:
backend:
serviceName: mern-demo
servicePort: 4000
One other note is that my app is using react router. Based on further research I am wondering if this affects things at all.
Any help would be greatly appreciated. Thanks
rewrite-target annotation which was used in your YAML
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
works only for Nginx Ingress. As you are using your default ingress it will not work. You would need to install it manually as it is mentioned here.
Now depends on your env if it's local or cloud you would need to configure MetalLB. For more details you can check this thread.
There was also similar StackOverflow question regarding Nginx Ingress issue on MicroK8s, you can read about it in this SO thread.
However, do you need to use rewrite? You cannot use multiple paths and default backend? Something like this:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: my-ingress
spec:
backend:
serviceName: hello-world
servicePort: 60000
rules:
- http:
paths:
- path: /world
backend:
serviceName: hello-world
servicePort: 60000
- path: /kube
backend:
serviceName: hello-kubernetes
servicePort: 80
I have below configuration with one path for ui and another path for web api but api path doesnt work.
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: myingress
annotations:
kubernetes.io/ingress.class: azure/application-gateway
appgw.ingress.kubernetes.io/use-private-ip: "true"
appgw.ingress.kubernetes.io/ssl-redirect: "true"
appgw.ingress.kubernetes.io/backend-path-prefix: /
spec:
tls:
- secretName: mysecret
rules:
- host: dev-ingress.com
- http:
paths:
- path: /
backend:
serviceName: uidev
servicePort: 80
- path: /gateway
backend:
serviceName: ocelotapigatewaydev
servicePort: 80
uidev path works but ocelotapigatewaydev dot net web api is not working when i test the api with gateway/api.
Strangely if i have html at the root of the ocelotapigatewaydev web api project then it loads it..Not sure how to fix it.
Changing api calls path to below has fixed the issue
- path: /gateway/.*
courtesy:
https://kubernetes.github.io/ingress-nginx/user-guide/ingress-path-matching/
I have one service and a single ingress resource with kubenetes nginx ingress controller. I want the /student path of my url to go to the root of the application and match any other url segments which follow the student.
For example: http://example.com/student/ver should match the /ver route of my application.
However, my ingress always hit the application with the /student url path prefixing the other url segments. If I call http://example.com/student/ver, my application is hit with the same url (student/ver).
My ingress:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
ingress.kubernetes.io/rewrite-target: /
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/ssl-redirect: "false"
name: ingress-resource
spec:
rules:
- host: example.com
http:
paths:
- backend:
serviceName: lesson-streaming
servicePort: 80
path: /student
I spent days with this and was not successful once.
Edit:
The ingress is changed to the following - not my requests say http 404
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
ingress.kubernetes.io/rewrite-target: /$2
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/ssl-redirect: "false"
name: ingress-resource
namespace: default
spec:
rules:
- host: example.com
http:
paths:
- backend:
serviceName: lesson-streaming
servicePort: 80
path: /student(/|$)(.*)
You can follow the link to use the rewrite-target annotation correctly and keep the right key nginx.ingress.kubernetes.io/rewrite-target.
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
name: rewrite
namespace: default
spec:
rules:
- host: rewrite.bar.com
http:
paths:
- backend:
serviceName: http-svc
servicePort: 80
path: /something(/|$)(.*)
Im using k8 - v1.25.2 along with nginx-Ingress v2.4.1 https://docs.nginx.com/nginx-ingress-controller/installation/installation-with-manifests/
nginx.ingress.kubernetes.io/rewrite-target: /$2 - doesnt work
instead use :
nginx.org/rewrites: "serviceName=app1-svc rewrite=/;serviceName=app2-svc rewrite=/"
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: path-ingress
namespace: default
annotations:
nginx.org/rewrites: "serviceName=app1-svc rewrite=/;serviceName=app2-svc rewrite=/"
spec:
ingressClassName: nginx
rules:
- host: apps.relo.com
http:
paths:
- backend:
service:
name: app1-svc
port:
number: 2041
path: /app1
pathType: Prefix
- backend:
service:
name: app2-svc
port:
number: 2042
path: /app2
pathType: Prefix
I have tried many times to execute properly path based routing in nginx ingress controller but I have found the main reason behind the path based routing not working.
replace the (nginx.ingress.kubernetes.io/rewrite-target: /) to (nginx.org/rewrites: "serviceName=servicename rewrite=/")
must add ingressClassName in spec
in my case
I have kubernetes 1.23.0 & nginx/1.21.6
I hope this will resolve the above problem.
Best of luck
I have a Python Flask app I've deployed on IBM Kubernetes Service. My deployment YAML specifies path: /, which is handled in my code with #app.route('/'). That works fine. I then attempted to move the app by changing path: / to path: /foo in my deployment YAML. I was expecting the request coming into my app to still come in as /, but it's coming in as /foo. Ultimately what I'm trying to do is to be flexible in the deployment of the app without having the change source code. I don't see a way in either Kubernetes or Flask to create this level of indirection. Am I missing something?
Original YAML:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: my-ingress
spec:
tls:
- hosts:
- my....us-east.containers.appdomain.cloud
secretName: my...
rules:
- host: my....us-east.containers.appdomain.cloud
http:
paths:
- path: /
backend:
serviceName: my-service
servicePort: 5000
Need to check the content of your ingress yaml definition.
Here's an example yaml definition with rewrites
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
name: rewrite
namespace: default
spec:
rules:
- host: rewrite.bar.com
http:
paths:
- backend:
serviceName: http-svc
servicePort: 80
path: /something(/|$)(.*)
For example, the ingress definition above will result in the following rewrites:
rewrite.bar.com/something rewrites to rewrite.bar.com/
rewrite.bar.com/something/ rewrites to rewrite.bar.com/
rewrite.bar.com/something/new rewrites to rewrite.bar.com/new
You can check Nginx Ingress controller Rewrite annotations here. You can also customize Ingress routing with annotations on IBM Cloud following the documentation here