A Kubernetes operator for managing middleware updates for serverless functions deployed with the func CLI. This operator monitors deployed functions and automatically rebuilds them when outdated middleware is detected, ensuring functions stay up-to-date with the latest middleware versions.
- Kubernetes cluster (1.31+)
- Knative Serving installed
- Tekton Pipelines installed
- Container registry for storing function images
Deploy the operator to your cluster:
kubectl apply -f https://github.com/functions-dev/func-operator/releases/latest/download/func-operator.yamlCreate a Function custom resource to register an existing function for middleware monitoring and updates:
apiVersion: functions.dev/v1alpha1
kind: Function
metadata:
name: my-function
namespace: default
spec:
repository:
url: https://github.com/your-org/your-function.git
authSecretRef:
name: git-credentials
registry:
authSecretRef:
name: registry-credentialsApply the resource:
kubectl apply -f function.yamlNote: This registers an existing function with the operator for middleware management. To initially deploy a function, use the func CLI directly:
func deploy --path <function-path> --registry <registry-path>For private registries, create a secret with registry credentials:
apiVersion: v1
kind: Secret
metadata:
name: registry-credentials
namespace: default
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: <base64-encoded-docker-config>Or use kubectl:
kubectl create secret docker-registry registry-credentials \
--docker-server=<registry-url> \
--docker-username=<username> \
--docker-password=<password> \
--docker-email=<email>For private Git repositories, create a secret with the Git credentials:
apiVersion: v1
kind: Secret
metadata:
name: git-credentials
namespace: default
data:
token: <base64-encoded-access-token>or
apiVersion: v1
kind: Secret
metadata:
name: git-credentials
namespace: default
data:
username: <base64-encoded-username>
password: <base64-encoded-password>Then reference it in the Function under .spec.repository.authSecretRef.name
apiVersion: functions.dev/v1alpha1
kind: Function
metadata:
name: my-function
namespace: default
spec:
repository:
url: https://github.com/your-org/your-function.git
authSecretRef:
name: git-credentialsView the middleware status of your function:
kubectl get function my-function -o yamlThe status will include:
- Function name and runtime
- Middleware update conditions
- Whether the function needs rebuilding due to outdated middleware
For functions located in a subdirectory of a repository (e.g., in a monorepo), use the repository.path field to specify the path to your function:
apiVersion: functions.dev/v1alpha1
kind: Function
metadata:
name: my-function
namespace: default
spec:
repository:
url: https://github.com/your-org/your-monorepo.git
path: functions/my-function
authSecretRef:
name: git-credentials
registry:
authSecretRef:
name: registry-credentialsThe operator will clone the repository and use the specified path as the function root directory.
The operators main responsibility it to rebuild functions when outdated middleware is detected. Anyhow this behavior can be enabled/disabled at two levels:
Configure the operator-wide default by editing the func-operator-controller-config ConfigMap in the operators namespace (func-operator-system by default):
apiVersion: v1
kind: ConfigMap
metadata:
name: func-operator-controller-config
namespace: func-operator-system
data:
autoUpdateMiddleware: "true" # or "false" to disable by defaultIndividual functions can override the operator default using the autoUpdateMiddleware field:
apiVersion: functions.dev/v1alpha1
kind: Function
metadata:
name: my-function
namespace: default
spec:
repository:
url: https://github.com/your-org/your-function.git
autoUpdateMiddleware: false # Disable middleware updates for this functionPrecedence: Function-level settings always take priority over the operator default.
For local development, you can use the provided script to set up a Kind cluster with all prerequisites:
./hack/create-kind-cluster.shThis script will:
- Create a local Kind cluster with multiple worker nodes
- Set up a local container registry on
localhost:5001 - Install Tekton Pipelines
- Install Knative Serving with Kourier
- Configure the cluster to use the local registry
make docker-build IMG=<your-registry>/func-operator:latest
make deploy IMG=<your-registry>/func-operator:latestFor debugging the operator with Delve, use the debug targets:
# Build the debug image (includes Delve debugger and debug symbols)
make docker-build-debugger IMAGE_TAG_BASE=<your-registry>/func-operator
# Push the debug image
make docker-push-debugger IMAGE_TAG_BASE=<your-registry>/func-operator
# Deploy the operator in debug mode
make deploy-debugger IMAGE_TAG_BASE=<your-registry>/func-operatorThe debug deployment runs the operator under Delve in headless mode, listening on port 40000. To connect your debugger:
# Port-forward to access the debugger
kubectl port-forward -n func-operator-system deployment/func-operator-controller-manager 40000:40000
# Connect with Delve CLI
dlv connect localhost:40000You can also connect using your IDE's remote debugging features (VS Code, GoLand, etc.) by configuring it to connect to localhost:40000.
# Unit tests
make test
# E2E tests (requires Kind cluster with Gitea)
make create-kind-cluster # Sets up cluster with Gitea
make test-e2e
# Bundle tests
make test-e2e-bundleE2E tests use an in-cluster Gitea instance instead of GitHub, providing complete test isolation. See Gitea Integration for details on the test infrastructure.
# Run linter
make lint| Field | Type | Required | Description |
|---|---|---|---|
repository.url |
string | Yes | URL of the Git repository containing the function |
repository.branch |
string | No | Branch of the repository |
repository.path |
string | No | Path to the function inside the repository. Defaults to "." |
repository.authSecretRef |
object | No | Reference to the auth secret for private repository authentication |
registry.authSecretRef |
object | No | Reference to the secret containing credentials for registry authentication |
autoUpdateMiddleware |
boolean | No | Defines if the operator should rebuild when outdated middleware is detected. When not specified, defaults to the operator-wide setting in the func-operator-controller-config ConfigMap (default: true). Function-level setting takes precedence over operator default |
| Field | Type | Description |
|---|---|---|
name |
string | Function name from metadata |
runtime |
string | Detected function runtime |
conditions |
array | Status conditions |
Remove the operator and CRDs:
# Undeploy operator
make undeploy
# Uninstall CRDs
make uninstall