Search code examples
dockerkubernetesmicroservices

how do you set up two microservices that communicate with each other, one being public and one private, using Kubernetes?


I think that you can configure this in the -service.yaml. For example I have a frontend and a backend. The frontend should be public and my backend should be private. So how do you set up two microservices that communicate with each other, one being public and one private, using Kubernetes?

frontend-service.yaml

apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  labels:
    app: frontend
  name: frontend
spec:
  ports:
  - port: 8081
    protocol: TCP
    targetPort: 8081
  selector:
    app: frontend
  type: LoadBalancer
status:
  loadBalancer: {}

backend-service.yaml

apiVersion: v1
kind: Service
metadata:
  creationTimestamp: null
  labels:
    app: backend
  name: backend
spec:
  ports:
  - port: 8080
    protocol: TCP
    targetPort: 8080
  selector:
    app: backend
  type: LoadBalancer
status:
  loadBalancer: {}

What I tried

kubectl apply -f frontend-deploy.yaml
kubectl get pods
kubectl apply -f frontend-service.yaml
kubectl get service
kubectl apply -f backend-deploy.yaml
kubectl get pods
kubectl apply -f backend-service.yaml
kubectl get service
kubectl expose deployment frontend --type=LoadBalancer --name=frontend-service.yaml

Solution

  • You should use ClusterIP type for the private / internal services which will make your application only available within the cluster:

    • ClusterIP: Exposes the Service on a cluster-internal IP. Choosing this value makes the Service only reachable from within the cluster. This is the default ServiceType

    ...and LoadBalancer type for the public services which are designed to receive requests from the outside the cluster:

    • LoadBalancer: Exposes the Service externally using a cloud provider's load balancer. NodePort and ClusterIP Services, to which the external load balancer routes, are automatically created.

    Example:

    Let's say that I have created frontend and backend deployments - frontend on 8081 port and backend on 8080. Services yamls are similar to yours (I used LoadBalancer for the frontend, and ClusterIP for the backend). Fronted service is available at the 80 port, backend at the 8080:

    apiVersion: v1
    kind: Service
    metadata:
      labels:
        app: frontend
      name: frontend
    spec:
      ports:
      - port: 80
        protocol: TCP
        targetPort: 8081
      selector:
        app: frontend
      type: LoadBalancer
    ---
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        app: backend
      name: backend
    spec:
      ports:
      - port: 8080
        protocol: TCP
        targetPort: 8080
      selector:
        app: backend
      type: ClusterIP
    

    Let's check the services:

    $ kubectl get svc
    NAME                                TYPE           CLUSTER-IP     EXTERNAL-IP      PORT(S)        AGE
    backend                             ClusterIP      10.36.9.41     <none>           8080/TCP       19m
    frontend                            LoadBalancer   10.36.4.172    xx.xxx.xxx.xxx   80:32126/TCP   19m
    

    As can see, both services have ClusterIP (used for communication inside the cluster) and frontend service has a LoadBalancer with public IP.

    Let's exec into a pod and send request to the frontend and backend using just a service name:

    root@my-nginx-deployment-5bbb68bb8f-jgvrk:/# curl backend:8080
    "hello world backend"
    root@my-nginx-deployment-5bbb68bb8f-jgvrk:/# curl frontend:80
    "hello world frontend"
    

    It's working properly, because the pod that I exec into is in the same namespace (default). For communication between different namespaces you should use <service-name>.<namespace>.svc.cluster.local or ClusterIP:

    root@my-nginx-deployment-5bbb68bb8f-jgvrk:/# curl backend.default.svc.cluster.local:8080
    "hello world backend"
    root@my-nginx-deployment-5bbb68bb8f-jgvrk:/# curl 10.36.9.41:8080
    "hello world backend"
    

    This is how communication inside cluster works in Kubernetes

    For requests outside the cluster use LoadBalancer IP (EXTERNAL-IP in the kubectl get svc command):

    user@shell-outside-the-cluster:~$ curl xx.xxx.xxx.xxx
    "hello world frontend"
    

    Consider using Ingress when you have multiple applications which you want to expose publicly.

    Also check these: