Service-to-service communication in Kubernetes
I post this to have a good reference (for myself and others) for a minimal Kubernetes manifest that allows service-to-service communication.
The problem
How could the developer of the microservice
frontend
configure their application such that it can talk tobackend
, before either microservice has been deployed?
The detailed functionality of the microservices is not relevant for the example, but it is assumed that frontend
wants
to make HTTP requests towards backend
.
Proposal
By deploying their application as seen below, frontend
can be configured to communicate with
http://backend-service
1, without knowing the Cluster IP
of the backend
microservice.
Your DNS server of choice, in Kubernetes, will handle the translation.
A quick note
The frontend-service
exposes a NodePort
.
This is useful if you run minikube, k3s or something
similar, and you want to test your deployment locally.
In a production scenario, you should front your service
with an
Ingress instead of connecting straight to the
service
.
Manifests
# File: backend.yaml
# Documentation for deployments: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/
# kubectl explain --api-version=apps/v1 Deployment
apiVersion: apps/v1
kind: Deployment
# The metadata applies to the deployment itself.
# We give it a name and put the deployment in a namespace.
# http://kubernetes.io/docs/user-guide/labels
metadata:
name: backend-deployment
namespace: default
# The specification of the desired behaviour of the Deployment.
spec:
# Number of desired pods
replicas: 3
# Existing ReplicaSets whose pods are selected by this will be the ones affected by this deployment.
# The label selector is the core grouping primitive in Kubernetes.
# It must match the pod template's labels below.
selector:
matchLabels:
app: backend
# Template describes the pods that will be created.
template:
# Standard object's metadata.
# The label app: frontend, is what groups the pod to the Deployment.
metadata:
labels:
app: backend
# Specification of the desired behaviour of the Pod.
spec:
# List of containers belonging to the pod along with settings for them.
# We use IfNotPresent to avoid pulling images from a registry if they already exist locally.
containers:
- name: backend
image: backend:latest
imagePullPolicy: IfNotPresent
ports:
- name: "backend-http"
containerPort: 80
---
# Documentation: https://kubernetes.io/docs/concepts/services-networking/service/
# kubectl explain --api-version=v1 Service
apiVersion: v1
kind: Service
# Metadata concerning the Service
metadata:
name: backend-service
namespace: default
# The specification for the Service
spec:
# Type determines how the Service is exposed.
# Defaults to ClusterIP.
type: ClusterIP
# Route service traffic to pods with label keys and values matching this selector.
# In the deployment-yaml, the pods are given the same label as the one here.
selector:
app: backend
# There are three ports specified here:
# port, is the port that will be exposed by this service
# targetPort, is the name (or number) of the port to access on the pods targeted by the service
ports:
- port: 80
targetPort: backend-http
I have omitted the comments that are simply duplicates of the backend
-YAML-comments.
# File: frontend.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: frontend-deployment
namespace: default
spec:
replicas: 1
selector:
matchLabels:
app: frontend
template:
metadata:
labels:
app: frontend
spec:
containers:
- name: frontend
image: frontend:latest
imagePullPolicy: IfNotPresent
ports:
- name: "frontend-http"
containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: frontend-service
namespace: default
spec:
# Valid options are: ExternalName, ClusterIP, NodePort, and LoadBalancer.
# https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types
# We use NodePort here since we want to expose the frontend outside of the cluster.
# Reaching the service from a browser or using curl is a bit tricky though.
# You connect using the <Node-IP>:<NodePort>.
# Retrieve the NodeIP by running: kubectl get nodes -o json | jq -r '.items[0].metadata.annotations."alpha.kubernetes.io/provided-node-ip"'
# Retrieve the NodePort by running: kubectl get svc frontend-service -o json | jq '.spec.ports[0].nodePort'
type: NodePort
selector:
app: frontend
ports:
- port: 8080
targetPort: frontend-http
-
It is assumed that communication between the pods is made using Port 80. ↩