Kubernetes deploy a single NodePort for two deployments in different namespaces - kubernetes

I have to deploy on my kubernetes cluster two deployments that use the same service for communicate but the two deployments are located into two differents namespaces:
apiVersion: apps/v1
kind: Deployment
metadata:
name: app1
namespace: namespace1
labels:
app: app1
spec:
replicas: 2
selector:
matchLabels:
app: app1
template:
metadata:
labels:
app: app1
spec:
containers:
- name: app1
image: eu.gcr.io/direct-variety-20998876/test1:dev
resources:
requests:
cpu: "100m"
memory: "128Mi"
ports:
- containerPort: 8000
imagePullPolicy: Always
env:
...
and an identical second but in another amespace:
apiVersion: apps/v1
kind: Deployment
metadata:
name: app2
namespace: namespace2
labels:
app: app2
spec:
replicas: 2
selector:
matchLabels:
app: app2
template:
metadata:
labels:
app: app2
spec:
containers:
- name: app2
image: eu.gcr.io/direct-variety-20998876/test1:prod
resources:
requests:
cpu: "100m"
memory: "128Mi"
ports:
- containerPort: 8000
imagePullPolicy: Always
env:
...
so i have to create a common service for bot deployment that run over the two namespaces:
I try:
kind: Service
apiVersion: v1
metadata:
name: apps-service
namespace: ???
spec:
selector:
app: ???
ports:
- protocol: TCP
port: 8000
targetPort: 8000
type: NodePort
Until now i create one service for any app in specific namespace but there is a method for create a single service for manage both deployment (and then associate an unique ingress)?
So many thanks in advance

First, I would like to provide some general explanations.
As we can see in the Ingress documentation:
You must have an Ingress controller to satisfy an Ingress. Only creating an Ingress resource has no effect.
Ingress Controller can be deployed in any namespace and is often deployed in a namespace separate from the application namespace.
Ingress resource (Ingress rules) should be deployed in the same namespace as the services they point to.
It is possible to have one ingress controller for multiple ingress resources.
Deploying an Ingress resource in the same namespace as the Services it points to is the most common approach (I recommend this approach).
However, there is way to have Ingress in one namespace and Services in another namespaces using externalName Services.
I will create an example to illustrate how it may work.
Suppose, I have two Deployments (app1, app2) deployed in two different Namespaces (namespace1, namespace2):
$ cat app1.yml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: app1
name: app1
namespace: namespace1
spec:
selector:
matchLabels:
app: app1
template:
metadata:
labels:
app: app1
spec:
containers:
- image: nginx
name: nginx
$ cat app2.yml
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: app2
name: app2
namespace: namespace2
spec:
selector:
matchLabels:
app: app2
template:
metadata:
labels:
app: app2
spec:
containers:
- image: nginx
name: nginx
And I exposed these Deployments with ClusterIP Services:
$ cat svc-app1.yml
apiVersion: v1
kind: Service
metadata:
labels:
app: app1
name: app1
namespace: namespace1
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: app1
$ cat svc-app2.yml
apiVersion: v1
kind: Service
metadata:
labels:
app: app2
name: app2
namespace: namespace2
spec:
ports:
- port: 80
protocol: TCP
targetPort: 80
selector:
app: app2
We want to have a single Ingress resource in a separate Namespace (default).
First, we need to deploy Services of type ExternalName that map a Service to a DNS name.
$ cat external-app1.yml
kind: Service
apiVersion: v1
metadata:
name: external-app1
spec:
type: ExternalName
externalName: app1.namespace1.svc
$ cat external-app2.yml
kind: Service
apiVersion: v1
metadata:
name: external-app2
spec:
type: ExternalName
externalName: app2.namespace2.svc
Then we can deploy Ingress resource:
$ cat ingress.yml
apiVersion: networking.k8s.io/v1beta1
kind: Ingress
metadata:
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /
name: app-ingress
spec:
rules:
- http:
paths:
- path: /app1
backend:
serviceName: external-app1
servicePort: 80
- path: /app2
backend:
serviceName: external-app2
servicePort: 80
$ kubectl apply -f ingress.yml
ingress.networking.k8s.io/app-ingress created
Finally, we can check if it works as expected:
$ curl 34.118.X.207/app1
app1
$ curl 34.118.X.207/app2
app2
NOTE: This is a workaround and may work differently with different ingress controllers. It is ususally better to have two or more Ingress resources in different namespaces.

Related

Kubernetes service not exposed on minikube

I'm new to k8 and i'm trying to figure out how to deploy my first docker image on minikube.
My k8.yaml file is:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-deployment
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-docker-image
image: my-docker-image:1.0
ports:
- containerPort: 8080
---
apiVersion: v1
kind: Service
metadata:
name: my-service
namespace: default
spec:
type: LoadBalancer
selector:
app: my-service
ports:
- port: 8080
targetPort: 8080
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
ingressClassName: my-ingress
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-service
port:
number: 8080
Everything seems fine to me, however, I'm not able to reach my service on cluster.
I tried to create a tunnel using the minikube tunnel command and i have this result if i execute kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-service LoadBalancer 10.109.154.236 127.0.0.1 8080:30558/TCP 2m53s
However, if i try to call my service at 127.0.0.1:30588 host is unreachable.
Can someone help me?
There is an issue in the service selector as well, so first, we need to fix this service selector and it should match with with deployment label
replicas: 1
selector:
matchLabels:
app: my-app
and the service should refer to this selector
the selector should be my-app in the service or same as above for deployment
type: LoadBalancer
selector:
app: my-app
ports:
- port: 8080
targetPort: 8080
to access from the host
minikube service my-service
and here you go
kubectl delete -f myapp.yaml
kubectl apply -f myapp.yaml
deployment manifest
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-deployment
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: my-app
template:
metadata:
labels:
app: my-app
spec:
containers:
- name: my-docker-image
image: nginx
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: my-service
namespace: default
spec:
type: LoadBalancer
selector:
app: my-app
ports:
- port: 80
targetPort: 80
Also worth considering the service type for Minikube.
What's the difference between ClusterIP, NodePort and LoadBalancer service types in Kubernetes?

multiple kubernetes deployments using same global yaml as template

I have ran into an issue.
My goal: Create multiple nginx deployments using the same "template" file and use kustomize to replace the container name. This is just an example, as in the next steps I will add/replace/remove lines (for eg.: resources) from "nginx_temaplate.yml" for different deployments. For now I want to make the patches work to create multiple deployments :-) I am not even sure, if the structure is correct.
The structure is:
base/nginx_template.yml
base/kustomization.yml
base/apps/nginx1/nginx1.yml
base/apps/nginx2/nginx2.yml
base/nginx_template.yml:
---
apiVersion: apps/v1 # for versions before 1.9.0 use apps/v1beta2
kind: Deployment
metadata:
name: nginx
spec:
strategy:
type: Recreate
selector:
matchLabels:
app: nginx
replicas: 1 # tells deployment to run 1 pods matching the template
template: # create pods using pod definition in this template
metadata:
labels:
app: nginx
spec:
containers:
- name: template
image: nginx
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: nginx
namespace: default
labels:
app: nginx
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
spec:
externalTrafficPolicy: Local
ports:
- name: http
port: 80
protocol: TCP
targetPort: 80
selector:
app: nginx
type: LoadBalancer
base/kustomization.yml:
resources:
- nginx_template.yml
patches:
- path: ./apps/nginx1/nginx1.yml
target:
kind: Deployment
- path: ./apps/nginx2/nginx2.yml
target:
kind: Deployment
base/apps/nginx1/nginx1.yml:
- op: replace
path: /spec/template/spec/containers/0/name
value: nginx-1
base/apps/nginx2/nginx2.yml:
- op: replace
path: /spec/template/spec/containers/0/name
value: nginx-2
All it does now is, that it only creates the nginx-2. Thank you for any help.

Kubernetes ingress not routing

I have 2 services and deployments deployed on minikube on local dev. Both are accessible when I run minikube start service. For the sake of simplicity I have attached code with only one service
However, ingress routing is not working
CoffeeApiDeployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: coffeeapi-deployment
labels:
app: coffeeapi
spec:
replicas: 1
selector:
matchLabels:
app: coffeeapi
template:
metadata:
labels:
app: coffeeapi
spec:
containers:
- name: coffeeapi
image: manigupta31286/coffeeapi:latest
env:
- name: ASPNETCORE_URLS
value: "http://+"
- name: ASPNETCORE_ENVIRONMENT
value: "Development"
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: coffeeapi-service
spec:
selector:
app: coffeeapi
type: NodePort
ports:
- protocol: TCP
port: 8080
targetPort: 80
nodePort: 30036
Ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp-ingress
annotations:
nginx.ingress.kubernetes.io/rewrite-target: /$1
spec:
rules:
- http:
paths:
- path: /coffee
pathType: Prefix
backend:
service:
name: coffeeapi-service
port:
number: 8080
You are missing the ingress class in the spec.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: myapp-ingress
spec:
ingressClassName: nginx # (or the class you configured)
Using NodePort on your service may also be problematic. At least it's not required since you want to use the ingress controller to route traffic via the ClusterIP and not use the NodePort directly.

Deploy same image two different namespaces same port

I have a single node k8s cluster. I have two namespaces, call them n1 and n2. I want to deploy the same image, on the same port but in different namespaces.
How do I do this?
namespace yamls:
apiVersion: v1
kind: Namespace
metadata:
name: n1
and
apiVersion: v1
kind: Namespace
metadata:
name: n2
service yamls:
apiVersion: v1
kind: Service
metadata:
name: my-app-n1
namespace: n1
labels:
app: my-app-n1
spec:
type: LoadBalancer
ports:
- name: http
port: 80
targetPort: http
protocol: TCP
selector:
app: my-app-n1
and
apiVersion: v1
kind: Service
metadata:
name: my-app-n2
namespace: n2
labels:
app: my-app-n2
spec:
type: LoadBalancer
ports:
- name: http
port: 80
targetPort: http
protocol: TCP
selector:
app: my-app-n2
deployment yamls:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app-n1
labels:
app: my-app-n1
spec:
replicas: 1
selector:
matchLabels:
app: my-app-n1
template:
metadata:
labels:
app: my-app-n1
spec:
containers:
- name: waiter
image: waiter:v1
ports:
- containerPort: 80
and
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app-n2
labels:
app: my-app-n2
spec:
replicas: 1
selector:
matchLabels:
app: my-app-n2
template:
metadata:
labels:
app: my-app-n2
spec:
containers:
- name: waiter
image: waiter:v1
ports:
- containerPort: 80
waiter:v1 corresponds to this repo: https://hub.docker.com/r/adamgardnerdt/waiter
Surely I can do this as namespaces are supposed to represent different environments? eg. nonprod vs. prod. So surely I can deploy identically into two different "environments" aka "namespaces"?
For Service you have specified namespaces , that is correct.
For Deployments you should also specify namespaces othervise they will go to default namespace.
Example:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app-n1
namespace: n1
labels:
app: my-app-n1
spec:
replicas: 1
selector:
matchLabels:
app: my-app-n1
template:
metadata:
labels:
app: my-app-n1
spec:
containers:
- name: waiter
image: waiter:v1
ports:
- containerPort: 80
I want to deploy the same image, on the same port but in different namespaces.
You are already doing that with your configs, except for deployment objects, that should refer to correct namespaces (as mentioned by answer from Ijaz Ahmad Khan), available to other services in the namespaces using DNS names my-app-n1 and my-app-n2 respectively.
Because waiter is a web server, I assume you would like to access both instances of it from the internet. Hence, you should:
change the type of both services to ClusterIP,
add ingress object, one per each namespace, containing a host name, e.g. myapp.com and staging.myapp.com respectively),
put a load balancer in front of your cluster: the load balancer will use ingress objects to know which hostname matches which service (your cloud provider should create a load balancer automatically).

Kubernetes ingress-nginx gives 502 error (Bad Gateway)

I have an EKS cluster for which I want :
- 1 Load Balancer per cluster,
- Ingress rules to direct to the right namespace and the right service.
I have been following this guide : https://www.digitalocean.com/community/tutorials/how-to-set-up-an-nginx-ingress-with-cert-manager-on-digitalocean-kubernetes
My deployments:
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-world
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: hello-world
template:
metadata:
labels:
app: hello-world
spec:
containers:
- name: hello-world
image: IMAGENAME
ports:
- containerPort: 8000
name: hello-world
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: bleble
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: bleble
template:
metadata:
labels:
app: bleble
spec:
containers:
- name: bleble
image: IMAGENAME
ports:
- containerPort: 8000
name: bleble
the service of those deployments:
apiVersion: v1
kind: Service
metadata:
name: hello-world-svc
spec:
ports:
- port: 8080
protocol: TCP
targetPort: 8000
selector:
app: hello-world
type: NodePort
---
apiVersion: v1
kind: Service
metadata:
name: bleble-svc
spec:
ports:
- port: 8080
protocol: TCP
targetPort: 8000
selector:
app: bleble
type: NodePort
My Load balancer:
kind: Service
apiVersion: v1
metadata:
name: ingress-nginx
namespace: ingress-nginx
annotations:
service.beta.kubernetes.io/aws-load-balancer-internal: "true"
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
spec:
externalTrafficPolicy: Local
type: LoadBalancer
selector:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
ports:
- name: http
port: 80
targetPort: http
My ingress:
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: simple-fanout-example
namespace : default
annotations:
kubernetes.io/ingress.class: nginx
nginx.ingress.kubernetes.io/rewrite-target: /
spec:
rules:
- host: internal-lb.aws.com
http:
paths:
- path: /bleble
backend:
serviceName: bleble-svc
servicePort: 80
- path: /hello-world
backend:
serviceName: hello-world-svc
servicePort: 80
I've set up the Nginx Ingress Controller with this : kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/nginx-0.24.1/deploy/mandatory.yaml
I am unsure why I get a 503 Service Temporarily Unavailable for one service and one 502 for another... I would guess it's a problem of ports or of namespace? In the guide, they don't define namespace for the deployment...
Every resources create correctly, and I think the ingress is actually working but is getting confused where to go.
Thanks for your help!
In general, use externalTrafficPolicy: Cluster instead of Local. You can gain some performance (latency) improvement by using Local but you need to configure those pod allocations with a lot efforts. You will hit 5xx errors with those misconfigurations. In addition, Cluster is the default option for externalTrafficPolicy.
In your ingress, you route /bleble to service bleble, but your service name is actually bleble-svc. please make them consistent. Also, you would need to set your servicePort to 8080 as you exposed 8080 in your service configuration.
For internal service like bleble-svc, Cluster IP is good enough in your case as it does not need external access.
Hope this helps.
Found it!
The containerPort in the Deployment were set to 8000, the targetport of the services as well, but the person who did the Dockerfile of the code exposed the port 80. Which was the reason it was getting the 502 Bad getaway!
Thanks a lot as well to #Fei who has been a fantastic helper!