Tilting


Note

For more background information, make sure to check out the demos overview page.

Tilt is great, check out the official docs.1 The local development experience is especially good, with automatic reloading and slick web-UI that makes it very easy to navigate services, logs, and identify problems in complex bootstrap. Depending on your interests, you can also pretty quickly build out diagnostic suites, small smoke-test suites, simple event-triggering, etc, with UI components generated from code.

The main problems with Tilt are:

  1. Tilt kind of emphasizes "local-only"2, not local-first.
  2. And yet.. it also doesn't work by itself locally, so you need another orchestration layer.[^3]
  3. In some ways, it also seems to resist automation and proper daemonization3.

Some of these "problems" are arguably good design, but.. it does mean that tilt expects other tools to handle orchestration at some point.4

There's a few ways that k8s.mk can help here. Besides a container spec for tilt, there's easy access to cluster lifecycle automation with k3d, minikube, or kind, without any host dependencies besides docker+make. Run tilt anywhere (including from CI/CD), without actually having tilt installed. Besides putting related automation together, you can also easily override versions for tilt or minikube from one place.

Combos & Caveats


This is a basic demo, just enough to show some orchestration. For a more complete workbench, it combines well with the kubetail demo. Although Tilt does have some native support for docker-compose, using it even for prototyping tends to break the similarity for dev/prod, which is something that's nice to have. Instead consider combining with the kompose demo, and you'll have a pretty close match no matter what backend cluster tech you're using.

Tilt support in k8s.mk is basic: most of the tilt CLI commands that interact with the tilt API don't work from the containerized version of tilt currently. The main use-cases are fixing daemonization/automation3, using tilt up without requiring a tilt installation, and getting to the tilt web UI for everything else.

Bonus: Besides running tilt from k8s.mk, you can also run k8s.mk from Tiltfiles. Doing this has basically the same benefits as using k8s.mk from Jenkins or github-actions, and you may find that helps to decouple your automation from a specific platform at the same time as it makes it more usable from all platforms.

Source Code


Just a few lines to handle cluster details and lifecycle automation aliases, and a few to start and daemonize the tilt server while looking at an external Tiltfile:

Summary
#!/usr/bin/env -S make -f
# Working with Tilt and Tiltfiles, part 1.
# Cluster Management + External Tiltfile
#   
# See the documentation here[1] for more discussion.
# This demo ships with the `k8s-tools` repo and runs as part of the test-suite.
#
# USAGE: 
#   ./demos/tilt.mk clean create deploy test
#
# REF:
#   [1] https://robot-wranglers.github.io/k8s-tools/demos/tilt/
#░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░

include k8s.mk
export KUBECONFIG:=./local.cluster.yml
export TILT_PORT=10351

$(shell umask 066; touch ${KUBECONFIG})
$(call compose.import, file=k8s-tools.yml)

## Cluster lifecycle basics.  These are the same for most demos.

__main__: clean create deploy test

cluster.name=tilt
minikube.args=\
  --driver=docker -v1 --wait=all --embed-certs

wait: k8s.wait
clean: stage/clean minikube.delete/${cluster.name}
create: stage/create minikube.get_or_create/${cluster.name}

## Tilt specifics 
deploy: stage/deploy tilt.serve/demos/data/Tiltfile io.wait/7 
test: tilt.get_logs/100

Another variation, a useful trick is to build wrappers/extensions. Inline one Tiltfile testing custom behaviour, then use the inline to include an existing external file.

Summary
#!/usr/bin/env -S make -f
# Working with Tilt and Tiltfiles, part 2.
# Cluster Management + Inlined Tiltfile
#   
# See the documentation here[1] for more discussion.
# This demo ships with the `k8s-tools` repo and runs as part of the test-suite.
#
# USAGE: 
#   ./demos/tilt-inlined.mk clean create deploy.inlined test
#
# REF:
#   [1] https://robot-wranglers.github.io/k8s-tools/demos/tilt/
#   [2] https://docs.tilt.dev/api.html
#░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░░

include demos/tilt.mk

# You can use an ephemeral tmpfile here instead, but anything that's 
# cleaned up when the process exits tends to confuse `tilt` because 
# it's tracking changes for the file.
tiltfile=.tmp.Tiltfile

deploy.inlined: stage/deploy
    ${mk.def.read}/Tiltfile > ${tiltfile} \
    && ${make} tilt.serve/${tiltfile} io.wait/7

define Tiltfile
print("🚀 Inlined Tiltfile")

## Must match the cluster-name that minikube is using.
allow_k8s_contexts('tilt')

os.putenv('CMK_INTERNAL', '0')

local_resource(
    'k8s.mk',
    cmd='''
# Currently in the demos/data folder 
# (This is relative to Tiltfile location)
pwd

# Run commands from project Makefile
./demos/tilt.mk flux.ok
./demos/tilt.mk tilt.ps

# Use k8s.mk directly, in stand-alone mode.
./k8s.mk k8s.stat
''',
    auto_init=False, labels=['cmk'],
    trigger_mode=TRIGGER_MODE_MANUAL,
)
include('demos/data/Tiltfile')
endef

Basic Usage


Cluster lifecycle looks more or less the same as any of the other demos.

# Default entrypoint runs clean, create, 
# deploy, test, but does not tear down the cluster. 
$ ./demos/tilt.mk clean create
# As part of `deploy`, `tilt up` will run.
$ ./demos/tilt.mk deploy

# In this case, test just retrieves logs for tilt, 
# then drops a link for web UI so you can test.
$ ./demos/tilt.mk test
# Stop the daemonizes tilt-server, tear down the cluster.
$ ./demos/tilt.mk tilt.stop clean


  1. https://tilt.dev/ 

  2. designed to work locally*, and 1. [^3]: It doesn't work by itself locally

  3. Automation/daemonization can be difficult. 

  4. Part of why Tiltfile's can struggle to stay DRY and related logic starts to get duplicated in different places: On the one hand, you're not supposed to use your Tiltfile to deploy to prod. To re-use Tiltfile automation from CI/CD, you'll also need to do cluster management and bring a tilt container. Sometimes you actually need N versions of a deployment for local/dev/prod/ci, but it's always nice to avoid that.