In this post I will show how to deploy microservices to Kubernetes. My example will show how to deploy a microservice with a public IP in front of an internal service with a cluster scoped IP.
This specific example uses asp.net core, but the general idea is framework agnostic.
Asp .Net
I have created a simple car service in front of a greeting service where the car service calls the greeting service to create a car specific greeting.
Car service will be deployed with a public IP to allow traffic from outside the cluster. Greeting service doesn’t need to be exposed outside the cluster, so it will be deploy with a cluster specific IP (ClusterIP).
The source code for the two services is listed below:
Car Service
namespace cars.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class CarsController : ControllerBase
{
private readonly IHttpClientFactory _clientFactory;
public CarsController(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
// GET api/values
[HttpGet]
public async Task<string> Get()
{
var client = _clientFactory.CreateClient();
string response = await client.GetStringAsync("http://greetings-service:8000/api/Greetings");
return $"{response} from BMW";
}
}
}
Greeting Service
namespace greetings.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class GreetingsController : ControllerBase
{
// GET api/values
[HttpGet]
public ActionResult<string> Get()
{
return "Hello";
}
}
}
Docker
The first step is to create Docker images that can be deployed to Kubernetes. Dockerfiles for both services are included below:
Car Service
FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build
COPY cars/*.csproj /cars/
COPY cars/. /cars/
WORKDIR /cars
RUN dotnet restore
RUN dotnet publish cars.csproj -c Release -o out
FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS runtime
WORKDIR /app
COPY --from=build /cars/out ./
EXPOSE 80
ENTRYPOINT ["dotnet", "cars.dll"]
Greeting Service
FROM mcr.microsoft.com/dotnet/core/sdk:2.2 AS build
COPY greetings/*.csproj /greetings/
COPY greetings/. /greetings/
WORKDIR /greetings
RUN dotnet restore
RUN dotnet publish greetings.csproj -c Release -o out
FROM mcr.microsoft.com/dotnet/core/aspnet:2.2 AS runtime
WORKDIR /app
COPY --from=build /greetings/out ./
EXPOSE 80
ENTRYPOINT ["dotnet", "greetings.dll"]
Kubernetes
Once the images are built and deployed to a registry, or just locally, we can proceed to set up Kubernetes deployments and services to deploy the microservices to Kubernetes.
I have included the .yml files below:
Car Service
apiVersion: apps/v1
kind: Deployment
metadata:
name: cars
spec:
selector:
matchLabels:
app: cars
replicas: 5
template:
metadata:
labels:
app: cars
spec:
containers:
- name: cars
image: "car-service:v5"
ports:
- name: http
containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: cars
spec:
selector:
app: cars
ports:
- protocol: TCP
port: 1234
targetPort: 80
type: LoadBalancer
Greeting Service
apiVersion: apps/v1
kind: Deployment
metadata:
name: greetings
spec:
selector:
matchLabels:
app: greetings
replicas: 5
template:
metadata:
labels:
app: greetings
spec:
containers:
- name: greetings
image: "greeting-service:v9"
ports:
- name: http
containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: greetings-service
spec:
selector:
app: greetings
ports:
- protocol: TCP
port: 8000
name: http
targetPort: 80
type: ClusterIP
One important difference between the two yamls is the type field in the Service section. Car service is configured as a LoadBalancer since we want a public IP to allow traffic from outside the cluster. Greeting service is of type ClusterIP which will ensure that it gets an IP that is only accessible from inside the cluster.
Since the Cluster IP is auto generated, how can we call Greeting Service from Car Service? Luckily, Kubernetes helps out here by abstracting the IP with an internal host name. By default this hostname is determined by the name of the .yml service (greetings-service). This means we can access Greeting service as http://greetings-service:8000/api/Greetings instead of using the IP address.
I have pushed the code to Github in case you would like to try it out yourself.