Deploying .Net Core WebApi Docker Image to Azure Kubernetes Service using Nginx Ingress Controller - nginx

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.

Related

Can I deploy ingress.yaml file in another namespace and run my deploy.yaml file in AKS

I have created 2 namespaces which are "ingress-basic" and "wallarm-ingress" now I have applied the deploying file in "ingress-basic" namespace and I want to know whether I can have applied my ingress.yaml file in "wallarm-ingress" namespace and expose the deployment to the internet.
This the deployment yaml file
`
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
spec:
replicas: 1
selector:
matchLabels:
app: api
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: newwallarmacr.azurecr.io/api-app:v1
ports:
- containerPort: 3333
---
apiVersion: v1
kind: Service
metadata:
name: api
spec:
type: ClusterIP
ports:
- port: 3333
selector:
app: api
`
And this is the ingress.yaml file
`
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: hello-world-ingress
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "false"
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/rewrite-target: /$2
kubernetes.io/ingress.class: nginx
name: api
namespace: ingress-basic
spec:
ingressClassName: nginx
rules:
- http:
paths:
- path: /one(/|$)(.*)
pathType: Prefix
backend:
service:
name: api
port:
number: 3333
- path: /(.*)
pathType: Prefix
backend:
service:
name: api
port:
number: 3333
`
I tried this and this didn't work so I want to know which parts should be added, edited to get this deployment expose to the internet.
By default every workload (pod, endpoints, services) are exposed inside particular namespace. But for your case, you want to access a service hosted in wallarm-ingress via an ingress hosted in ingress-basic. In that case service should be called via this syntax.
{serviceName}.{serviceName-namespace}.svc
So your ingress object should be like this
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: hello-world-ingress
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "false"
nginx.ingress.kubernetes.io/use-regex: "true"
nginx.ingress.kubernetes.io/rewrite-target: /$2
kubernetes.io/ingress.class: nginx
name: api
namespace: ingress-basic
spec:
ingressClassName: nginx
rules:
- http:
paths:
- path: /one(/|$)(.*)
pathType: Prefix
backend:
service:
name: api.wallarm-ingress.svc
port:
number: 3333
- path: /(.*)
pathType: Prefix
backend:
service:
name: api.wallarm-ingress.svc
port:
number: 3333

Ingress in GKE does not do the routing identically despite same IP at DNS level

I have setup in my GKE cluster an nginx ingress as follows:
helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx
helm install ingress-nginx ingress-nginx/ingress-nginx --namespace nginx-ingress
A load balancer with its IP came up.
Now I added two DNS pointing to that domain at Cloudflare:
In addition I created a namespace app-a
kubectl create namespace app-a
kubectl label namespace app-a project=a
and deployed an app there:
apiVersion: v1
kind: Service
metadata:
name: echo1
namespace: app-a
spec:
ports:
- port: 80
targetPort: 5678
selector:
app: echo1
type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: echo1
namespace: app-a
spec:
selector:
matchLabels:
app: echo1
replicas: 2
template:
metadata:
labels:
app: echo1
spec:
containers:
- name: echo1
image: hashicorp/http-echo
args:
- "-text=echo1"
ports:
- containerPort: 5678
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: echo-ingress-global
namespace: app-a
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.ingress.kubernetes.io/ssl-redirect: "false"
spec:
rules:
- host: "test.my-domain.com"
http:
paths:
- pathType: Prefix
path: "/"
backend:
service:
name: echo1
port:
number: 80
Things look good in Lens, so I thought to test it out.
When I was entering eu1.my-domain.com, I get
which is intended, of course.
but when I entered test.my-domain.com, I get that the website is unreachable: DNS_PROBE_FINISHED_NXDOMAIN, although I expected to see the dummy output of the dummy app.
Even more strangely, no matter if I get the well-responding result or the non-responding one, in the logs of the nginx controller there is nothing showing up for any of the calls.
Can you help me, such that I can access the test.my-domain.com homepage?

forward from ingress nginx controller to different nginx pods according to port numbers

in my k8s system I have a nginx ingress controller as LoadBalancer and accessing it to ddns adress like hedehodo.ddns.net and this triggering to forward web traffic to another nginx port.
Now I deployed another nginx which works on node.js app but I cannot forward nginx ingress controller for any request to port 3000 to go another nginx
here is the nginx ingress controller yaml
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: test-ingress
namespace: default
spec:
rules:
- host: hedehodo.ddns.net
http:
paths:
- path: /
backend:
serviceName: my-nginx
servicePort: 80
- path: /
backend:
serviceName: helloapp-deployment
servicePort: 3000
helloapp deployment works a Loadbalancer and I can access it from IP:3000
could any body help me?
Each host cannot share multiple duplicate paths, so in your example, the request to host: hedehodo.ddns.net will always map to the first service listed: my-nginx:80.
To use another service, you have to specify a different path. That path can use any service that you want. Your ingress should always point to a service, and that service can point to a deployment.
You should also use HTTPS by default for your ingress.
Ingress example:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: test-ingress
spec:
rules:
- host: my.example.net
http:
paths:
- path: /
backend:
serviceName: my-nginx
servicePort: 80
- path: /hello
backend:
serviceName: helloapp-svc
servicePort: 3000
Service example:
---
apiVersion: v1
kind: Service
metadata:
name: helloapp-svc
spec:
ports:
- port: 3000
name: app
protocol: TCP
targetPort: 3000
selector:
app: helloapp
type: NodePort
Deployment example:
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: helloapp
labels:
app: helloapp
spec:
replicas: 1
selector:
matchLabels:
app: helloapp
template:
metadata:
labels:
app: helloapp
spec:
containers:
- name: node
image: my-node-img:v1
ports:
- name: web
containerPort: 3000
You can't have the same "path: /" for the same host. Change the path to a different one for your the new service.

The problem about expose prometheus web UI through nginx ingress controller

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

Kubernetes Nginx Ingress removing part of URL

I'm deploying a simple app in Kubernetes (on AKS) which is sat behind an Ingress using Nginx, deployed using the Nginx helm chart. I have a problem that for some reason Nginx doesn't seem to be passing on the full URL to the backend service.
For example, my Ingress is setup with the URL of http://app.client.com and a path of /app1g going http://app.client.com/app1 works fine. However if I try to go to http://app.client.com/app1/service1 I just end up at http://app.client.com/app1, it seems to be stripping everything after the path.
My Ingress looks like this:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /
creationTimestamp: "2019-04-03T12:44:22Z"
generation: 1
labels:
chart: app-1.1
component: app
hostName: app.client.com
release: app
name: app-ingress
namespace: default
resourceVersion: "1789269"
selfLink: /apis/extensions/v1beta1/namespaces/default/ingresses/app-ingress
uid: 34bb1a1d-560e-11e9-bd46-9a03420914b9
spec:
rules:
- host: app.client.com
http:
paths:
- backend:
serviceName: app-service
servicePort: 8080
path: /app1
tls:
- hosts:
- app.client.com
secretName: app-prod
status:
loadBalancer:
ingress:
- {}
If I port forward to the service and hit that directly it works.
So I found the answer to this. It seems that as of Nginx v0.22.0 you are required to use capture groups to capture any substrings in the request URI. Prior to 0.22.0 using just nginx.ingress.kubernetes.io/rewrite-target: / worked for any substring. Now it does not. I needed to ammend my ingress to use this:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /$1
creationTimestamp: "2019-04-03T12:44:22Z"
generation: 1
labels:
chart: app-1.1
component: app
hostName: app.client.com
release: app
name: app-ingress
namespace: default
resourceVersion: "1789269"
selfLink: /apis/extensions/v1beta1/namespaces/default/ingresses/app-ingress
uid: 34bb1a1d-560e-11e9-bd46-9a03420914b9
spec:
rules:
- host: app.client.com
http:
paths:
- backend:
serviceName: app-service
servicePort: 8080
path: /app1/?(.*)
tls:
- hosts:
- app.client.com
secretName: app-prod
status:
loadBalancer:
ingress:
- {}
Removing this line should fix your problem:
nginx.ingress.kubernetes.io/rewrite-target: /
The rewrite target annotation will do exactly what it says: rewrite your request to hit the "/" location. See nginx-ingress docs for rewrite target.

Resources