Skip to main content

Kubernetes and Crossplane

The Kubernetes library turns any registered Go API type into a Graphene resource: initialize applies and waits, reconcile heals drift, finalize deletes. Crossplane resources use the same mechanism; the provider and credentials belong to the user's cluster.

Client and types​

client := k8slib.NewClientFromSecret(
pipeline.Secret(ctx, "kubeconfig"),
k8slib.WithScheme(providerapis.AddToScheme),
)

The kubeconfig resolves from the secret only inside the run worker. Built-in Kubernetes types are registered by default; WithScheme adds CRDs from their native Go packages.

Declare a resource​

network := k8slib.Resource(ctx, client, "net", &vpc.Network{
Spec: vpc.NetworkSpec{ForProvider: vpc.NetworkParameters{
FolderID: &params.FolderId,
}},
},
k8slib.WithReady(func(live *vpc.Network) bool {
return live.Status.GetCondition(xpv1.TypeReady).Status == corev1.ConditionTrue
}),
k8slib.WithTimeout[vpc.Network](30*time.Minute),
k8slib.WithResourceOption[vpc.Network](pipeline.WithLabels(labels)),
)

The name argument becomes both record id and metadata.name; a conflicting name on the object is rejected. Ready returns the live typed object, including status written by the cluster or provider.

Options​

OptionDefaultContract
WithReady(fn)kstatus/Ready-condition conventiondecide readiness from the live object
WithDrifted(fn)only disappearance is driftdecide whether to reapply desired state
WithValidate(fn)nonereject desired state before activity execution
WithReconcileEvery(d)30sdrift-check period
WithPollInterval(d)5sreadiness polling period
WithTimeout(d)20mmaximum convergence wait
WithFailed(fn)nonea non-nil error ends the declaration at once — broken for good
WithResourceOption(...)run ownershipparent, children, labels and flows

The first declaration of a Go kind fixes its handlers for that worker. Keep the same options for subsequent instances.

Crossplane managed resources often have no conditions immediately after apply; provide WithReady for the provider's real readiness signal.

What the controller says reaches a person while the object converges: each change of status.conditions is a conditions event of the record and a log line — a warning when a condition is False with a reason, for example Synced=False (ReconcileError: Quota limit compute.ssdDisks.size exceeded). A declaration that fails — the timeout, or WithFailed returning an error on an observation — carries the last observed conditions in its error and is not retried: declaring again would create the object anew and wait out the same refusal. A failed declaration takes its object out of the cluster before its record closes, and waits up to ten minutes for it to be gone: a controller left with the object would finish creating it once the cloud allowed — a network refused for quota appearing an hour later, with nothing to delete it. An object that does not go away in time is said on the record: a warning and an orphaned event. Use WithFailed for refusals that will not change, such as quota or permission. The apply and observe calls of a converging object give up after ten failed attempts in a row. Prefer native reference fields between Kubernetes objects: the cluster resolves them without moving generated ids through workflow history.

The current project has unit coverage for the library but no shipped live-kind cluster conformance suite. Treat provider behavior as part of your pipeline's tested contract.

Local tests​

See Local tests for fixtures, dependency adapters and pipeline assertions.

Installation cluster​

k8slib.NewClientInCluster(opts...) explicitly selects the run worker's projected ServiceAccount credentials. Configure serviceAccountName and RBAC in the installation's managed.pod_template. Only grant this identity to trusted pipeline workers. A missing or invalid NewClientFromSecret credential never falls back to the installation identity. The selected connection is retained for reconciliation and deletion, including deletion after a failed initialization.

For externally owned configuration with its own explicit lifecycle, an activity may use client.ObjectClient(ctx, object) to obtain the native Kubernetes resource interface. This does not create a Graphene entity or automatic cleanup. Use Resource for run-owned objects. Resolve secrets within the activity and never include their contents in workflow inputs, activity results or logs.