This guide walks through deploying function-starlark to a staging Kubernetes cluster for end-to-end validation (QUAL-04). It covers building, installing, and verifying the function with the example XBucket composition.
- Kubernetes cluster (v1.28+) with kubectl access
- Crossplane installed (v1.17+)
- Docker for building the function image
- A container registry accessible from the cluster (e.g., GHCR, ECR, Docker Hub)
Verify Crossplane is running:
kubectl get pods -n crossplane-system
# NAME READY STATUS RESTARTS AGE
# crossplane-xxxxxxxxxx-xxxxx 1/1 Running 0 5m
# crossplane-rbac-manager-xxxxxxxxxx-xxxxx 1/1 Running 0 5m# Build the image
make build
# Tag for your registry
docker tag runtime ghcr.io/YOUR_ORG/function-starlark:v0.1.0
# Push
docker push ghcr.io/YOUR_ORG/function-starlark:v0.1.0Alternatively, build a Crossplane package:
make xpkg
# Produces function-starlark.xpkgOption A: Direct image reference
apiVersion: pkg.crossplane.io/v1beta1
kind: Function
metadata:
name: function-starlark
spec:
package: ghcr.io/YOUR_ORG/function-starlark:v0.1.0kubectl apply -f - <<EOF
apiVersion: pkg.crossplane.io/v1beta1
kind: Function
metadata:
name: function-starlark
spec:
package: ghcr.io/YOUR_ORG/function-starlark:v0.1.0
EOFOption B: Crossplane package
# Push the package to a registry
crossplane xpkg push ghcr.io/YOUR_ORG/function-starlark:v0.1.0 \
-f function-starlark.xpkg
# Install via Function resource
kubectl apply -f - <<EOF
apiVersion: pkg.crossplane.io/v1beta1
kind: Function
metadata:
name: function-starlark
spec:
package: ghcr.io/YOUR_ORG/function-starlark:v0.1.0
EOFVerify the function is installed and healthy:
kubectl get functions
# NAME INSTALLED HEALTHY PACKAGE AGE
# function-starlark True True ghcr.io/YOUR_ORG/function-starlark:v0.1.0 30sIf using ConfigMap-mounted scripts instead of inline source, create a DeploymentRuntimeConfig to mount the ConfigMap:
apiVersion: pkg.crossplane.io/v1beta1
kind: DeploymentRuntimeConfig
metadata:
name: function-starlark-scripts
spec:
deploymentTemplate:
spec:
template:
spec:
containers:
- name: package-runtime
volumeMounts:
- name: scripts
mountPath: /scripts/my-scripts
readOnly: true
volumes:
- name: scripts
configMap:
name: my-scriptsThen reference it in the Function:
apiVersion: pkg.crossplane.io/v1beta1
kind: Function
metadata:
name: function-starlark
spec:
package: ghcr.io/YOUR_ORG/function-starlark:v0.1.0
runtimeConfigRef:
name: function-starlark-scriptsFor inline scripts (the common case), skip this step.
Apply the example XBucket XRD:
kubectl apply -f - <<EOF
apiVersion: apiextensions.crossplane.io/v1
kind: CompositeResourceDefinition
metadata:
name: xbuckets.example.crossplane.io
spec:
group: example.crossplane.io
names:
kind: XBucket
plural: xbuckets
claimNames:
kind: Bucket
plural: buckets
versions:
- name: v1
served: true
referenceable: true
schema:
openAPIV3Schema:
type: object
properties:
spec:
type: object
properties:
region:
type: string
description: AWS region for the buckets
environment:
type: string
description: Deployment environment (dev, staging, prod)
enum: [dev, staging, prod]
required: [region, environment]
status:
type: object
properties:
bucketCount:
type: integer
region:
type: string
environment:
type: string
EOFApply the example Composition:
kubectl apply -f example/composition.yamlVerify:
kubectl get compositions
# NAME READY COMPOSITION-SCHEMA-AWARE AGE
# xbuckets.example.crossplane.io True True 10s
kubectl get xrds
# NAME ESTABLISHED OFFERED AGE
# xbuckets.example.crossplane.io True True 10skubectl apply -f - <<EOF
apiVersion: example.crossplane.io/v1
kind: XBucket
metadata:
name: test-xbucket
spec:
region: us-east-1
environment: prod
EOFCheck that the XBucket is created and resources are composed:
# Check XR status
kubectl get xbucket test-xbucket -o yaml
# Check composed resources
kubectl get managed -l crossplane.io/composite=test-xbucketExpected resources (10 total):
- 8 S3 Bucket resources (bucket-0 through bucket-7)
- 1 monitoring Dashboard (prod-only)
- 1 SNS Topic
Check conditions:
kubectl get xbucket test-xbucket -o jsonpath='{.status.conditions}' | jq .Expected condition:
[
{
"type": "Ready",
"status": "True",
"reason": "Available",
"message": "All 10 resources created in us-east-1"
}
]Check events:
kubectl get events --field-selector involvedObject.name=test-xbucketkubectl get xbucket test-xbucket -o jsonpath='{.status}' | jq .Expected:
{
"bucketCount": 8,
"region": "us-east-1",
"environment": "prod"
}kubectl delete xbucket test-xbucket
kubectl delete composition xbuckets.example.crossplane.io
kubectl delete xrd xbuckets.example.crossplane.io
kubectl delete function function-starlarkkubectl describe function function-starlark
kubectl logs -n crossplane-system -l pkg.crossplane.io/function=function-starlarkCommon causes:
- Image not accessible from the cluster (check registry credentials)
- Image architecture mismatch (build for linux/amd64 if cluster runs on amd64)
# Check function logs
kubectl logs -n crossplane-system -l pkg.crossplane.io/function=function-starlark
# Check events on the XR
kubectl describe xbucket test-xbucketCommon causes:
- Starlark script syntax error (check function logs for stack trace)
- Missing spec fields in the XR (the script uses
get()with defaults)
# Verify ConfigMap exists
kubectl get configmap my-scripts -o yaml
# Verify DeploymentRuntimeConfig is applied
kubectl get deploymentruntimeconfig function-starlark-scripts -o yaml
# Check pod volume mounts
kubectl get pods -n crossplane-system -l pkg.crossplane.io/function=function-starlark \
-o jsonpath='{.items[0].spec.containers[0].volumeMounts}' | jq .Common causes:
- ConfigMap not in the crossplane-system namespace
- Volume mount path does not match expected
/scripts/{configmap-name}/{key} - DeploymentRuntimeConfig not referenced in Function spec
Before deploying to a cluster, validate locally:
make render
# Or for regression checking:
make render-checkThis builds the Docker image and runs crossplane render against the example
fixtures without requiring a Kubernetes cluster.