new year update (#4)

* Bring operator to the brand new world of build and deployments.

* Clean up the code and basic improvements.

* More fixes, moving from python to golang worker.

* fixup! More fixes, moving from python to golang worker.

* fixup! fixup! More fixes, moving from python to golang worker.

* fixup! fixup! fixup! More fixes, moving from python to golang worker.

* fixup! fixup! fixup! fixup! More fixes, moving from python to golang worker.

* fixup! fixup! fixup! fixup! fixup! More fixes, moving from python to golang worker.

* fixup! fixup! fixup! fixup! fixup! fixup! More fixes, moving from python to golang worker.
This commit is contained in:
2025-12-18 14:41:24 +00:00
committed by GitHub
parent 067a51c9c7
commit 3880af56a7
56 changed files with 5829 additions and 1118 deletions
@@ -0,0 +1,21 @@
apiVersion: v2
name: kube-images-sync
description: |
A Helm chart for Kubernetes Images Sync Operator.
Kubernetes Images Sync Operator is responsible for backing up and restoring images from a Kubernetes cluster.
Its ultimate goal is to provide synchronization of images between multiple environments, quite often air-gapped.
It compiles the list of images currently present in the cluster and uploads them to the specified storage.
Whenever a new CRD is created - it will try to figure out which images were already uploaded and which are new and
upload only the new ones to avoid repetition.
type: application
version: 0.5.54
appVersion: "0.5.54"
home: https://github.com/lukaszraczylo/kubernetes-images-sync-operator
maintainers:
- name: lukaszraczylo
email: github-enquiries@raczylo.com
@@ -0,0 +1,58 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "chart.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "chart.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "chart.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "chart.labels" -}}
helm.sh/chart: {{ include "chart.chart" . }}
{{ include "chart.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "chart.selectorLabels" -}}
app.kubernetes.io/name: {{ include "chart.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Get the worker image
*/}}
{{- define "chart.workerImage" -}}
{{- printf "%s:%s" .Values.images.worker.repository .Values.images.worker.tag }}
{{- end }}
@@ -0,0 +1,126 @@
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: clusterimages.raczylo.com
annotations:
controller-gen.kubebuilder.io/version: v0.17.1
labels:
{{- include "chart.labels" . | nindent 4 }}
spec:
group: raczylo.com
names:
kind: ClusterImage
listKind: ClusterImageList
plural: clusterimages
singular: clusterimage
scope: Namespaced
versions:
- additionalPrinterColumns:
- jsonPath: .spec.exportName
name: Ref
type: string
- jsonPath: .spec.image
name: Image
type: string
- jsonPath: .spec.tag
name: Tag
type: string
- jsonPath: .spec.sha
name: SHA
type: string
- jsonPath: .spec.storage
name: Storage
type: string
- jsonPath: .spec.exportPath
name: Path
type: string
- jsonPath: .status.progress
name: Progress
type: string
- jsonPath: .status.retryCount
name: Retries
type: integer
- jsonPath: .metadata.creationTimestamp
name: Age
type: date
name: v1
schema:
openAPIV3Schema:
description: ClusterImage is the Schema for the clusterimages API
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
type: string
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string
metadata:
type: object
spec:
description: ClusterImageSpec defines the desired state of ClusterImage
properties:
exportName:
type: string
exportPath:
type: string
fullName:
type: string
image:
type: string
imageNamespace:
type: string
imagePullSecrets:
items:
description: |-
LocalObjectReference contains enough information to let you locate the
referenced object inside the same namespace.
properties:
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
type: object
x-kubernetes-map-type: atomic
type: array
jobAnnotations:
additionalProperties:
type: string
type: object
sha:
type: string
storage:
type: string
tag:
type: string
required:
- exportName
type: object
status:
description: ClusterImageStatus defines the observed state of ClusterImage
properties:
progress:
type: string
retryCount:
default: 0
description: default value is 0
type: integer
type: object
type: object
served: true
storage: true
subresources:
status: {}
@@ -0,0 +1,186 @@
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: clusterimageexports.raczylo.com
annotations:
controller-gen.kubebuilder.io/version: v0.17.1
labels:
{{- include "chart.labels" . | nindent 4 }}
spec:
group: raczylo.com
names:
kind: ClusterImageExport
listKind: ClusterImageExportList
plural: clusterimageexports
singular: clusterimageexport
scope: Namespaced
versions:
- additionalPrinterColumns:
- jsonPath: .spec.basePath
name: BasePath
type: string
- jsonPath: .spec.storage.target
name: Storage
type: string
- jsonPath: .status.progress
name: Progress
type: string
- jsonPath: .status.completedImages
name: Images
type: string
- jsonPath: .status.totalImages
name: Total
type: string
- jsonPath: .metadata.creationTimestamp
name: Age
type: date
name: v1
schema:
openAPIV3Schema:
description: ClusterImageExport is the Schema for the clusterimageexports
API
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
type: string
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string
metadata:
type: object
spec:
description: ClusterImageExportSpec defines the desired state of ClusterImageExport
properties:
additionalImages:
items:
type: string
type: array
basePath:
description: Base path for the export - both file and S3
maxLength: 255
minLength: 1
type: string
createdAt:
format: date-time
type: string
excludedNamespaces:
items:
type: string
type: array
excludes:
description: Exclude images which contain these strings
items:
type: string
type: array
imagePullSecrets:
items:
description: |-
LocalObjectReference contains enough information to let you locate the
referenced object inside the same namespace.
properties:
name:
default: ""
description: |-
Name of the referent.
This field is effectively required, but due to backwards compatibility is
allowed to be empty. Instances of this type with an empty value here are
almost certainly wrong.
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
type: string
type: object
x-kubernetes-map-type: atomic
type: array
includes:
description: Include only images which contain these strings
items:
type: string
type: array
jobAnnotations:
additionalProperties:
type: string
type: object
maxConcurrentJobs:
default: 5
maximum: 100
minimum: 1
type: integer
name:
type: string
namespaces:
items:
type: string
type: array
storage:
description: ClusterImageStorageSpec defines the desired state of
ClusterImageStorage
properties:
s3:
properties:
accessKey:
description: S3 bucket credentials
type: string
bucket:
description: Bucket name
type: string
endpoint:
description: |-
Defines the endpoint for the S3 storage
If none specified - default AWS endpoint will be used
type: string
region:
type: string
roleARN:
description: RoleARN is the ARN of the role to be used for
the deployment
type: string
secretKey:
type: string
secretName:
description: Defines the secret name for credentials
type: string
useRole:
type: boolean
required:
- bucket
- region
type: object
target:
enum:
- FILE
- S3
type: string
required:
- target
type: object
required:
- basePath
- maxConcurrentJobs
- name
- storage
type: object
status:
description: ClusterImageExportStatus defines the observed state of ClusterImageExport
properties:
completedImages:
description: Number of images that have completed export
type: integer
progress:
type: string
totalImages:
description: Total number of images to be exported
type: integer
type: object
type: object
served: true
storage: true
subresources:
status: {}
@@ -0,0 +1,83 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "chart.fullname" . }}-controller-manager
labels:
control-plane: controller-manager
{{- include "chart.labels" . | nindent 4 }}
spec:
replicas: {{ .Values.controllerManager.replicas }}
selector:
matchLabels:
control-plane: controller-manager
{{- include "chart.selectorLabels" . | nindent 6 }}
template:
metadata:
labels:
control-plane: controller-manager
{{- include "chart.selectorLabels" . | nindent 8 }}
annotations:
kubectl.kubernetes.io/default-container: manager
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/arch
operator: In
values:
- amd64
- arm64
- key: kubernetes.io/os
operator: In
values:
- linux
containers:
- args:
{{- toYaml .Values.controllerManager.manager.args | nindent 8 }}
command:
- /manager
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: POD_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_SERVICE_ACCOUNT
valueFrom:
fieldRef:
fieldPath: spec.serviceAccountName
- name: WORKER_IMAGE
value: {{ quote .Values.controllerManager.manager.env.workerImage }}
- name: KUBERNETES_CLUSTER_DOMAIN
value: {{ quote .Values.kubernetesClusterDomain }}
image: {{ .Values.controllerManager.manager.image.repository }}:{{ .Values.controllerManager.manager.image.tag | default .Chart.AppVersion }}
livenessProbe:
httpGet:
path: /healthz
port: 8081
initialDelaySeconds: 15
periodSeconds: 20
name: manager
ports:
- containerPort: 8443
name: https
protocol: TCP
readinessProbe:
httpGet:
path: /readyz
port: 8081
initialDelaySeconds: 5
periodSeconds: 10
resources:
{{- toYaml .Values.controllerManager.manager.resources | nindent 10 }}
securityContext:
{{- toYaml .Values.controllerManager.manager.containerSecurityContext | nindent 10 }}
securityContext:
{{- toYaml .Values.controllerManager.podSecurityContext | nindent 8 }}
serviceAccountName: {{ include "chart.fullname" . }}-controller-manager
terminationGracePeriodSeconds: 10
@@ -0,0 +1,74 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: {{ include "chart.fullname" . }}-impex-mgr
labels:
{{- include "chart.labels" . | nindent 4 }}
rules:
- apiGroups:
- ""
resources:
- pods
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- apps
resources:
- daemonsets
- deployments
verbs:
- get
- list
- watch
- apiGroups:
- batch
resources:
- cronjobs
verbs:
- get
- list
- watch
- apiGroups:
- batch
resources:
- jobs
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- raczylo.com
resources:
- '*'
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- raczylo.com
resources:
- '*/finalizers'
verbs:
- update
- apiGroups:
- raczylo.com
resources:
- '*/status'
verbs:
- get
- patch
- update
@@ -0,0 +1,14 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: {{ include "chart.fullname" . }}-impex-mgrbinding
labels:
{{- include "chart.labels" . | nindent 4 }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: '{{ include "chart.fullname" . }}-impex-mgr'
subjects:
- kind: ServiceAccount
name: '{{ include "chart.fullname" . }}-controller-manager'
namespace: '{{ .Release.Namespace }}'
@@ -0,0 +1,19 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: {{ include "chart.fullname" . }}-metrics-auth-raczylo
labels:
{{- include "chart.labels" . | nindent 4 }}
rules:
- apiGroups:
- authentication.k8s.io
resources:
- tokenreviews
verbs:
- create
- apiGroups:
- authorization.k8s.io
resources:
- subjectaccessreviews
verbs:
- create
@@ -0,0 +1,14 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: {{ include "chart.fullname" . }}-metrics-auth-raczylobinding
labels:
{{- include "chart.labels" . | nindent 4 }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: '{{ include "chart.fullname" . }}-metrics-auth-raczylo'
subjects:
- kind: ServiceAccount
name: '{{ include "chart.fullname" . }}-controller-manager'
namespace: '{{ .Release.Namespace }}'
@@ -0,0 +1,11 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: {{ include "chart.fullname" . }}-metrics-raczylo
labels:
{{- include "chart.labels" . | nindent 4 }}
rules:
- nonResourceURLs:
- /metrics
verbs:
- get
@@ -0,0 +1,38 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: {{ include "chart.fullname" . }}-raczylo-com-leader
labels:
{{- include "chart.labels" . | nindent 4 }}
rules:
- apiGroups:
- ""
resources:
- configmaps
verbs:
- get
- list
- watch
- create
- update
- patch
- delete
- apiGroups:
- coordination.k8s.io
resources:
- leases
verbs:
- get
- list
- watch
- create
- update
- patch
- delete
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
@@ -0,0 +1,14 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: {{ include "chart.fullname" . }}-raczylo-com-leaderbinding
labels:
{{- include "chart.labels" . | nindent 4 }}
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: '{{ include "chart.fullname" . }}-raczylo-com-leader'
subjects:
- kind: ServiceAccount
name: '{{ include "chart.fullname" . }}-controller-manager'
namespace: '{{ .Release.Namespace }}'
@@ -0,0 +1,28 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: {{ include "chart.fullname" . }}-raczylo.com-clusterimage-editor-role
labels:
{{- include "chart.labels" . | nindent 4 }}
rules:
- apiGroups:
- raczylo.com
resources:
- clusterimages
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- raczylo.com
resources:
- clusterimages/status
verbs:
- get
- patch
- update
- watch
@@ -0,0 +1,22 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: {{ include "chart.fullname" . }}-raczylo.com-clusterimage-viewer-role
labels:
{{- include "chart.labels" . | nindent 4 }}
rules:
- apiGroups:
- raczylo.com
resources:
- clusterimages
verbs:
- get
- list
- watch
- apiGroups:
- raczylo.com
resources:
- clusterimages/status
verbs:
- get
- watch
@@ -0,0 +1,28 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: {{ include "chart.fullname" . }}-raczylo.com-clusterimageexport-editor-role
labels:
{{- include "chart.labels" . | nindent 4 }}
rules:
- apiGroups:
- raczylo.com
resources:
- clusterimageexports
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- raczylo.com
resources:
- clusterimageexports/status
verbs:
- get
- patch
- update
- watch
@@ -0,0 +1,16 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: {{ include "chart.fullname" . }}-raczylo.com-clusterimageexport-viewer-role
labels:
{{- include "chart.labels" . | nindent 4 }}
rules:
- apiGroups:
- raczylo.com
resources:
- clusterimageexports
- clusterimageexports/status
verbs:
- get
- list
- watch
@@ -0,0 +1,14 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "chart.fullname" . }}-metrics-service
labels:
control-plane: controller-manager
{{- include "chart.labels" . | nindent 4 }}
spec:
type: {{ .Values.metricsService.type }}
selector:
control-plane: controller-manager
{{- include "chart.selectorLabels" . | nindent 4 }}
ports:
{{- .Values.metricsService.ports | toYaml | nindent 2 }}
@@ -0,0 +1,8 @@
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "chart.fullname" . }}-controller-manager
labels:
{{- include "chart.labels" . | nindent 4 }}
annotations:
{{- toYaml .Values.controllerManager.serviceAccount.annotations | nindent 4 }}
@@ -0,0 +1,31 @@
{{- if .Values.serviceMonitor.enabled }}
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: {{ include "chart.fullname" . }}-metrics
{{- if .Values.serviceMonitor.namespace }}
namespace: {{ .Values.serviceMonitor.namespace }}
{{- end }}
labels:
{{- include "chart.labels" . | nindent 4 }}
{{- with .Values.serviceMonitor.labels }}
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
endpoints:
- path: /metrics
port: https
scheme: https
interval: {{ .Values.serviceMonitor.interval }}
scrapeTimeout: {{ .Values.serviceMonitor.scrapeTimeout }}
tlsConfig:
insecureSkipVerify: true
bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
namespaceSelector:
matchNames:
- {{ .Release.Namespace }}
selector:
matchLabels:
control-plane: controller-manager
{{- include "chart.selectorLabels" . | nindent 6 }}
{{- end }}
@@ -0,0 +1,53 @@
kubernetesClusterDomain: cluster.local
controllerManager:
manager:
# Command line arguments for the manager
args:
- --metrics-bind-address=:8443
- --metrics-secure
- --leader-elect
- --health-probe-bind-address=:8081
containerSecurityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
env:
workerImage: ghcr.io/lukaszraczylo/kubernetes-images-sync-worker:0.5.54
image:
repository: ghcr.io/lukaszraczylo/kubernetes-images-sync-operator
tag: "0.5.54"
resources:
limits:
cpu: 500m
memory: 128Mi
requests:
cpu: 10m
memory: 64Mi
podSecurityContext:
runAsNonRoot: true
replicas: 1
serviceAccount:
annotations: {}
# Metrics service configuration
metricsService:
ports:
- name: https
port: 8443
protocol: TCP
targetPort: 8443
type: ClusterIP
# ServiceMonitor for Prometheus Operator integration
serviceMonitor:
enabled: false
# Namespace where ServiceMonitor will be created (defaults to release namespace)
namespace: ""
# Additional labels for ServiceMonitor
labels: {}
# Scrape interval
interval: 30s
# Scrape timeout
scrapeTimeout: 10s