Kubernetes: Create, Update, and Destroy
This tutorial shows you how to use Pulumi to write and manage a Kubernetes application through it’s lifecycle. We will use the Pulumi Kubernetes TypeScript SDK to write the Kubernetes applications, and the Pulumi CLI to create, update, and destroy resources on the Kubernetes cluster.
Along the way, we will get a taste for several of Pulumi’s features for visualizing and understanding how an update will impact the application running in the cluster.
For example, in the gif below, we can see how updating one resource (in this case, a ConfigMap
) “ripples through” the rest of the application, causing other resources to be updated, as well.
Topics:
- Prerequisites
- Provisioning a Kubernetes application
- Using Pulumi’s notion of “stack outputs”
- Using Pulumi’s diff facilities to understand how a change affects an application
- Updating an application
Prerequisites
IMPORTANT: This tutorial expects that you have provisioned a Kubernetes cluster and have an active kubeconfig file.
- Install Node.js.
- Install a package manager for Node.js, such as npm or Yarn.
- Install the Pulumi CLI.
Provisioning a Kubernetes application
We’re going to provision one of Pulumi’s example applications. We’ll dig into the code when we modify it later.
This application will:
- Create a container running nginx (an open source web server).
- Create a
ConfigMap
with an configuration file that configures nginx to proxy traffic topulumi.github.io
. - Mount that configuration data into the nginx container.
- Expose the nginx container to the internet using a
Service
.
To provision the application, we need to:
Run
pulumi new
.$ mkdir test-pulumi && cd test-pulumi # Clones the application into the current directory, and begins provisioning it in the active # context of your kubeconfig file. $ pulumi new https://github.com/pulumi/examples/tree/master/kubernetes-ts-configmap-rollout
Answer the questions prompted by
pulumi new
. This will bring up a CLI prompt that looks like the following, asking you questions to get you started. It is ok to accept default values for all questions exceptisMinikube
, where it is important to answerfalse
.IMPORTANT: If you are using minikube, Docker for Mac, or any other compute provider that can’t allocate a load balancer, you can answer
true
, but you won’t be able to bring up the service in your browser without using something likekubectl port-forward
.Accept the update. After all the questions are answered, you should see a prompt like the following, asking if you’d like to proceed with the update. You can opt to view the diff, if you like, but we’ll also do this later when we update the application.
Resources: + 4 to create Do you want to perform this update? yes > no details
Once all this is complete, Pulumi will begin provisioning the application. It should look something like the following gif, though it will be slightly different, depending on the name you’ve given your stack.
There are several things to notice here:
Resources are provisioned in a specific order. We can see from the output that the
ConfigMap
is provisioned first, theDeployment
second, and theService
third.As we will see in the following sections, Pulumi keeps track of resources as a graph. We will also see that this allows Pulumi to tell us how a change to one resource will affect other resources.
We get intermediate status updates as resources provision. As the
Service
rolls out, for example, we can see distinct stages in the initialization.
These two things will be important in the next sections.
Using Pulumi’s notion of “stack outputs”
It’s worth noting briefly that Pulumi provides convenient tooling for “exporting” values of initialized resources.
This application exports frontendIp
, which is the IP address of the load balancer that the
underlying compute provider provisioned when you started the service. You can view it with the following command:
$ pulumi stack output frontendIp
35.247.60.31
If you paste this IP into your browser, you should see that it’s redirected you to the Pulumi homepage. Alternatively, you can run this:
$ curl -sL $(pulumi stack output frontendIp):80 | grep -C 1 "<title>"
<title>Pulumi. Serverless // Containers // Infrastructure // Cloud // DevOps</title>
Using Pulumi’s diff facilities to understand how a change affects an application
In this section, we’ll re-configure nginx to point at google.com by changing the data in the
ConfigMap
.
This is one of the “gotchas” of Kubernetes – by default kubectl
will not trigger a rollout among
the containers that reference a ConfigMap
when its data will change. Instead, the kubelet silently, transparently syncs the data to the containers after the TTL expires.
In this section, we will see that Pulumi plans a safe update of the ConfigMap
. It will:
- Create a new
ConfigMap
with a new name and the new data. - Update the
PodTemplate
of theDeployment
to point at the newConfigMap
. This update triggers theDeployment
controller to try to roll out a new set of containers with mounts that contain this new data. - Only once that succeeds, delete the old
ConfigMap
.
Here are the steps to make this change:
Find the configuration data we need to change. In index.ts we can see the definition of the
ConfigMap
:// nginx Configuration data to proxy traffic to `pulumi.github.io`. Read from // `default.conf` file. const nginxConfig = new k8s.core.v1.ConfigMap(appName, { metadata: { labels: appLabels }, data: { "default.conf": fs.readFileSync("default.conf").toString() }, });
This indicates that the
ConfigMap
is reading thedefault.conf
file usingfs.readFileSync
.Change the configuration file. If you’re on macOS, you can run:
$ sed -i bak "s/pulumi.github.io/google.com/g" default.conf
If you’re running a platform that does not support
sed
, paste the following into yourdefault.conf
file:upstream node { server google.com; } server { listen 80; server_name _; root /usr/share/nginx/html; location / { proxy_set_header X-Real-IP \$remote_addr; proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for; proxy_set_header Host google.com; proxy_pass http://node; proxy_redirect off; port_in_redirect off; } }
Get a high-level view of the changes with
pulumi preview
. It should look something like the picture below. As we mentioned before, we can see that Pulumi plans to explicitly trigger a rollout in theDeployment
by replacing theConfigMap
. This is in contrast tokubectl
, which will silently sync the new version of the file to the containers.Get a more detailed view of the changes with
pulumi preview --diff
.. It will look conceptually something like the following gif (though this gif is a different app).
Updating an application
Once we’re confident this is what we want, we can run the update:
Run
pulumi up
.$ pulumi up
The output should look something like this.
Verify the rollout worked. You can do this by pasting the URL into the browser (be sure to disable the cache), or by running the following:
$ curl -sL $(pulumi stack output frontendIp) | grep -o "<title>Google</title>" <title>Google</title>
Destroying an application
Once we’re done with the application, it’s possible to destroy it using:
$ pulumi destroy