Help us shape the future of Go! Take the 2026 Go Developer Survey

kubernetes

package
v0.2.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 1, 2026 License: MIT Imports: 18 Imported by: 0

Documentation

Overview

Package kubernetes projects a parsed devcontainer.json (plus its resolved features) into the Kubernetes API objects that would launch the same container on a cluster.

The package is pure: no client-go, no apiserver round-trips. Project returns a *corev1.Pod (and any ancillary objects) so the caller — an operator's controller, a CLI's render command, an admission webhook — can decide how to apply, validate, or serialize them.

The translation mirrors the field mapping that pkg/host/docker performs against the docker engine API. Where docker has a single flat HostConfig, Kubernetes splits the same surface across PodSpec, SecurityContext, Resources, and Volumes — Project handles the re-shaping and rejects fields that don't have a clean Kubernetes equivalent rather than silently dropping them.

Embedding

pj, err := kubernetes.Project(kubernetes.ProjectRequest{
    Spec:           dc,
    SpecPath:       dc.Path,
    LocalWorkspace: workspace,
    Image:          "registry.example.com/devbox:1.2.3",
    Name:           "alice-devbox",
    Namespace:      "dev",
})
// apply pj.Pod with controller-runtime, kubectl apply -f, etc.

Lifecycle commands

Project does not embed onCreate/postCreate/postStart/postAttach into initContainers or lifecycle hooks: those phases need the running container's userspace state (features installed by previous phases, the workspace bind contents) and can't be modeled as static manifest fields. The imperative pkg/host/kubernetes execs them after the pod reaches Ready, the same shape pkg/host/docker uses today.

Index

Constants

View Source
const (
	AnnotationComposeProject = "devcontainer.compose.project"
	AnnotationComposeService = "devcontainer.compose.service"
)

AnnotationComposeProject and AnnotationComposeService record which compose project/primary-service produced the Pod. Useful for an operator that wants to correlate a Pod back to the source spec without re-parsing.

View Source
const (
	AnnotationLocalFolder = "devcontainer.local_folder"
	AnnotationConfigFile  = "devcontainer.config_file"
)

Annotations written onto the projected Pod so upstream tooling (and pkg/host/kubernetes) can reverse-look-up which devcontainer / workspace produced the pod. Keys mirror the docker host labels exactly — see pkg/host/docker.LabelLocalFolder / LabelConfigFile — but live on annotations rather than labels because path values aren't valid Kubernetes label values.

View Source
const DefaultContainerName = "devcontainer"

DefaultContainerName is the container name used when the request doesn't supply one.

Variables

View Source
var DefaultComposeVolumeStorage = resource.MustParse("1Gi")

DefaultComposeVolumeStorage is the storage request applied to PVCs generated for compose named volumes when the request doesn't set one. Small enough that a 1Gi-default storage class is happy; large enough that a basic devcontainer workflow has somewhere to write.

Functions

func EncodeYAMLDocuments

func EncodeYAMLDocuments(objects []runtime.Object) ([]byte, error)

EncodeYAMLDocuments serializes Kubernetes objects as multi-document YAML.

Types

type ComposeProjectRequest

type ComposeProjectRequest struct {
	// Spec is the parsed devcontainer.json (must be in compose mode).
	Spec *spec.DevContainer

	// SpecPath is the host path the spec was loaded from. Stored as
	// AnnotationConfigFile.
	SpecPath string

	// LocalWorkspace is the host workspace path. Stored as
	// AnnotationLocalFolder and used as the default workspace
	// HostPath source.
	LocalWorkspace string

	// ContainerWorkspace is where the workspace mounts inside the
	// primary container. Falls back to spec.WorkspaceFolder, then
	// "/workspaces/<basename>".
	ContainerWorkspace string

	// Project is the parsed compose project. Required.
	Project *composetypes.Project

	// PrimaryImage, when non-empty, replaces the primary service's
	// compose `image:`. Used to point the Pod at a feature-derived
	// image produced by pkg/host/dockercompose.BuildPrimaryImage.
	PrimaryImage string

	// Features as resolved by pkg/features. Their containerEnv,
	// init/privileged/capAdd/securityOpt, and mounts merge into the
	// primary container only — sidecar services don't see them.
	Features []features.Resolved

	// Name and Namespace seed metadata.
	Name      string
	Namespace string

	// Labels and Annotations seed metadata.
	Labels      map[string]string
	Annotations map[string]string

	// WorkspaceVolumeSource overrides the workspace volume source.
	// When nil, falls back to a HostPath sourced from LocalWorkspace
	// (matching the single-container projection's default).
	WorkspaceVolumeSource *corev1.VolumeSource

	// VolumeStorageClass is set on PVCs generated for compose named
	// volumes. Empty means the cluster's default storage class.
	VolumeStorageClass string

	// VolumeStorageRequest is the per-PVC storage request. Defaults
	// to DefaultComposeVolumeStorage when zero.
	VolumeStorageRequest resource.Quantity

	// Profiles activates compose service profiles. Services whose
	// `profiles:` list is non-empty are excluded from the projected
	// Pod unless one of their entries matches Profiles (or Profiles
	// contains "*"). The primary service stays enabled regardless.
	Profiles []string

	// LocalEnv is the lookup table for compose `secrets:` /
	// `configs:` declared with `environment:` source. Materializing
	// happens at projection time, so the env variable's value is
	// baked into the resulting Secret/ConfigMap.
	LocalEnv map[string]string
}

ComposeProjectRequest captures the inputs needed to render a compose-mode devcontainer into a single multi-container Pod plus any backing PVCs.

The shape mirrors ProjectRequest where it can — Spec, Image override, Features, metadata, workspace — and adds compose-specific inputs: the parsed *types.Project (use pkg/host/dockercompose.LoadProject to produce it) and the storage knobs for named-volume PVCs.

type ComposeProjection

type ComposeProjection struct {
	Pod                    *corev1.Pod
	PersistentVolumeClaims []*corev1.PersistentVolumeClaim
	ConfigMaps             []*corev1.ConfigMap
	Secrets                []*corev1.Secret
}

ComposeProjection bundles the rendered Pod with any PVCs, Secrets, and ConfigMaps that need to exist for the Pod's volume references to resolve. The caller applies them in order (PVCs/ConfigMaps/ Secrets first, then the Pod).

func ProjectCompose

func ProjectCompose(req ComposeProjectRequest) (*ComposeProjection, error)

ProjectCompose translates a compose-mode devcontainer into a single multi-container Pod (sidecar model) plus PVCs for any compose named volumes.

Scope cuts in this iteration (mirroring pkg/host/dockercompose so behavior stays consistent across hosts):

  • depends_on: containers in a Pod can't be ordered through the compose model; compose `depends_on` is ignored.
  • watch / develop: file-watch loops aren't a static manifest concept and aren't honored by the projection. The imperative pkg/host/dockercompose host has Watch() for that.
  • Compose-side `build:` for any service (including the primary): not built. Each service must reference a pullable `image:`.
  • tmpfs/image/cluster volume types: tmpfs translates to EmptyDir(memory); image and cluster types return an error.

Profiles, configs, secrets, and service-name DNS are honored:

  • Profiles narrow the projected Pod to services whose `profiles:` match `req.Profiles` (with "*" as a wildcard). The primary stays enabled regardless.
  • Configs become ConfigMaps (or external references) and are mounted at `/<source>` by default.
  • Secrets become Secrets (or external references) and are mounted at `/run/secrets/<source>` by default.
  • Service-name DNS works inside the Pod via pod.spec.hostAliases: each compose service name (and any compose network alias) is mapped to 127.0.0.1, where its container is actually listening since all containers in a Pod share the network namespace. So `db:5432` resolves the same way it would on a compose user-defined network.

func (*ComposeProjection) Objects

func (p *ComposeProjection) Objects() []runtime.Object

Objects returns the Kubernetes resources needed for a compose projection, in creation order.

type ProjectRequest

type ProjectRequest struct {
	// Spec is the parsed devcontainer.json. Required.
	Spec *spec.DevContainer

	// SpecPath is the host-side path the spec was loaded from. When
	// non-empty it's stored in the AnnotationConfigFile annotation so
	// downstream tooling can reverse-look-up the source file.
	SpecPath string

	// LocalWorkspace is the host-side workspace folder (absolute). When
	// non-empty it's stored in AnnotationLocalFolder and used as the
	// default HostPath source for the workspace volume.
	LocalWorkspace string

	// ContainerWorkspace is the path inside the container where the
	// workspace is mounted. Falls back to spec.WorkspaceFolder, then
	// "/workspaces/<basename>".
	ContainerWorkspace string

	// Image is the already-built container image reference.
	Image string

	// Features as resolved by pkg/features. Their containerEnv,
	// init/privileged/capAdd/securityOpt, and mounts merge into the
	// pod the same way the docker host merges them.
	Features []features.Resolved

	// Name is the metadata.name written onto the projected Pod. May be
	// empty — the caller can fill it in or use generateName.
	Name string

	// Namespace is metadata.namespace. May be empty.
	Namespace string

	// ContainerName overrides the container's name. Defaults to
	// DefaultContainerName.
	ContainerName string

	// Labels and Annotations are seeded onto metadata. The package adds
	// AnnotationLocalFolder and AnnotationConfigFile on top.
	Labels      map[string]string
	Annotations map[string]string

	// WorkspaceVolumeSource overrides the default workspace volume.
	// When nil, a HostPath sourced from LocalWorkspace is used — a fit
	// for single-node clusters (kind, minikube, docker-desktop) where
	// the host workspace is reachable from the kubelet. Set to a
	// PersistentVolumeClaim or other source for remote clusters.
	WorkspaceVolumeSource *corev1.VolumeSource
}

ProjectRequest captures the inputs needed to render a devcontainer into Kubernetes objects. The caller is responsible for building the image (use pkg/builder) and resolving features (use pkg/features); on Kubernetes there's no equivalent of the docker host's host-side variable substitution loop, so any ${localEnv:VAR} / ${devcontainerId} references in the spec should already be resolved before Project is called (the substitute package can do this).

type Projection

type Projection struct {
	Pod *corev1.Pod
}

Projection is the rendered Kubernetes object set. Today only Pod is populated; future fields (Service for forwardPorts, PVC for the workspace) will be additive.

func Project

func Project(req ProjectRequest) (*Projection, error)

Project translates a devcontainer spec into Kubernetes manifests.

It rejects with an error any spec field or runArg that has no clean Kubernetes equivalent (e.g. --network, --gpus device IDs, named docker volumes), rather than silently dropping it: a missing --cap-add or --userns flag changes the container's security model. Embedders that want the request to succeed regardless can strip the offending fields before calling.

func (*Projection) Objects

func (p *Projection) Objects() []runtime.Object

Objects returns the Kubernetes resources needed for a single-container projection, in creation order.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL