# Streamlined Kubernetes Development with Draft

- URL: https://baeke.info/2019/05/16/draft-for-kubernetes-revisited/
- Author: Geert Baeke
- Published: May 16, 2019
- Topics: api, cloud, containers, golang, kubernetes, az, draft, go, golang, helm, kubernetes
- Outdated: This version of Draft was archived, and Helm 2 with Tiller is gone.

A longer time ago, I wrote a post about [draft](https://draft.sh/). Draft is a tool to streamline your Kubernetes development experience. It basically automates, based on your code, the creation of a container image, storing the image in a registry and installing a container based on that image using a Helm chart. Draft is meant to be used during the development process while you are still messing around with your code. It is not meant as a deployment mechanism in production.

The typical workflow is the following:

-   in the folder with your source files, run **draft create**
-   to build, push and install the container run **draft up**; in the background a Helm chart is used
-   to see the logs and connect to the app in your container over an SSH tunnel, run **draft connect**
-   modify your code and run **draft up** again
-   rinse and repeat…

Let’s take a look at how it works in a bit more detail, shall we?

## Prerequisites

Naturally, you need a Kubernetes cluster with kubectl, the Kubernetes cli, configured to use that cluster.

Next, install [Helm](https://helm.sh/) on your system and install Tiller, the server-side component of Helm on the cluster. Full installation instructions are [here](https://helm.sh/docs/using_helm/#installing-helm). If your cluster uses rbac, [check out](https://helm.sh/docs/using_helm/#role-based-access-control) how to configure the proper service account and role binding. Run **helm init** to initialize Helm locally and install Tiller at the same time.

Now install draft on your system. Check out the [quickstart](https://github.com/Azure/draft/blob/master/docs/quickstart.md) for installation instructions. Run **draft** **init** to initialize it.

## Getting some source code

Let’s use a small Go program to play with draft. You can use the [realtime-go](https://github.com/gbaeke/realtime-go) repository. Clone it to your system and checkout the httponly branch:

```bash
git clone https://github.com/gbaeke/realtime-go.git
git checkout httponly
```

You will need a redis server as a back-end for the realtime server. Let’s install that the quick and dirty way:

```bash
kubectl run redis --image=redis --replicas=1 
kubectl expose deploy/redis --port 6379
```

## Running draft create

In the realtime-go folder, run **draft create**. You should get the following output:

![](https://baeke.info/_astro/2019-05-image-26.DFdpuA-r_1r5f72.webp)

*draft create output*

The command tries to detect the language and it found several. In this case, because there is no pack for Coq (what is that? 😉) and HTML, it used Go. Knowing the language, draft creates a simple Dockerfile if there is no such file in the folder:

```dockerfile
FROM golang
ENV PORT 8080
EXPOSE 8080

WORKDIR /go/src/app
COPY . .

RUN go get -d -v ./...
RUN go install -v ./...

CMD ["app"]
```

Usually, I do not use the Dockerfile created by draft. If there already is a Dockerfile in the folder, draft will use that one. That’s what happened in our case because the folder contains a [2-stage Dockerfile](https://github.com/gbaeke/realtime-go/blob/master/Dockerfile).

Draft created some other files as well:

-   draft.toml: configuration file ([more info](https://github.com/Azure/draft/blob/master/docs/reference/dep-006.md)); can be used to create environments like staging and production with different settings such as the Kubernetes namespace to deploy to or the Dockerfile to use
-   draft.tasks.toml: run commands before or after you deploy your container with draft ([more info](https://github.com/Azure/draft/blob/master/docs/reference/dep-008.md)); we could have used this to install and remove the redis container
-   .draftignore: yes, to ignore stuff

Draft also created a charts folder that contains the Helm chart that draft will use to deploy your container. It can be modified to suit your particular needs as we will see later.

![](https://baeke.info/_astro/2019-05-image-27.CiQJmBxx_Z15NCfz.webp)

*Helm charts folder and a partial view on the deployment.yaml file in the chart*

## Setting the container registry

In older versions of draft, the source files were compressed and sent to a sever-side component that created the container. At present though, the container is built locally and then pushed to a registry of your choice. If you want to use Azure Container Registry (ACR), run the following commands (set and login):

```bash
draft config set registry REGISTRYNAME.azurecr.io
az acr login -n REGISTRYNAME
```

Note that you need the Azure CLI for the last command. You also need to set the subscription to the one that contains the registry you reference.

With this configuration, you need Docker on your system. Docker will build and push the container. If you want to build in the cloud, you can use ACR Build Tasks. To do that, use these commands:

```bash
draft config set container-builder acrbuild
draft config set registry REGISTRYNAME.azurecr.io
draft config set resource-group-name RESOURCEGROUPNAME
```

Make sure your are logged in to the subscription (az login) and login to ACR as well before continuing. In this example, I used ACR build tasks.

Note: because ACR build tasks do not cache intermediate layers, this approach can lead to longer build times; when the image is small as in this case, doing a local build and push is preferred!

## Running draft up

We are now ready to run **draft up**. Let’s do so and see what happens:

![](https://baeke.info/_astro/2019-05-image-28.DMgFMfPP_Z2snOTR.webp)

*results of draft up*

YES!!!! Draft built the container image and released it. Run **helm ls** to check the release. It did not have to push the image because it was built in ACR and pushed from there. Let’s check the ACR build logs in the portal (you can also use the draft logs command):

![](https://baeke.info/_astro/2019-05-image-29.QzhOcfno_1exFce.webp)

*acr build log for the 2-stage Docker build*

## Fixing issues

Although the container is properly deployed (check it with **helm ls**), if you run **kubectl get pods** you will notice an error:

![](https://baeke.info/_astro/2019-05-image-30.Dh_SNe0w_MAnaS.webp)

*container error*

In this case, the container errors out because it cannot find the redis host, which is a dependency. We can tell the container to look for redis via a REDISHOST environment variable. You can add it to deployment.yaml in the chart like so:

![](https://baeke.info/_astro/2019-05-image-31.C5oYCGD1_Z17p21H.webp)

*environment variable in deployment.yaml*

After this change, just run **draft up** again and hope for the best!

## Running draft connect

With the realtime-go container up and running, run **draft connect**:

![](https://baeke.info/_astro/2019-05-image-32.D2IOJVD0_ZY4drz.webp)

*output of draft connect*

This maps a local port on your system to the remote port over an ssh tunnel. In addition, it streams the logs from the container. You can now connect to [http://localhost:18181](http://localhost:18181) (or whatever port you’ll get):

![](https://baeke.info/_astro/2019-05-image-33.CO_l_U13_xR8No.webp)

*Great success! The app is running*

If you want a public IP for your service, you can modify the Helm chart. In values.yaml, set service.type to LoadBalancer instead of ClusterIP and run **draft up** again. You can verify the external IP by running **kubectl get svc**.

## Conclusion

Working with draft while your are working on one or more containers and still hacking away at your code really is smooth sailing. If you are not using it yet, give it a go and see if you like it. I bet you will!
