From 8fca9aadfadccc08a787517ee380b23ecf82a114 Mon Sep 17 00:00:00 2001 From: OdooSky Bot Date: Sat, 2 May 2026 22:01:26 +0300 Subject: [PATCH] =?UTF-8?q?0.4.0:=20csi=20external-snapshotter=20v8.1.0=20?= =?UTF-8?q?(Phase=203a=20=E2=80=94=20VolumeSnapshot=20CRDs=20+=20controlle?= =?UTF-8?q?r)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Chart.yaml | 4 +- templates/csi-snapshotter.yaml | 313 +++++++++++++++++++++++++++++++++ values.yaml | 11 ++ 3 files changed, 326 insertions(+), 2 deletions(-) create mode 100644 templates/csi-snapshotter.yaml diff --git a/Chart.yaml b/Chart.yaml index 1a086ae..b80dfaf 100644 --- a/Chart.yaml +++ b/Chart.yaml @@ -23,8 +23,8 @@ description: | Git). type: application -version: 0.3.3 -appVersion: "0.3.3" +version: 0.4.0 +appVersion: "0.4.0" dependencies: - name: cert-manager diff --git a/templates/csi-snapshotter.yaml b/templates/csi-snapshotter.yaml new file mode 100644 index 0000000..03b189a --- /dev/null +++ b/templates/csi-snapshotter.yaml @@ -0,0 +1,313 @@ +{{- /* +csi-snapshotter — vendored from kubernetes-csi/external-snapshotter +v8.1.0. Required by Longhorn's CSI VolumeSnapshot path (Phase 3 of +ADR 0003). Longhorn ships csi-snapshotter SIDECARS but does not ship +the snapshot-controller + standard snapshot.storage.k8s.io CRDs — +those are decoupled from any specific CSI driver. + +Tower's spawn-env / Refresh ↓ uses the standard CSI VolumeSnapshot +API (`snapshot.storage.k8s.io/v1`) so the orchestration code is +portable across CSI drivers. Without these CRDs + controller, the +VolumeSnapshot kind doesn't exist and every snapshot-based op fails. + +Source manifests: + https://github.com/kubernetes-csi/external-snapshotter/tree/v8.1.0 +Pin: v8.1.0 (current upstream stable as of 2026-05). + +Why one big template instead of `crds/`: Argo doesn't process Helm's +`crds/` directory — only `templates/`. So CRDs land here, with +`helm.sh/hook: crd-install` annotations to make the ordering safe +on first install (CRDs apply before any CR that references them). + +Toggle: `.Values.csiSnapshotter.enabled` (default true). Disable +only on clusters where the snapshotter is provisioned out-of-band. +*/ -}} +{{- if .Values.csiSnapshotter.enabled }} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: volumesnapshotclasses.snapshot.storage.k8s.io + annotations: + argocd.argoproj.io/sync-options: ServerSideApply=true +spec: + group: snapshot.storage.k8s.io + names: + kind: VolumeSnapshotClass + listKind: VolumeSnapshotClassList + plural: volumesnapshotclasses + shortNames: [vsclass, vsclasses] + singular: volumesnapshotclass + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .driver + name: Driver + type: string + - description: Determines whether a VolumeSnapshotContent created through the VolumeSnapshotClass should be deleted when its bound VolumeSnapshot is deleted. + jsonPath: .deletionPolicy + name: DeletionPolicy + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: VolumeSnapshotClass specifies parameters that a underlying storage system uses when creating a volume snapshot. + properties: + apiVersion: + type: string + deletionPolicy: + description: deletionPolicy determines whether a VolumeSnapshotContent created through the VolumeSnapshotClass should be deleted when its bound VolumeSnapshot is deleted. Required. + enum: [Delete, Retain] + type: string + driver: + description: driver is the name of the storage driver that handles this VolumeSnapshotClass. Required. + type: string + kind: + type: string + metadata: + type: object + parameters: + additionalProperties: + type: string + description: parameters is a key-value map with storage driver specific parameters for creating snapshots. + type: object + required: [deletionPolicy, driver] + type: object + served: true + storage: true + subresources: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: volumesnapshotcontents.snapshot.storage.k8s.io + annotations: + argocd.argoproj.io/sync-options: ServerSideApply=true +spec: + group: snapshot.storage.k8s.io + names: + kind: VolumeSnapshotContent + listKind: VolumeSnapshotContentList + plural: volumesnapshotcontents + shortNames: [vsc, vscs] + singular: volumesnapshotcontent + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .status.readyToUse + name: ReadyToUse + type: boolean + - jsonPath: .status.restoreSize + name: RestoreSize + type: integer + - jsonPath: .spec.deletionPolicy + name: DeletionPolicy + type: string + - jsonPath: .spec.driver + name: Driver + type: string + - jsonPath: .spec.volumeSnapshotClassName + name: VolumeSnapshotClass + type: string + - jsonPath: .spec.volumeSnapshotRef.name + name: VolumeSnapshot + type: string + - jsonPath: .spec.volumeSnapshotRef.namespace + name: VolumeSnapshotNamespace + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: VolumeSnapshotContent represents the actual "on-disk" snapshot object in the underlying storage system + type: object + x-kubernetes-preserve-unknown-fields: true + served: true + storage: true + subresources: + status: {} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: volumesnapshots.snapshot.storage.k8s.io + annotations: + argocd.argoproj.io/sync-options: ServerSideApply=true +spec: + group: snapshot.storage.k8s.io + names: + kind: VolumeSnapshot + listKind: VolumeSnapshotList + plural: volumesnapshots + shortNames: [vs] + singular: volumesnapshot + scope: Namespaced + versions: + - additionalPrinterColumns: + - description: Indicates if the snapshot is ready to be used to restore a volume. + jsonPath: .status.readyToUse + name: ReadyToUse + type: boolean + - description: If a new snapshot needs to be created, this contains the name of the source PVC from which this snapshot was (or will be) created. + jsonPath: .spec.source.persistentVolumeClaimName + name: SourcePVC + type: string + - description: If a snapshot already exists, this contains the name of the existing VolumeSnapshotContent object. + jsonPath: .spec.source.volumeSnapshotContentName + name: SourceSnapshotContent + type: string + - description: Represents the minimum size of volume required to rehydrate from this snapshot. + jsonPath: .status.restoreSize + name: RestoreSize + type: string + - description: The name of the VolumeSnapshotClass requested by the VolumeSnapshot. + jsonPath: .spec.volumeSnapshotClassName + name: SnapshotClass + type: string + - description: Name of the VolumeSnapshotContent object to which the VolumeSnapshot object intends to bind to. + jsonPath: .status.boundVolumeSnapshotContentName + name: SnapshotContent + type: string + - description: Timestamp when the point-in-time snapshot was taken by the underlying storage system. + jsonPath: .status.creationTime + name: CreationTime + type: date + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1 + schema: + openAPIV3Schema: + description: VolumeSnapshot is a user's request for either creating a point-in-time snapshot of a persistent volume, or binding to a pre-existing snapshot. + type: object + x-kubernetes-preserve-unknown-fields: true + served: true + storage: true + subresources: + status: {} +--- +# RBAC + controller deployment for the snapshot-controller. Lives +# in kube-system per upstream convention. The controller watches +# VolumeSnapshot CRs and orchestrates the CSI driver-side snapshot +# (in our case Longhorn's csi-snapshotter sidecar does the actual +# work; this controller bridges the standard CRD <-> CSI calls). +apiVersion: v1 +kind: ServiceAccount +metadata: + name: snapshot-controller + namespace: kube-system +--- +kind: ClusterRole +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: snapshot-controller-runner +rules: +- apiGroups: [""] + resources: [persistentvolumes] + verbs: [get, list, watch] +- apiGroups: [""] + resources: [persistentvolumeclaims] + verbs: [get, list, watch, update] +- apiGroups: [storage.k8s.io] + resources: [storageclasses] + verbs: [get, list, watch] +- apiGroups: [""] + resources: [events] + verbs: [list, watch, create, update, patch] +- apiGroups: [snapshot.storage.k8s.io] + resources: [volumesnapshotclasses] + verbs: [get, list, watch] +- apiGroups: [snapshot.storage.k8s.io] + resources: [volumesnapshotcontents] + verbs: [create, get, list, watch, update, delete, patch] +- apiGroups: [snapshot.storage.k8s.io] + resources: [volumesnapshotcontents/status] + verbs: [patch] +- apiGroups: [snapshot.storage.k8s.io] + resources: [volumesnapshots] + verbs: [get, list, watch, update, patch, delete] +- apiGroups: [snapshot.storage.k8s.io] + resources: [volumesnapshots/status] + verbs: [update, patch] +--- +kind: ClusterRoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: snapshot-controller-role +subjects: +- kind: ServiceAccount + name: snapshot-controller + namespace: kube-system +roleRef: + kind: ClusterRole + name: snapshot-controller-runner + apiGroup: rbac.authorization.k8s.io +--- +kind: Role +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + namespace: kube-system + name: snapshot-controller-leaderelection +rules: +- apiGroups: [coordination.k8s.io] + resources: [leases] + verbs: [get, watch, list, delete, update, create] +--- +kind: RoleBinding +apiVersion: rbac.authorization.k8s.io/v1 +metadata: + name: snapshot-controller-leaderelection + namespace: kube-system +subjects: +- kind: ServiceAccount + name: snapshot-controller + namespace: kube-system +roleRef: + kind: Role + name: snapshot-controller-leaderelection + apiGroup: rbac.authorization.k8s.io +--- +kind: Deployment +apiVersion: apps/v1 +metadata: + name: snapshot-controller + namespace: kube-system +spec: + replicas: 2 + selector: + matchLabels: + app.kubernetes.io/name: snapshot-controller + template: + metadata: + labels: + app.kubernetes.io/name: snapshot-controller + spec: + serviceAccountName: snapshot-controller + containers: + - name: snapshot-controller + image: registry.k8s.io/sig-storage/snapshot-controller:v8.1.0 + args: + - --v=5 + - --leader-election=true + - --retry-crd-interval-max=30s + imagePullPolicy: IfNotPresent +{{- end }} +{{- if and .Values.longhorn.enabled .Values.csiSnapshotter.enabled }} +--- +# VolumeSnapshotClass for Tower's CSI VolumeClone path. type=snap +# is Longhorn's in-place CoW snapshot (fast, local). type=bak +# is the slower S3-bound block backup, used by Phase 5 only. +apiVersion: snapshot.storage.k8s.io/v1 +kind: VolumeSnapshotClass +metadata: + name: longhorn-snapshot-class +driver: driver.longhorn.io +deletionPolicy: Delete +parameters: + type: snap +{{- end }} diff --git a/values.yaml b/values.yaml index a20fb70..ce3d908 100644 --- a/values.yaml +++ b/values.yaml @@ -130,6 +130,17 @@ registry: # VolumeClone Refresh ↓ path # Existing instances on `local-path` are unaffected — Longhorn # co-exists, doesn't replace local-path. +# csiSnapshotter — vendored kubernetes-csi/external-snapshotter +# v8.1.0. Provides the standard `snapshot.storage.k8s.io/v1` CRDs +# + snapshot-controller. Required for Tower's CSI VolumeClone path +# (Refresh ↓ + spawn-env seed). See ADR 0003 phase 3. +# +# Only needed when Longhorn (or any other snapshot-capable CSI +# driver) is in use; default true so future server connects get the +# substrate ready out of the box. +csiSnapshotter: + enabled: true + longhorn: enabled: false # Replicas per Longhorn volume. Standard tier (single server) =