diff --git a/workspaces/controller/.dockerignore b/workspaces/controller/.dockerignore index a3aab7af..1d1bdf66 100644 --- a/workspaces/controller/.dockerignore +++ b/workspaces/controller/.dockerignore @@ -1,3 +1,2 @@ # More info: https://docs.docker.com/engine/reference/builder/#dockerignore-file # Ignore build and test binaries. -bin/ diff --git a/workspaces/controller/DEVELOPMENT.md b/workspaces/controller/DEVELOPMENT.md new file mode 100644 index 00000000..f567829d --- /dev/null +++ b/workspaces/controller/DEVELOPMENT.md @@ -0,0 +1,107 @@ +# Development Guide + +## Table of Contents + +- [Development Guide](#development-guide) + - [Table of Contents](#table-of-contents) + - [Introduction](#introduction) + - [Prerequisites](#prerequisites) + - [Getting Started](#getting-started) + - [In an existing cluster](#in-an-existing-cluster) + - [Using kind](#using-kind) + - [Teardown](#teardown) + - [Pull Request Checklist](#pull-request-checklist) + - [Best Practices](#best-practices) + - [Troubleshooting](#troubleshooting) + - ["Build Failed: failed to dial gRPC: unable to upgrade to h2c, received 404"](#build-failed-failed-to-dial-grpc-unable-to-upgrade-to-h2c-received-404) + +## Introduction + +This guide will help you set up a development environment for the Kubeflow Notebooks project. + +## Prerequisites + +- Go >= 1.22 +- Kubectl >= 1.22 +- A Kubernetes cluster (e.g. [kind](https://kind.sigs.k8s.io/#installation-and-usage)) +- Cert-manager installed in the cluster, see [cert-manager installation guide](https://cert-manager.io/docs/installation/#default-static-install) + +## Getting Started + +This project uses [Tilt](https://tilt.dev/) to manage the development environment. Tilt will watch for changes in the project and automatically rebuild the Docker image and redeploy the application in the **current Kubernetes context**. + +### Cluster Selection + +Make sure you have a Kubernetes cluster running and `kubectl` is configured to use it. + * `kubectl config current-context` will report which context Tilt will interact with + +💡 For development purposes, you may find using `kind` to be beneficial. You can create your own local cluster with the following command: +- `kind create cluster` + - This command will also change the `current-context` of `kubectl` to the `kind` cluster that is created + +### Running Tilt + +1. Run the following command to start Tilt: + +```bash +make -C devenv tilt-up +``` + +ℹ️ Please make sure you are in the `workspaces/controller` directory when executing the command. + +2. Hit `space` to open the Tilt dashboard in your browser and here you can see the logs and status of every resource deployed. + +## Teardown + +To stop Tilt and remove all resources created by it, run: + +```bash +make -C devenv tilt-down +``` + +ℹ️ Please make sure you are in the `workspaces/controller` directory when executing the command. + +## Pull Request Checklist + +Before raising a PR, ensure you run the following checks to maintain code quality and reliability: + +1. **Linting** + ```bash + make lint + ``` + - This runs static code analysis to ensure code style consistency + - Fix any linting errors before proceeding + +2. **Unit Tests** + ```bash + make test + ``` + - Runs all unit tests in the project + - Ensure all tests pass before submitting changes + - Consider adding new tests for any new functionality + +3. **End-to-End Tests** + ```bash + make test-e2e + ``` + - Validates the complete workflow of the application + - Requires a running Kubernetes cluster + +### Best Practices + +- Run tests locally before pushing changes +- Write meaningful commit messages +- Keep PRs focused and small +- Update documentation if you change functionality +- Consider adding new tests for new features +- Run all checks in sequence before final submission + +## Troubleshooting + +### "Build Failed: failed to dial gRPC: unable to upgrade to h2c, received 404" + +If you see the following error message when tilt builds the image, try setting `DOCKER_BUILDKIT=0`: + +```bash +DOCKER_BUILDKIT=0 make -C devenv tilt-up +``` diff --git a/workspaces/controller/devenv/.gitignore b/workspaces/controller/devenv/.gitignore new file mode 100644 index 00000000..7c51d2be --- /dev/null +++ b/workspaces/controller/devenv/.gitignore @@ -0,0 +1,2 @@ +bin/* +tilt_config.json diff --git a/workspaces/controller/devenv/Makefile b/workspaces/controller/devenv/Makefile new file mode 100644 index 00000000..ae54603e --- /dev/null +++ b/workspaces/controller/devenv/Makefile @@ -0,0 +1,58 @@ +detected_OS := $(shell uname -s) +real_OS := $(detected_OS) +arch := $(shell uname -m) +goarch := $(shell go env GOARCH) +ifeq ($(detected_OS),Darwin) + detected_OS := mac + real_OS := darwin +endif +ifeq ($(detected_OS),Linux) + detected_OS := linux + real_OS := linux +endif + +## Cleanup targets + +.PHONY: cleanup-crds +cleanup-crds: + @echo "Cleaning up CRDs..." + @kubectl delete -f ../config/crd/bases/ || true + +## Requirements + +.PHONY: check-cert-manager +check-cert-manager: cmctl + @echo "Verifying cert-manager installation..." + @$(LOCALBIN)/cmctl check api > /dev/null 2>&1 || (printf "cert-manager is either not installed or not ready. Please install cert-manager or wait until it becomes ready.\nInstallation instructions can be found here: https://cert-manager.io/docs/installation/\n\n" && exit 1) + @echo "cert-manager is installed and ready." + +## Location to install dependencies to +LOCALBIN ?= $(shell pwd)/bin +$(LOCALBIN): + mkdir -p $(LOCALBIN) + +## Tool Binaries +TILT ?= $(LOCALBIN)/tilt +CMCTL ?= $(LOCALBIN)/cmctl + +## Tool Versions +TILT_VERSION := 0.33.22 +CMCTL_VERSION := 2.1.1 + +.PHONY: cmctl +.PHONY: $(CMCTL) +cmctl: $(CMCTL) +$(CMCTL): $(LOCALBIN) + test -s $(LOCALBIN)/cmctl || curl -fsSL https://github.com/cert-manager/cmctl/releases/download/v$(CMCTL_VERSION)/cmctl_$(real_OS)_$(goarch).tar.gz | tar -xz -C $(LOCALBIN) cmctl + +.PHONY: tilt +.PHONY: $(TILT) +tilt: $(TILT) +$(TILT): $(LOCALBIN) + test -s $(LOCALBIN)/tilt || curl -fsSL https://github.com/tilt-dev/tilt/releases/download/v$(TILT_VERSION)/tilt.$(TILT_VERSION).$(detected_OS).$(arch).tar.gz | tar -xz -C $(LOCALBIN) tilt + +tilt-up: tilt check-cert-manager + $(LOCALBIN)/tilt up + +tilt-down: tilt cleanup-crds + $(LOCALBIN)/tilt down diff --git a/workspaces/controller/devenv/Tiltfile b/workspaces/controller/devenv/Tiltfile new file mode 100644 index 00000000..f6dc968e --- /dev/null +++ b/workspaces/controller/devenv/Tiltfile @@ -0,0 +1,122 @@ +load("ext://restart_process", "docker_build_with_restart") + +load_dynamic("./configs/tiltfiles/Tiltfile.setup") + +config.define_string_list("services") + +parsed_config = config.parse() + +for service in parsed_config.get("services", []): + load_dynamic("./configs/tiltfiles/Tiltfile.%s" % (service)) + +manifests = kustomize("../config/default") + +objects = decode_yaml_stream(manifests) + +for o in objects: + if o["kind"] == "Deployment" and o.get("metadata").get("name") in ["workspace-controller-controller-manager"]: + o["spec"]["template"]["spec"]["securityContext"] = {"runAsNonRoot": False, "readOnlyRootFilesystem": False} + o["spec"]["template"]["spec"]["containers"][0]["imagePullPolicy"] = "Always" + +overridden_manifests = encode_yaml_stream(objects) + +k8s_yaml(overridden_manifests, allow_duplicates=True) + +local_resource( + "cert-manager-req-check", + serve_cmd="while true; do sleep 86400; done", + labels="requirements", + readiness_probe=probe( + exec=exec_action( + command=["/bin/sh", "-c", "./bin/cmctl check api"] + ), initial_delay_secs=5, timeout_secs=60 + ) +) + +k8s_resource( + new_name="certs", + objects=[ + "workspace-controller-serving-cert:certificate", + "workspace-controller-selfsigned-issuer:issuer" + ], + labels="controller", + resource_deps=[ + "controller-namespace", + "cert-manager-req-check" + ] +) + +k8s_resource( + new_name="reqs", + objects=[ + "workspace-controller-controller-manager:serviceaccount", + "workspace-controller-leader-election-role:role", + "workspace-controller-manager-role:clusterrole", + "workspace-controller-workspace-editor-role:clusterrole", + "workspace-controller-workspace-viewer-role:clusterrole", + "workspace-controller-workspacekind-editor-role:clusterrole", + "workspace-controller-workspacekind-viewer-role:clusterrole", + "workspace-controller-leader-election-rolebinding:rolebinding", + "workspace-controller-manager-rolebinding:clusterrolebinding", + "workspace-controller-validating-webhook-configuration:validatingwebhookconfiguration" + ], + labels="controller", + resource_deps=[ + "controller-namespace" + ] +) + +k8s_resource( + new_name="crds", + objects=[ + "workspacekinds.kubeflow.org:customresourcedefinition", + "workspaces.kubeflow.org:customresourcedefinition" + ], + labels="controller", + resource_deps=[ + "controller-namespace", + ] +) + +k8s_resource( + new_name="controller-namespace", + objects=["workspace-controller-system:Namespace:default"], + labels="requirements" +) + +k8s_resource( + workload="workspace-controller-controller-manager", + new_name="controller", + labels="controller", + resource_deps=[ + "controller-namespace", + "cert-manager-req-check", + "certs" + ] +) + +local_resource( + "manager-bin", + "CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o bin/manager cmd/main.go", + dir = "../", + deps = [ + "../cmd", + "../internal", + "../go.mod", + "../go.sum", + ], + labels="controller", +) + +docker_build_with_restart( + "ghcr.io/kubeflow/notebooks/workspace-controller", + context = "../", + dockerfile = "../tilt.dockerfile", + entrypoint = ["/manager"], + only=[ + "bin/", + ], + live_update = [ + sync("../bin/manager", "/manager"), + ], +) diff --git a/workspaces/controller/devenv/configs/tiltfiles/Tiltfile.setup b/workspaces/controller/devenv/configs/tiltfiles/Tiltfile.setup new file mode 100644 index 00000000..2bed6f56 --- /dev/null +++ b/workspaces/controller/devenv/configs/tiltfiles/Tiltfile.setup @@ -0,0 +1,4 @@ +# Disable analytics +analytics_settings(False) + +update_settings(k8s_upsert_timeout_secs = 120) diff --git a/workspaces/controller/tilt.dockerfile b/workspaces/controller/tilt.dockerfile new file mode 100644 index 00000000..a49ee054 --- /dev/null +++ b/workspaces/controller/tilt.dockerfile @@ -0,0 +1,7 @@ +FROM alpine:3.12 + +WORKDIR / + +COPY bin/manager /manager + +ENTRYPOINT ["/manager"]