-
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathknowledge.yaml
More file actions
1529 lines (1528 loc) · 58.3 KB
/
Copy pathknowledge.yaml
File metadata and controls
1529 lines (1528 loc) · 58.3 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
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
# 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: Queries
json: queries
type: '[]DiscoveryQuery'
required: false
doc: Queries is the list of named raw-data sources. Each query is referenced by name from signals.
- name: Signals
json: signals
type: '[]DiscoverySignal'
required: false
doc: Signals is the list of named per-image metrics derived from query results. Each signal is referenced by name from the ranking configuration.
- name: Ranking
json: ranking
type: '*DiscoveryRanking'
required: false
doc: Ranking defines how signals are combined into a final ordered image list.
- 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-runs the pipeline 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 reconciliation attempt.
- name: QueryResults
json: queryResults
type: '[]QueryResult'
required: false
doc: QueryResults reports the outcome of each named query execution.
- name: DiscoveredImages
json: discoveredImages
type: '[]DiscoveredImage'
required: false
doc: DiscoveredImages is the ordered list of discovered and ranked images.
- name: ImageCount
json: imageCount
type: int32
required: false
doc: ImageCount is the number of discovered images.
- 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="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: AggregateSignalConfig
doc: AggregateSignalConfig configures the aggregate signal type.
fields:
- name: Method
json: method
type: AggregationMethod
required: true
enum:
- sum
- count
- avg
- max
- min
doc: Method is the aggregation function applied to all samples per image.
- 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 and ranked image.
fields:
- name: Image
json: image
type: string
required: true
doc: Image is the fully qualified image reference.
- name: Rank
json: rank
type: int32
required: true
doc: Rank is the position of this image in the final ordered list (1 = highest score).
- name: FinalScore
json: finalScore
type: string
required: true
doc: FinalScore is the computed ranking score as a decimal string.
- name: DiscoveryLokiQuery
doc: DiscoveryLokiQuery defines the Loki-specific query parameters.
fields:
- name: Endpoint
json: endpoint
type: string
required: true
doc: 'Endpoint is the Loki API URL. Example: "https://loki.example.com"'
- name: Query
json: query
type: string
required: true
doc: Query is the LogQL expression.
- name: QueryType
json: queryType
type: LokiQueryType
required: false
default: range
doc: QueryType controls how the query is executed. Currently only "range" is supported.
- name: Lookback
json: lookback
type: '*metav1.Duration'
required: false
doc: 'Lookback is the time window for the query (start=now-lookback, end=now). Example: "168h" (7 days), "24h"'
- name: Parser
json: parser
type: '*LokiParser'
required: false
doc: Parser configures how log lines are parsed into structured event records.
- 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: DiscoveryPrometheusQuery
doc: DiscoveryPrometheusQuery defines the Prometheus-specific query parameters. The PromQL result MUST carry an "image" label; that label value is the image reference.
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. Must return results with an "image" label. Example: count(container_memory_working_set_bytes{namespace="gitlab-runner"}) by (image)'
- name: QueryType
json: queryType
type: QueryType
required: false
default: range
doc: 'QueryType controls how the query is executed: "range" or "instant". Default: "range".'
- name: Lookback
json: lookback
type: '*metav1.Duration'
required: false
doc: 'Lookback is the time window for range queries (start=now-lookback, end=now). Required when queryType is "range". Ignored when queryType is "instant". Example: "168h" (7 days), "24h", "72h"'
- name: Step
json: step
type: '*metav1.Duration'
required: false
doc: 'Step is the resolution step for range queries. Smaller steps increase data-point density but also increase Prometheus load. Default: 5m. Example: "1m", "15m"'
- name: DiscoveryQuery
doc: DiscoveryQuery defines a named raw-data source referenced by signals.
fields:
- name: Name
json: name
type: string
required: true
doc: Name is the unique identifier for this query within the policy. Signals reference queries by this name via query.
- name: Type
json: type
type: DiscoveryQueryType
required: true
enum:
- prometheus
- loki
- registry
doc: Type selects the backend. Must be "prometheus", "loki", or "registry".
- name: Prometheus
json: prometheus
type: '*DiscoveryPrometheusQuery'
required: false
doc: Prometheus contains the configuration when type=prometheus.
- name: Loki
json: loki
type: '*DiscoveryLokiQuery'
required: false
doc: Loki contains the configuration when type=loki.
- name: Registry
json: registry
type: '*DiscoveryRegistryQuery'
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 pod namespace (default "drop-system") for auth/TLS. Supported Secret keys: token, username, password, ca.crt, tls.crt, tls.key, headers.<name>.'
- name: DiscoveryRanking
doc: DiscoveryRanking defines how signals are combined into the final ordered image list.
fields:
- name: Strategy
json: strategy
type: RankingStrategy
required: true
enum:
- signal
- weightedSum
- modelExposure
doc: Strategy selects the ranking algorithm.
- name: Signal
json: signal
type: string
required: false
doc: Signal is the name of the signal whose values determine image rank. Must match a signals[].name within the same policy. Required when strategy=signal.
- name: WeightedSum
json: weightedSum
type: '*WeightedSumRankingConfig'
required: false
doc: WeightedSum is required when strategy=weightedSum.
- name: ModelExposure
json: modelExposure
type: '*ModelExposureRankingConfig'
required: false
doc: ModelExposure is required when strategy=modelExposure.
- name: DiscoveryRegistryQuery
doc: DiscoveryRegistryQuery 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: TagSeek
json: tagSeek
type: string
required: false
doc: 'TagSeek is a pagination cursor passed to the registry as the `last` query parameter. The registry lists tags lexically after this value, letting you skip large numbers of irrelevant earlier tags without fetching them. It is not a real tag name — any string works. Example: "x86_64-u~" jumps straight to the "x86_64-v*" tags on a repo with tens of thousands of digest tags (GitLab runner helper).'
- name: TopX
json: topX
type: int32
required: false
doc: 'TopX limits the number of tags kept per repository after tagFilter is applied. Tags are sorted newest-first (by version) before this cap is applied, so the newest N tags are kept. Example: 3 (keep the 3 newest matching tags per repo)'
- name: MaxScan
json: maxScan
type: int32
required: false
doc: 'MaxScan caps how many tags are fetched per repository before filtering. Registries can hold tens of thousands of tags; this bounds the work. Pair it with tagSeek to fetch only the relevant range. Defaults to 1000 when unset. Example: 500'
- name: VersionPattern
json: versionPattern
type: string
required: false
doc: 'VersionPattern is a regex with a single capture group that extracts the version substring from each tag for newest-first sorting. Use it when tags carry a prefix/suffix around the version, e.g. GitLab runner helper tags like "x86_64-v17.5.0" (pattern "x86_64-v(.+)"). When unset, Drop tries a strict semver parse, then falls back to extracting an embedded semver substring. Tags with no parseable version keep registry push order and sort after versioned tags. Example: "x86_64-v(.+)"'
- 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.example.com/{{.Repository}}:{{.Tag}}"'
- name: DiscoverySignal
doc: DiscoverySignal defines a named per-image metric derived from a single query.
fields:
- name: Name
json: name
type: string
required: true
doc: Name is the unique identifier for this signal within the policy. Ranking configurations reference signals by this name.
- name: Query
json: query
type: string
required: true
doc: Query is the name of the query that provides raw data for this signal. Must match a queries[].name within the same policy.
- name: Type
json: type
type: SignalType
required: true
enum:
- aggregate
- timeWeightedAggregate
- windowAggregate
- eventPullTime
doc: Type selects the signal derivation method.
- name: Aggregate
json: aggregate
type: '*AggregateSignalConfig'
required: false
doc: Aggregate is required when type=aggregate.
- name: TimeWeightedAggregate
json: timeWeightedAggregate
type: '*TimeWeightedAggregateSignalConfig'
required: false
doc: TimeWeightedAggregate is required when type=timeWeightedAggregate.
- name: WindowAggregate
json: windowAggregate
type: '*WindowAggregateSignalConfig'
required: false
doc: WindowAggregate is required when type=windowAggregate.
- name: EventPullTime
json: eventPullTime
type: '*EventPullTimeSignalConfig'
required: false
doc: EventPullTime is required when type=eventPullTime.
- name: EventPullTimeSignalConfig
doc: EventPullTimeSignalConfig configures the eventPullTime signal type. The referenced query must be a Loki query. Pull duration and image size are extracted from the same Pulled events; metric selects which one to rank on.
fields:
- name: Metric
json: metric
type: EventMetric
required: false
default: pullTime
doc: Metric selects which per-image quantity to aggregate. Defaults to pullTime, which correlates strongly with cold-start cost. Use imageSize to rank by bytes.
- name: Statistic
json: statistic
type: EventStatistic
required: true
enum:
- p50
- p90
- p95
- avg
- max
- count
doc: Statistic selects how the metric's samples are aggregated per image.
- 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: LokiParser
doc: LokiParser configures structured parsing of Loki log entries.
fields:
- name: Type
json: type
type: LokiParserType
required: true
enum:
- kubernetesEvents
doc: Type selects the parser. Currently only "kubernetesEvents" is supported.
- name: PodField
json: podField
type: string
required: false
doc: 'PodField is the log label or field that contains the pod name. Example: "involvedObject_name"'
- name: ReasonField
json: reasonField
type: string
required: false
doc: 'ReasonField is the log label or field that contains the event reason. Example: "reason"'
- name: MessageField
json: messageField
type: string
required: false
doc: 'MessageField is the log label or field that contains the event message. Example: "message"'
- name: ImageField
json: imageField
type: string
required: false
doc: 'ImageField is the log label or field from which the image reference is extracted. For kubernetesEvents, the image is parsed out of the message text. Example: "message"'
- name: ModelExposureRankingConfig
doc: ModelExposureRankingConfig configures the modelExposure ranking strategy. Score = J_target(I) * (1 - 1/N)^J_pre(I) * p_hat(I) where N is the node count (see NodeCountConfig), J_pre is pre-window usage, J_target is target-window usage, and p_hat is the pull-time signal value.
fields:
- name: Nodes
json: nodes
type: '*NodeCountConfig'
required: false
doc: Nodes determines N (the eligible node count) in the exposure formula, either as a static count or dynamically via a label selector.
- name: PreWindowUsageSignal
json: preWindowUsageSignal
type: string
required: true
doc: PreWindowUsageSignal is the name of the signal representing usage before the target window. Must match a signals[].name within the same policy.
- name: TargetWindowUsageSignal
json: targetWindowUsageSignal
type: string
required: true
doc: TargetWindowUsageSignal is the name of the signal representing usage during the target window. Must match a signals[].name within the same policy.
- name: PullTimeSignal
json: pullTimeSignal
type: string
required: true
doc: PullTimeSignal is the name of the signal providing per-image pull-time estimates. Must match a signals[].name within the same policy.
- name: NodeCountConfig
doc: NodeCountConfig determines N (the eligible node count) for the modelExposure formula. Provide a static Count, a dynamic Selector, or both (Selector wins; Count is the fallback).
fields:
- name: Count
json: count
type: '*int32'
required: false
doc: Count is the static number of eligible nodes. Used when Selector is unset, or as a fallback if node discovery fails.
- name: Selector
json: selector
type: '*corev1.NodeSelector'
required: false
doc: 'Selector dynamically determines N by counting Ready nodes that match it via the Kubernetes API at each sync. This is a standard node selector (the same shape used by node affinity): nodeSelectorTerms are ORed, and within a term matchExpressions (node labels) and matchFields (e.g. metadata.name) are ANDed. A nil selector counts all Ready nodes. When set, it takes precedence over Count.'
- 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: QueryResult
doc: QueryResult reports the outcome of a single named query execution.
fields:
- name: Name
json: name
type: string
required: true
doc: Name matches the queries[].name that produced this result.
- name: Type
json: type
type: DiscoveryQueryType
required: true
doc: Type is the query backend type (prometheus, loki, or registry).
- name: Status
json: status
type: QueryResultStatus
required: true
doc: Status is "success" or "failed".
- name: Message
json: message
type: string
required: false
doc: Message describes the failure reason when status=failed.
- name: TimeOfDayWindow
doc: TimeOfDayWindow defines a fixed wall-clock time range within each day.
fields:
- name: Start
json: start
type: string
required: true
doc: 'Start is the inclusive start time in "HH:MM" format (24-hour, local time). Example: "09:00"'
- name: End
json: end
type: string
required: true
doc: 'End is the exclusive end time in "HH:MM" format (24-hour, local time). Example: "17:00"'
- name: TimeWeightedAggregateSignalConfig
doc: TimeWeightedAggregateSignalConfig configures the timeWeightedAggregate signal type. Each sample value is multiplied by the weight of the matching time window before aggregation.
fields:
- name: Method
json: method
type: AggregationMethod
required: true
enum:
- sum
- count
- avg
- max
- min
doc: Method is the aggregation function applied after weighting (currently only "sum" is meaningful).
- name: Timezone
json: timezone
type: string
required: true
doc: 'Timezone is the IANA time zone used to evaluate window boundaries (wall-clock hours). Example: "Europe/Berlin", "America/New_York", "UTC"'
- name: DefaultWeight
json: defaultWeight
type: resource.Quantity
required: true
doc: DefaultWeight is applied to samples that do not fall in any configured window. Use "0" to exclude off-hours samples entirely.
- name: Windows
json: windows
type: '[]TimeWeightedWindow'
required: true
doc: Windows is the list of hour-of-day windows with associated weights.
- name: TimeWeightedWindow
doc: TimeWeightedWindow defines a wall-clock hour range and its weight factor.
fields:
- name: StartHour
json: startHour
type: int32
required: true
doc: StartHour is the inclusive start of the window in local time (0–23).
- name: EndHour
json: endHour
type: int32
required: true
doc: EndHour is the exclusive end of the window in local time (1–24).
- name: Weight
json: weight
type: resource.Quantity
required: true
doc: Weight is the factor applied to sample values within this window. Use "1.0" for full weight, "0.3" for partial, "0" to exclude.
- name: WeightedSumRankingConfig
doc: WeightedSumRankingConfig configures the weightedSum ranking strategy. Score = Σ weight_k * normalize(signal_k(image)).
fields:
- name: Normalize
json: normalize
type: NormalizeMethod
required: true
default: minMax
enum:
- minMax
doc: Normalize selects the normalization method applied to each signal before weighting. Currently only "minMax" is supported.
- name: MissingSignal
json: missingSignal
type: MissingSignalBehavior
required: true
default: zero
enum:
- zero
- drop
doc: MissingSignal controls behavior when an image has no value for a required signal. "zero" treats missing as 0; "drop" removes the image from ranking.
- name: Terms
json: terms
type: '[]WeightedSumTerm'
required: true
doc: Terms is the list of signals and their weights.
- name: WeightedSumTerm
doc: WeightedSumTerm defines one signal contribution in a weightedSum ranking.
fields:
- name: Signal
json: signal
type: string
required: true
doc: Signal is the name of the signal to include in the weighted sum. Must match a signals[].name within the same policy.
- name: Weight
json: weight
type: resource.Quantity
required: true
doc: 'Weight is the factor applied to the normalized signal value. All weights should be non-negative; they do not need to sum to 1. Example: "0.7"'
- name: WindowAggregateSignalConfig
doc: WindowAggregateSignalConfig configures the windowAggregate signal type. Exactly one of relativeWindow or (window + timezone) must be set.
fields:
- name: Method
json: method
type: AggregationMethod
required: true
enum:
- sum
- count
- avg
- max
- min
doc: Method is the aggregation function applied to the windowed samples.
- name: RelativeWindow
json: relativeWindow
type: '*metav1.Duration'
required: false
doc: 'RelativeWindow aggregates only samples from the last N duration before now. Mutually exclusive with window + timezone. Example: "2h" (last 2 hours)'
- name: Timezone
json: timezone
type: string
required: false
doc: Timezone is the IANA time zone for evaluating wall-clock window boundaries. Required when window is set.
- name: Window
json: window
type: '*TimeOfDayWindow'
required: false
doc: Window defines fixed wall-clock start/end times within each day. Mutually exclusive with relativeWindow.
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.
imports:
- api/v1alpha1
- 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
- rule: Documentation must never contain unverified information — verify all examples against a real cluster before merging
scope:
- code
- rule: Always document which resources you looked at in which order (short summary + time spent + tokens consumed + context consumed)
scope:
- code
- rule: Always lint and fix linter issues locally before pushing code
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: ConnectionRefused
controller: DiscoveryPolicy
meaning: ""
- reason: DNSError
controller: DiscoveryPolicy
meaning: ""
- reason: Synced
controller: DiscoveryPolicy
meaning: Pipeline executed successfully; N images discovered.
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