CRD Reference
All resources are cluster-scoped under drop.corewire.io/v1alpha1.
Quick Example
apiVersion: drop.corewire.io/v1alpha1
kind: CachedImage
metadata:
name: nginx
spec:
image: docker.io/library/nginx
tag: latest
nodeSelector:
kubernetes.io/arch: amd64CachedImage
CachedImage ensures a single container image is pre-cached on cluster nodes.
Controller: internal/controller/cachedimage_controller.go
Spec
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
image | string | Yes | — | Image is the fully qualified image reference without tag or digest. Example: “docker.io/library/nginx”, “registry.example.com/team/app” |
tag | string | No | — | Tag to pull. Mutually exclusive with Digest. Example: “1.25-alpine”, “v2.4.1”, “latest” |
digest | string | No | — | Digest to pull as an immutable reference. Mutually exclusive with Tag. Use this for reproducible deployments where the exact image layer matters. Example: “sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4” |
imagePullPolicy | corev1.PullPolicy | No | Always | ImagePullPolicy controls when kubelet pulls the image on each node. - Always (default): check the registry for a newer digest even if the tag exists locally. - IfNotPresent: skip the registry check when the tag already exists on the node. - Never: never pull (only useful for pre-loaded images). (Always | IfNotPresent | Never) |
imagePullSecrets | []corev1.LocalObjectReference | No | — | ImagePullSecrets are references to Secrets in the namespace where Drop creates pull Pods. The default namespace is “drop-system” unless the controller is started with a different –pod-namespace. The Secret must contain a .dockerconfigjson key. Example: [{name: “ghcr-creds”}, {name: “ecr-creds”}] |
nodeSelector | map[string]string | No | — | NodeSelector restricts which nodes to cache the image on. Only nodes matching ALL key-value pairs will be targeted. Example: {“node-role.kubernetes.io/build”: “true”} |
tolerations | []corev1.Toleration | No | — | Tolerations allow the pull pod to be scheduled on tainted nodes. Example: [{key: “node-role.kubernetes.io/build”, operator: “Exists”, effect: “NoSchedule”}] |
priority | *int32 | No | — | Priority is a pull ordering hint. Lower values are pulled first. Images with the same priority are pulled in alphabetical order. Default: 0 (no priority). Example: 10 (low priority), -10 (high priority) |
policyRef | *PolicyReference | No | — | PolicyRef references a PullPolicy resource that controls pacing (concurrency, backoff, delays). If unset, the operator uses built-in defaults (1 concurrent node, 10s delay, 30s initial backoff). Example: {name: “conservative”} |
Status
| Field | Type | Description |
|---|---|---|
observedGeneration | int64 | ObservedGeneration is the last generation reconciled. |
phase | string | Phase summarizes the overall state. |
ready | string | Ready is a human-readable “nodesReady/nodesTargeted” fraction for display. |
resolvedDigest | string | ResolvedDigest is the sha256 digest of the image as reported by the container runtime after pull. |
nodesTargeted | int32 | NodesTargeted is the number of nodes that should have this image. |
nodesReady | int32 | NodesReady is the number of nodes that have successfully pulled the image. |
nodesPulling | int32 | NodesPulling is the number of nodes currently pulling the image. |
cachedNodes | []string | CachedNodes is the list of node names that have successfully cached the image. |
consecutiveFailures | int32 | ConsecutiveFailures counts sequential reconcile failures for backoff calculation. |
lastPulledAt | *metav1.Time | LastPulledAt is the timestamp of the most recent successful pull. |
lastAttemptedAt | *metav1.Time | LastAttemptedAt is the timestamp of the most recent pull attempt (success or failure). |
conditions | []metav1.Condition | Conditions represent the latest available observations. Condition types: Ready, PullProgress. |
CachedImageSet
CachedImageSet manages a group of images to cache, optionally backed by a DiscoveryPolicy.
Controller: internal/controller/cachedimageset_controller.go
Spec
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
policyRef | *PolicyReference | No | — | PolicyRef references a PullPolicy for pacing controls. Propagated to all child CachedImages. Example: {name: “conservative”} |
discoveryPolicyRef | *DiscoveryPolicyReference | No | — | DiscoveryPolicyRef references a DiscoveryPolicy that provides a dynamic image list. When set, the operator reads status.discoveredImages from the referenced DiscoveryPolicy and creates/deletes child CachedImages accordingly. Can be combined with static images. Example: {name: “popular-build-images”} |
imagePullPolicy | corev1.PullPolicy | No | Always | ImagePullPolicy controls when kubelet pulls images. Propagated to all child CachedImages. Default: “Always”. See CachedImage.spec.imagePullPolicy for details. (Always | IfNotPresent | Never) |
imagePullSecrets | []corev1.LocalObjectReference | No | — | ImagePullSecrets for private registries. Propagated to all child CachedImages. Secrets must exist in the namespace where Drop creates pull Pods (default: “drop-system”). Example: [{name: “ghcr-creds”}] |
nodeSelector | map[string]string | No | — | NodeSelector restricts which nodes to cache images on. Propagated to all child CachedImages. Example: {“node-role.kubernetes.io/build”: “true”} |
tolerations | []corev1.Toleration | No | — | Tolerations for tainted nodes. Propagated to all child CachedImages. Example: [{key: “node-role.kubernetes.io/build”, operator: “Exists”, effect: “NoSchedule”}] |
images | []ImageEntry | No | — | Images is a static list of images to cache. Each entry creates one child CachedImage. Can be used alone or combined with discoveryPolicyRef (both lists are merged). |
Status
| Field | Type | Description |
|---|---|---|
observedGeneration | int64 | ObservedGeneration is the last generation reconciled. |
phase | string | Phase summarizes the overall state. |
imagesManaged | int32 | ImagesManaged is the number of CachedImage children managed by this set. |
imagesReady | int32 | ImagesReady is the number of children in Ready phase. |
conditions | []metav1.Condition | Conditions represent the latest available observations. |
DiscoveryPolicy
DiscoveryPolicy automatically discovers images from registries or Prometheus metrics.
Controller: internal/controller/discoverypolicy_controller.go
Spec
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
sources | []DiscoverySource | Yes | — | Sources is the list of discovery backends to query. At least one source is required. Multiple sources are merged and ranked together before maxImages is applied. |
imageFilter | string | No | — | ImageFilter is a regex applied to discovered image references. Only matching images are kept. Example: “registry.example.com/team/.*” (only keep images from that registry path) |
syncInterval | metav1.Duration | No | 30m | SyncInterval is how often the operator re-queries all sources and updates status.discoveredImages. Default: “30m”. Example: “1h”, “15m” |
maxImages | int32 | No | 50 | MaxImages caps the total number of images stored in status.discoveredImages. Images are ranked by score; lowest-scoring images are dropped when the cap is exceeded. Default: 50. Example: 30, 100 |
Status
| Field | Type | Description |
|---|---|---|
lastSyncTime | *metav1.Time | LastSyncTime is the timestamp of the last successful sync. |
discoveredImages | []DiscoveredImage | DiscoveredImages is the list of discovered images from all sources. |
imageCount | int32 | ImageCount is the number of discovered images. |
sourceCount | int32 | SourceCount is the number of configured sources. |
conditions | []metav1.Condition | Conditions represent the latest available observations. |
PullPolicy
PullPolicy controls the pacing and retry behavior for image pulls across cluster nodes. It is a configuration-only resource with no status.
Spec
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
maxConcurrentNodes | int32 | No | 1 | MaxConcurrentNodes is the maximum number of nodes pulling simultaneously for images that reference this policy. Increase for large clusters; keep low for bandwidth-constrained nodes. Default: 1. Example: 3 (pull on up to 3 nodes at once) |
minDelayBetweenPulls | metav1.Duration | No | 10s | MinDelayBetweenPulls is the minimum wait time between starting a pull on one node and starting the next pull on another node. Prevents burst traffic to the registry. Default: “10s”. Example: “30s”, “1m” |
failureBackoff | *BackoffConfig | No | — | FailureBackoff configures exponential retry delays when a pull fails. If unset, defaults to initial=30s, max=5m. |
repullInterval | *metav1.Duration | No | — | RepullInterval defines how often to re-pull already-cached images to pick up digest changes. Unset or zero means never re-pull (rely on imagePullPolicy=Always on the CachedImage instead). Example: “24h” (re-pull daily), “6h” |
nodeSelector | map[string]string | No | — | NodeSelector scopes this policy to a specific node pool. Only relevant when the same PullPolicy should only pace pulls on a subset of nodes. Example: {“node-role.kubernetes.io/build”: “true”} |
tolerations | []corev1.Toleration | No | — | Tolerations allow the pull pods created under this policy to schedule on tainted nodes. Example: [{key: “dedicated”, value: “ci”, effect: “NoSchedule”}] |
Helper Types
BackoffConfig
BackoffConfig defines exponential retry backoff behavior for failed pulls.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
initial | metav1.Duration | No | 30s | Initial delay before the first retry attempt after a failure. Default: “30s”. Example: “1m” |
max | metav1.Duration | No | 5m | Max is the upper bound on backoff delay. Retries will never wait longer than this. Default: “5m”. Example: “10m” |
DiscoveredImage
DiscoveredImage represents a single discovered image with metadata.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
image | string | Yes | — | Image is the fully qualified image reference. |
score | int64 | Yes | — | Score is the ranking score from the source (higher = more relevant). |
source | string | Yes | — | Source identifies which discovery source produced this image. |
DiscoveryPolicyReference
DiscoveryPolicyReference is a reference to a DiscoveryPolicy resource.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
name | string | Yes | — | Name of the DiscoveryPolicy resource. |
DiscoverySource
DiscoverySource defines a single discovery backend.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
type | string | Yes | — | Type identifies the discovery backend. Must be “prometheus” or “registry”. |
prometheus | *PrometheusSource | No | — | Prometheus contains the configuration when type=prometheus. |
registry | *RegistrySource | No | — | Registry contains the configuration when type=registry. |
secretRef | *corev1.LocalObjectReference | No | — | SecretRef references a Secret in the namespace where Drop creates pull Pods. The default namespace is “drop-system” unless the controller is started with a different –pod-namespace. Supported Secret keys: token, username, password, ca.crt, tls.crt, tls.key, headers. |
ImageEntry
ImageEntry defines a single image to include in a set.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
image | string | Yes | — | Image is the fully qualified image reference without tag or digest. Example: “docker.io/library/nginx”, “registry.example.com/team/app” |
tag | string | No | — | Tag to pull. Mutually exclusive with Digest. Example: “1.25-alpine”, “v2.4.1” |
digest | string | No | — | Digest to pull as an immutable reference. Mutually exclusive with Tag. Example: “sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4” |
PolicyReference
PolicyReference is a reference to a PullPolicy resource.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
name | string | Yes | — | Name of the PullPolicy resource. |
PrometheusSource
PrometheusSource defines Prometheus query configuration for image discovery.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
endpoint | string | Yes | — | Endpoint is the Prometheus-compatible API URL (Prometheus, Thanos, Mimir, VictoriaMetrics). Example: “http://prometheus.monitoring.svc:9090”, “https://mimir.example.com” |
query | string | Yes | — | Query is the PromQL expression. It MUST return results with an “image” label — that label value is used as the discovered image reference. The query result value is used as the ranking score (higher = more relevant). Example: count(container_memory_working_set_bytes{container!="",container!=“POD”,namespace=“gitlab-runner”}) by (image) |
lookback | *metav1.Duration | No | — | Lookback is the time window for aggregation. When set, the operator uses query_range (start=now-lookback, end=now) and sums all returned values per image to produce a score. When unset, uses an instant query (/api/v1/query) and the point-in-time value is the score. Example: “168h” (7 days), “24h”, “72h” |
step | string | No | 5m | Step is the resolution step for range queries (only used when lookback is set). Smaller steps = more data points = more accurate sums but higher Prometheus load. Default: “5m”. Example: “1m”, “15m” |
RegistrySource
RegistrySource defines OCI registry tag listing configuration for image discovery.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
url | string | Yes | — | URL is the registry base URL (without repository path). Example: “https://registry.example.com”, “https://ghcr.io” |
repositories | []string | Yes | — | Repositories is the list of repository paths to list tags from. Example: [“team/app”, “team/worker”, “infra/tools”] |
tagFilter | string | No | — | TagFilter is a regex applied to tag names. Only matching tags are discovered. Example: “^v[0-9]+\.” (semver tags only), “^main-” (main branch builds) |
topX | int32 | No | — | TopX limits the number of tags kept per repository after tagFilter is applied. The registry API does not provide creation timestamps here; Drop keeps the last N tags returned by the registry. Example: 3 (keep the last 3 matching tags returned per repo) |
imageTemplate | string | No | — | ImageTemplate is a Go text/template for constructing the full image reference from discovered tags. Available variables: {{.Registry}}, {{.Repository}}, {{.Tag}} Default (when unset): “{{.Registry}}/{{.Repository}}:{{.Tag}}” Example: “{{.Registry}}/{{.Repository}}@{{.Tag}}” (if tags are actually digests) |