In this article, we will build a simple microservice application using Docker and deploy it on a local Kubernetes cluster.
Prerequisite Installation
Docker
This article uses Docker as a container run time engine. The Docker can also be used to install the local Kubernetes cluster. You can check instructions about installing the Docker at the official documentation.
Kubernetes Cluster
There are various ways you can set up and run Kubernetes. You can deploy a Kubernetes cluster on a local machine, cloud, on-prem datacenter, or choose a managed Kubernetes cluster.
- Cloud: You can create a free trial account in any of the public cloud providers (such as AWS, Azure, Google Cloud) and start a Kubernetes cluster.
- Ketacoda: Ketacoda is a free playground offered by O’Reilly. This is ideal for playing around and understanding concepts of Kubernetes quickly.
- Play with Kubernetes: Similar to Ketacoda, you can quickly get started to play around with Kubernetes.
- Minikube: Using Minikube you can start a local Kubernetes cluster in no time. All you need is a machine with at least 2 CPU, 2GB of free memory, 20GB of free disk space, internet connection, and either container (such as Docker) or virtual machine manager (such as Virtual Box)
- Kind: If you have docked installed and configured then you can use kind to spin up a new Kubernetes cluster locally.
- Kubeadm: Kubeadm is another tool using which you can install the Kubernetes cluster locally.
You can run this example using kind (Kubernetes in Docker) or Minikube as a local Kubernetes cluster.
Kubectl
Kubectl is a command-line utility that is used to connect to the Kubernetes cluster. You can check the official documentation for the instructions to install Kubectl.
CODE EXAMPLE
The working code example of this article is listed on GitHub . It’s a simple Spring Boot-based microservice application that exposes two REST
endpoints.
POST /products/
– to create a product.GET /products/{productId}
– to get product information based onproductId
.
You can download the code and start service locally in any IDE and test using curl
or Postman
.
POST Endpoint:
The POST endpoint code is very simple. It maps HTTP POST
request to /products/
as:
@PostMapping("/products/")
public ResponseEntity<Product> saveProduct(@RequestBody Product product) {
log.info("Saving product");
var savedProduct = productRepository.save(product);
return new ResponseEntity<>(savedProduct, HttpStatus.OK);
}
Request/Response:
curl --location --request POST 'http://localhost:8080/products/' \
--header 'Content-Type: application/json' \
--data-raw '{
"name": "Apple iPhone 12",
"description": "Apple iPhone 12 Mini 64 GB, Black",
"price": 800
}'
//Returns
{
"id": "7e7e53ee-dc8b-4919-8316-844b310470ac",
"name": "Apple iPhone 12",
"description": "Apple iPhone 12 Mini 64 GB, Black",
"price": 800.0
}
GET Endpoint:
The GET
endpoints get previously saved product as:
@GetMapping("/products/{productId}")
public ResponseEntity<Product> getProduct(@PathVariable String productId) {
log.info("Fetching product {}", productId);
var productOptional = productRepository.getProduct(productId);
Product product = productOptional.orElseThrow(RecordNotFoundException::new);
return new ResponseEntity<>(product, HttpStatus.OK);
}
Request/Response:
curl --location --request GET 'http://localhost:8080/products/7e7e53ee-dc8b-4919-8316-844b310470ac'
//Returns
{
"id": "7e7e53ee-dc8b-4919-8316-844b310470ac",
"name": "Apple iPhone 12",
"description": "Apple iPhone 12 Mini 64 GB, Black",
"price": 800.0
}
Kubernetes Constructs
Before we start deploying an application on Kubernetes, we need to familiarize ourselves with some common Kubernetes constructs we are going to use.
POD
Pods are the smallest deployable computing unit that we can create and manage in Kubernetes. A Pod contains one or more containers, with shared storage and network resources and specifications about running containers. A typical microservices application contains multiple Pods, which exposes API endpoints to communicates with each other.
Let’s look at a typical Pod definition defined as manifest YAML.
apiVersion: v1
kind: Pod
metadata:
name: product-svc
labels:
app: product
type: backend
spec:
containers:
- name: product
imagePullPolicy: IfNotPresent
image: product:1.0
The Pod definition manifest can be broken down into four parts
- ApiVersion – the version of the Kubernetes API we are using
- Kind – the type of Kubernetes object we want to create
- Metadata – the metadata information about the object such as name and labels
- Spec – specification of Pod such as name, container image, etc.
ApiVersion, kind, and metadata are required fields that apply to all Kubernetes objects, not just pods.
We will see later how to run Pods in the Kubernetes cluster.
Container
A Pod encapsulates the container. You can’t run a Pod without defining a container.
So what is a container?
A container is a small and lightweight execution environment that makes shared use of the operating system kernel but otherwise runs in isolation from one another.
Docker is popular container technology. To run an application in Docker we first need to create an application image. This can be done using Dockerfile
. A Dockerfile
is a text file that contains the instructions to set up an environment for a Docker container. For our sample application, Dokcerfile
looks like
FROM openjdk:11-jre-slim
RUN mkdir /app
WORKDIR /app
ADD ./target/product-svc-1.0.0.jar /app/app.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "app.jar"]
- The
FROM
instruction defines the base image asopenjdk:11-jre-slim
. - The
RUN
instruction creates a new directory calledapp
. - The
ADD
instruction adds contents of the target directory to the/app
directory. - The
EXPOSE
instruction instructs Docker that the container listens to the specific port at the runtime. - The
ENTRYPOINT
instruction tells Docker which command to run at the startup.
For more information, you can check the official Dockerfile documentation.
To create a docker image, run the following instructions.
- Creating Spring Boot jar: run command
mvnw clean package spring-boot:repackage
fromproduct-svc
directory. This will createproduct-svc-1.0.0.jar
in/target
directory. To test if the application has been packaged successfully run the commandjava -jar target/product-svc-1.0.0.jar
from the terminal. You should see the logdev.techdozo.product.ProductApplication : Started ProductApplication in 2.643 seconds (JVM running for 3.238)
- Creating Docker Image: to create the docker image run the command
docker build . -t product:1.0
fromproduct-svc
directory. To validate if the image has been created successfully run commanddocker images ls
and you should a docker imageproduct
with tag1.0
. - Run Docker Container: Optionally if you want to validate if the image has been created and can be run successfully, run the command
docker run -p 8080:8080 product:1.0
. You should see the spring boot application starting up in the terminal.
If you are using kind then kind has no idea about your local registry. You need to tell kind to load image from the local registry as kind load docker-image product:1.0 product:1.0
Running Kubernetes Pod
Before you begin, you need to tell Kubernetes to use the correct context. The Kubernetes uses a YAML file called kubeconfig
which stores cluster authentication information for kubectl.
You can run command kubectl apply -f deployments/product-pod-definition.yaml
to create Pod. To check if Pod is created correctly run command kubectl get pods
and you see something like
NAME READY STATUS RESTARTS AGE
product-svc 1/1 Running 0 17m
You can check the log of the pod by using the command kubectl logs product-svc
. Once, you run the command you will see Spring boot log in the terminal.
Accessing Pod locally
You must be wondering, now we have our product service running in the local Kubernetes cluster, how can I start working with the application. You can use Kubernetes port forward to access our application locally. Run command kubectl port-forward product-svc 8080:8080
to forward the Product service port 8080
to localhost:8080
. Now you can access product service locally on http://localhost:8080/products/
.

This is obviously not a production-grade deployment and port forwarding is not recommended for production deployment but it’s a nice tool to debug Kubernetes applications locally.
Summary
In this article, we covered lots of ground by deploying a microservices-based application on local the Kubernetes cluster. We understood how we can create a Docker image using Dockerfile
. We also understood how to define a Pod using the Pod manifest file and deploy the Pod using kubectl
. Obviously, the steps mentioned here are not for production deployment (that’s for another article).
Discussion about this post