In Part 2 we took the docker container for a basic Spring Boot application and ran it in a kubernetes Pod. In this post we explore the next level in kubernetes concept: Deployments. At a high level, Deployments allow declarative updates to Pods by expressing desired state. In this guide we create a kubernetes Deployment for a Spring Boot Application, inspect the definition for the Deployment, and update the deployment.

Environment Setup

In this guide I won’t focus too much on getting your local environment setup because there are already so many helpful resources out there. During this series, I use docker desktop with kubernetes support enabled. I’ve found it to be the easiest way to get started with kubernetes quickly on a local machine. Here are a few helpful links to get your local environment configured:

Deployments

Previously, when working with Pods we were creating and managing a kubernetes resource directly. With Deployments, we create a kubernetes controller that manages other resources - in this case Pods. This is accomplished by expressing the desired state of the application. By state, think of concepts like:

  • There should be a certain number of instances of an Application
  • The Application should be restarted if it fails a certain condition
  • Scale the number of instances of the Application based on certain conditions

Not only can we express the desired state, it can be updated through rolling out updates to Deployments. Read more about Deployments here.

Creating a Deployment

The quickest way to create a deployment is using kubectl, for the demo Application we’ve been building we can do this with the following command:

kubectl create deployment springboot-demo --image-docker.io/library/springbooktk8s:0.0.1-SNAPSHOT --save-config

To check the status of the deployment run:

kubectl get deployments

And we should see output similar to:

NAME              READY   UP-TO-DATE   AVAILABLE   AGE
springboot-demo   1/1     1            1           4s

For this deployment the only options specified were the name and the image to use for the underlying Pods. Because of this, there is only be a single Pod created to run the image. This can be checked with kubectl get pods to see an output similar to this:

NAME                               READY   STATUS    RESTARTS   AGE
springboot-demo-5797d86dfb-w8lw9   1/1     Running   0          7s

Like last time, we can take a look at the Deployment definition using the --dry-run=client option and output to yaml using:

kubectl create deployment springboot-demo --image-docker.io/library/springbooktk8s:0.0.1-SNAPSHOT  --save-config --dry-run=client -o yaml

And this outputs the following yaml:

# kubernetes/original-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  creationTimestamp: null
  labels:
    app: springboot-demo
  name: springboot-demo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: springboot-demo
  strategy: {}
  template:
    metadata:
      creationTimestamp: null
      labels:
        app: springboot-demo
    spec:
      containers:
        - image: docker.io/library/springbooktk8s:0.0.1-SNAPSHOT
          name: springbooktk8s
          resources: {}
status: {}

There’s a few things to note in this yaml.

  • This yaml could be used to create the Deployment to using kubectl apply -f deployment.yaml
  • spec.template.spec.containers should appear similar to the Pod definition we saw in the last time because this is defining the Deployment’s template for Pods.
  • spec.replicas indicates how many Pod replicas of the Application matched by spec.selector.matchLabels to run. This matches the spec.template.metadata.labels variable for the Pod definition.

Updating a Deployment

Previously when working directly with Pods, the configuration could not be updated directly. The Pods would need to be deleted and recreated in order to update their configuration in anyway (such as changing underlying container image). Deployments do not have this restriction. To demonstrate how to update the deployment created earlier, we add a container port to the Pod template of the Deployment:

# kubernetes/deployment.yaml
spec:
  containers:
    - image: docker.io/library/springbooktk8s:0.0.1-SNAPSHOT
      name: springbooktk8s
      ports:
        - containerPort: 8080
      resources: {}

And then apply the change:

kubectl apply -f deployment.yaml --record

If we check the status of the Pods during the update with kubectl get pods, then the output shows the Pod without a container port terminating and a new Pod is running:

NAME                               READY   STATUS        RESTARTS   AGE
springboot-demo-5797d86dfb-sdjqh   1/1     Terminating   0          2m33s
springboot-demo-7b9646b797-pm4d5   1/1     Running       0          8s

In the case that we wanted to undo this change, we could undo the deployment with the following command:

kubectl rollout undo deployment springboot-demo

Conclusion

In this post, we created and updated a kubernetes Deployment for a small Spring Boot Application. In later posts we look into how this Deployment could be configured further with useful features such as liveness and readiness probes or scaling. As usual, the source code over can be found on github. Thanks for reading!