From 4eff26db6886aadc4e0c3e47deb3a1b49b922808 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 26 Dec 2025 00:13:16 +0000 Subject: [PATCH] Release kubemirror 0.2.8 --- charts/kubemirror/Chart.yaml | 18 ++++ charts/kubemirror/templates/NOTES.txt | 36 +++++++ charts/kubemirror/templates/_helpers.tpl | 60 +++++++++++ charts/kubemirror/templates/clusterrole.yaml | 57 +++++++++++ .../templates/clusterrolebinding.yaml | 14 +++ charts/kubemirror/templates/deployment.yaml | 95 ++++++++++++++++++ charts/kubemirror/templates/service.yaml | 19 ++++ .../kubemirror/templates/serviceaccount.yaml | 12 +++ charts/kubemirror/values.yaml | 86 ++++++++++++++++ charts/packages/kubemirror-0.2.8.tgz | Bin 0 -> 3358 bytes index.yaml | 25 ++++- 11 files changed, 421 insertions(+), 1 deletion(-) create mode 100644 charts/kubemirror/Chart.yaml create mode 100644 charts/kubemirror/templates/NOTES.txt create mode 100644 charts/kubemirror/templates/_helpers.tpl create mode 100644 charts/kubemirror/templates/clusterrole.yaml create mode 100644 charts/kubemirror/templates/clusterrolebinding.yaml create mode 100644 charts/kubemirror/templates/deployment.yaml create mode 100644 charts/kubemirror/templates/service.yaml create mode 100644 charts/kubemirror/templates/serviceaccount.yaml create mode 100644 charts/kubemirror/values.yaml create mode 100644 charts/packages/kubemirror-0.2.8.tgz diff --git a/charts/kubemirror/Chart.yaml b/charts/kubemirror/Chart.yaml new file mode 100644 index 0000000..6dcc110 --- /dev/null +++ b/charts/kubemirror/Chart.yaml @@ -0,0 +1,18 @@ +apiVersion: v2 +name: kubemirror +description: Kubernetes controller for mirroring resources across namespaces +type: application +version: 0.2.8 +appVersion: "0.2.8" +keywords: + - kubernetes + - controller + - mirror + - secrets + - configmaps +home: https://github.com/lukaszraczylo/kubemirror +sources: + - https://github.com/lukaszraczylo/kubemirror +maintainers: + - name: Lukasz Raczylo + email: lukasz@raczylo.com diff --git a/charts/kubemirror/templates/NOTES.txt b/charts/kubemirror/templates/NOTES.txt new file mode 100644 index 0000000..5709c23 --- /dev/null +++ b/charts/kubemirror/templates/NOTES.txt @@ -0,0 +1,36 @@ +Thank you for installing {{ .Chart.Name }}. + +Your release is named {{ .Release.Name }}. + +To learn more about the release, try: + + $ helm status {{ .Release.Name }} -n {{ .Release.Namespace }} + $ helm get all {{ .Release.Name }} -n {{ .Release.Namespace }} + +KubeMirror is now running and will automatically mirror resources across namespaces. + +To mirror a Secret or ConfigMap, add this LABEL and ANNOTATIONS: + + # Label (required for server-side filtering): + kubemirror.raczylo.com/enabled: "true" + + # Annotations: + kubemirror.raczylo.com/sync: "true" + kubemirror.raczylo.com/target-namespaces: "namespace1,namespace2" + +Or use "all" to mirror to all namespaces with the allow-mirrors label: + + kubemirror.raczylo.com/target-namespaces: "all" + +To allow a namespace to receive mirrored resources, add this label: + + kubemirror.raczylo.com/allow-mirrors: "true" + +View controller logs: + + $ kubectl logs -n {{ .Release.Namespace }} -l app.kubernetes.io/name={{ include "kubemirror.name" . }} + +Check metrics: + + $ kubectl port-forward -n {{ .Release.Namespace }} svc/{{ include "kubemirror.fullname" . }}-metrics {{ .Values.service.metricsPort }}:{{ .Values.service.metricsPort }} + $ curl http://localhost:{{ .Values.service.metricsPort }}/metrics diff --git a/charts/kubemirror/templates/_helpers.tpl b/charts/kubemirror/templates/_helpers.tpl new file mode 100644 index 0000000..04d3ab0 --- /dev/null +++ b/charts/kubemirror/templates/_helpers.tpl @@ -0,0 +1,60 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "kubemirror.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +*/}} +{{- define "kubemirror.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 "kubemirror.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "kubemirror.labels" -}} +helm.sh/chart: {{ include "kubemirror.chart" . }} +{{ include "kubemirror.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "kubemirror.selectorLabels" -}} +app.kubernetes.io/name: {{ include "kubemirror.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "kubemirror.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "kubemirror.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/charts/kubemirror/templates/clusterrole.yaml b/charts/kubemirror/templates/clusterrole.yaml new file mode 100644 index 0000000..b8ce4f0 --- /dev/null +++ b/charts/kubemirror/templates/clusterrole.yaml @@ -0,0 +1,57 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: {{ include "kubemirror.fullname" . }} + labels: + {{- include "kubemirror.labels" . | nindent 4 }} +rules: + # Discovery - read access to all API groups for resource discovery + # This is required for auto-discovering available resource types + - apiGroups: ["*"] + resources: ["*"] + verbs: + - get + - list + - watch + + # Full access to all mirrorable resources + # Required for creating, updating, and deleting mirrors across all resource types + # The controller will only mirror resources that are explicitly marked with + # kubemirror.raczylo.com/enabled label and kubemirror.raczylo.com/sync annotation + - apiGroups: ["*"] + resources: ["*"] + verbs: + - create + - update + - patch + - delete + + # Namespaces - read only (for listing and filtering) + - apiGroups: [""] + resources: + - namespaces + verbs: + - get + - list + - watch + + # Leader election - coordination.k8s.io/v1 + - apiGroups: ["coordination.k8s.io"] + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete + + # Events - for creating events about mirroring operations + - apiGroups: [""] + resources: + - events + verbs: + - create + - patch diff --git a/charts/kubemirror/templates/clusterrolebinding.yaml b/charts/kubemirror/templates/clusterrolebinding.yaml new file mode 100644 index 0000000..fe30d53 --- /dev/null +++ b/charts/kubemirror/templates/clusterrolebinding.yaml @@ -0,0 +1,14 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "kubemirror.fullname" . }} + labels: + {{- include "kubemirror.labels" . | nindent 4 }} +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: {{ include "kubemirror.fullname" . }} +subjects: + - kind: ServiceAccount + name: {{ include "kubemirror.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} diff --git a/charts/kubemirror/templates/deployment.yaml b/charts/kubemirror/templates/deployment.yaml new file mode 100644 index 0000000..aa85ab2 --- /dev/null +++ b/charts/kubemirror/templates/deployment.yaml @@ -0,0 +1,95 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "kubemirror.fullname" . }} + labels: + {{- include "kubemirror.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + {{- include "kubemirror.selectorLabels" . | nindent 6 }} + template: + metadata: + annotations: + {{- toYaml .Values.podAnnotations | nindent 8 }} + labels: + {{- include "kubemirror.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "kubemirror.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + {{- with .Values.priorityClassName }} + priorityClassName: {{ . }} + {{- end }} + containers: + - name: controller + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + command: + - /kubemirror + args: + - --metrics-bind-address={{ .Values.controller.metricsBindAddress }} + - --health-probe-bind-address={{ .Values.controller.healthProbeBindAddress }} + {{- if .Values.controller.leaderElect }} + - --leader-elect + {{- end }} + - --leader-election-id={{ .Values.controller.leaderElectionID }} + - --max-targets={{ .Values.controller.maxTargets }} + - --worker-threads={{ .Values.controller.workerThreads }} + - --rate-limit-qps={{ .Values.controller.rateLimitQPS }} + - --rate-limit-burst={{ .Values.controller.rateLimitBurst }} + {{- if .Values.controller.excludedNamespaces }} + - --excluded-namespaces={{ .Values.controller.excludedNamespaces }} + {{- end }} + {{- if .Values.controller.includedNamespaces }} + - --included-namespaces={{ .Values.controller.includedNamespaces }} + {{- end }} + {{- if .Values.controller.resourceTypes }} + - --resource-types={{ join "," .Values.controller.resourceTypes }} + {{- end }} + - --discovery-interval={{ .Values.controller.discoveryInterval }} + ports: + - name: metrics + containerPort: 8080 + protocol: TCP + - name: health + containerPort: 8081 + protocol: TCP + livenessProbe: + httpGet: + path: /healthz + port: health + initialDelaySeconds: 15 + periodSeconds: 20 + timeoutSeconds: 5 + failureThreshold: 3 + readinessProbe: + httpGet: + path: /readyz + port: health + initialDelaySeconds: 5 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 3 + resources: + {{- toYaml .Values.resources | nindent 12 }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + terminationGracePeriodSeconds: 10 + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/charts/kubemirror/templates/service.yaml b/charts/kubemirror/templates/service.yaml new file mode 100644 index 0000000..0ace2cc --- /dev/null +++ b/charts/kubemirror/templates/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "kubemirror.fullname" . }}-metrics + labels: + {{- include "kubemirror.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - name: metrics + port: {{ .Values.service.metricsPort }} + targetPort: metrics + protocol: TCP + - name: health + port: {{ .Values.service.healthPort }} + targetPort: health + protocol: TCP + selector: + {{- include "kubemirror.selectorLabels" . | nindent 4 }} diff --git a/charts/kubemirror/templates/serviceaccount.yaml b/charts/kubemirror/templates/serviceaccount.yaml new file mode 100644 index 0000000..ca61f42 --- /dev/null +++ b/charts/kubemirror/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "kubemirror.serviceAccountName" . }} + labels: + {{- include "kubemirror.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/kubemirror/values.yaml b/charts/kubemirror/values.yaml new file mode 100644 index 0000000..9502b06 --- /dev/null +++ b/charts/kubemirror/values.yaml @@ -0,0 +1,86 @@ +replicaCount: 1 + +image: + repository: ghcr.io/lukaszraczylo/kubemirror + pullPolicy: IfNotPresent + tag: "0.2.8" + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + create: true + annotations: {} + name: "" + +podAnnotations: + prometheus.io/scrape: "true" + prometheus.io/port: "8080" + prometheus.io/path: "/metrics" + +podSecurityContext: + runAsNonRoot: true + runAsUser: 65532 + fsGroup: 65532 + seccompProfile: + type: RuntimeDefault + +securityContext: + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + runAsNonRoot: true + capabilities: + drop: + - ALL + +controller: + # Metrics and health endpoints + metricsBindAddress: ":8080" + healthProbeBindAddress: ":8081" + + # Leader election + leaderElect: true + leaderElectionID: "kubemirror-controller-leader" + + # Resource types to mirror + # Examples: ["Secret.v1", "ConfigMap.v1", "Ingress.v1.networking.k8s.io"] + # If empty, auto-discovery will find all mirrorable resources + resourceTypes: [] + + # Auto-discovery interval (only used when resourceTypes is empty) + # How often to rediscover available resources in the cluster + discoveryInterval: "5m" + + # Resource limits + maxTargets: 100 + workerThreads: 5 + + # API rate limiting + rateLimitQPS: 50.0 + rateLimitBurst: 100 + + # Namespace filtering + excludedNamespaces: "" + includedNamespaces: "" + +service: + type: ClusterIP + metricsPort: 8080 + healthPort: 8081 + +resources: + limits: + cpu: 500m + memory: 512Mi + requests: + cpu: 100m + memory: 128Mi + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +priorityClassName: "" diff --git a/charts/packages/kubemirror-0.2.8.tgz b/charts/packages/kubemirror-0.2.8.tgz new file mode 100644 index 0000000000000000000000000000000000000000..074b88e3c83fc7731f061e33259d47448ad92fe4 GIT binary patch literal 3358 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