Kubernetes Rolling Updates from Java with Fabric8 Kubernetes Client 7
Introduction
In the world of cloud-native applications, it's essential to keep your services up-to-date and running smoothly. Users demand 24/7 availability, and downtime can lead to lost revenue and dissatisfied customers. At the same time, developers face increasing pressure to deliver new features and bug fixes quickly.
Kubernetes provides a powerful feature called Rolling Updates that allows you to update your applications without downtime. By gradually replacing the old version of your application with the new one, Kubernetes ensures your services remain available throughout the update process.
In this post, I'll show you how to perform a Kubernetes Rolling Update from Java using the Fabric8 Kubernetes Client version 7.
How do Rolling Updates work?
In Kubernetes, Deployments are the most common way to deploy application workloads. A Deployment specifies the desired state of your application, including the number of replicas, container images, and configuration settings. Kubernetes, being a declarative system, works to ensure the actual state matches the desired state.
When you create or update a Deployment, Kubernetes creates a new ReplicaSet to manage the updated version of your application. The ReplicaSet ensures that the desired number of replicas (Pods) are running and healthy.
During a Rolling Update, Kubernetes will create a new ReplicaSet with the updated version of your application and gradually scale up the new ReplicaSet while scaling down the old one. Kubernetes waits for the new Pods to become healthy before terminating the old ones, ensuring minimal disruption.
If something goes wrong during the update, Kubernetes allows you to roll back to a previous version. In this case, the process is reversed: the old ReplicaSet is scaled up while the new one is scaled down.
How to perform a Rolling Update from Java
Now, let’s see how to perform Kubernetes Rolling Updates programmatically using the Fabric8 Kubernetes Client version 7.
For demonstration, we’ll use Nginx as our example application. Let's start by deploying it to the cluster.
Deploying the Nginx application
First, we create a Deployment
for the nginx
application.
We can easily use the Fabric8 Kubernetes Client and its DSL to create and apply the Deployment
to the cluster.
The following snippet demonstrates how:
import io.fabric8.kubernetes.api.model.PodSpecBuilder;
import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder;
import io.fabric8.kubernetes.api.model.apps.DeploymentSpecBuilder;
import io.fabric8.kubernetes.client.KubernetesClientBuilder;
public class DeployNginx {
public static void main(String[] args) {
try (var client = new KubernetesClientBuilder().build()) {
var nginx = new DeploymentBuilder()
.withNewMetadata().withName("nginx").endMetadata()
.withSpec(new DeploymentSpecBuilder()
.withReplicas(1)
.withNewSelector().addToMatchLabels("app", "nginx").endSelector()
.withNewTemplate()
.withNewMetadata().addToLabels("app", "nginx").endMetadata()
.withSpec(new PodSpecBuilder()
.addNewContainer()
.withName("nginx")
.withImage("nginx:1.26")
.addNewPort().withContainerPort(80).endPort()
.endContainer()
.build())
.endTemplate()
.build())
.build();
client.apps().deployments().inNamespace("default").resource(nginx).serverSideApply();
}
}
}
This code creates a new Deployment
for the nginx application with a single replica.
The Deployment
uses the nginx image nginx:1.26
and exposes port 80
.
It then uses the serverSideApply()
method to apply the new Deployment
to the cluster.
Updating the nginx version application
Now that we have deployed the nginx application, let's update it to a new version.
We can easily update the Deployment
using the Fabric8 Kubernetes Client and its DSL.
import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder;
import io.fabric8.kubernetes.client.KubernetesClientBuilder;
public class UpdateNginx {
public static void main(String[] args) {
try (var client = new KubernetesClientBuilder().build()) {
client.apps().deployments().inNamespace("default").withName("nginx")
.edit(nginx -> new DeploymentBuilder(nginx)
.editSpec().editTemplate().editSpec().editContainer(0)
.withImage("nginx:1.27")
.endContainer().endSpec().endTemplate().endSpec()
.build());
}
}
}
In this example, we update the nginx application to version 1.27
by changing the container image in the Deployment
.
For this purpose, we use the edit()
method to modify the Deployment
in place and apply the changes to the cluster.
Note how the existing deployment is passed to the DeploymentBuilder
constructor to modify it in place and preserving the rest of the configuration.
Rolling back the nginx application
If something goes wrong during the update process, we can easily roll back to the previous version of the nginx application.
The following snippet shows you how to roll back the nginx application to version 1.26
:
import io.fabric8.kubernetes.client.KubernetesClientBuilder;
public class RollbackNginx {
public static void main(String[] args) {
try (var client = new KubernetesClientBuilder().build()) {
client.apps().deployments().inNamespace("default").withName("nginx")
.rolling().undo();
}
}
}
In this example, we use the rolling().undo()
method to roll back the nginx application to the previous version.
Kubernetes will automatically scale up the old ReplicaSet while scaling down the new ReplicaSet.
Pausing and Resuming the Rolling Update
Kubernetes provides the means to pause rollouts to prevent further changes to the Deployment's ReplicaSet. This can be useful in case you want to apply multiple fixes between a pause and resume without triggering rollouts in between.
The following snippet shows you how to pause rolling updates for the nginx application:
import io.fabric8.kubernetes.client.KubernetesClientBuilder;
public class PauseNginx {
public static void main(String[] args) {
try (var client = new KubernetesClientBuilder().build()) {
client.apps().deployments().inNamespace("default").withName("nginx")
.rolling().pause();
}
}
}
In this example, we use the rolling().pause()
method to pause the rolling updates for the nginx application.
Whatever changes we apply to the Deployment will not trigger a rollout until we resume the rolling updates.
The following snippet shows you how to resume rolling updates for the nginx application:
import io.fabric8.kubernetes.client.KubernetesClientBuilder;
public class ResumeNginx {
public static void main(String[] args) {
try (var client = new KubernetesClientBuilder().build()) {
client.apps().deployments().inNamespace("default").withName("nginx")
.rolling().resume();
}
}
}
In this example, we use the rolling().resume()
method to resume the rolling updates for the nginx application.
Conclusion
Kubernetes provides a powerful feature called Rolling Updates that allows you to update your application without downtime. Leveraging the Fabric8 Kubernetes Client, you can easily perform Rolling Updates from Java, ensuring your services remain available during the update process.
In this post, we've seen how to deploy an application, update its version, roll back to a previous version, and pause and resume the Rolling Update process. The Fabric8 Kubernetes Client provides a simple and intuitive API to interact with Kubernetes resources, making it easy to manage your applications from Java.