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