sigs.k8s.io/cluster-api@v1.6.3/docs/book/src/developer/tilt.md (about) 1 # Developing Cluster API with Tilt 2 3 ## Overview 4 5 This document describes how to use [kind](https://kind.sigs.k8s.io) and [Tilt](https://tilt.dev) for a simplified 6 workflow that offers easy deployments and rapid iterative builds. 7 8 ## Prerequisites 9 10 1. [Docker](https://docs.docker.com/install/): v19.03 or newer 11 1. [kind](https://kind.sigs.k8s.io): v0.20.0 or newer 12 1. [Tilt](https://docs.tilt.dev/install.html): v0.30.8 or newer 13 1. [kustomize](https://github.com/kubernetes-sigs/kustomize): provided via `make kustomize` 14 1. [envsubst](https://github.com/drone/envsubst): provided via `make envsubst` 15 1. [helm](https://github.com/helm/helm): v3.7.1 or newer 16 1. Clone the [Cluster API](https://github.com/kubernetes-sigs/cluster-api) repository 17 locally 18 1. Clone the provider(s) you want to deploy locally as well 19 20 ## Getting started 21 22 ### Create a kind cluster 23 A script to create a KIND cluster along with a local Docker registry and the correct mounts to run CAPD is included in the hack/ folder. 24 25 To create a pre-configured cluster run: 26 27 ```bash 28 ./hack/kind-install-for-capd.sh 29 ``` 30 31 You can see the status of the cluster with: 32 33 ```bash 34 kubectl cluster-info --context kind-capi-test 35 ``` 36 37 ### Create a tilt-settings file 38 39 Next, create a `tilt-settings.yaml` file and place it in your local copy of `cluster-api`. Here is an example that uses the components from the CAPI repo: 40 41 ```yaml 42 default_registry: gcr.io/your-project-name-here 43 enable_providers: 44 - docker 45 - kubeadm-bootstrap 46 - kubeadm-control-plane 47 ``` 48 49 To use tilt to launch a provider with its own repo, using Cluster API Provider AWS here, `tilt-settings.yaml` should look like: 50 51 ```yaml 52 default_registry: gcr.io/your-project-name-here 53 provider_repos: 54 - ../cluster-api-provider-aws 55 enable_providers: 56 - aws 57 - kubeadm-bootstrap 58 - kubeadm-control-plane 59 ``` 60 61 <aside class="note"> 62 63 If you prefer JSON, you can create a `tilt-settings.json` file instead. YAML will be preferred if both files are present. 64 65 </aside> 66 67 #### tilt-settings fields 68 69 **allowed_contexts** (Array, default=[]): A list of kubeconfig contexts Tilt is allowed to use. See the Tilt documentation on 70 [allow_k8s_contexts](https://docs.tilt.dev/api.html#api.allow_k8s_contexts) for more details. 71 72 **default_registry** (String, default=[]): The image registry to use if you need to push images. See the [Tilt 73 documentation](https://docs.tilt.dev/api.html#api.default_registry) for more details. 74 Please note that, in case you are not using a local registry, this value is required; additionally, the Cluster API 75 Tiltfile protects you from accidental push on `gcr.io/k8s-staging-cluster-api`. 76 77 **build_engine** (String, default="docker"): The engine used to build images. Can either be `docker` or `podman`. 78 NB: the default is dynamic and will be "podman" if the string "Podman Engine" is found in `docker version` (or in `podman version` if the command fails). 79 80 **kind_cluster_name** (String, default="capi-test"): The name of the kind cluster to use when preloading images. 81 82 **provider_repos** (Array[]String, default=[]): A list of paths to all the providers you want to use. Each provider must have a 83 `tilt-provider.yaml` or `tilt-provider.json` file describing how to build the provider. 84 85 **enable_providers** (Array[]String, default=['docker']): A list of the providers to enable. See [available providers](#available-providers) 86 for more details. 87 88 **template_dirs** (Map{String: Array[]String}, default={"docker": [ 89 "./test/infrastructure/docker/templates"]}): A map of providers to directories containing cluster templates. An example of the field is given below. See [Deploying a workload cluster](#deploying-a-workload-cluster) for how this is used. 90 91 ```yaml 92 template_dirs: 93 docker: 94 - ./test/infrastructure/docker/templates 95 - <other-template-dir> 96 azure: 97 - <azure-template-dir> 98 aws: 99 - <aws-template-dir> 100 gcp: 101 - <gcp-template-dir> 102 ``` 103 104 **kustomize_substitutions** (Map{String: String}, default={}): An optional map of substitutions for `${}`-style placeholders in the 105 provider's yaml. These substitutions are also used when deploying cluster templates. See [Deploying a workload cluster](#deploying-a-workload-cluster). 106 107 **Note**: When running E2E tests locally using an existing cluster managed by Tilt, the following substitutions are required for successful tests: 108 ```yaml 109 kustomize_substitutions: 110 CLUSTER_TOPOLOGY: "true" 111 EXP_MACHINE_POOL: "true" 112 EXP_CLUSTER_RESOURCE_SET: "true" 113 EXP_KUBEADM_BOOTSTRAP_FORMAT_IGNITION: "true" 114 EXP_RUNTIME_SDK: "true" 115 EXP_MACHINE_SET_PREFLIGHT_CHECKS: "true" 116 ``` 117 118 {{#tabs name:"tab-tilt-kustomize-substitution" tabs:"AWS,Azure,DigitalOcean,GCP,vSphere"}} 119 {{#tab AWS}} 120 121 For example, if the yaml contains `${AWS_B64ENCODED_CREDENTIALS}`, you could do the following: 122 123 ```yaml 124 kustomize_substitutions: 125 AWS_B64ENCODED_CREDENTIALS: "your credentials here" 126 ``` 127 128 {{#/tab }} 129 {{#tab AZURE}} 130 131 An Azure Service Principal is needed for populating the controller manifests. This utilizes [environment-based authentication](https://docs.microsoft.com/en-us/go/azure/azure-sdk-go-authorization#use-environment-based-authentication). 132 133 1. Save your Subscription ID 134 135 ```bash 136 AZURE_SUBSCRIPTION_ID=$(az account show --query id --output tsv) 137 az account set --subscription $AZURE_SUBSCRIPTION_ID 138 ``` 139 140 2. Set the Service Principal name 141 142 ```bash 143 AZURE_SERVICE_PRINCIPAL_NAME=ServicePrincipalName 144 ``` 145 146 3. Save your Tenant ID, Client ID, Client Secret 147 148 ```bash 149 AZURE_TENANT_ID=$(az account show --query tenantId --output tsv) 150 AZURE_CLIENT_SECRET=$(az ad sp create-for-rbac --name http://$AZURE_SERVICE_PRINCIPAL_NAME --query password --output tsv) 151 AZURE_CLIENT_ID=$(az ad sp show --id http://$AZURE_SERVICE_PRINCIPAL_NAME --query appId --output tsv) 152 ``` 153 154 Add the output of the following as a section in your `tilt-settings.yaml`: 155 156 ```bash 157 cat <<EOF 158 kustomize_substitutions: 159 AZURE_SUBSCRIPTION_ID_B64: "$(echo "${AZURE_SUBSCRIPTION_ID}" | tr -d '\n' | base64 | tr -d '\n')" 160 AZURE_TENANT_ID_B64: "$(echo "${AZURE_TENANT_ID}" | tr -d '\n' | base64 | tr -d '\n')" 161 AZURE_CLIENT_SECRET_B64: "$(echo "${AZURE_CLIENT_SECRET}" | tr -d '\n' | base64 | tr -d '\n')" 162 AZURE_CLIENT_ID_B64: "$(echo "${AZURE_CLIENT_ID}" | tr -d '\n' | base64 | tr -d '\n')" 163 EOF 164 ``` 165 166 {{#/tab }} 167 {{#tab DigitalOcean}} 168 169 ```yaml 170 kustomize_substitutions: 171 DO_B64ENCODED_CREDENTIALS: "your credentials here" 172 ``` 173 174 {{#/tab }} 175 {{#tab GCP}} 176 177 You can generate a base64 version of your GCP json credentials file using: 178 ```bash 179 base64 -i ~/path/to/gcp/credentials.json 180 ``` 181 182 ```yaml 183 kustomize_substitutions: 184 GCP_B64ENCODED_CREDENTIALS: "your credentials here" 185 ``` 186 187 {{#/tab }} 188 {{#tab vSphere}} 189 190 ```yaml 191 kustomize_substitutions: 192 VSPHERE_USERNAME: "administrator@vsphere.local" 193 VSPHERE_PASSWORD: "Admin123" 194 ``` 195 196 {{#/tab }} 197 {{#/tabs }} 198 199 **deploy_observability** ([string], default=[]): If set, installs on the dev cluster one of more observability 200 tools. 201 Important! This feature requires the `helm` command to be available in the user's path. 202 203 Supported values are: 204 205 * `grafana`*: To create dashboards and query `loki`, `prometheus` and `tempo`. 206 * `kube-state-metrics`: For exposing metrics for Kubernetes and CAPI resources to `prometheus`. 207 * `loki`: To receive and store logs. 208 * `metrics-server`: To enable `kubectl top node/pod`. 209 * `prometheus`*: For collecting metrics from Kubernetes. 210 * `promtail`: For providing pod logs to `loki`. 211 * `parca`*: For visualizing profiling data. 212 * `tempo`: To store traces. 213 * `visualizer`*: Visualize Cluster API resources for each cluster, provide quick access to the specs and status of any resource. 214 215 \*: Note: the UI will be accessible via a link in the tilt console 216 217 **additional_kustomizations** (map[string]string, default={}): If set, install the additional resources built using kustomize to the cluster. 218 Example: 219 ```yaml 220 additional_kustomizations: 221 capv-metrics: ../cluster-api-provider-vsphere/config/metrics 222 ``` 223 224 **debug** (Map{string: Map} default{}): A map of named configurations for the provider. The key is the name of the provider. 225 226 Supported settings: 227 228 * **port** (int, default=0 (disabled)): If set to anything other than 0, then Tilt will run the provider with delve 229 and port forward the delve server to localhost on the specified debug port. This can then be used with IDEs such as 230 Visual Studio Code, Goland and IntelliJ. 231 232 * **continue** (bool, default=true): By default, Tilt will run delve with `--continue`, such that any provider with 233 debugging turned on will run normally unless specifically having a breakpoint entered. Change to false if you 234 do not want the controller to start at all by default. 235 236 * **profiler_port** (int, default=0 (disabled)): If set to anything other than 0, then Tilt will enable the profiler with 237 `--profiler-address` and set up a port forward. A "profiler" link will be visible in the Tilt Web UI for the controller. 238 239 * **metrics_port** (int, default=0 (disabled)): If set to anything other than 0, then Tilt will port forward to the 240 default metrics port. A "metrics" link will be visible in the Tilt Web UI for the controller. 241 242 * **race_detector** (bool, default=false) (Linux amd64 only): If enabled, Tilt will compile the specified controller with 243 cgo and statically compile in the system glibc and enable the race detector. Currently, this is only supported when 244 building on Linux amd64 systems. You must install glibc-static or have libc.a available for this to work. 245 246 Example: Using the configuration below: 247 248 ```yaml 249 debug: 250 core: 251 continue: false 252 port: 30000 253 profiler_port: 40000 254 metrics_port: 40001 255 ``` 256 257 ##### Wiring up debuggers 258 ###### Visual Studio 259 When using the example above, the core CAPI controller can be debugged in Visual Studio Code using the following launch configuration: 260 261 ```json 262 { 263 "version": "0.2.0", 264 "configurations": [ 265 { 266 "name": "Core CAPI Controller", 267 "type": "go", 268 "request": "attach", 269 "mode": "remote", 270 "remotePath": "", 271 "port": 30000, 272 "host": "127.0.0.1", 273 "showLog": true, 274 "trace": "log", 275 "logOutput": "rpc" 276 } 277 ] 278 } 279 ``` 280 281 ###### Goland / IntelliJ 282 With the above example, you can configure [a Go Remote run/debug 283 configuration](https://www.jetbrains.com/help/go/attach-to-running-go-processes-with-debugger.html#step-3-create-the-remote-run-debug-configuration-on-the-client-computer) 284 pointing at port 30000. 285 286 <br/> 287 288 **deploy_cert_manager** (Boolean, default=`true`): Deploys cert-manager into the cluster for use for webhook registration. 289 290 **trigger_mode** (String, default=`auto`): Optional setting to configure if tilt should automatically rebuild on changes. 291 Set to `manual` to disable auto-rebuilding and require users to trigger rebuilds of individual changed components through the UI. 292 293 **extra_args** (Object, default={}): A mapping of provider to additional arguments to pass to the main binary configured 294 for this provider. Each item in the array will be passed in to the manager for the given provider. 295 296 Example: 297 298 ```yaml 299 extra_args: 300 kubeadm-bootstrap: 301 - --logging-format=json 302 ``` 303 304 With this config, the respective managers will be invoked with: 305 306 ```bash 307 manager --logging-format=json 308 ``` 309 310 ### Create a kind cluster and run Tilt! 311 312 To create a pre-configured kind cluster (if you have not already done so) and launch your development environment, run 313 314 ```bash 315 make tilt-up 316 ``` 317 318 This will open the command-line HUD as well as a web browser interface. You can monitor Tilt's status in either 319 location. After a brief amount of time, you should have a running development environment, and you should now be able to 320 create a cluster. There are [example worker cluster 321 configs](https://github.com/kubernetes-sigs/cluster-api/tree/main/test/infrastructure/docker/examples) available. 322 These can be customized for your specific needs. 323 324 ### Deploying a workload cluster 325 326 After your kind management cluster is up and running with Tilt, you can deploy a workload clusters in the Tilt web UI based off of YAML templates from the directories specified in 327 the `template_dirs` field from the [tilt-settings.yaml](#tilt-settings-fields) file (default `./test/infrastructure/docker/templates`). 328 329 Templates should be named according to clusterctl conventions: 330 331 - template files must be named `cluster-template-{name}.yaml`; those files will be accessible in the Tilt web UI under the label grouping `{provider-label}.templates`, i.e. `CAPD.templates`. 332 - cluster class files must be named `clusterclass-{name}.yaml`; those file will be accessible in the Tilt web UI under the label grouping `{provider-label}.clusterclasses`, i.e. `CAPD.clusterclasses`. 333 334 By selecting one of those items in the Tilt web UI set of buttons will appear, allowing to create - with a dropdown for customizing variable substitutions - or delete clusters. 335 Custom values for variable substitutions can be set using `kustomize_substitutions` in `tilt-settings.yaml`, e.g. 336 337 ```yaml 338 kustomize_substitutions: 339 NAMESPACE: "default" 340 KUBERNETES_VERSION: "v1.29.0" 341 CONTROL_PLANE_MACHINE_COUNT: "1" 342 WORKER_MACHINE_COUNT: "3" 343 # Note: kustomize substitutions expects the values to be strings. This can be achieved by wrapping the values in quotation marks. 344 ``` 345 346 ### Cleaning up your kind cluster and development environment 347 348 After stopping Tilt, you can clean up your kind cluster and development environment by running 349 350 ```bash 351 make clean-kind 352 ``` 353 354 To remove all generated files, run 355 356 ```bash 357 make clean 358 ``` 359 360 Note that you must run `make clean` or `make clean-charts` to fetch new versions of charts deployed using `deploy_observability` in `tilt-settings.yaml`. 361 362 <h1>Use of clusterctl</h1> 363 364 When the worker cluster has been created using tilt, `clusterctl` should not be used for management 365 operations; this is because tilt doesn't initialize providers on the management cluster like clusterctl init does, so 366 some of the clusterctl commands like clusterctl config won't work. 367 368 This limitation is an acceptable trade-off while executing fast dev-test iterations on controllers logic. If instead 369 you are interested in testing clusterctl workflows, you should refer to the 370 [clusterctl developer instructions](../clusterctl/developers.md). 371 372 ## Available providers 373 374 The following providers are currently defined in the Tiltfile: 375 376 * **core**: cluster-api itself 377 * **kubeadm-bootstrap**: kubeadm bootstrap provider 378 * **kubeadm-control-plane**: kubeadm control-plane provider 379 * **docker**: Docker infrastructure provider 380 * **in-memory**: In-memory infrastructure provider 381 * **test-extension**: Runtime extension used by CAPI E2E tests 382 383 Additional providers can be added by following the procedure described in following paragraphs: 384 385 ### tilt-provider configuration 386 387 A provider must supply a `tilt-provider.yaml` file describing how to build it. Here is an example: 388 389 ```yaml 390 name: aws 391 config: 392 image: "gcr.io/k8s-staging-cluster-api-aws/cluster-api-aws-controller" 393 live_reload_deps: ["main.go", "go.mod", "go.sum", "api", "cmd", "controllers", "pkg"] 394 label: CAPA 395 ``` 396 397 398 <aside class="note"> 399 400 If you prefer JSON, you can create a `tilt-provider.json` file instead. YAML will be preferred if both files are present. 401 402 </aside> 403 404 #### config fields 405 406 **image**: the image for this provider, as referenced in the kustomize files. This must match; otherwise, Tilt won't 407 build it. 408 409 **live_reload_deps**: a list of files/directories to watch. If any of them changes, Tilt rebuilds the manager binary 410 for the provider and performs a live update of the running container. 411 412 **version**: allows to define the version to be used for the Provider CR. If empty, a default version will 413 be used. 414 415 **additional_docker_helper_commands** (String, default=""): Additional commands to be run in the helper image 416 docker build. e.g. 417 418 ``` Dockerfile 419 RUN wget -qO- https://dl.k8s.io/v1.21.2/kubernetes-client-linux-amd64.tar.gz | tar xvz 420 RUN wget -qO- https://get.docker.com | sh 421 ``` 422 423 **additional_docker_build_commands** (String, default=""): Additional commands to be appended to 424 the dockerfile. 425 The manager image will use docker-slim, so to download files, use `additional_helper_image_commands`. e.g. 426 427 ``` Dockerfile 428 COPY --from=tilt-helper /usr/bin/docker /usr/bin/docker 429 COPY --from=tilt-helper /go/kubernetes/client/bin/kubectl /usr/bin/kubectl 430 ``` 431 432 **kustomize_config** (Bool, default=true): Whether or not running kustomize on the ./config folder of the provider. 433 Set to `false` if your provider does not have a ./config folder or you do not want it to be applied in the cluster. 434 435 **go_main** (String, default="main.go"): The go main file if not located at the root of the folder 436 437 **label** (String, default=provider name): The label to be used to group provider components in the tilt UI 438 in tilt version >= v0.22.2 (see https://blog.tilt.dev/2021/08/09/resource-grouping.html); as a convention, 439 provider abbreviation should be used (CAPD, KCP etc.). 440 441 **additional_resources** ([]string, default=[]): A list of paths to yaml file to be loaded into the tilt cluster; 442 e.g. use this to deploy an ExtensionConfig object for a RuntimeExtension provider. 443 444 **resource_deps** ([]string, default=[]): A list of tilt resource names to be installed before the current provider; 445 e.g. set this to ["capi_controller"] to ensure that this provider gets installed after Cluster API. 446 447 ## Customizing Tilt 448 449 If you need to customize Tilt's behavior, you can create files in cluster-api's `tilt.d` directory. This file is ignored 450 by git so you can be assured that any files you place here will never be checked in to source control. 451 452 These files are included after the `providers` map has been defined and after all the helper function definitions. This 453 is immediately before the "real work" happens. 454 455 ## Under the covers, a.k.a "the real work" 456 457 At a high level, the Tiltfile performs the following actions: 458 459 1. Read `tilt-settings.yaml` 460 1. Configure the allowed Kubernetes contexts 461 1. Set the default registry 462 1. Define the `providers` map 463 1. Include user-defined Tilt files 464 1. Deploy cert-manager 465 1. Enable providers (`core` + what is listed in `tilt-settings.yaml`) 466 1. Build the manager binary locally as a `local_resource` 467 1. Invoke `docker_build` for the provider 468 1. Invoke `kustomize` for the provider's `config/` directory 469 470 ### Live updates 471 472 Each provider in the `providers` map has a `live_reload_deps` list. This defines the files and/or directories that Tilt 473 should monitor for changes. When a dependency is modified, Tilt rebuilds the provider's manager binary **on your local 474 machine**, copies the binary to the running container, and executes a restart script. This is significantly faster 475 than rebuilding the container image for each change. It also helps keep the size of each development image as small as 476 possible (the container images do not need the entire go toolchain, source code, module dependencies, etc.). 477 478 ## IDE support for Tiltfile 479 480 For IntelliJ, Syntax highlighting for the Tiltfile can be configured with a TextMate Bundle. For instructions, please see: 481 [Tiltfile TextMate Bundle](https://github.com/tilt-dev/tiltfile.tmbundle). 482 483 For VSCode the [Bazel plugin](https://marketplace.visualstudio.com/items?itemName=BazelBuild.vscode-bazel) can be used, it provides 484 syntax highlighting and auto-formatting. To enable it for Tiltfile a file association has to be configured via user settings: 485 ```json 486 "files.associations": { 487 "Tiltfile": "starlark", 488 }, 489 ``` 490 491 ## Using Podman 492 493 [Podman](https://podman.io) can be used instead of Docker by following these actions: 494 495 1. Enable the podman unix socket: 496 - on Linux/systemd: `systemctl --user enable --now podman.socket` 497 - on macOS: create a podman machine with `podman machine init` 498 1. Set `build_engine` to `podman` in `tilt-settings.yaml` (optional, only if both Docker & podman are installed) 499 1. Define the env variable `DOCKER_HOST` to the right socket: 500 - on Linux/systemd: `export DOCKER_HOST=unix:///run/user/$(id -u)/podman/podman.sock` 501 - on macOS: `export DOCKER_HOST=$(podman machine inspect <machine> | jq -r '.[0].ConnectionInfo.PodmanSocket.Path')` where `<machine>` is the podman machine name 502 1. Run `tilt up` 503 504 NB: The socket defined by `DOCKER_HOST` is used only for the `hack/tools/internal/tilt-prepare` command, the image build is running the `podman build`/`podman push` commands. 505 506 ## Troubleshooting Tilt 507 508 ### Tilt is stuck 509 510 Sometimes tilt looks stuck when it's waiting on connections. 511 512 Ensure that docker/podman is up and running and your kubernetes cluster is reachable. 513 514 ### Errors running tilt-prepare 515 516 #### `failed to get current context from the KubeConfig file` 517 518 - Ensure the cluster in the default context is reachable by running `kubectl cluster-info` 519 - Switch to the right context with `kubectl config use-context` 520 - Ensure the context is allowed, see [**allowed_contexts** field](#tilt-settings-fields) 521 522 #### `Cannot connect to the Docker daemon` 523 524 - Ensure the docker daemon is running ;) or for podman see [Using Podman](#using-podman) 525 - If a DOCKER_HOST is specified: 526 - check that the DOCKER_HOST has the correct prefix (usually `unix://`) 527 - ensure docker/podman is listening on $DOCKER_HOST using `fuser` / `lsof` / `netstat -u` 528 529 ### Errors pulling/pushing to the registry 530 531 #### `connection refused` / `denied` / `not found` 532 533 Ensure the [**default_registry** field](#tilt-settings-fields) is a valid registry where you can pull and push images. 534 535 #### `server gave HTTP response to HTTPS client` 536 537 By default all registries except localhost:5000 are accessed via HTTPS. 538 539 If you run a HTTP registry you may have to configure the registry in docker/podman. 540 541 For example, in podman a `localhost:5001` registry configuration should be declared in `/etc/containers/registries.conf.d` with this content: 542 ```` 543 [[registry]] 544 location = "localhost:5001" 545 insecure = true 546 ```` 547 548 NB: on macOS this configuration should be done **in the podman machine** by running `podman machine ssh <machine>`. 549 550 ### Errors loading images in kind 551 552 You may try manually to load images in kind by running: 553 ```` 554 kind load docker-image --name=<kind_cluster> <image> 555 ```` 556 557 #### `image: "..." not present locally` 558 559 If you are running podman, you may have hit this bug: https://github.com/kubernetes-sigs/kind/issues/2760 560 561 The workaround is to create a `docker` symlink to your `podman` executable and try to load the images again.