Automating rolling updates for zero-downtime deployments
TypeScriptRolling updates are a strategy for updating the software on your servers with zero downtime. This is accomplished by incrementally updating servers with a new version of the software and slowly rolling this change out across your fleet of servers. By using a managed rolling update strategy, you can achieve zero downtime because only a subset of servers is taken down at any given time. The overall goal is to update your application without interrupting the user experience.
To demonstrate rolling updates with Pulumi, I will walk you through a Pulumi program that uses a Kubernetes
Deployment
object to manage the desired state of a set of replicas of a given application container. By defining thestrategy
field in the Deployment specification, Kubernetes will handle rolling updates to the application. ThemaxUnavailable
field specifies the maximum number of Pods that can be unavailable during the update process, and themaxSurge
field specifies the maximum number of additional Pods that can be created above the desired number of Pods.Here's a TypeScript Pulumi program that defines a Kubernetes Deployment with a RollingUpdate strategy:
import * as k8s from "@pulumi/kubernetes"; // A new Kubernetes namespace for our example const ns = new k8s.core.v1.Namespace("app-ns", { metadata: { name: "example-ns" } }); // The application container image const appImage = "nginx:1.19.3"; // For example purposes, we'll use nginx // Define the Kubernetes Deployment const appDeployment = new k8s.apps.v1.Deployment("app-deployment", { metadata: { namespace: ns.metadata.name, }, spec: { replicas: 3, // Amount of desired replicas selector: { matchLabels: { app: "nginx" } }, template: { metadata: { labels: { app: "nginx" } }, spec: { containers: [{ name: "nginx", image: appImage }] } }, strategy: { type: "RollingUpdate", rollingUpdate: { // During an update, the max number of pods that can be unavailable maxUnavailable: 1, // The max number of new pods that can be added above the desired number of pods maxSurge: 1 } } }, }, {dependsOn: ns}); // Export the Deployment name export const deploymentName = appDeployment.metadata.name;
In the program above, we first import the necessary Pulumi Kubernetes SDK. We create a namespace where our application will reside. It's good practice to namespace your Kubernetes applications, as it provides a unique scope for names and provides a mechanism to attach authorization and policy to a subsection of your cluster.
We then define the deployment for our application. In this case, it's a simple nginx server, but this would be replaced with your application's image in a real scenario. We define the
strategy
for updating the pods to be of typeRollingUpdate
withmaxUnavailable
andmaxSurge
options. These options control the rolling update behavior.Finally, we export the deployment name, which you can use with other Pulumi programs or connect to other app resources in the same stack.
This program would be applied by running
pulumi up
, and Kubernetes would then ensure that the rolling update strategy defined is followed when the deployment’s pod template is modified (e.g., when you change the container image).Remember, for this example to work, you need to have
- Pulumi CLI installed and configured.
- Access to a Kubernetes cluster (where you have permissions to create resources).
- Your Pulumi stack configured for the appropriate Kubernetes cluster.
By changing the
appImage
to a new version and runningpulumi up
, you would see a rolling update in action. Pulumi will show you the planned changes before they are applied, and you can confirm them to initiate the rolling update.You can also observe the progress directly via Kubernetes tooling, like
kubectl rollout status deployment/app-deployment
which will give you live feedback on the rolling update process.