-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathknowledge.yaml
More file actions
828 lines (827 loc) · 33 KB
/
Copy pathknowledge.yaml
File metadata and controls
828 lines (827 loc) · 33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
# Generated by make docs-gen — DO NOT EDIT
# Source: hack/gen-ai-docs/
# Regenerate: make docs-gen
project:
name: drop
description: Kubernetes operator that pre-caches container images on cluster nodes
apiGroup: drop.corewire.io/v1alpha1
goVersion: 1.26.0
module: github.com/corewire/drop
license: MIT
crds:
- kind: CachedImage
doc: CachedImage ensures a single container image is pre-cached on cluster nodes.
scope: Cluster
controller: internal/controller/cachedimage_controller.go
testFile: internal/controller/cachedimage_controller_test.go
specFields:
- name: Image
json: image
type: string
required: true
doc: 'Image is the fully qualified image reference without tag or digest. Example: "docker.io/library/nginx", "registry.example.com/team/app"'
- name: Tag
json: tag
type: string
required: false
doc: 'Tag to pull. Mutually exclusive with Digest. Example: "1.25-alpine", "v2.4.1", "latest"'
- name: Digest
json: digest
type: string
required: false
doc: '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"'
- name: ImagePullPolicy
json: imagePullPolicy
type: corev1.PullPolicy
required: false
default: Always
enum:
- Always
- IfNotPresent
- Never
doc: '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).'
- name: ImagePullSecrets
json: imagePullSecrets
type: '[]corev1.LocalObjectReference'
required: false
doc: '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"}]'
- name: NodeSelector
json: nodeSelector
type: map[string]string
required: false
doc: '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"}'
- name: Tolerations
json: tolerations
type: '[]corev1.Toleration'
required: false
doc: 'Tolerations allow the pull pod to be scheduled on tainted nodes. Example: [{key: "node-role.kubernetes.io/build", operator: "Exists", effect: "NoSchedule"}]'
- name: Priority
json: priority
type: '*int32'
required: false
doc: '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)'
- name: PolicyRef
json: policyRef
type: '*PolicyReference'
required: false
doc: '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"}'
statusFields:
- name: ObservedGeneration
json: observedGeneration
type: int64
required: false
doc: ObservedGeneration is the last generation reconciled.
- name: Phase
json: phase
type: string
required: false
enum:
- Pending
- Pulling
- Ready
- Degraded
doc: Phase summarizes the overall state.
- name: Ready
json: ready
type: string
required: false
doc: Ready is a human-readable "nodesReady/nodesTargeted" fraction for display.
- name: ResolvedDigest
json: resolvedDigest
type: string
required: false
doc: ResolvedDigest is the sha256 digest of the image as reported by the container runtime after pull.
- name: NodesTargeted
json: nodesTargeted
type: int32
required: false
doc: NodesTargeted is the number of nodes that should have this image.
- name: NodesReady
json: nodesReady
type: int32
required: false
doc: NodesReady is the number of nodes that have successfully pulled the image.
- name: NodesPulling
json: nodesPulling
type: int32
required: false
doc: NodesPulling is the number of nodes currently pulling the image.
- name: CachedNodes
json: cachedNodes
type: '[]string'
required: false
doc: CachedNodes is the list of node names that have successfully cached the image.
- name: ConsecutiveFailures
json: consecutiveFailures
type: int32
required: false
doc: ConsecutiveFailures counts sequential reconcile failures for backoff calculation.
- name: LastPulledAt
json: lastPulledAt
type: '*metav1.Time'
required: false
doc: LastPulledAt is the timestamp of the most recent successful pull.
- name: LastAttemptedAt
json: lastAttemptedAt
type: '*metav1.Time'
required: false
doc: LastAttemptedAt is the timestamp of the most recent pull attempt (success or failure).
- name: Conditions
json: conditions
type: '[]metav1.Condition'
required: false
doc: 'Conditions represent the latest available observations. Condition types: Ready, PullProgress.'
markers:
- +kubebuilder:printcolumn:name="Policy",type=string,JSONPath=`.spec.policyRef.name`,priority=1
- +kubebuilder:printcolumn:name="Message",type=string,JSONPath=`.status.conditions[?(@.type=="Ready")].message`,priority=1
- +kubebuilder:printcolumn:name="Set",type=string,JSONPath=`.metadata.labels.drop\.corewire\.io/imageset`,description="Parent CachedImageSet",priority=1
- +kubebuilder:printcolumn:name="Digest",type=string,JSONPath=`.status.resolvedDigest`,priority=1
- +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
- +kubebuilder:printcolumn:name="Ready",type=string,JSONPath=`.status.ready`
- +kubebuilder:printcolumn:name="Status",type=string,JSONPath=`.status.conditions[?(@.type=="Ready")].reason`
- +kubebuilder:printcolumn:name="Tag",type=string,JSONPath=`.spec.tag`
- +kubebuilder:printcolumn:name="Image",type=string,JSONPath=`.spec.image`
- +kubebuilder:resource:scope=Cluster,categories=drop
- +kubebuilder:subresource:status
- +kubebuilder:object:root=true
- kind: CachedImageSet
doc: CachedImageSet manages a group of images to cache, optionally backed by a DiscoveryPolicy.
scope: Cluster
controller: internal/controller/cachedimageset_controller.go
testFile: internal/controller/cachedimageset_controller_test.go
specFields:
- name: PolicyRef
json: policyRef
type: '*PolicyReference'
required: false
doc: 'PolicyRef references a PullPolicy for pacing controls. Propagated to all child CachedImages. Example: {name: "conservative"}'
- name: DiscoveryPolicyRef
json: discoveryPolicyRef
type: '*DiscoveryPolicyReference'
required: false
doc: '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"}'
- name: ImagePullPolicy
json: imagePullPolicy
type: corev1.PullPolicy
required: false
default: Always
enum:
- Always
- IfNotPresent
- Never
doc: 'ImagePullPolicy controls when kubelet pulls images. Propagated to all child CachedImages. Default: "Always". See CachedImage.spec.imagePullPolicy for details.'
- name: ImagePullSecrets
json: imagePullSecrets
type: '[]corev1.LocalObjectReference'
required: false
doc: '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"}]'
- name: NodeSelector
json: nodeSelector
type: map[string]string
required: false
doc: 'NodeSelector restricts which nodes to cache images on. Propagated to all child CachedImages. Example: {"node-role.kubernetes.io/build": "true"}'
- name: Tolerations
json: tolerations
type: '[]corev1.Toleration'
required: false
doc: 'Tolerations for tainted nodes. Propagated to all child CachedImages. Example: [{key: "node-role.kubernetes.io/build", operator: "Exists", effect: "NoSchedule"}]'
- name: Images
json: images
type: '[]ImageEntry'
required: false
doc: 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).
statusFields:
- name: ObservedGeneration
json: observedGeneration
type: int64
required: false
doc: ObservedGeneration is the last generation reconciled.
- name: Phase
json: phase
type: string
required: false
enum:
- Pending
- Ready
- Degraded
doc: Phase summarizes the overall state.
- name: ImagesManaged
json: imagesManaged
type: int32
required: false
doc: ImagesManaged is the number of CachedImage children managed by this set.
- name: ImagesReady
json: imagesReady
type: int32
required: false
doc: ImagesReady is the number of children in Ready phase.
- name: Conditions
json: conditions
type: '[]metav1.Condition'
required: false
doc: Conditions represent the latest available observations.
markers:
- +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
- +kubebuilder:printcolumn:name="Message",type=string,JSONPath=`.status.conditions[?(@.type=="Ready")].message`,priority=1
- +kubebuilder:printcolumn:name="Source",type=string,JSONPath=`.spec.discoveryPolicyRef.name`
- +kubebuilder:printcolumn:name="Managed",type=integer,JSONPath=`.status.imagesManaged`
- +kubebuilder:printcolumn:name="Ready",type=string,JSONPath=`.status.imagesReady`
- +kubebuilder:printcolumn:name="Status",type=string,JSONPath=`.status.conditions[?(@.type=="Ready")].reason`
- +kubebuilder:resource:scope=Cluster,categories=drop
- +kubebuilder:subresource:status
- +kubebuilder:object:root=true
- kind: DiscoveryPolicy
doc: DiscoveryPolicy automatically discovers images from registries or Prometheus metrics.
scope: Cluster
controller: internal/controller/discoverypolicy_controller.go
testFile: internal/controller/discoverypolicy_controller_test.go
specFields:
- name: Sources
json: sources
type: '[]DiscoverySource'
required: true
doc: 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.
- name: ImageFilter
json: imageFilter
type: string
required: false
doc: '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)'
- name: SyncInterval
json: syncInterval
type: metav1.Duration
required: false
default: 30m
doc: 'SyncInterval is how often the operator re-queries all sources and updates status.discoveredImages. Default: "30m". Example: "1h", "15m"'
- name: MaxImages
json: maxImages
type: int32
required: false
default: "50"
doc: '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'
statusFields:
- name: LastSyncTime
json: lastSyncTime
type: '*metav1.Time'
required: false
doc: LastSyncTime is the timestamp of the last successful sync.
- name: DiscoveredImages
json: discoveredImages
type: '[]DiscoveredImage'
required: false
doc: DiscoveredImages is the list of discovered images from all sources.
- name: ImageCount
json: imageCount
type: int32
required: false
doc: ImageCount is the number of discovered images.
- name: SourceCount
json: sourceCount
type: int32
required: false
doc: SourceCount is the number of configured sources.
- name: Conditions
json: conditions
type: '[]metav1.Condition'
required: false
doc: Conditions represent the latest available observations.
markers:
- +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
- +kubebuilder:printcolumn:name="Message",type=string,JSONPath=`.status.conditions[?(@.type=="Ready")].message`,priority=1
- +kubebuilder:printcolumn:name="LastSync",type=date,JSONPath=`.status.lastSyncTime`
- +kubebuilder:printcolumn:name="Images",type=integer,JSONPath=`.status.imageCount`
- +kubebuilder:printcolumn:name="Sources",type=integer,JSONPath=`.status.sourceCount`
- +kubebuilder:printcolumn:name="Status",type=string,JSONPath=`.status.conditions[?(@.type=="Ready")].reason`
- +kubebuilder:resource:scope=Cluster,categories=drop
- +kubebuilder:subresource:status
- +kubebuilder:object:root=true
- kind: PullPolicy
doc: PullPolicy controls the pacing and retry behavior for image pulls across cluster nodes. It is a configuration-only resource with no status.
scope: Cluster
specFields:
- name: MaxConcurrentNodes
json: maxConcurrentNodes
type: int32
required: false
default: "1"
doc: '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)'
- name: MinDelayBetweenPulls
json: minDelayBetweenPulls
type: metav1.Duration
required: false
default: 10s
doc: '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"'
- name: FailureBackoff
json: failureBackoff
type: '*BackoffConfig'
required: false
doc: FailureBackoff configures exponential retry delays when a pull fails. If unset, defaults to initial=30s, max=5m.
- name: RepullInterval
json: repullInterval
type: '*metav1.Duration'
required: false
doc: '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"'
- name: NodeSelector
json: nodeSelector
type: map[string]string
required: false
doc: '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"}'
- name: Tolerations
json: tolerations
type: '[]corev1.Toleration'
required: false
doc: 'Tolerations allow the pull pods created under this policy to schedule on tainted nodes. Example: [{key: "dedicated", value: "ci", effect: "NoSchedule"}]'
markers:
- +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`
- +kubebuilder:printcolumn:name="RepullInterval",type=string,JSONPath=`.spec.repullInterval`
- +kubebuilder:printcolumn:name="MinDelay",type=string,JSONPath=`.spec.minDelayBetweenPulls`
- +kubebuilder:printcolumn:name="MaxNodes",type=integer,JSONPath=`.spec.maxConcurrentNodes`
- +kubebuilder:resource:scope=Cluster,categories=drop
- +kubebuilder:object:root=true
helperTypes:
- name: BackoffConfig
doc: BackoffConfig defines exponential retry backoff behavior for failed pulls.
fields:
- name: Initial
json: initial
type: metav1.Duration
required: false
default: 30s
doc: 'Initial delay before the first retry attempt after a failure. Default: "30s". Example: "1m"'
- name: Max
json: max
type: metav1.Duration
required: false
default: 5m
doc: 'Max is the upper bound on backoff delay. Retries will never wait longer than this. Default: "5m". Example: "10m"'
- name: DiscoveredImage
doc: DiscoveredImage represents a single discovered image with metadata.
fields:
- name: Image
json: image
type: string
required: true
doc: Image is the fully qualified image reference.
- name: Score
json: score
type: int64
required: true
doc: Score is the ranking score from the source (higher = more relevant).
- name: Source
json: source
type: string
required: true
doc: Source identifies which discovery source produced this image.
- name: DiscoveryPolicyReference
doc: DiscoveryPolicyReference is a reference to a DiscoveryPolicy resource.
fields:
- name: Name
json: name
type: string
required: true
doc: Name of the DiscoveryPolicy resource.
- name: DiscoverySource
doc: DiscoverySource defines a single discovery backend.
fields:
- name: Type
json: type
type: string
required: true
enum:
- prometheus
- registry
doc: Type identifies the discovery backend. Must be "prometheus" or "registry".
- name: Prometheus
json: prometheus
type: '*PrometheusSource'
required: false
doc: Prometheus contains the configuration when type=prometheus.
- name: Registry
json: registry
type: '*RegistrySource'
required: false
doc: Registry contains the configuration when type=registry.
- name: SecretRef
json: secretRef
type: '*corev1.LocalObjectReference'
required: false
doc: '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.<name>. Example: {name: "prometheus-creds"}'
- name: ImageEntry
doc: ImageEntry defines a single image to include in a set.
fields:
- name: Image
json: image
type: string
required: true
doc: 'Image is the fully qualified image reference without tag or digest. Example: "docker.io/library/nginx", "registry.example.com/team/app"'
- name: Tag
json: tag
type: string
required: false
doc: 'Tag to pull. Mutually exclusive with Digest. Example: "1.25-alpine", "v2.4.1"'
- name: Digest
json: digest
type: string
required: false
doc: 'Digest to pull as an immutable reference. Mutually exclusive with Tag. Example: "sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4"'
- name: PolicyReference
doc: PolicyReference is a reference to a PullPolicy resource.
fields:
- name: Name
json: name
type: string
required: true
doc: Name of the PullPolicy resource.
- name: PrometheusSource
doc: PrometheusSource defines Prometheus query configuration for image discovery.
fields:
- name: Endpoint
json: endpoint
type: string
required: true
doc: 'Endpoint is the Prometheus-compatible API URL (Prometheus, Thanos, Mimir, VictoriaMetrics). Example: "http://prometheus.monitoring.svc:9090", "https://mimir.example.com"'
- name: Query
json: query
type: string
required: true
doc: '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)'
- name: Lookback
json: lookback
type: '*metav1.Duration'
required: false
doc: '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"'
- name: Step
json: step
type: string
required: false
default: 5m
doc: '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"'
- name: RegistrySource
doc: RegistrySource defines OCI registry tag listing configuration for image discovery.
fields:
- name: URL
json: url
type: string
required: true
doc: 'URL is the registry base URL (without repository path). Example: "https://registry.example.com", "https://ghcr.io"'
- name: Repositories
json: repositories
type: '[]string'
required: true
doc: 'Repositories is the list of repository paths to list tags from. Example: ["team/app", "team/worker", "infra/tools"]'
- name: TagFilter
json: tagFilter
type: string
required: false
doc: 'TagFilter is a regex applied to tag names. Only matching tags are discovered. Example: "^v[0-9]+\\." (semver tags only), "^main-" (main branch builds)'
- name: TopX
json: topX
type: int32
required: false
doc: '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)'
- name: ImageTemplate
json: imageTemplate
type: string
required: false
doc: '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)'
relationships:
- from: CachedImage
to: PullPolicy
type: references
mechanism: spec.policyRef
- from: CachedImageSet
to: PullPolicy
type: references
mechanism: spec.policyRef
- from: CachedImageSet
to: DiscoveryPolicy
type: references
mechanism: spec.discoveryPolicyRef
packages:
- path: api/v1alpha1
role: Package v1alpha1 contains API Schema definitions for the drop v1alpha1 API group.
- path: internal/controller
role: Package controller implements Kubernetes reconcilers for the drop CRDs (one per Kind).
imports:
- api/v1alpha1
- internal/discovery
- internal/metrics
- internal/pacing
- internal/podbuilder
- path: internal/discovery
role: Package discovery implements image discovery from registries and Prometheus metrics.
- path: internal/metrics
role: Package metrics registers Prometheus metrics for the drop operator.
- path: internal/pacing
role: Package pacing implements the shared rate-limiting engine for image pull scheduling.
imports:
- api/v1alpha1
- internal/podbuilder
- path: internal/podbuilder
role: Package podbuilder constructs pull Pods as a pure function (no Kubernetes client dependency).
imports:
- api/v1alpha1
conventions:
- rule: No privileged containers — kubelet-based image pulls only
scope:
- code
- rule: Single responsibility reconcilers — one controller per CRD
scope:
- code
- rule: Pod builder is a pure function in internal/podbuilder/ (no k8s client)
scope:
- code
- rule: Pacing logic lives exclusively in internal/pacing/
scope:
- code
- rule: Don't manually edit generated files — run make docs-gen
scope:
- code
errors:
- reason: Cached
controller: CachedImage
meaning: Image cached on all N target nodes
- reason: Complete
controller: CachedImage
meaning: All pulls complete
- reason: Idle
controller: CachedImage
meaning: Waiting to start pulls
- reason: InProgress
controller: CachedImage
meaning: N/N nodes ready
- reason: PullFailed
controller: CachedImage
meaning: N/N nodes ready
- reason: Pulling
controller: CachedImage
meaning: Actively pulling on N node(s), N/N complete
- reason: Stalled
controller: CachedImage
meaning: 'Pull stalled: N/N nodes ready, retrying with backoff'
- reason: Degraded
controller: CachedImageSet
meaning: 'N/N images cached, failing: N'
- reason: Progressing
controller: CachedImageSet
meaning: N/N images cached
- reason: Ready
controller: CachedImageSet
meaning: All N images are cached
- reason: AllSourcesHealthy
controller: DiscoveryPolicy
meaning: All discovery sources responded successfully
- reason: ConnectionRefused
controller: DiscoveryPolicy
meaning: ""
- reason: DNSError
controller: DiscoveryPolicy
meaning: ""
- reason: PartiallyFailed
controller: DiscoveryPolicy
meaning: 'Discovered N images, but some sources failed: N'
- reason: SourceError
controller: DiscoveryPolicy
meaning: One or more sources failed to respond
- reason: SyncFailed
controller: DiscoveryPolicy
meaning: ""
- reason: Synced
controller: DiscoveryPolicy
meaning: Discovered N images
metrics:
- name: drop_images_cached_total
help: Total number of images successfully cached on nodes.
type: counter
- name: drop_pull_duration_seconds
help: Duration of image pull operations in seconds.
type: histogram
- name: drop_pull_errors_total
help: Total number of failed image pull attempts.
type: counter
- name: drop_discovery_images_found
help: Number of images found by a discovery policy.
type: gauge
- name: drop_active_pulls
help: Current number of active image pull Pods.
type: gauge
- name: drop_reconcile_total
help: Total number of reconciliation attempts.
type: counter
- name: drop_discovery_source_health
help: Whether a discovery source is reachable and queryable (1=healthy, 0=unhealthy).
type: gauge
- name: drop_discovery_source_latency_seconds
help: Latency of discovery source queries in seconds.
type: histogram
- name: drop_nodes_targeted
help: Number of nodes targeted by each CachedImage resource.
type: gauge
- name: drop_nodes_cached
help: Number of nodes where the image is successfully cached.
type: gauge
- name: drop_consecutive_failures
help: Current number of consecutive pull failures for a CachedImage.
type: gauge
makeTargets:
- name: help
desc: Display this help.
- name: build
desc: Build manager binary.
- name: run
desc: Run controller from your host.
- name: fmt
desc: Run go fmt.
- name: vet
desc: Run go vet.
- name: lint
desc: Run golangci-lint.
- name: lint-fix
desc: Run golangci-lint with auto-fix.
- name: generate
desc: Generate DeepCopy methods.
- name: manifests
desc: Generate CRD and RBAC manifests.
- name: sync-crds
desc: Sync generated CRDs into Helm chart templates.
- name: codegen
desc: Run all code generation (deepcopy + CRDs + docs).
- name: test
desc: Run unit tests.
- name: test-e2e
desc: Run Chainsaw E2E tests (requires kind cluster).
- name: kind-create
desc: Create kind cluster for development.
- name: kind-delete
desc: Delete the kind cluster.
- name: install
desc: Install CRDs into cluster.
- name: uninstall
desc: Uninstall CRDs from cluster.
- name: e2e-infra
desc: Deploy Prometheus + Registry for E2E/dev.
- name: docker-build
desc: Build docker image.
- name: docker-push
desc: Push docker image.
- name: kind-load
desc: Build and load image into kind.
- name: helm-lint
desc: Lint the Helm chart.
- name: helm-template
desc: Render Helm templates locally.
- name: docs-serve
desc: Serve Hugo docs locally.
- name: docs-gen
desc: Regenerate AI agent docs (llms.txt, instructions, etc.) from source.
- name: docs-gen-check
desc: Verify generated AI docs are up to date.
- name: tools
desc: Install local tooling and check optional docs/chart binaries.
samples: |
# Dev samples: deployed by Tilt for interactive testing
---
# === PullPolicy ===
apiVersion: drop.corewire.io/v1alpha1
kind: PullPolicy
metadata:
name: dev-conservative
spec:
maxConcurrentNodes: 1
minDelayBetweenPulls: 5s
repullInterval: 1h
failureBackoff:
initial: 30s
max: 5m
---
# === CachedImage: healthy ===
apiVersion: drop.corewire.io/v1alpha1
kind: CachedImage
metadata:
name: dev-nginx
spec:
image: docker.io/library/nginx
tag: "1.25-alpine"
policyRef:
name: dev-conservative
---
apiVersion: drop.corewire.io/v1alpha1
kind: CachedImage
metadata:
name: dev-redis
spec:
image: docker.io/library/redis
tag: "7-alpine"
policyRef:
name: dev-conservative
---
# === CachedImage: broken (DNS failure → ImagePullBackOff) ===
apiVersion: drop.corewire.io/v1alpha1
kind: CachedImage
metadata:
name: test-invalid-image
spec:
image: registry.invalid.local:9999/does-not-exist
tag: "nope"
policyRef:
name: dev-conservative
---
# === CachedImageSet: healthy (static images) ===
apiVersion: drop.corewire.io/v1alpha1
kind: CachedImageSet
metadata:
name: dev-set
spec:
policyRef:
name: dev-conservative
images:
- image: docker.io/library/alpine
tag: "3.19"
- image: docker.io/library/busybox
tag: "1.36"
---
# === CachedImageSet: dynamic (backed by DiscoveryPolicy) ===
apiVersion: drop.corewire.io/v1alpha1
kind: CachedImageSet
metadata:
name: dev-set-discovered
spec:
policyRef:
name: dev-conservative
discoveryPolicyRef:
name: dev-registry
---
# === DiscoveryPolicy: healthy (Prometheus range query) ===
apiVersion: drop.corewire.io/v1alpha1
kind: DiscoveryPolicy
metadata:
name: dev-prometheus
spec:
sources:
- type: prometheus
prometheus:
endpoint: "http://prometheus.e2e-infra.svc.cluster.local:9090"
query: 'count(container_memory_working_set_bytes{container!="", container!="POD", namespace="build-stuff", pod=~"runner-.*"}) by (image)'
lookback: 24h
step: 5m
syncInterval: 30s
maxImages: 10
---
# === DiscoveryPolicy: healthy (registry tag listing) ===
apiVersion: drop.corewire.io/v1alpha1
kind: DiscoveryPolicy
metadata:
name: dev-registry
spec:
sources:
- type: registry
registry:
url: "http://registry.e2e-infra.svc.cluster.local:5000"
repositories:
- "test/myapp"
topX: 3
syncInterval: 30s
maxImages: 10
---
# === DiscoveryPolicy: broken (DNS error → DNSError) ===
apiVersion: drop.corewire.io/v1alpha1
kind: DiscoveryPolicy
metadata:
name: test-broken-prom
spec:
sources:
- type: prometheus
prometheus:
endpoint: "http://nonexistent-prometheus:9090"
query: "up{}"
syncInterval: 30m
maxImages: 10
---
# === DiscoveryPolicy: broken (DNS error → DNSError) ===
apiVersion: drop.corewire.io/v1alpha1
kind: DiscoveryPolicy
metadata:
name: test-broken-registry
spec:
sources:
- type: registry
registry:
url: "http://nonexistent-registry:5000"
repositories:
- "test/nope"
syncInterval: 30m
maxImages: 10
---
# === DiscoveryPolicy: broken (repo doesn't exist → NotFound) ===
apiVersion: drop.corewire.io/v1alpha1
kind: DiscoveryPolicy
metadata:
name: test-notfound-repo
spec:
sources:
- type: registry
registry:
url: "http://registry.e2e-infra.svc.cluster.local:5000"
repositories:
- "this/does-not-exist"
syncInterval: 30m
maxImages: 10