Skaffold
I’ve been playing with a lot of development work flow tools over the last few weeks. I was an early adopter of Docker and have always been passionate about reducing friction in the development process, especially locally. Quick performance wins for individual developers add up to substantial productivity improvements across a whole team. I’ve been interested in how these tools are evolving, as we expand beyond the basic tools Docker provided with containers. As an outcome of this exploration I’m going to write a few posts on these tools.
The posts:
Skaffold
Skaffold is Google’s contribution to Kubernetes’ local development. In their words:
Skaffold handles the workflow for building, pushing and deploying your application. So you can focus more on application development.
At its core, Skaffold provides fast, local development on a local or remote Kubernetes cluster. It automatically detects changes in your source code and rebuilds and redeploys your application upon change. It handles local logging, showing you the output from your application in a local development server. Skaffold supports multiple environments, each configurable with different requirements for different scenarios. Skaffold also integrates into your CI/CD pipeline, allowing you to run local builds and tests, before pushing changes into the next stage of the pipeline or sharing them with your peers. Interestingly, unlike some other tools in this space, it’s client-side only. Your Kubernetes cluster doesn’t require any configuration or a server component.
Let’s take a look at installing and running Skaffold now.
Installing Skaffold
We’re going to install on macOS but the documentation has installation instructions for Linux and Windows too. There are several prerequisites for Skaffold:
- Docker and a local Kubernetes cluster (you can also point Skaffold at an external cluster).
- A local
kubectl
binary.
Let’s get these sorted first.
Installing Kubernetes
First, we will need to install Docker and a local Kubernetes environment. One of the easiest ways to do this locally is to use Docker for Mac, which installs both. You could also install something like Minikube. Install one or the other and initiate a local Kubernetes cluster, either enabling it in Docker for Mac, or initiating and building a Minikube cluster.
Installing kubectl
We’ll also need the kubectl
binary, which is a CLI for Kubernetes. There’s documentation to install and configure it on several platforms but we’ll use the Homebrew recipe.
|
|
We can then test kubectl
is installed.
|
|
If you’ve set up Minikube or Docker for Mac already then it’ll have configured kubectl
to connect to your local cluster, otherwise you’ll need to configure it.
Installing Skaffold
Next, we need to install Skaffold itself. We can either download a binary for our preferred environment, or use a tool like Homebrew or Chocolatey. As we’re on MacOS, we’re going to again use Homebrew.
|
|
We can then test it is working like so:
|
|
Configuring applications for Skaffold
Let’s add Skaffold support to an application. We’re going to use a Skaffold example we’ve pre-built to take you through the process. You can find it on Github.
Let’s checkout our project.
|
|
Here we’ve checked out the project, changed into the resulting directory, and listed its contents. We have a README
for the project and the files for an application called mate
, including a Dockerfile
that builds the application. The mate
application is a Sinatra-based Ruby application.
We also have our Kubernetes configuration in a directory called k8s
, with a single file, k8s-pod.yaml
. This file defines the basics of a pod to run our mate
application. Let’s look at it first.
|
|
We’ve created a skeleton Kubernetes Pod configuration containing a single container, using the image jamtur01/skaffold-mate
. Skaffold will build this image if it doesn’t exist.
To enable Skaffold for our application we need to initialize it in our repository. We do this using the skaffold init
command.
|
|
The init
command writes a Skaffold configuration based on the Kubernetes’ Pod configuration we just saw. We type y
to write that configuration out to the file skaffold.yaml
.
Let’s look at the skaffold.yaml
file we’ve just generated.
|
|
We can see a Skaffold Config object. It has two elements: build
and deploy
. The build
element describes what Skaffold should build, in our case an image called skaffold-mate
. The deploy
element tell Skaffold to use kubectl
to deploy the Kubernetes Pod configuration contained in the k8s-pod.yaml
file.
We need to add some more configuration to the file to support port forwarding, so Skaffold knows which ports to forward for our application.
To do this we add another block, portForward
, to our skaffold.yaml
file.
|
|
Our new block tells Skaffold to forward port 3000
exposed on our mate
Pod to local port 3001
(if you specify a local port it’ll try to map the same port number or choose a random port).
If you have different configuration, for example you want to forward ports in a deployment or a service, you can also do that using this approach.
skaffold.yaml
file’s full definition in the Skaffold documentation.Deploying applications with Skaffold
Now Skaffold is configured for our mate
application we can use it to deploy the application in testing. Skaffold has two modes:
- Development mode - in which Skaffold monitors your source code for changes and then rebuilds and redeploys your application upon change.
- Deployment mode - in which Skaffold runs once, builds the relevant artifacts and then exits. This is useful to use in a CI/CD or code promotion context.
We’re going to use the development mode to test Skaffold right now. We initiate that via the skaffold dev
command.
|
|
We’ve run skaffold dev
with a single flag, --port-forward
, that enables port forwarding (which is otherwise off by default). We can see that Skaffold has built our Docker image and deployed a pod to Kubernetes. It’s mapped port 3000
on our pod to port 3001
on our local host. The final stage of our process, Skaffold has echoed the output of the application’s Sinatra server. It’s now watching our code for changes.
We can curl
the application’s endpoint on the mapped port to test it’s all working.
|
|
Developing with Skaffold
Now we have the application deployed, let’s add another endpoint to the mate
application in the mate.rb
file.
|
|
After we save the file, we’ll see Skaffold kick off the rebuild process in the window running our skaffold dev
process.
|
|
And our application will be redeployed and we can curl
our new endpoint.
|
|
We’ve now got a development life cycle running inside Skaffold!
Summary
I hope this was useful as a walk through. This just scratches the surface of Skaffold’s capabilities. It’s capable of integrating with a large number of potential Builders for your Docker images. You can also integrate local tests into your rebuild process, using container structure testing, to ensure the consistency of your build. Additionally, Skaffold allows you to build these features with profiles, to allow different builders, test approaches, or deployment processes for different environments. You can explore features and other uses cases in the documentation.