From 69c9e57341b68e3ca4474a1dcbde5b6475e16d9e Mon Sep 17 00:00:00 2001 From: aa638 Date: Wed, 11 Mar 2026 10:45:40 +0100 Subject: [PATCH 1/6] Fix OpenShift deployment issues found during real cluster install - Use mirror.gcr.io for postgres:16 to avoid Docker Hub rate limits - Increase Knative operator install timeout from 5m to 10m (OpenShift takes longer due to SCC and admission webhook overhead) - Set gatewayName default to "public" in openshift-values.yaml and add comment explaining that an empty value causes HTTPRoute validation failure --- deploy/postgresql.yaml | 2 +- hack/openshift-values.yaml | 4 +++- justfile | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/deploy/postgresql.yaml b/deploy/postgresql.yaml index bc4f278..b1131c6 100644 --- a/deploy/postgresql.yaml +++ b/deploy/postgresql.yaml @@ -37,7 +37,7 @@ spec: spec: containers: - name: postgresql - image: docker.io/library/postgres:16 + image: mirror.gcr.io/library/postgres:16 ports: - containerPort: 5432 env: diff --git a/hack/openshift-values.yaml b/hack/openshift-values.yaml index aba36f7..39598eb 100644 --- a/hack/openshift-values.yaml +++ b/hack/openshift-values.yaml @@ -60,9 +60,11 @@ ingress: # Gateway API is used on OpenShift instead of standard Ingress. # Set gatewayName and gatewayNamespace to match your Envoy Gateway install. +# gatewayName is required -- leaving it empty will cause HTTPRoute validation to fail. +# Example: --set gateway.gatewayName=public --set gateway.hostname=kuberless.apps..example.com gateway: enabled: true - gatewayName: "" + gatewayName: "public" gatewayNamespace: envoy-gateway-system hostname: kuberless.example.com appsDomain: example.com diff --git a/justfile b/justfile index 71ca681..9132061 100644 --- a/justfile +++ b/justfile @@ -181,7 +181,7 @@ deploy-knative: --repo https://knative.github.io/operator knative-operator \ --version {{knative_op_ver}} \ --namespace knative-operator --create-namespace \ - --wait --timeout 5m + --wait --timeout 10m # Create namespace ahead of time so we can apply OpenShift SCC before Knative pods start kubectl create namespace knative-serving --dry-run=client -o yaml | kubectl apply -f - if [[ "{{openshift}}" == "true" ]]; then From d2767964a35db7ba527aac5df80232415feb9e97 Mon Sep 17 00:00:00 2001 From: aa638 Date: Wed, 11 Mar 2026 11:44:39 +0100 Subject: [PATCH 2/6] fix: login flowf --- cli/cmd/login.go | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/cli/cmd/login.go b/cli/cmd/login.go index 6a8f658..df30a3f 100644 --- a/cli/cmd/login.go +++ b/cli/cmd/login.go @@ -17,21 +17,26 @@ var loginCmd = &cobra.Command{ Use: "login", Short: "Authenticate with the kuberless platform", RunE: func(cmd *cobra.Command, args []string) error { - reader := bufio.NewReader(os.Stdin) - serverURL, _ := cmd.Flags().GetString("server") + username, _ := cmd.Flags().GetString("username") + password, _ := cmd.Flags().GetString("password") - fmt.Print("Username: ") - username, _ := reader.ReadString('\n') - username = strings.TrimSpace(username) + if username == "" { + reader := bufio.NewReader(os.Stdin) + fmt.Print("Username: ") + u, _ := reader.ReadString('\n') + username = strings.TrimSpace(u) + } - fmt.Print("Password: ") - passwordBytes, err := term.ReadPassword(int(os.Stdin.Fd())) - if err != nil { - return fmt.Errorf("reading password: %w", err) + if password == "" { + fmt.Print("Password: ") + passwordBytes, err := term.ReadPassword(int(os.Stdin.Fd())) + if err != nil { + return fmt.Errorf("reading password: %w", err) + } + fmt.Println() + password = string(passwordBytes) } - fmt.Println() - password := string(passwordBytes) cfg := &client.Config{ APIBaseURL: serverURL, @@ -69,4 +74,6 @@ var loginCmd = &cobra.Command{ func init() { loginCmd.Flags().String("server", "http://localhost:8080", "API server URL") + loginCmd.Flags().String("username", "", "Username (skips interactive prompt)") + loginCmd.Flags().String("password", "", "Password (skips interactive prompt)") } From 0953c2a5c6a4cba425bd118650560f9ed51093d6 Mon Sep 17 00:00:00 2001 From: aa638 Date: Wed, 11 Mar 2026 11:45:08 +0100 Subject: [PATCH 3/6] feat: add gatewayname value --- deploy/helm/kuberless/templates/httproute.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/helm/kuberless/templates/httproute.yaml b/deploy/helm/kuberless/templates/httproute.yaml index 186cf1e..0e89c7b 100644 --- a/deploy/helm/kuberless/templates/httproute.yaml +++ b/deploy/helm/kuberless/templates/httproute.yaml @@ -1,4 +1,4 @@ -{{- if .Values.gateway.enabled }} +{{- if and .Values.gateway.enabled .Values.gateway.gatewayName }} apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: From 06c83b564c68904f76787bfa8ff22bd711d8d1dd Mon Sep 17 00:00:00 2001 From: aa638 Date: Wed, 11 Mar 2026 14:03:26 +0100 Subject: [PATCH 4/6] Fix kind local dev and update README - Fix ko-build-local: use per-component KO_DOCKER_REPO so images are tagged as ko.local/operator:latest etc. instead of all overwriting ko.local:latest - Fix _patch-kourier-nodeport: Kourier service is in knative-serving namespace, not kourier-system - README: fix just env var syntax (HOST=... just recipe, not just recipe HOST=...) - README: add ko as kind prerequisite and document DOCKER_HOST for macOS - README: document OpenShift required params (HOST, gateway.gatewayName) - README: add sslip.io URL pattern for kind apps - README: simplify values example, add --server to login example --- README.md | 31 ++++++++++++++++++++----------- justfile | 10 +++++----- 2 files changed, 25 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index ed53662..aa5ec7c 100644 --- a/README.md +++ b/README.md @@ -15,13 +15,13 @@ Built as a learning project — no backup strategy, no monitoring, error handlin - Kubernetes cluster with [Cilium](https://docs.cilium.io/en/stable/gettingstarted/) >= 1.15 as CNI - [`just`](https://just.systems) task runner -- cert-manager, Knative Serving, Capsule, and PostgreSQL — installed separately via `just deploy-prereqs` +- cert-manager, Knative Serving, Capsule, and PostgreSQL — installed via `just deploy-prereqs` ## Install ```bash just deploy-prereqs -just deploy-kuberless HOST=kuberless.example.com ADMIN_PASSWORD=yourpassword +HOST=kuberless.example.com ADMIN_PASSWORD=yourpassword just deploy-kuberless ``` Or with helm directly: @@ -38,8 +38,6 @@ Minimal `my-values.yaml`: global: auth: adminLogin: - enabled: true - username: "admin" password: "yourpassword" ingress: @@ -64,18 +62,34 @@ just deploy-teardown-all # removes everything ### OpenShift +Requires [Envoy Gateway](https://gateway.envoyproxy.io/) installed on the cluster. Set `HOST` to your apps domain and `gateway.gatewayName` to match your Gateway resource. + ```bash -just openshift-deploy +HOST=kuberless.apps.mycluster.example.com \ + just openshift-deploy \ + -- --set gateway.gatewayName=public --set gateway.appsDomain=apps.mycluster.example.com + just openshift-teardown ``` +Or pass overrides via `hack/openshift-values.yaml` before running `just openshift-deploy`. + ## Local development (kind) +Requires [`ko`](https://ko.build) in addition to `just` and Docker. + +On macOS with Docker Desktop, set `DOCKER_HOST` so `ko` can reach the daemon: + ```bash +export DOCKER_HOST=unix://$HOME/.docker/run/docker.sock just kind-dev # one-shot: cluster + prereqs + images + deploy just kind-redeploy # rebuild and restart after code changes just kind-teardown +``` + +Apps are reachable at `http://-tenant-.127.0.0.1.sslip.io` once deployed. Port-forward to use the API and frontend locally: +```bash kubectl port-forward -n kuberless-system svc/kuberless-apiserver 8080:8080 kubectl port-forward -n kuberless-system svc/kuberless-frontend 3000:3000 ``` @@ -89,7 +103,7 @@ just lint ## CLI ```bash -kuberless login +kuberless login --server http://localhost:8080 kuberless tenant create my-org --plan starter kuberless deploy ghcr.io/myorg/myapp:latest --name myapp --port 8080 kuberless apps list @@ -99,11 +113,6 @@ kuberless domains add myapp api.example.com kuberless apps pause myapp ``` -## Tenant isolation - -Each tenant gets a namespace (`tenant-{name}`) with a Capsule Tenant, CiliumNetworkPolicy (cross-tenant traffic denied), and ResourceQuota: - -Plans: Free / Starter / Pro / Enterprise (see `api/v1alpha1/`). ## License diff --git a/justfile b/justfile index 9132061..d5185b1 100644 --- a/justfile +++ b/justfile @@ -101,9 +101,9 @@ run-frontend: # Build all Go images locally with ko (tagged :latest) ko-build-local: - KO_DOCKER_REPO=ko.local ko build ./operator --bare --platform={{platforms}} --tags=latest - KO_DOCKER_REPO=ko.local ko build ./apiserver --bare --platform={{platforms}} --tags=latest - KO_DOCKER_REPO=ko.local ko build ./cli --bare --platform={{platforms}} --tags=latest + KO_DOCKER_REPO=ko.local/operator ko build ./operator --bare --platform={{platforms}} --tags=latest + KO_DOCKER_REPO=ko.local/apiserver ko build ./apiserver --bare --platform={{platforms}} --tags=latest + KO_DOCKER_REPO=ko.local/cli ko build ./cli --bare --platform={{platforms}} --tags=latest # Build and push all Go images with ko (git SHA + latest tags) ko-build: @@ -336,9 +336,9 @@ _patch-kourier-nodeport: set -euo pipefail echo "Waiting for Kourier service..." for i in $(seq 1 30); do - if kubectl get svc kourier -n kourier-system &>/dev/null; then + if kubectl get svc kourier -n knative-serving &>/dev/null; then echo "Patching Kourier service with kind NodePort values..." - kubectl patch service kourier -n kourier-system \ + kubectl patch service kourier -n knative-serving \ --type merge \ --patch '{ "spec": { From e326ee6c8c05fdba4182721cd57af243be671b3f Mon Sep 17 00:00:00 2001 From: aa638 Date: Wed, 11 Mar 2026 14:13:25 +0100 Subject: [PATCH 5/6] Release CLI binaries for macOS and Linux Build native binaries for darwin/arm64, darwin/amd64, linux/arm64, linux/amd64 and attach them to GitHub releases. Add curl one-liner install instructions to release notes. --- .github/workflows/release.yml | 57 ++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index f7a8734..c146561 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -99,10 +99,50 @@ jobs: cache-from: type=gha,scope=frontend cache-to: type=gha,mode=max,scope=frontend + cli-binaries: + name: Build CLI binaries + runs-on: ubuntu-latest + permissions: + contents: read + strategy: + matrix: + include: + - goos: darwin + goarch: arm64 + - goos: darwin + goarch: amd64 + - goos: linux + goarch: arm64 + - goos: linux + goarch: amd64 + steps: + - name: Clone the code + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Setup Go + uses: actions/setup-go@7a3fe6cf4cb3a834922a1244abfce67bcef6a0c5 # v6.2.0 + with: + go-version-file: go.mod + cache: true + + - name: Build + env: + GOOS: ${{ matrix.goos }} + GOARCH: ${{ matrix.goarch }} + CGO_ENABLED: "0" + run: | + go build -trimpath -ldflags="-s -w" -o kuberless-${{ matrix.goos }}-${{ matrix.goarch }} ./cli + + - name: Upload artifact + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: kuberless-${{ matrix.goos }}-${{ matrix.goarch }} + path: kuberless-${{ matrix.goos }}-${{ matrix.goarch }} + github-release: name: GitHub Release runs-on: ubuntu-latest - needs: [go-images, frontend] + needs: [go-images, frontend, cli-binaries] permissions: contents: write steps: @@ -112,11 +152,26 @@ jobs: VERSION=${GITHUB_REF#refs/tags/} echo "version=${VERSION}" >> $GITHUB_OUTPUT + - name: Download CLI binaries + uses: actions/download-artifact@95815c38cf2ff2164869cbab79da8d1f422bc89e # v4.2.1 + with: + pattern: kuberless-* + merge-multiple: true + - name: Create GitHub Release uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2.5.0 with: generate_release_notes: true + files: kuberless-* body: | + ## Install CLI + + **macOS / Linux:** + ```bash + curl -fsSL https://github.com/${{ github.repository }}/releases/download/${{ steps.version.outputs.version }}/kuberless-$(uname -s | tr '[:upper:]' '[:lower:]')-$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/') -o /usr/local/bin/kuberless + chmod +x /usr/local/bin/kuberless + ``` + ## Container Images Multi-platform images (linux/amd64, linux/arm64) available at: From 743d181c25523fe0e4012d31849d5b8780ad3ef0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Mar 2026 13:14:34 +0000 Subject: [PATCH 6/6] deps: bump actions/upload-artifact from 4.5.0 to 7.0.0 Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4.5.0 to 7.0.0. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/6f51ac03b9356f520e9adb1b1b7802705f340c2b...bbbca2ddaa5d8feaa63e36b76fdaad77386f024f) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: 7.0.0 dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/build.yml | 2 +- .github/workflows/release.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f63dc60..6e0d16a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -35,7 +35,7 @@ jobs: run: go test $(go list ./... | grep -v /e2e | grep -v /operator/controller) -coverprofile cover.out - name: Upload coverage - uses: actions/upload-artifact@6f51ac03b9356f520e9adb1b1b7802705f340c2b # v4.5.0 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: coverage path: cover.out diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c146561..e370308 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -134,7 +134,7 @@ jobs: go build -trimpath -ldflags="-s -w" -o kuberless-${{ matrix.goos }}-${{ matrix.goarch }} ./cli - name: Upload artifact - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: kuberless-${{ matrix.goos }}-${{ matrix.goarch }} path: kuberless-${{ matrix.goos }}-${{ matrix.goarch }}