Hello! Welcome to our next lesson on containerization with Kubernetes.
In our last session, we built a solid theoretical foundation by exploring the four essential Kubernetes objects: Pods, ReplicaSets, Deployments, and Services. We learned that you declare a desired state using a Deployment, and Kubernetes works tirelessly to maintain it, providing self-healing and scalability.
Today, we'll put that theory into practice. Your learning outcome is to deploy a Spring Boot application to Kubernetes using a Deployment manifest. We will translate our application requirements into a declarative YAML file that Kubernetes can understand and execute. This is a fundamental, hands-on skill you'll be expected to demonstrate in any senior engineering role involving microservices.
1. The Anatomy of a Deployment Manifest
A Kubernetes manifest is a YAML file that describes a resource. For a Deployment, this file is our contract with the cluster, detailing exactly how our Spring Boot application should run.
Every Kubernetes resource manifest has four top-level fields:
apiVersion: Specifies the Kubernetes API version to use for this object. For Deployments, this is typicallyapps/v1.kind: The type of resource we are creating. In this case,Deployment.metadata: Data that helps uniquely identify the object, such as itsname.spec: The most important field. This is where you declare the desired state for the resource—how many replicas, which container image to use, what configuration to apply, and more.
Kubernetes YAML File Explained - Deployment and Service | Kubernetes Tutorial 19
To start, let's watch a short, clear explanation of this fundamental structure from the 'Kubernetes YAML File Explained' video by TechWorld with Nana.
Watch from 00:32 to 03:30. Pay close attention to the distinction between the 'spec' (your desired state) and the 'status' (the actual state, managed by Kubernetes).
Now, let's look at a visual breakdown of a simple Deployment manifest. While this example uses Nginx, the structure is identical for any application, including our Spring Boot service.
2. Crafting the Deployment spec
The spec section is where the real work happens. It tells the Deployment controller how to manage your application's Pods. Let's focus on the most critical fields within spec.
The article 'Developing and deploying Spring Boot microservices on Kubernetes' from LearnKube provides an excellent, detailed walkthrough of a Deployment manifest for a Java application. We'll use this as our primary reference.
Read the section titled 'Defining a Deployment'. Focus on understanding the purpose of replicas, selector, and the nested template fields. You don't need to create the files yourself yet; just absorb the concepts.
As you just read, the spec contains three key parts:
-
replicas: A simple integer that defines how many identical copies (Pods) of your application you want running. This is the foundation for both high availability and scaling. -
selector: This tells the Deployment which Pods it is responsible for managing. It uses labels to make this connection. ThematchLabelsfield must correspond to the labels defined in the Pod template. This is the glue that binds the Deployment to its Pods. -
template: This is a blueprint for the Pods that the Deployment will create. It has its ownmetadata(where we define the Pod's labels) andspec. The Podspecis where we define the containers that will run inside it.
The Container Specification
Inside spec.template.spec, the containers array is where you define your Spring Boot application container. This is the most critical part for a developer.
Here's an example deployment.yaml for a typical Spring Boot application:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-springboot-app-deployment
spec:
replicas: 2 # We want 2 running instances of our app
selector:
matchLabels:
app: my-springboot-app
template:
metadata:
labels:
app: my-springboot-app # Pods get this label, matching the selector
spec:
containers:
- name: springboot-app-container
image: your-dockerhub-username/my-app:1.0.0 # The image we built previously
imagePullPolicy: Always
ports:
- containerPort: 8080 # The port our Spring Boot app listens on
env:
- name: SPRING_PROFILES_ACTIVE
value: "kubernetes"
- name: DATABASE_URL
value: "jdbc:postgresql://db-service:5432/mydatabase"
Let's break down the containers section:
name: A name for the container within the Pod.image: This is the full name of the Docker image you pushed to a container registry (like Docker Hub) in our previous lessons.ports: An array specifying which ports the container exposes.containerPort: 8080tells Kubernetes that our application inside the container is listening on port 8080. This does not expose the port outside the Pod; aServiceis required for that.env: This is how you pass configuration to your application. It's an array of name-value pairs that are injected as environment variables. This is the standard way to provide profile-specific properties, database connection strings, or other external configurations to a Spring Boot application running in Kubernetes.
3. Deploying the Application
Once your deployment.yaml file is ready, you can submit it to the Kubernetes cluster using the kubectl command-line tool.
The command is straightforward:
kubectl apply -f deployment.yaml
Kubernetes will now read your manifest and work to achieve the desired state:
- The Deployment controller will create a ReplicaSet.
- The ReplicaSet controller will create 2 Pods (based on
replicas: 2). - The Kubernetes scheduler will find suitable nodes for these Pods.
- The Kubelet on each node will pull the specified Docker image (
your-dockerhub-username/my-app:1.0.0) and start the container.
You can watch this happen with a few simple commands:
kubectl get deployments: Check the status of the Deployment itself.kubectl get pods: See the Pods being created. Their status will transition fromPendingtoContainerCreatingtoRunning.kubectl describe deployment my-springboot-app-deployment: Get detailed information and a log of events for the deployment, which is incredibly useful for debugging.
Deploy Springboot Microservices to Kubernetes Cluster | Full Example
To see this entire process in action with a Spring Boot application, let's watch a segment from the 'Deploy Springboot Microservices to Kubernetes Cluster' video. The example is more complex, but focus on the core process of creating the YAML and applying it.
Watch the following two segments: 27:37 - 31:36: Here, the presenter creates a user-service.yml file. Observe how he defines the Deployment and its container spec. He also defines a Service, which we will cover in the next lesson. 44:22 - 47:34: Watch as he applies all the configuration files using kubectl apply -f . and then verifies the created resources with kubectl get all.
Test your understanding! (Interview Question)
You've just run kubectl apply -f my-app-deployment.yaml to deploy a new version of your application. However, when you run kubectl get pods, you see that the new Pods are stuck in the ImagePullBackOff or ErrImagePull state. What are the most likely causes of this issue, and how would you investigate?
Show answer
This is a very common real-world problem and a frequent interview question. The ImagePullBackOff status means that Kubernetes tried to pull the container image but failed.
Likely Causes:
- Incorrect Image Name or Tag: You may have a typo in the
image:field in yourdeployment.yaml. The repository name, image name, or tag might not exist. - Private Repository without Credentials: If the image is in a private registry (like a private Docker Hub repo or a company's internal registry), Kubernetes needs credentials to access it. By default, it can only pull from public repositories.
- Network Issues: The Kubernetes node might not have network access to the container registry.
Investigation Steps:
- Describe the Pod: This is the most crucial first step. Run
kubectl describe pod <pod-name>, replacing<pod-name>with the name of a failing pod. Look at theEventssection at the bottom. It will contain a detailed error message, such as "image not found" or "authentication required." - Check the Deployment Manifest: Carefully review the
image:field in yourdeployment.yamlfor any typos. - Manual Image Pull: Try to SSH into one of the Kubernetes nodes (if possible) and manually run
docker pull <image-name>:<tag>. This will confirm if the issue is with the image name or network connectivity from the node. - Verify Secrets: If the repository is private, ensure you have created a
docker-registrySecret in Kubernetes and referenced it in your Deployment's Pod template using theimagePullSecretsfield.
This question tests your practical debugging skills within the Kubernetes ecosystem. The kubectl describe command is your best friend for troubleshooting Pod startup issues. (This scenario is adapted from the "Kubernetes Deployment fails after an upgrade" question in the DataCamp resource.)
Conclusion
Congratulations! You have now learned how to take a containerized Spring Boot application and define its deployment for a Kubernetes cluster. This process turns your static Docker image into a living, managed application.
Key Takeaways:
- A Deployment manifest is a YAML file that declaratively defines how your application should run on Kubernetes.
- The
spec.templatesection is the Pod blueprint, where you specify the containerimage,ports, and crucialenvvariables for configuration. - Labels and selectors are the mechanism that connects the Deployment to the Pods it manages.
- The command
kubectl apply -f <filename>is used to submit your manifest to the cluster. kubectl getandkubectl describeare your essential tools for verifying and debugging your deployment.
Preview of the Next Lesson:
Our application is now running in the cluster, but it's isolated and unreachable. In the next lesson, "Expose a Kubernetes Deployment to internal and external traffic using a Service," we will write a Service manifest. This will create a stable network endpoint, allowing other microservices within the cluster and users from the internet to communicate with our newly deployed Spring Boot application.