I read that I needed to run another service in Namespace B which maps to Namespace A loadbalancer service. (You can see this service on my yaml b).
I don't want to use the external IPs given by the loadbalancers (If my scenario was replicated on the cloud using GCP/Azure/AWS/IBM cloud/OpenShift).
I deployed the next scenario using minikube v1.6.2 and Kubernetes v1.17:
Namespace a:
deployment/python-hello-world READY: 1/1
service/python-hello-world
TYPE: Loadbalancer CLUSTER-IP: 10.96.167.227 EXT-IP: <pending> PORTS: 80:31603/TCP
Namespace b:
deployment/python-hello-world READY: 1/1
service/python-hello-world
TYPE: Loadbalancer CLUSTER-IP: 10.96.67.10 EXT-IP: <pending> PORTS: 80:31595/TCP
service/connection
TYPE: ExternalName CLUSTER-IP: <none> EXTERNAL-IP: python-hello-world-external.a.svc.cluster.local PORT: 31603/TCP
Kubernetes yaml a:
apiVersion: apps/v1
kind: Deployment
metadata:
name: python-hello-world
namespace: a
spec:
replicas: 1
selector:
matchLabels:
app: python-hello-world
template:
metadata:
labels:
app: python-hello-world
spec:
containers:
- name: server
image: python-hello-world
ports:
- containerPort: 9090
env:
- name: PORT
value: "9090"
---
apiVersion: v1
kind: Service
metadata:
name: python-hello-world-external
namespace: a
spec:
type: LoadBalancer
selector:
app: python-hello-world
ports:
- name: http
port: 80
targetPort: 9090
Kubernetes yaml b:
apiVersion: apps/v1
kind: Deployment
metadata:
name: python-hello-world
namespace: b
spec:
replicas: 1
selector:
matchLabels:
app: python-hello-world
template:
metadata:
labels:
app: python-hello-world
spec:
containers:
- name: server
image: python-hello-world
ports:
- containerPort: 9091
env:
- name: PORT
value: "9091"
---
apiVersion: v1
kind: Service
metadata:
name: python-hello-world-external
namespace: b
spec:
type: LoadBalancer
selector:
app: python-hello-world
ports:
- name: http
port: 80
targetPort: 9091
---
apiVersion: v1
kind: Service
metadata:
name: connection
namespace: b
spec:
type: ExternalName
externalName: python-hello-world-external.a.svc.cluster.local
ports:
- port: 31603
For accessing API A in my browser I ran in the terminal:
$ minikube service python-hello-world-external -n a
|-----------|-----------------------------|-------------|-----------------------------|
| NAMESPACE | NAME | TARGET PORT | URL |
|-----------|-----------------------------|-------------|-----------------------------|
| a | python-hello-world-external | http | http://192.168.39.196:31603 |
|-----------|-----------------------------|-------------|-----------------------------|
For accessing API B:
$ minikube service python-hello-world-external -n b
|-----------|-----------------------------|-------------|-----------------------------|
| NAMESPACE | NAME | TARGET PORT | URL |
|-----------|-----------------------------|-------------|-----------------------------|
| b | python-hello-world-external | http | http://192.168.39.196:31595 |
|-----------|-----------------------------|-------------|-----------------------------|
Flask API A:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return "Hello World A"
if __name__ == '__main__':
app.run(debug=False, port=9090, host='0.0.0.0')
Flask API B:
import requests
from flask import Flask
app = Flask(__name__)
@app.route('/a')
def call_a():
response = requests.get("I DONT KNOW WHAT TO PUT HERE")
return response
if __name__ == '__main__':
app.run(debug=False, port=9091, host='0.0.0.0')
As guys already suggested in comments LoadBalancer
isn't the best choice here. Actually it has completely different purpose, namely it serves for exposing your app externally which by the way will not work in Minikube the intended way (instead simple NodePort
service is created). To use fully functional LoadBalancer
you would need to use some cloud provider's services. All major players such as GCP, AWS or Azure support this functionality. Probably you decided to use LoadBalancer
in order to have load balancer functionality implemented, but don't worry, simple ClusterIP
also can do that. If you have let's say 3 fron-end Pods
(usually managed by Deployment
) and they need to communicate with 3 other Pods
which are providing back-end-service, simple ClusterIP
Service (you can omit the type as this is the default one) will do the job, including proper load balancing of requests to all underlying back-end Pods
. As @David Maze suggested, familiarize with this article in official Kubernetes docs and you should grasp the whole concept easily.
Here you can find one of my old answers on a very similar topic. I guess you may find it useful as it explains in detail how communication between different sets of Pods
, representing different microservices
in your application architecture, should be done within Kubernetes Cluster.
As to communication between resources living in different namespaces, it can be also easily done in Kubernetes using short form suggested by @jordanm: <service_name>.<namespace>
or fully qualified domain name <service-name>.<namespace-name>.svc.cluster.local
(even more recommended). More details you can find here.
When you create a Service, it creates a corresponding DNS entry. This entry is of the form
<service-name>.<namespace-name>.svc.cluster.local
, which means that if a container just uses<service-name>
, it will resolve to the service which is local to a namespace. This is useful for using the same configuration across multiple namespaces such as Development, Staging and Production. If you want to reach across namespaces, you need to use the fully qualified domain name (FQDN).
Here is 1 example of accessing 1 API service from 2nd API service but within same namespace. Maybe it can help.
Create your 2 API servers in Python in following manner, tried and tested on my Minikube. Host the 1st one in Kubernetes as a ClusterIp service. Host the 2nd one using NodePort to access outside Minikube cluster.
The 1st service is accessed using it's ClusterIp inside the 2nd service as shown in the Python code below, I tried to access using service name but did not work.
Here is 1st flask api server (.py file) which would be called from with in the 2nd flask api server:
import flask
from flask import Flask
import json
from flask import request
application = Flask(__name__)
@application.route('/api/v1/square', methods=['GET'])
def square():
# sample api call: http://0.0.0.0:8003/api/v1/square?nb1=11
nb1 = request.args.get('nb1')
sq_nb1 = int(nb1)*int(nb1)
return flask.jsonify(sq_nb1)
if __name__ == '__main__':
application.run(debug=True, host="0.0.0.0", port=8003)
2nd API server (.py file) which calls the 1st API server hosted as ClusterIP in Kubernetes
import flask
from flask import Flask
import json
from flask import request
import requests
application = Flask(__name__)
@application.route('/api/v1/sumsq', methods=['GET'])
def sumSq():
# sample api call: http://0.0.0.0:8002/api/v1/sumsq?nb1=111&nb2=222
nb1 = request.args.get('nb1')
nb2 = request.args.get('nb2')
sum_val = int(nb1) + int(nb2)
# call square micro-service (Svc: 3-Internal-API-Server)
api_url = "http://10.96.55.98/api/v1/square?nb1={v}".format(v=sum_val)
# get IP using 'kubectl get svc -n <ns_name>' command
res = requests.get(url=api_url)
sum_sq_val = res.json()
return flask.jsonify(sum_sq_val)
if __name__ == '__main__':
application.run(debug=True, host="0.0.0.0", port=8002)