I'm new to Kubernetes and am experiencing a weird issue with my nginx-ingress router. My cluster is run locally on a raspberry pi using Microk8s, where I have 4 different deployments. The cluster uses an ingress router to route packets for the UI and API.
In short, my issue is that I receive intermittent 502 errors on calls from the UI to the backend. Intermittent meaning that for every 3 successful POSTs, there are 3 unsuccessful 502 requests (regardless of how quickly these requests are called). E.g.,
I've applied the following Ingress configuration to my cluster:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-router
annotations:
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/cors-allow-methods: "PUT, GET, POST, OPTIONS"
nginx.ingress.kubernetes.io/cors-allow-credentials: "true"
nginx.ingress.kubernetes.io/use-regex: "true"
spec:
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: ui
port:
number: 80
- http:
paths:
- path: /lighting/.*
pathType: Prefix
backend:
service:
name: api
port:
number: 8000
And the deployments for UI and API are as follow:
UI:
apiVersion: apps/v1
kind: Deployment
metadata:
name: ui
spec:
selector:
matchLabels:
app: iot-control-center
replicas: 3
template:
metadata:
labels:
app: iot-control-center
spec:
containers:
- name: ui-container
image: canadrian72/iot-control-center:ui
imagePullPolicy: Always
ports:
- containerPort: 80
API:
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
spec:
selector:
matchLabels:
app: iot-control-center
replicas: 3
template:
metadata:
labels:
app: iot-control-center
spec:
containers:
- name: api-container
image: canadrian72/iot-control-center:api
imagePullPolicy: Always
ports:
- containerPort: 8000
- containerPort: 1883
After looking around online, I found this Reddit post which most closely resembles my issue, although I'm not too sure where to go from here. I have a feeling it's a load issue for either the pods or the ingress controller, so I tried adding 3 replicas to each pod (it was 1 before), but this only decreased the frequency of 502 errors.
Edit
It’s not necessarily 1 to one for 200 and 502 responses, it’s fairly random but about an even distribution of 502 and 200 responses. Also to add that I had configured this same setup with LoadBalancer (metallb) and everything worked like a charm, except for CORS. Which is why I went for Ingress to deal with CORS.
Leaving this up if anyone has a similar issue. My issue was that in the ingress configuration, the backend services referenced the deployments themselves instead of a nodeport/clusterIP service.
I instead created two cluster IP services for the UI and API, like follows:
UI
apiVersion: v1
kind: Service
metadata:
name: ui-cluster-ip
spec:
type: ClusterIP
selector:
app: iot-control-center
svc: ui
ports:
- port: 80
API
apiVersion: v1
kind: Service
metadata:
name: lighting-api-cluster-ip
spec:
type: ClusterIP
selector:
app: iot-control-center
svc: lighting-api
ports:
- port: 8000
And then referenced these services from the ingress yaml as follows:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: ingress-router
annotations:
kubernetes.io/ingress.class: public
nginx.ingress.kubernetes.io/configuration-snippet: |
more_set_headers "Access-Control-Allow-Origin: $http_origin";
nginx.ingress.kubernetes.io/cors-allow-credentials: "true"
nginx.ingress.kubernetes.io/cors-allow-methods: PUT, GET, POST,
OPTIONS, DELETE, PATCH
nginx.ingress.kubernetes.io/enable-cors: "true"
nginx.ingress.kubernetes.io/use-regex: "true"
spec:
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: ui-cluster-ip
port:
number: 80
- http:
paths:
- path: /lighting/.*
pathType: Prefix
backend:
service:
name: lighting-api-cluster-ip
port:
number: 8000
I'm not sure why the previous configuration posted resulted in some 503 responses and some 200 (in my mind it should've all been 503), but in any case this solution works.
Related
I am experiencing exactly this issue: Nginx-ingress-controller fails to start after AKS upgrade to v1.22, with the exception that none of the proposed solutions is working for my case.
I am running a Kubernetes Cluster on Oracle Cloud and I accidentally upgraded the cluster and now I cannot connect anymore to the services through nginx-controller. After reading the official nginx documentation, I am aware of the new version of nginx, so I checked the documentation and re-installed the nginx-controller following Oracle Cloud official documentation.
I am able to perform step by step as I run:
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v0.44.0/deploy/static/provider/cloud/deploy.yaml
And then an ingress-nginx namespace is created and a LoadBalancer is created. Then as in the guide I have created a simple hello application (though not running on port 80):
apiVersion: apps/v1
kind: Deployment
metadata:
name: docker-hello-world
labels:
app: docker-hello-world
spec:
selector:
matchLabels:
app: docker-hello-world
replicas: 1
template:
metadata:
labels:
app: docker-hello-world
spec:
containers:
- name: docker-hello-world
image: scottsbaldwin/docker-hello-world:latest
ports:
- containerPort: 8088
---
apiVersion: v1
kind: Service
metadata:
name: docker-hello-world-svc
spec:
selector:
app: docker-hello-world
ports:
- port: 8088
targetPort: 8088
type: ClusterIP
and then the ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: hello-world-ing
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
tls:
- secretName: tls-secret
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: docker-hello-world-svc
port:
number: 8088
But when running the curl commands I only get a curl: (56) Recv failure: Connection reset by peer.
So I then tried to connect to some python microservices that are already running by simply editing the ingress, but whatever I do I get the same error message. And when setting the host as the following:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: hello-world-ing
namespace: ingress-nginx
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: SUBDOMAIN.DOMAIN.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: ANY_MICROSERVICE_RUNNING_IN_CLUSTER
port:
number: EXPOSED_PORT_BY_MICROSERVICE
Then, by setting the subdomain on CloudFlare I only get a 520 Bad Gateway.
Can you help me find what is that I do not see?
This may be related to your Ingress resource.
In Kubernetes versions v1.19 and above, Ingress resources should use ingressClassName instead of the older annotation syntax. Additional information on what should be done when upgrading can be found on the official Kubernetes documentation.
However, with the changes it requires at face value, from the information you're provided so far, your Ingress resource should look this:
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: hello-world-ing
spec:
ingressClassName: nginx
rules:
- host: SUBDOMAIN.DOMAIN.com
http:
paths:
- backend:
service:
name: docker-hello-world-svc
port:
number: 8088
path: /
pathType: Prefix
tls:
- hosts:
- SUBDOMAIN.DOMAIN.com
secretName: tls-secret
Additionally, please provide the deployment Nginx-ingress logs if you still have issues, as the Cloudflare error does not detail what could be wrong apart from providing a starting point.
As someone who uses Cloudflare and Nginx, there are multiple reasons why you're receiving a 520 error, so it'd be better if we could reduce the scope of what could be the main issue. Let me know if you have any questions.
I have created a sample .Net Core WebApi and pushed the images to ACR. Now I am deploying it to AKS with Nginx Ingress Controller using Ingress Resources pointing to ClusterIP Service that points to Deployed Pods running the image.
Issue is when I change ClusterIP service to LoadBalancer to hit it directly for testing, I get the results from WebApi. But when I change it back to ClusterIP and hit using Nginx Ingress Controller IP address, I always get 404 Not Found.
Below is the code. Please suggest.
apiVersion: apps/v1
kind: Deployment
metadata:
name: weather-forecast-webapi-deployment
namespace: development
spec:
replicas: 1
selector:
matchLabels:
app: weather-forecast-webapi-pod
template:
metadata:
labels:
app: weather-forecast-webapi-pod
spec:
containers:
- name: weather-forecast-webapi-container
image: employeeconnectacr.azurecr.io/demoapi:latest
ports:
- containerPort: 80
apiVersion: v1
kind: Service
metadata:
name: weather-forecast-webapi-service-clusterip
namespace: development
spec:
ports:
- port: 80
targetPort: 80
selector:
app: weather-forecast-webapi-pod
kind: Ingress
apiVersion: networking.k8s.io/v1beta1
metadata:
name: econnect-ingress
namespace: development
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /$1
nginx.ingress.kubernetes.io/ssl-redirect: 'false'
nginx.ingress.kubernetes.io/use-regex: 'true'
spec:
rules:
- http:
paths:
- path: /demo
pathType: Prefix
backend:
serviceName: weather-forecast-webapi-service-clusterip
servicePort: 80
status:
loadBalancer:
ingress:
- ip: 52.141.219.175
Looks like you messed up your ingress object. I assume you want to rewrite the /demo path to / so that paths like: /demo/foo/bar are rewritten to /foo/bar.
Here is the rewrite explained.
Here is the example:
kind: Ingress
apiVersion: networking.k8s.io/v1beta1
metadata:
name: econnect-ingress
namespace: development
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /$2
nginx.ingress.kubernetes.io/ssl-redirect: 'false'
spec:
rules:
- http:
paths:
- path: /demo(/|$)(.*)
pathType: Prefix
backend:
serviceName: weather-forecast-webapi-service-clusterip
servicePort: 80
Notice that all I changed is path and rewtire-tager group number. In /demo(/|$)(.*) the brackets () create a group that is referenced in rewrite-target: /$2. The $1 is referencing the first group: / or end of string, and the second group is everything after it; so you copy everything after the /demo/ and make it a new path.
I have no idea what's the problem for my case.
I deploy an Prometheus server on AKS(Azure's k8s) and want to expose the Prometheus web UI through ingress controller for the following config.
And I also refer this
https://coreos.com/operators/prometheus/docs/latest/user-guides/exposing-prometheus-and-alertmanager.html
# Prometheus
apiVersion: monitoring.coreos.com/v1
kind: Prometheus
metadata:
name: prometheus
namespace: monitoring
spec:
version: v2.13.1
replicas: 2
retention: 1d
serviceAccountName: prometheus
...
# Service
apiVersion: v1
kind: Service
metadata:
name: prometheus-service
namespace: monitoring
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 9090
selector:
app: prometheus
# Ingress
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: prometheus-ingress
namespace: monitoring
annotations:
kubernetes.io/ingress.class: nginx
# nginx.ingress.kubernetes.io/ssl-redirect: "false"
# nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
rules:
- http:
paths:
# Just try another subpath make sure the nginx is work
# - backend:
# serviceName: aks-helloworld-one
# servicePort: 80
# path: /hello-world-one
- backend:
serviceName: prometheus-service
servicePort: 80
path: /prometheus
I have added another path in my test stage, the nginx work successfully for aks-helloworld-one.
However, it not work for Prometheus server, I always got "404 page not found" in return.
Does anyone know how to solve this problem?
I think I know where the problem is. Actually my previous comment was wrong:
If it's available under /, you don't need any rewrites in your ingress
and it should work straight away.
Well... actually it won't for one simple reason. When you try to access your Prometheus UI via ingress, you use <ingress ip>/prometheus URL. Choosing /prometheus path redirects you correctly to the appropriate backend Service:
- backend:
serviceName: prometheus-service
servicePort: 80
path: /prometheus
But the problem occurs because the /prometheus path (that you need to be redirected to the prometheus-service and eventually to one of the Pods, exposed by this Service) gets forwarded to the target Pod serving the actual content.
You get 404 page not found error message because the http request that gets to the target webserver is claiming for the content of /prometheus directory instead of / from which it is actually served.
So if you change your ingress to something like this:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: prometheus-ingress
namespace: monitoring
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- http:
paths:
- backend:
serviceName: prometheus-service
servicePort: 80
path: /
most probably everything would work as expected and you'll get the Prometheus UI website rather than 404 Not found.
Well, although it may work, it's good only for debugging purposes as no one wants to use ingress just to be able to expose something under root path.
The following ingress definition should resolve your problem (Yes, rewrites are necessary in this scenario!):
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: prometheus-ingress
namespace: monitoring
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
rules:
- http:
paths:
- backend:
serviceName: prometheus-service
servicePort: 80
path: /prometheus(/|$)(.*)
Rewrite that was used above will ensure that the original access path /prometheus gets rewritten to / before reaching the target Pod.
I am deploying the cluster in a AWS, I did this configuration with Helm Charts and it worked for me.
Ingress: Notice nginx.ingress.kubernetes.io/rewrite-target: /$2 and path: /prometheus(/|$)(.*) in this file as mentioned in other answers.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: prometheus-ingress
namespace: monitoring
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/proxy-read-timeout: "12h"
nginx.ingress.kubernetes.io/ssl-redirect: "true"
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
cert-manager.io/acme-challenge-type: "http01"
cert-manager.io/cluster-issuer: "letsencrypt-prod"
nginx.ingress.kubernetes.io/rewrite-target: /$2
spec:
tls:
- hosts:
- myhost.cl
secretName: mysecret-tls
rules:
- host: myhost.cl
http:
paths:
- path: /prometheus(/|$)(.*)
pathType: Prefix
backend:
service:
name: monitoring-kube-prometheus-prometheus
port:
number: 9090
Prometheus: There is a label inside spec called externalUrl that makes you redirect whatever you want when you access in browser.
# Source: kube-prometheus-stack/templates/prometheus/prometheus.yaml
apiVersion: monitoring.coreos.com/v1
kind: Prometheus
metadata:
name: monitoring-kube-prometheus-prometheus
namespace: monitoring
labels:
app: kube-prometheus-stack-prometheus
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/instance: monitoring
app.kubernetes.io/version: "19.0.2"
app.kubernetes.io/part-of: kube-prometheus-stack
chart: kube-prometheus-stack-19.0.2
release: "monitoring"
heritage: "Helm"
prometheus: devops
spec:
# ... Your data here
externalUrl: http://myhost.cl/prometheus
Also be careful to not expose your prometheus instance and at least use an authentication method like basic auth, here's something that can help you with that: https://kubernetes.github.io/ingress-nginx/examples/auth/basic/
I think issue is with your rewrite-target & path, can you try with a sub-domain, rather than path to confirm? I have the following Prometheus Ingress working on Subdomain
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
ingress.kubernetes.io/force-ssl-redirect: "true"
ingress.kubernetes.io/rewrite-target: /
kubernetes.io/ingress.class: nginx-ingress
name: prometheus-monitoring
namespace: monitoring
spec:
backend:
serviceName: prometheus
servicePort: 9090 #As my service is listening on 9090
rules:
- host: prometheus-monitoring.DOMAIN
http:
paths:
- backend:
serviceName: prometheus
servicePort: 9090 #As my service is listening on 9090
path: /
And below is my service manifest
apiVersion: v1
kind: Service
metadata:
labels:
app: prometheus
chart: prometheus-operator-5.11.0
heritage: Tiller
name: prometheus
namespace: monitoring
spec:
ports:
- name: web
port: 9090
protocol: TCP
targetPort: 9090
selector:
app: prometheus
prometheus: k8s
sessionAffinity: None
type: ClusterIP
I have an issue I can't figure out. I have setup Nginx Ingress Controller on my managed k8s cluster. I'm trying to reach an SSL enabled pod behind and it does not work. I have 404 not found from Nginx and the certificate which is presented is the Nginx one. I have deployed the controller using their github repo and the default files following their doc.
I have setup a clear http pod for purpose tests and it works. It seems to be related to ssl.
I have tried many things to no avail. How can I reach an SSL pod behind nginx ?
Here's the Deployment + service (for the https one) resource I have setup :
apiVersion: apps/v1
kind: Deployment
metadata:
name: moulip-https
spec:
selector:
matchLabels:
app: moulip-https
replicas: 2
template:
metadata:
labels:
app: moulip-https
spec:
containers:
- name: "wabam"
image: "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
ports:
- containerPort: 443
imagePullSecrets:
- name: regcrd
---
apiVersion: v1
kind: Service
metadata:
name: https-svc
labels:
app: moulip-https
spec:
ports:
- port: 443
targetPort: 443
protocol: TCP
name: https
selector:
app: moulip-https
and my Ingress :
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: ingress
annotations:
nginx.ingress.kubernetes.io/secure-backends: "true"
nginx.ingress.kubernetes.io/ssl-passthrough: "true"
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
nginx.ingress.kubernetes.io/rewrite-target: /
namespace: default
spec:
rules:
- host: https.moulip.lan
http:
paths:
- backend:
serviceName: https-svc
servicePort: 443
- host: test.moulip.lan
http:
paths:
- backend:
serviceName: hostname-svc
servicePort: 80
Many thanks for any guidance you could provide me with.
You are missing tls configuration in the ingress. follow sample below
apiVersion: v1
kind: Secret
metadata:
name: testsecret-tls
namespace: default
data:
tls.crt: base64 encoded cert
tls.key: base64 encoded key
type: kubernetes.io/tls
---
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: tls-example-ingress
spec:
tls:
- hosts:
- sslexample.foo.com
secretName: testsecret-tls
rules:
- host: sslexample.foo.com
http:
paths:
- path: /
backend:
serviceName: service1
servicePort: 80
Cloud: Google Cloud Platform.
I have the following configuration
kind: Deployment
apiVersion: apps/v1
metadata:
name: api
spec:
replicas: 2
selector:
matchLabels:
run: api
template:
metadata:
labels:
run: api
spec:
containers:
- name: api
image: gcr.io/*************/api
ports:
- containerPort: 8080
livenessProbe:
httpGet:
path: /_ah/health
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
---
kind: Service
apiVersion: v1
metadata:
name: api
spec:
selector:
run: api
type: NodePort
ports:
- protocol: TCP
port: 8080
targetPort: 8080
---
kind: Ingress
apiVersion: extensions/v1beta1
metadata:
name: main-ingress
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- http:
paths:
- path: /api/*
backend:
serviceName: api
servicePort: 8080
All set. GKE saying that all deployments are okay, pods number are met and main ingress with nginx-ingress-controllers are set as well. But I'm not able to reach any of the services. Even application specific 404. Nothing. Like, it's not resolved at all.
Another related question I see to entrypoints. The first one through main-ingress. It created it's own LoadBalancer with own IP address. The second one address from nginx-ingress-controller. The second one is at least returning 404 from default backend, but also not pointing to expected api service.