How to setup NGINX Ingress for GKE gRPC - nginx

For the past two weeks, I've been working on deploying a gRPC service (also with a gRPC gateway). I got stuck a lot at many points and it still doesn't work... Why? I am not sure to know.
I first used Ingress from Google but it wasn't working with gRPC, so I moved to Ingress NGINX, but I still have issues...
I installed NGINX from https://kubernetes.github.io/ingress-nginx/deploy/#gce-gke
I added some annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/backend-protocol: "GRPC"
nginx.ingress.kubernetes.io/grpc-backend: "true"
service.yaml (containing my Service, Deployment, Ingress (gRPC) and Ingress (REST))
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: gkegrpcservice
namespace: default
spec:
replicas: 1
selector:
matchLabels:
run: gkegrpcservice
template:
metadata:
labels:
run: gkegrpcservice
spec:
containers:
- name: gkegrpcservice
image: gcr.io/<PROJECT_ID>/gkegrpcservice:latest
imagePullPolicy: Always
ports:
- containerPort: 8080
- containerPort: 8081
---
apiVersion: v1
kind: Service
metadata:
annotations:
cloud.google.com/app-protocols: '{"grpc":"HTTP2"}'
name: gkegrpcservice
namespace: default
spec:
type: NodePort
selector:
run: gkegrpcservice
ports:
# Port that accepts gRPC and JSON/HTTP2 requests over HTTP.
- port: 8080
targetPort: 8080
protocol: TCP
name: grpc
# Port that accepts REST requests over HTTP.
- port: 8081
targetPort: 8081
protocol: TCP
name: rest
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: gkegrpcservice-ingress
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/backend-protocol: "GRPC"
nginx.ingress.kubernetes.io/grpc-backend: "true"
namespace: default
spec:
rules:
- http:
paths:
- path: /GKEgRPCService.GKEgRPCService/*
backend:
serviceName: gkegrpcservice
servicePort: 8080
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: gkegrpcservice-gateway-ingress
annotations:
kubernetes.io/ingress.class: nginx
spec:
rules:
- http:
paths:
- path: /rest/*
backend:
serviceName: gkegrpcservice
servicePort: 8081
I also created a github repository, so you can access the whole code/configuration but also the Dockerfile and the service.yaml: https://github.com/Emixam23/GKE-gRPC-Service-Ingress
based on the above, I then describe my Ingress:
MacBook-Pro-de-Emixam23:src emixam23$ kubectl describe ingress
Name: gkegrpcservice-gateway-ingress
Namespace: default
Address: 35.228.118.83
Default backend: default-http-backend:80 (10.4.2.7:8080)
Rules:
Host Path Backends
---- ---- --------
*
/rest/* gkegrpcservice:8081 (10.4.1.25:8081)
Annotations:
kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"extensions/v1beta1","kind":"Ingress","metadata":{"annotations":{"kubernetes.io/ingress.class":"nginx","nginx.ingress.kubernetes.io/ssl-redirect":"false"},"name":"gkegrpcservice-gateway-ingress","namespace":"default"},"spec":{"rules":[{"http":{"paths":[{"backend":{"serviceName":"gkegrpcservice","servicePort":8081},"path":"/rest/*"}]}}]}}
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/ssl-redirect: false
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal CREATE 26m nginx-ingress-controller Ingress default/gkegrpcservice-gateway-ingress
Normal UPDATE 115s (x3 over 26m) nginx-ingress-controller Ingress default/gkegrpcservice-gateway-ingress
Name: gkegrpcservice-ingress
Namespace: default
Address: 35.228.118.83
Default backend: default-http-backend:80 (10.4.2.7:8080)
Rules:
Host Path Backends
---- ---- --------
*
/GKEgRPCService.GKEgRPCService/* gkegrpcservice:8080 (10.4.1.25:8080)
Annotations:
nginx.ingress.kubernetes.io/backend-protocol: GRPC
nginx.ingress.kubernetes.io/grpc-backend: true
nginx.ingress.kubernetes.io/ssl-redirect: false
kubectl.kubernetes.io/last-applied-configuration: {"apiVersion":"extensions/v1beta1","kind":"Ingress","metadata":{"annotations":{"kubernetes.io/ingress.class":"nginx","nginx.ingress.kubernetes.io/backend-protocol":"GRPC","nginx.ingress.kubernetes.io/grpc-backend":"true","nginx.ingress.kubernetes.io/ssl-redirect":"false"},"name":"gkegrpcservice-ingress","namespace":"default"},"spec":{"rules":[{"http":{"paths":[{"backend":{"serviceName":"gkegrpcservice","servicePort":8080},"path":"/GKEgRPCService.GKEgRPCService/*"}]}}]}}
kubernetes.io/ingress.class: nginx
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal CREATE 6m43s nginx-ingress-controller Ingress default/gkegrpcservice-ingress
Normal UPDATE 6m6s nginx-ingress-controller Ingress default/gkegrpcservice-ingress
From here, 35.228.118.83/rest/health_check should return
200 {}
But only a 404 get returned...
However, this (to me) doesn't make sense, even by taking out /rest/, I should get a response, but OK, it doesn't work.
I then move to my ingress-controller freshly created from the link above. The logs I get are:
I don't really understand all the logs but it doesn't seem to display much about me pinging...
Do someone has any idea about what is really happening and if I have any way to maybe debug something? Because right now, based on the Internet, I am good to go, but in reality, nothing seems to work at all...

Related

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?

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

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.

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

K8S baremetal nginx ingress controller not works

I encountered a problem when integrating K8S nginx ingress. I installed the nginx ingress controller and established the testing ingress resources according to the instructions on the document, but I was not able to jump to the normal path. The test serive was normal and Accessible via cluster IP. Am I missing something?
Install script
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/mandatory.yaml
Bare-metal Using NodePort
kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/master/deploy/static/provider/baremetal/service-nodeport.yaml
Ingress controller is OK
Testing ingress resource
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-nginx
spec:
selector:
matchLabels:
app: my-nginx
template:
metadata:
labels:
app: my-nginx
spec:
containers:
- name: my-nginx
image: nginx:latest
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: my-nginx
labels:
app: my-nginx
spec:
ports:
- port: 80
protocol: TCP
name: http
selector:
app: my-nginx
---
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: my-nginx
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: nginx1.beencoding.com
http:
paths:
- path: /
backend:
serviceName: nginx-1
servicePort: 80
We can see the test nginx pod raised and works fine, I can access the nginx index page by cluster IP
But I can't access nginx1.beencoding.com
Can't access via browser
I have solved the problem by setting hostnetwork: true
It says can't resolve.
Either put the domain in /etc/hosts/ file, or do the curl as follows:
curl -H "Host: nginx1.beecoding.com" IP_ADDRESS
Should work.

Kubernetes nginx ingress is not resolving services

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.

Resources