Draft
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:
Draft
Draft is developed by Microsoft and:
makes it easy to build applications that run on Kubernetes. Draft targets the “inner loop” of a developer’s workflow: as they hack on code, but before code is committed to version control.
Draft is designed to handle local development, allowing a developer to make changes, test, and resolve issues, before committing your code and letting your CI/CD pipeline take over for deployment. To help reduce the friction of this deployment, Draft produces Helm-compatible artifacts.
Draft has a couple of neat features, the first is automatically detecting and bootstrapping your application. IT can peek at your code and help you generate the right configuration and Helm charts files to run your application in Kubernetes. This includes generating Dockerfile
’s and Kubernetes configuration files.
The second feature is at the heart of several of these products, the ability to do quickly re-deploy your applications when they change. Draft doesn’t quite automatically deploy changes. Rather, the approach is to rely on your IDE, there’s an integration for VS Code and KUbernetes that provides this capability.
You can read more about Draft’s architecture and what it is, and is not, in their design documentation.
So let’s get started by installing Draft locally and running it.
Installing Draft
We’re going to install on macOS but the documentation has installation instructions for Linux and Windows too. There are several prerequisites for Draft:
- Docker and a local Kubernetes cluster (you can also point Draft at an external cluster).
- A working Helm installation on the 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 Helm
We then need to install Helm, a package manager for Kubernetes, that is used to install packages, called charts, on Kubernetes clusters. We first install a local helm
binary. We’re going to use Homebrew for this but installation is also available for other platforms.
|
|
Then we need to initiate Helm on our cluster.
|
|
This will install Tiller, Helm’s server component, onto our Kubernetes 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 Draft
Next, we need to install Draft 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:
|
|
Configure Draft
After we’ve installed Draft, we need to configure it. We do this with the draft init
command.
|
|
We can see we’ve downloaded some packs. Packs are what informs Draft about the configuration of applications written in various programming languages. Using packs, Draft knows how to build Dockerfile
’s, Helm charts, including Kubernetes manifests, to build and deploy applications written in languages like Ruby, Python, Java, and Go, etc. Packs are extensible too, so if you have a language that isn’t supported, or a tweak or adjustment specific to your environment or implementation you can modify packs to suit.
We can also see Draft has configured its home directory in ~/.draft
.
We’re now ready to deploy an application with Draft.
Deploying applications with Draft
Let’s test how well Draft can recognize an application. We’re going to use a Draft 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 a directory called mate
, that contains a service we’re going to test with Draft. The mate
service is a Sinatra-based Ruby application.
Configuring the mate service
Let’s see if Draft can recognize and deploy the mate
service. We change into the mate
directory which contains our Ruby application.
|
|
And then run draft create
to see if Draft can identify and build a scaffold for our application.
|
|
Woot! Looks like it correctly identified our application as Ruby-based. Let’s see what it did.
|
|
We can see it created a Dockerfile
, a directory called charts
, and a file called draft.toml
. The Dockerfile
will help us build our Ruby-based image, the charts
directory contains a Helm chart that Draft has created for our application, and the draft.toml
contains Draft’s defintion of our application. Let’s start by looking at the Dockerfile
.
|
|
Hmmmm… Looks pretty good. Almost correct, our application is called mate.rb
and not app.rb
but we can edit that to reflect our environment. Let’s look into the draft.toml
file.
|
|
The drafts.toml
file contains our application’s definition. It uses TOML and contains blocks of environments. Environments allow you to specify different running conditions for different purposes, for example how you configure your development environment might differ from how you create a test or staging environment. You can specify what environment Draft should deploy at runtime.
We can see we’ve only got one environment defined: environments.development
. It defines the name of our application, mate
, and the Kubernetes namespace into which it should be deployed, in our case the ever-popular default
.
We have also set the wait
option to true
, which ensures Draft will wait for all resources to be ready before it installs your application. The watch
option controls whether Draft should monitor for local file changes and automatically deploy them when they occur. The default is false
, and as mentioned above this functionality doesn’t currently work. Instead we’d enable monitor for changes in our IDE and re-deploy based on that.
The auto-connect
option controls whether Draft should automatically connect to the application after the deployment is successful.
The dockerfile
option controls the name of the Dockerfile
that will be used to build the image. The chart
option controls the path of the chart, relative to the location of the draft.toml
file, which will deploy the application. If nothing is specified then it’ll use the first directory it finds in the charts/
directory.
You can find the full specification for the draft.toml
file in the Draft documentation.
Let’s take a quick look at the charts
directory tree before we launch our application. Inside the charts
directory we have a directory called mate
, containing the generated Helm chart for our application.
|
|
Helm charts are templated. The easiest way to see what Helm will do when installing and configuring the mate
application is to look at the template values in the values.yaml
file.
|
|
We can see some basic network configuration, mapping port 3000
inside the application, to port 80
externally via a ClusterIP. And we’ve got some basic memory and CPU resources controls.
Now let’s see if we can deploy the mate
service.
Deploying the mate service
Draft deploys applications using the draft up
command.
|
|
Draft has used the Dockerfile
it generated to build an image and then deployed it to our local Kubernetes cluster via Helm. The log output will show the output of that build.
We can see our running application in the cluster using kubectl
.
|
|
helm package
and deploy it.Currently we have no way of reaching this service and testing it but Draft allows us to create local proxy tunnels that map ports and stream the services logs using the draft connect
command. Let’s do that now.
|
|
draft up
with the --auto-connect
flag to have Draft automatically connect to the application when the deployment completes. Or you can also set the auto-connect
option in draft.toml
to true
.We can see Draft has mapped port 3000
on our service to port 58037
on localhost
. If we curl
the API endpoint on this service we can see it in action.
|
|
We can also indicate a specific port for Draft to use.
|
|
Would set remote port 3000
to local port 3001
. If you don’t want to do this every time you run draft connect
, or you want to automatically connect, then you can use the override-ports
option in the draft.toml
file.
|
|
draft connect
documentation, including options for mapping multiple ports.Developing with Draft
So we’ve got our service running, now let’s make a change to it. We’re going to add a new endpoint to our service.
|
|
We then run draft up
again to deploy our new application.
|
|
If we now connect to the application we should be able to curl
our new endpoint.
|
|
And then check the new endpoint:
|
|
Woot! Now we can continue our development cycle by making changes and re-deploying.
Finally, when we’re done, we can shut down our Draft applications using:
|
|
Summary
I hope this was useful as a walk through. This just scratches the surface of Draft’s capabilities and you can explore features and other uses cases in the Draft documentation.