Build a platform for internal tools with Windmill

Deploy an open source platform to turn scripts into apps and more.

Goldilocks effect

Over time, we all end up with a collection of scripts tucked away in a scripts directory or git repo. Often these are written for a specific purpose and do not belong to a single category. In my case, I have Python scripts that configure infra, check for pre-requisite in clusters, generate data, query internal APIs and more. My teammates have their collection and other teams must have theirs too.

Scripts can become complex to run with many args while remaining trivial to be turned into full-fledged apps.

Fundamentally, they takeinput as args, perform actions and return an output.This is where Windmill shines. It generates UI which can be deployed as app using only the code. If you are concerned about running code on the cloud app, you can self-host on a Kubernetes cluster.

Here's my experience deploying Windmill on Kubernetes.

Windmill

Windmill docs are pretty good and straightforward. Helm chart makes it easy to deploy. You can start with minikube and then try on Kubernetes.

Preparation

Configure External database

It is better to have a hosted database instance ready in advance. You can disable the default postgresql in values.yaml, minio is also optional. However, ensure the database is configured correctly before proceeding. Otherwise, app pods will end up in a crashloop (as the docs mention). The database credentials are not secret but try to use sslmode=require.

Configure Ingress

The default ingress works well on minikube but you need to configure Ingress as per your k8s. Remember to setbaseDomain and baseProtocol (http to https) accordingly.

Workaround for private registry

If your k8s cannot access ghcr.io/windmill-labs registry then you can copy the images to a private registry. Luckily, they use only 2 images (as of version 1.109)

# <tag> should be same as release.
docker pull ghcr.io/windmill-labs/windmill:<tag>
docker pull ghcr.io/windmill-labs/windmill-lsp:<tag>
# Now tag and push them to the private registry

This is not ideal but a workaround if you are out of options. Next, clone the helm chart and replace these image: values. You can install this chart:

cd windmill-helm-charts
❯ helm install mywindmill ./charts/windmill

You can also use a private pipIndexUrl This would speed up Python code execution, as the script installs required packages.

Deployment

Deployment is easy as the docs say:

# add the Windmill helm repo
helm repo add windmill https://windmill-labs.github.io/windmill-helm-charts/
# install chart with default values
helm install windmill-chart windmill/windmill  \
      --namespace=windmill \
      --create-namespace

Navigate to URL and login with admin@windmill.dev / changeme

Generate UI from code

Start with a sample script which has a main function like this:

def main(
    no_default: str,
    #db: postgresql,
    name="Nicolas Bourbaki",
    age=42,
    obj: dict = {"even": "dicts"},
    l: list = ["or", "lists!"],
    file_: bytes = bytes(0),
):

Arguments to main are used to generate UI elements based on the type. On execution, imported packages are installed. All print or log statements are displayed in a log section and return values are shown in output.

Each script gets a unique path and you can see execution history, re-use previous inputs, and even schedule runs.

The Web IDE provides a decent editing experience. For Python, support for assistants (Pyright, Black, Ruff) helps keep the code clean.

Advanced Features

Auto-generated UI is one of the features of Windmill. It can create complex Workflow and comes with a decent drag-and-drop App builder. However, the code is the basic building block.

Conclusion

Windmill is an awesome open-source option to turn code into apps with reasonable deployment and configuration options. However, I could not find an easy way to enable authentication without using oauth integrations (which may be plenty for most people). Many integrations might work better out of the box in the cloud app.