Install
This document applies to the Modelplane main branch and not to the latest release v0.4.
Modelplane’s control plane is where everything runs: the Crossplane runtime, the providers it provisions infrastructure through, and the composition functions that reconcile the Modelplane APIs. You install it on a Kubernetes cluster that becomes the control cluster for your inference fleet.
The control cluster runs Modelplane itself, not model workloads, so it needs no GPUs.
Requirements
- A maintained Kubernetes version. Any release the Kubernetes project still supports works. Modelplane doesn’t pin the control cluster’s Kubernetes version.
- Helm and kubectl , to install Modelplane and reach the cluster.
- Room for Modelplane’s components. At rest they use a fraction of a CPU core and around 1.5 GiB of memory, split across Crossplane, its providers, and the composition functions. This grows as Modelplane provisions clusters and more providers activate, so give the control cluster a few GiB of headroom beyond what your Kubernetes distribution needs.
You can run the control plane anywhere. To try it locally, create a kind cluster:
# Pin to kind v0.30.0 default image (containerd 2.1.4)
# kind v0.31+ ships containerd 2.2.0 which breaks Modelplane
kind create cluster --name modelplane \
--image kindest/node:v1.34.0@sha256:7416a61b42b1662ca6ca89f02028ac133a309a2a30ba309614e8ec94d976dc5aGive your container engine room for it. On Docker Desktop, raise the memory limit to 8 GB (see the Docker documentation ).
Install Crossplane
Crossplane provides Modelplane’s reconciliation engine and package management. Modelplane needs Crossplane v2.3 or newer. Install it with Helm:
helm repo add crossplane-stable https://charts.crossplane.io/stable
helm repo update crossplane-stable
helm install crossplane crossplane-stable/crossplane \
--namespace crossplane-system --create-namespace \
--set "args={--enable-dependency-version-upgrades}" \
--set-json 'provider.defaultActivations=[]' \
--waitApply the bootstrap resources. They grant Crossplane the permissions it needs to manage your cluster:
kubectl apply -f https://docs.modelplane.ai/examples/install/prerequisites.yaml# Modelplane prerequisites. Apply once after installing Crossplane.
#
# These resources grant Crossplane and provider-helm the permissions
# Modelplane's compositions need, and configure provider-helm and
# provider-kubernetes. They cannot be self-composed because Crossplane
# needs the permissions before it can compose anything.
---
apiVersion: v1
kind: Namespace
metadata:
name: modelplane-system
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: crossplane-compose-modelplane
labels:
rbac.crossplane.io/aggregate-to-crossplane: "true"
rules:
- apiGroups: [""]
resources: ["namespaces"]
verbs: ["*"]
# Usages, which order teardown between composed resources. Everything else
# Modelplane composes lands on a workload cluster inside a provider-kubernetes
# Object or a provider-helm Release, so it needs no permission here: the
# providers carry their own, and reach the cluster with its kubeconfig.
- apiGroups: ["protection.crossplane.io"]
resources: ["usages"]
verbs: ["*"]
---
# Give provider-helm a deterministic SA name so we can grant it
# permissions. Without this, the SA name has a random hash.
apiVersion: pkg.crossplane.io/v1beta1
kind: DeploymentRuntimeConfig
metadata:
name: provider-helm-modelplane
spec:
serviceAccountTemplate:
metadata:
name: provider-helm-modelplane
---
# Grant provider-helm cluster-admin. It installs full Helm charts
# (MetalLB, Envoy Gateway, LeaderWorkerSet, Grove, etc.) that create arbitrary
# resource types across namespaces.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: provider-helm-modelplane
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-admin
subjects:
- kind: ServiceAccount
name: provider-helm-modelplane
namespace: crossplane-system
---
# Apply the DRC to provider-helm automatically via ImageConfig.
apiVersion: pkg.crossplane.io/v1beta1
kind: ImageConfig
metadata:
name: provider-helm-modelplane
spec:
matchImages:
- type: Prefix
prefix: xpkg.upbound.io/upbound/provider-helm
runtime:
configRef:
name: provider-helm-modelplane
---
# Stop provider-kubernetes copying Secret data into Object status.
#
# It writes an observed object's whole manifest to status.atProvider.manifest,
# so for an Object whose manifest is a Secret, that Secret's data is readable by
# anyone who can get objects, which is a wider audience than can get secrets.
# Modelplane composes Secrets holding caller API keys and serving certificate
# private keys, so this redacts them.
#
# Redaction applies to a copy used only for status. Drift detection still reads
# the unredacted object, so this doesn't cause an Object to be perpetually out
# of date.
apiVersion: pkg.crossplane.io/v1beta1
kind: DeploymentRuntimeConfig
metadata:
name: provider-kubernetes-modelplane
spec:
deploymentTemplate:
spec:
selector: {}
template:
spec:
containers:
- name: package-runtime
args:
- --sanitize-secrets
---
apiVersion: pkg.crossplane.io/v1beta1
kind: ImageConfig
metadata:
name: provider-kubernetes-modelplane
spec:
matchImages:
- type: Prefix
prefix: xpkg.upbound.io/upbound/provider-kubernetes
runtime:
configRef:
name: provider-kubernetes-modelplane
Install Modelplane
The Modelplane Configuration adds the Modelplane APIs and the composition functions that reconcile them:
# The Modelplane Crossplane Configuration. Installing it adds the Modelplane
# APIs (InferenceGateway, InferenceClass, InferenceCluster, ModelDeployment,
# ModelCache, ModelService) and the composition functions that reconcile them.
apiVersion: pkg.crossplane.io/v1
kind: Configuration
metadata:
name: modelplane
spec:
package: xpkg.upbound.io/modelplane/modelplane:v0.3.1
Wait until the configuration is healthy:
kubectl wait configuration/modelplane --for=condition=Healthy --timeout=5mNext step
With the control plane running, take the tour to provision a GPU cluster and serve a model, or register a cluster you already run.