Kubernetes: load-balance across two different namespaces - kubernetes

I want to deploy different versions of the same application in production:
kubectl create deployment hello-server --image=gcr.io/google-samples/hello-app:1.0 -n test-a
kubectl create deployment hello-server --image=gcr.io/google-samples/hello-app:2.0 -n test-b
kubectl expose deployment hello-server --port 80 --target-port 8080 -n test-a
kubectl expose deployment hello-server --port 80 --target-port 8080 -n test-b
I've tried to load-balance it like this:
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: test
annotations:
kubernetes.io/ingress.class: "nginx"
nginx.org/server-snippets: |
upstream test-servers-upstream {
server hello-server.test-a:80;
server hello-server.test-b:80;
}
spec:
rules:
- host: test-servers.example.com
http:
paths:
- path: /
backend:
serviceName: test-servers-upstream
servicePort: 80
but it returns an error:
/ test-servers-upstream:80 (<error: endpoints "test-servers-upstream" not found>)
Services:
$ kubectl get services -n test-b
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello-server ClusterIP 10.128.199.113 <none> 80/TCP 75m
$ kubectl get services -n test-a
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello-server ClusterIP 10.128.207.6 <none> 80/TCP 75m
How can I load-balance it?

Fresh ingress-nginx supports weight-based canary deployments out of box.
Looks like what you're asking for.
https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#canary.
Great example here.
https://medium.com/#domi.stoehr/canary-deployments-on-kubernetes-without-service-mesh-425b7e4cc862
Basically, you create 2 identical ingresses, one for each namespace.
They are different only in annotations and in pointing to different services.
# ingress for a service A in namespace A
kind: Ingress
metadata:
name: demo-ingress
namespace: demo-prod
spec:
rules:
- host: canary.example.com
http:
paths:
- backend:
serviceName: demo-prod
servicePort: 80
path: /
# ingress for a service B in namespace B
# note canary annotations
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/canary: "true"
nginx.ingress.kubernetes.io/canary-weight: "20"
name: demo-ingress
namespace: demo-canary
spec:
rules:
- host: canary.example.com
http:
paths:
- backend:
serviceName: demo-canary
servicePort: 80
path: /
Note, that ingress-nginx canary implementation actually requires your services to be in different namespaces.

Related

How to manage two paths on the same hostname?

I'm using Kubernetes v1.23.16 cluster (One master and three workers) bare metal based.
I have created couple of services in a separate namespace. The same as follows.
$ kubectl get services --all-namespaces
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
default kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 11d
app1 app1-service ClusterIP 10.103.151.235 <none> 80/TCP 19h
app2 app2-service ClusterIP 10.105.88.151 <none> 80/TCP 11d
kube-system kube-dns ClusterIP 10.96.0.10 <none> 53/UDP,53/TCP,9153/TCP 11d
Now I'm having below nginx resource yml to access the service outside. For example i would like access as given below.
http://web.example.com/app1
http://web.example.com/app2
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$2
name: app-ingress
spec:
ingressClassName: nginx
rules:
- host: web.example.com
http:
paths:
- path: /app1
pathType: Prefix
backend:
service:
name: app1-service
port:
number: 80
- path: /app2
pathType: Prefix
backend:
service:
name: app2-service
port:
number: 80
When i apply the nginx resource yml file it says service not found error.
$ kubectl describe ingress app-ingress
Name: app-ingress
Labels: <none>
Namespace: default
Address:
Default backend: default-http-backend:80 (<error: endpoints "default-http-backend" not found>)
Rules:
Host Path Backends
---- ---- --------
web.example.com
/app1 app1-service:80 (<error: endpoints "app1-service" not found>)
/app2 app2-service:80 (<error: endpoints "app2-service" not found>)
Annotations: nginx.ingress.kubernetes.io/rewrite-target: /$2
Since my applications services are running in different namespace separately and my nginx resource yml is running in default namespace. So now how do i configure nginx resource file to access both of my service?
An Ingress resource can only refer to Services in the same namespace as the Ingress. To manage two paths on the same hostname that lead to backends in different namespaces, you will need two separate Ingress resources.
In the app1 namespace:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
namespace: app1
spec:
ingressClassName: nginx
rules:
- host: web.example.com
http:
paths:
- path: /app1
pathType: Prefix
backend:
service:
name: app1-service
port:
number: 80
And in the app2 namespace:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
namespace: app2
spec:
ingressClassName: nginx
rules:
- host: web.example.com
http:
paths:
- path: /app2
pathType: Prefix
backend:
service:
name: app2-service
port:
number: 80
With these resources in place, requests for http://web.example.com/app1 will go to app1-service, and requests for http://web.example.com/app2 will go to app2-service.
NB: I've removed your nginx.ingress.kubernetes.io/rewrite-target annotation because you're not doing any regex-based path rewriting in this example.
I've put a deployable example online here.
Just remove your rewrite path in single ingress you can achieve it.
If you are creating the multiple make sure to change the name as Larsks suggested else it will overwrite the existing one.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: app-ingress
spec:
ingressClassName: nginx
rules:
- host: web.example.com
http:
paths:
- path: /app1
pathType: Prefix
backend:
service:
name: app1-service
port:
number: 80
- path: /app2
pathType: Prefix
backend:
service:
name: app2-service
port:
number: 80

Error: endpoints "default-http-backend" not found

I have Kubernetes cluster v1.19.16 set up in bare metal Ubuntu-18.04 server and currently i want to connect cluster jenkins service through http://jenkins.company.com. Haproxy server side frontend & backend already been configured.
My service.yaml file content as follows,
apiVersion: v1
kind: Service
metadata:
name: jenkins-svc
namespace: jenkins
annotations:
prometheus.io/scrape: 'true'
prometheus.io/path: /
prometheus.io/port: '8080'
spec:
selector:
app: jenkins-server
type: ClusterIP
ports:
- protocol: TCP
port: 8080
targetPort: 80
ingress-resource.yaml file content as follows,
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
name: jenkins-ingress
namespace: jenkins
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: "jenkins.company.com"
http:
paths:
- pathType: Prefix
path: "/"
backend:
serviceName: jenkins-svc
servicePort: 8080
# kubectl get service -n jenkins
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
jenkins-svc ClusterIP 10.96.136.255 <none> 8080/TCP 20m
# kubectl get ing jenkins-ingress
Warning: extensions/v1beta1 Ingress is deprecated in v1.14+, unavailable in v1.22+; use networking.k8s.io/v1 Ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
jenkins-ingress <none> jenkins.company.com 80 5h42m
# kubectl describe ingress -n jenkins
Warning: extensions/v1beta1 Ingress is deprecated in v1.14+, unavailable in v1.22+; use networking.k8s.io/v1 Ingress
Name: jenkins-ingress
Namespace: jenkins
Address:
Default backend: default-http-backend:80 (<error: endpoints "default-http-backend" not found>)
Rules:
Host Path Backends
---- ---- --------
jenkins.dpi.com
/ jenkins-svc:8080 (10.244.0.16:80)
Annotations: ingress.kubernetes.io/rewrite-target: /
kubernetes.io/ingress.class: nginx
Events: <none>
When i tried to access http://jenkins.company.com it shows below error message on browser.
Please let me know what i'm missing here?
The issue with the service port and container port. Jenkins default port is 8080, so I assume your service port is 80
ports:
- protocol: TCP
port: 80
targetPort: 8080
and ingress should be
spec:
rules:
- host: "jenkins.company.com"
http:
paths:
- pathType: Prefix
path: "/"
backend:
serviceName: jenkins-svc
servicePort: 80
port: The port of this service
targetPort The target port on the pod(s) to forward traffic to
Difference between targetPort and port in Kubernetes Service definition

tekton-pipeline ingress route conflicts with kubesphere-console

I have two ingress routes created as below,
kubesphere-console
tekton-pipelines
My manifest files are as like below.
**cat ingress-tekton-dashboard.yaml **
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tekton-dashboard
annotations:
ingress.kubernetes.io/ssl-redirect: "false"
nginx.ingress.kubernetes.io/ssl-redirect: "false"
ingressClassName: nginx
spec:
ingressClassName: nginx
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: tekton-dashboard
port:
number: 9097
#host: *
...
cat ../kubesphere/ingress-route-kubesphere.yaml
cat ../kubesphere/ingress-route-kubesphere.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: kubesphere-console
annotations:
kubesphere.io/creator: admin
spec:
ingressClassName: nginx
rules:
- host: crashandburn.australiaeast.cloudapp.azure.com
http:
paths:
- path: /
pathType: ImplementationSpecific
backend:
service:
name: ks-console
port:
number: 80
---
My ingress are as below:
k get ing -nkubesphere-system
NAME CLASS HOSTS ADDRESS PORTS AGE
kubesphere-console nginx * 20.92.133.79 80 28h
ameya#Azure:~/tekton$ k get ing -ntekton-pipelines
NAME CLASS HOSTS ADDRESS PORTS AGE
tekton-dashboard <none> * 80 2m32s
My service for tekton dashboard is like below:
k get svc -n tekton-pipelines
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
tekton-dashboard ClusterIP 10.0.202.127 <none> 9097/TCP 2d3h
tekton-pipelines-controller ClusterIP 10.0.53.46 <none> 9090/TCP,8008/TCP,8080/TCP 2d6h
tekton-pipelines-webhook ClusterIP 10.0.222.121 <none> 9090/TCP,8008/TCP,443/TCP,8080/TCP 2d6h
However, I get the error like below:
k apply -f ingress-tekton-dashboard.yaml -ntekton-pipelines
Error from server (BadRequest): error when applying patch:
{"metadata":{"annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"networking.k8s.io/v1\",\"kind\":\"Ingress\",\"metadata\":{\"annotations\":{\"ingress.kubernetes.io/ssl-redirect\":\"false\",\"ingressClassName\":\"nginx\",\"nginx.ingress.kubernetes.io/ssl-redirect\":\"false\"},\"name\":\"tekton-dashboard\",\"namespace\":\"tekton-pipelines\"},\"spec\":{\"ingressClassName\":\"nginx\",\"rules\":[{\"http\":{\"paths\":[{\"backend\":{\"service\":{\"name\":\"tekton-dashboard\",\"port\":{\"number\":9097}}},\"path\":\"/\",\"pathType\":\"Prefix\"}]}}]}}\n"}},"spec":{"ingressClassName":"nginx"}}
to:
Resource: "networking.k8s.io/v1, Resource=ingresses", GroupVersionKind: "networking.k8s.io/v1, Kind=Ingress"
Name: "tekton-dashboard", Namespace: "tekton-pipelines"
for: "ingress-tekton-dashboard.yaml": admission webhook "validate.nginx.ingress.kubernetes.io" denied the request: host "_" and path "/" is already defined in ingress kubesphere-system/kubesphere-console
However, I am using two differnt ports for tekton-dashboard and kubesphere-console so wondering why it is complaining.

Ingress cannot route the apis

My ingress cannot route to endpoint.
I provided everything. Nginx-controller works properly. I added the hostname bago.com as loadbalancerip. But it doesn't work.
Here is my ingres's yaml file
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: minimal-ingress
spec:
rules:
- host: bago.com
- http:
paths:
- path: /web1/
pathType: Exact
backend:
service:
name: web1-clusterip
port:
number: 8081
- path: /web2/
pathType: Exact
backend:
service:
name: web2-clusterip
port:
number: 8082
svc and ingress running
bahaddin#bahaddin-ThinkPad-E15-Gen-2:~/projects/personal/exposer/k8s-ingress$ k get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.12.0.1 <none> 443/TCP 154m
web1-clusterip ClusterIP 10.12.6.102 <none> 8081/TCP 145m
web2-clusertip ClusterIP 10.12.9.22 <none> 8082/TCP 149m
bahaddin#bahaddin-ThinkPad-E15-Gen-2:~/projects/personal/exposer/k8s-ingress$ k get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
minimal-ingress <none> bago.com 34.102.241.199 80 121m
bahaddin#bahaddin-ThinkPad-E15-Gen-2:~/projects/personal/exposer/k8s-ingress$
Here is my API java code.
#RequestMapping("/web1")
#RestController
public class Controller {
#GetMapping("/hello")
public String foo() {
return "hello from web1 ms";
}
}
server.port=8081 on container level
my service
Web1-service.
apiVersion: v1
kind: Service
metadata:
name: web1-clusterip
spec:
ports:
- protocol: "TCP"
port: 8081
selector:
app: web1-dp
type: ClusterIP
But when I type in the browser
http://bago.com/web1/hello
http://bago.com/web1/hello
I got a 404 not found error
Screenshot
You have an issue in your ingress manifest. You have two items in the list, while you want to have one. Additionally, you are missing the ingress class.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: minimal-ingress
spec:
rules:
# these are indivudal list items
- host: bago.com
- http: ...
You have to change the manifest so that you have a single item. You should also add the ingress class.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: minimal-ingress
spec:
# this should be the ingress class, i.e. nginx
ingressClassName: my-ingress-class
rules:
# this list has only 1 items, which is an object.
# note the dash (-)
- host: bago.com
http: ...
I see that for the ingress, you have class as <none> if your nginx-controller is making use of a class then you have to define that as ingressClassName under the spec section while creating ingress (rules).
you can identify the classname by describing the ingress-controller.
kubectl describe deployments.apps <your-ingress-controller-deployment> -n=<namespace> and look for --ingress-class parameter by default the classname should be nginx.
This class name is useful if more than one ingress-controller are present on the cluster, by defining the class we can tell which ingress-controller is responsible for which specific ingress rules.

rancher 2.x thru ingress controller returns 404

Rancher service:
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
rancher ClusterIP 10.10.17.245 <none> 80/TCP,443/TCP 1h
Ingress controller service:
NAMESPACE NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-ingress nginx-ingress LoadBalancer 10.10.15.181 <ext-IP> 80:30324/TCP,443:31022/TCP 3h
Ingress role:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: rancher-ing
annotations:
kubernetes.io/ingress.class: "rancher"
spec:
rules:
- host: api.sample.com
http:
paths:
- path: /
backend:
serviceName: rancher
servicePort: 443
Ingress:
$ kubectl get ingress
NAME HOSTS ADDRESS PORTS AGE
rancher api.sample.com 80 19s
When I am trying to reach rancher over the ingress controller ext-IP:
$ curl http://api.sample.com
As a response I have some not encoded string. If I do it thru web browser this string will be downloaded and I have got 404.
Similar role for some random service over http (without https) works fine so it's not a matter of wrong ingress controller configuration.
If you want to use kubernetes.io/ingress.class: "rancher" you have to deploy your ingress controller with the --ingress-class=rancher annotation.
Have a lot at
https://github.com/nginxinc/kubernetes-ingress/tree/master/examples/multiple-ingress-controllers and https://kubernetes.github.io/ingress-nginx/user-guide/multiple-ingress/
Cheers
If I follow default ingress controller installation:
https://github.com/nginxinc/kubernetes-ingress/blob/master/docs/installation.md
and apply rancher ingress role like:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
labels:
app: rancher
name: rancher
namespace: cattle-system
spec:
tls:
- hosts:
- api.sample.com
secretName: default-server-secret
rules:
- host: api.sample.com
http:
paths:
- path: /
backend:
serviceName: rancher
servicePort: 80
This solution enabled https to Rancher UI over the ingress controller without annotations.