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.
These posts are explorations of each solution, not comparisons or a pros and cons analysis. I think everyone’s development platform and experience is sufficiently different that they should explore solutions and identify which works for them. Additionally, in many cases, these solutions might not fit at all and something like Docker Compose might address your needs.
Tilt manages local development instances for teams that deploy to Kubernetes.
Tilt focuses on being easy to setup and deploy. Tilt is designed to be configured and shipped with your source code, allowing a team to work on a consistent and shareable development environment.
Like many of other tools, it has a file system watcher that identifies changes you’ve made to your code and rebuilds and redeploys your application.
Tilt also has a console and web UI that allows you to see the state of your local application.
Let’s take a look at installing Tilt and configuring a service.
Installing Tilt 🔗︎
We’re going to install on macOS but the documentation has installation instructions for Linux and Windows too. We will need to install Docker and a local Kubernetes environment (you could also use an external Kubernetes cluster). 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.
Then we can install Tilt itself via Homebrew. Tilt has its own tap you can add and a recipe called
$ brew tap windmilleng/tap $ brew install windmilleng/tap/tilt
You can later upgrade Tilt with
brew update; brew upgrade tilt.
We can now confirm Tilt is working.
$ tilt version v0.10.4, built 2019-08-14
Now let’s add Tilt to a service we’re building.
Configuring Tilt 🔗︎
We’re going to use a Tilt example we’ve pre-built to take you through the process. You can find it on Github.
Let’s checkout our project.
$ git clone firstname.lastname@example.org:jamtur01/tilt-example.git $ cd tilt-example $ ls README.md Tiltfile k8s-pod.yaml mate
Here we’ve checked out the project, changed into the resulting directory, and listed its contents. We have a
README for the project, the files for an application in a directory called
mate, including a
Dockerfile that builds the application. The
mate application is a Sinatra-based Ruby application. We have a Kubernetes configuration for a pod to run our application. Finally, we have a
Tiltfile that contains the definition for our application.
Our Kubernetes configuration is in a file called
k8s-pod.yaml. This file defines the basics of a pod to run our
mate application. Let’s look at it first.
--- apiVersion: v1 kind: Pod metadata: name: mate labels: app: service spec: containers: - name: mate image: jamtur01/tilt-mate ports: - containerPort: 3000
We’ve created a Kubernetes Pod configuration containing a single container, using the image
jamtur01/tilt-mate. We’ve also mapped port 3000 inside the pod to port 3000 on the local host. Tilt will build this image if it doesn’t exist as part of the deploy process.
Tilefile is Tilt’s definition of the application. It tells Tilt how to build and deploy the application. The file is written in Skylark, a language developed for the Bazel build system. Because of the language the
Tiltfile is technically a program and can contain functions, arrays, and loops. Let’s take a look at the file now.
k8s_yaml('k8s-pod.yaml') docker_build('jamtur01/tilt-mate', 'mate') k8s_resource('mate', port_forwards=3000)
Our file is broken into functions. The first,
k8s_yaml, defines the location of a Kubernetes configuration file. You can also specify multiple files, in an array:
Or by specifying multiple functions.
Or make calls to external programs, like Helm.
The next function,
docker_build, tells Tilt what to build using Docker. The function:
Is the equivalent of running:
docker build -t jamtur01/tilt-mate ./mate
And building the application it finds in the
mate directory, using the
Dockerfile in that directory, into an image called
jamtur01/tilt-mate. You can also provide build arguments or specify a particular
Dockerfile, for example one specific to a development build.
k8s_resource function, allows you to work with any Kubernetes resources you define in your
Tiltfile, for example the pod we’ve defined in our
k8s-pod.yaml file will become a resource inside Tilt. At this point you can only perform two operations on resources: name them and forward ports. Our specific function maps port
3000 inside the
mate pod to port
3000 on the local host.
read_file functions that allows you to run external commands and return their output to Tilt and trigger file accesses. This allows you to integrate Tilt with existing, external tools like configuration management or service discovery tools.
Now let’s see Tilt in action.
Running Tilt 🔗︎
Now we’ve configured an application with Tilt. We can run it using the
tilt up command.
$ tilt up
We can see Tilt has launched a CLI-based console, build our Docker image, and deployed our pod.
Ignore the error there - something seems wrong with Tilt’s JSON to YAML conversion. The file above is valid YAML but for some reason Tilt don’t like it.
We can see in the box at the bottom of the console our service’s logs showing Sinatra has launched and that our application is awaiting requests. Let’s quickly test it now.
$ curl localhost:3000/mate Mate!
You’ll also see that a web-based version of this console has launched.
Let’s add an endpoint to our application and see what happens. If we flip back to the Tilt console on the command line we can see our image being rebuilt and deployed again.
And we can test our new endpoint when it’s complete.
$ curl localhost:3000/folks Folks!
And that’s the basics of developing with Tilt!
I hope this was useful as a walk through. This just the basics of Tilt. You can find a lot more examples and tutorials in the Tilt documentation, including integration with CI/CD pipelines. There’s a specific tutorial for Bazel but it’s adaptable for other tools. There are also some good posts on the Tilt blog about making use of Tilt for different scenarios.