diff --git a/packs/garage-0.9.3/README.md b/packs/garage-0.9.3/README.md new file mode 100644 index 00000000..40ab9be7 --- /dev/null +++ b/packs/garage-0.9.3/README.md @@ -0,0 +1,213 @@ +# Garage + +[Garage](https://garagehq.deuxfleurs.fr/) is a lightweight, S3-compatible distributed object store built by [Deuxfleurs](https://deuxfleurs.fr/). It is designed for self-hosted, geo-distributed deployments running on commodity hardware — it tolerates high-latency links between nodes and does not require a dedicated storage network, which makes it a good fit for edge clusters and small on-prem footprints where Ceph or MinIO would be too heavy. + +This pack deploys Garage as a 3-replica StatefulSet using the upstream Helm chart (chart `0.9.3`, app `v2.3.0`). Nodes discover each other automatically through the built-in Kubernetes discovery mechanism, so no bootstrap peer list is needed. + +> [!IMPORTANT] +> Garage does not self-assemble into a usable cluster. After the pods are running you **must** manually assign a layout to each node before the S3 API will accept any data. See [Post-Installation](#post-installation). + + +## Prerequisites + +- A Kubernetes cluster with a default StorageClass, or an explicit `storageClass` set under `persistence` (see [Storage](#storage)). +- Permission to create cluster-scoped resources. The chart installs the `garagenodes.deuxfleurs.fr` CRD and a ClusterRole used for peer discovery. If you cannot grant cluster-scoped access, set `garage.kubernetesSkipCrd: true` and install the CRD out of band. +- At least 3 schedulable nodes if you keep the default `replicationFactor: "3"`. With fewer nodes, replicas will co-locate and you lose the durability the replication factor implies. + + +## Parameters + +| **Parameter** | **Description** | **Type** | **Default Value** | **Required** | +|---|---|---|---|---| +| `deployment.kind` | `StatefulSet` (PVC-backed) or `DaemonSet` (hostPath-backed) | String | `StatefulSet` | No | +| `deployment.replicaCount` | Number of Garage nodes | Integer | `3` | No | +| `garage.replicationFactor` | Copies of each object across the cluster | String | `"3"` | No | +| `garage.consistencyMode` | `consistent` (read-after-write), `degraded`, or `dangerous` | String | `"consistent"` | No | +| `garage.dbEngine` | Metadata engine: `lmdb` or `sqlite` | String | `"lmdb"` | No | +| `garage.blockSize` | Data block size in bytes | String | `"1048576"` | No | +| `garage.compressionLevel` | zstd level for stored blocks | String | `"1"` | No | +| `garage.metadataAutoSnapshotInterval` | Interval for automatic metadata DB snapshots, e.g. `6h`. Empty disables | String | `""` | No | +| `garage.rpcSecret` | Shared secret for inter-node RPC. Generated and stored in a Secret if left empty | String | `""` | No | +| `garage.existingRpcSecret` | Name of an existing Secret holding the RPC secret under key `rpcSecret` | String | `""` | No | +| `garage.kubernetesSkipCrd` | Skip installing the `garagenodes` CRD | Boolean | `false` | No | +| `garage.s3.api.region` | S3 region name advertised to clients | String | `"garage"` | No | +| `garage.s3.api.rootDomain` | Suffix enabling virtual-hosted bucket addressing | String | `".s3.garage.tld"` | No | +| `garage.s3.web.rootDomain` | Suffix for static website hosting from buckets | String | `".web.garage.tld"` | No | +| `garage.additionalTopLevelConfig` | Raw TOML appended to `garage.toml` | String | `""` | No | +| `garage.garageTomlString` | Full `garage.toml` template. **Overrides all other `garage.*` values** | String | `""` | No | +| `persistence.enabled` | Persist metadata and data | Boolean | `true` | No | +| `persistence.meta.size` | Metadata volume size | String | `100Mi` | **Yes — raise it** | +| `persistence.data.size` | Data volume size | String | `100Mi` | **Yes — raise it** | +| `service.type` | `ClusterIP`, `NodePort`, or `LoadBalancer` | String | `ClusterIP` | No | +| `ingress.s3.api.enabled` | Expose the S3 API through an Ingress | Boolean | `false` | No | +| `ingress.s3.web.enabled` | Expose bucket static-website serving through an Ingress | Boolean | `false` | No | +| `monitoring.metrics.enabled` | Annotate a Service for Prometheus scraping | Boolean | `false` | No | +| `monitoring.metrics.serviceMonitor.enabled` | Create a `ServiceMonitor` (requires Prometheus Operator) | Boolean | `false` | No | +| `resources` | Pod resource requests and limits | Object | `{}` | No | + +The full set of chart values is documented in [`charts/garage/README.md`](charts/garage/README.md). + + +## Storage + +The chart ships with `100Mi` volumes for both metadata and data. **These defaults are placeholders and are not usable for real workloads** — size them before the first deploy: + +```yaml +charts: + garage: + persistence: + meta: + storageClass: "fast-storage-class" # SSD-backed; LMDB is latency-sensitive + size: 5Gi + data: + storageClass: "bulk-storage-class" # Capacity matters more than latency here + size: 500Gi +``` + +Resizing after deployment is awkward: StatefulSet `volumeClaimTemplates` are immutable, so growing volumes requires orphaning the StatefulSet (`kubectl delete sts --cascade=orphan`), editing the PVCs, and letting the pack recreate the controller. Your StorageClass must have `allowVolumeExpansion: true`. Size generously up front. + +Setting `deployment.kind: DaemonSet` switches Garage to hostPath storage at `persistence.meta.hostPath` and `persistence.data.hostPath`, placing one node per host. This suits edge clusters with direct-attached disks, but the paths must exist and be writable by UID/GID `1000`. + + +## Usage + +To use this pack, create or edit an [add-on cluster profile](https://docs.spectrocloud.com/profiles/cluster-profiles/create-cluster-profiles/create-addon-profile/), search for the **garage** pack, and adjust the values. A minimal production-shaped override: + +```yaml +charts: + garage: + deployment: + replicaCount: 3 + garage: + replicationFactor: "3" + consistencyMode: "consistent" + metadataAutoSnapshotInterval: "6h" + s3: + api: + region: "us-east-1" + rootDomain: ".s3.example.com" + persistence: + meta: + storageClass: "fast-storage-class" + size: 5Gi + data: + storageClass: "bulk-storage-class" + size: 500Gi + resources: + requests: + cpu: 250m + memory: 1Gi + limits: + memory: 2Gi +``` + +The pack deploys into the `garage` namespace. + +### Exposing the S3 API + +By default the API is only reachable in-cluster at `garage.garage.svc.cluster.local:3900`. To reach it from outside, either set `service.type: LoadBalancer` or enable the Ingress. Virtual-hosted bucket addressing (`bucket.s3.example.com`) requires a wildcard host, and `garage.s3.api.rootDomain` must match: + +```yaml +charts: + garage: + ingress: + s3: + api: + enabled: true + className: "nginx" + hosts: + - host: "s3.example.com" + paths: + - path: / + pathType: Prefix + - host: "*.s3.example.com" + paths: + - path: / + pathType: Prefix + tls: + - secretName: garage-s3-tls + hosts: + - "s3.example.com" + - "*.s3.example.com" +``` + +S3 clients that only support path-style addressing (`s3.example.com/bucket`) work without the wildcard host. + + +## Post-Installation + +A freshly deployed Garage cluster has no layout, which means it has zero usable capacity and rejects all S3 operations. The `garage` CLI is bundled in the container image; run it via `kubectl exec` against any pod. + +**1. Confirm all nodes see each other.** Each pod should be listed with a node ID: + +```bash +kubectl exec -it -n garage garage-0 -- ./garage status +``` + +**2. Assign a layout role to each node.** Use the first several characters of each node ID (enough to be unique). `--zone` should reflect physical failure domains — with `replicationFactor: 3`, Garage spreads copies across distinct zones when it can. `--capacity` is the share of data the node accepts, and should track the size of its data volume: + +```bash +kubectl exec -it -n garage garage-0 -- ./garage layout assign -z dc1 -c 500G -t garage-0 +kubectl exec -it -n garage garage-0 -- ./garage layout assign -z dc2 -c 500G -t garage-1 +kubectl exec -it -n garage garage-0 -- ./garage layout assign -z dc3 -c 500G -t garage-2 +``` + +**3. Review and apply.** The version number must be exactly one greater than the current layout version — `1` for the first apply: + +```bash +kubectl exec -it -n garage garage-0 -- ./garage layout show +kubectl exec -it -n garage garage-0 -- ./garage layout apply --version 1 +``` + +**4. Create a bucket and a key, then grant access:** + +```bash +kubectl exec -it -n garage garage-0 -- ./garage bucket create my-bucket +kubectl exec -it -n garage garage-0 -- ./garage key create my-app-key +kubectl exec -it -n garage garage-0 -- ./garage bucket allow --read --write my-bucket --key my-app-key +``` + +`key create` prints the access key ID and secret access key **once** — capture them at that moment. Point any S3 client at the API endpoint using the region from `garage.s3.api.region`. + +Adding or removing nodes later repeats steps 2–3 with an incremented `--version`. Garage rebalances data automatically after the new layout is applied. + + +## Monitoring + +Garage exposes Prometheus metrics on the admin API port (`3903`). With the Prometheus Operator installed: + +```yaml +charts: + garage: + monitoring: + metrics: + enabled: true + serviceMonitor: + enabled: true + interval: 30s +``` + +The admin API is deliberately excluded from the main Service because its responses are not consistent across nodes — query a specific pod when using it directly. + + +## Uninstalling + +Removing the pack from the cluster profile deletes the workloads but leaves two things behind on purpose: + +- **PersistentVolumeClaims** are retained by the StatefulSet controller. Delete them explicitly to reclaim storage — and only once you are certain the data is not needed. +- **The `garagenodes.deuxfleurs.fr` CRD** is not removed by Helm and must be deleted manually if you are permanently retiring Garage. + + +## Kubernetes Compatibility + +Requires Kubernetes v1.19 or later (`networking.k8s.io/v1` Ingress). + + +## References + +- [Garage documentation](https://garagehq.deuxfleurs.fr/documentation/) +- [Deploying on Kubernetes](https://garagehq.deuxfleurs.fr/documentation/cookbook/kubernetes/) +- [Creating a cluster layout](https://garagehq.deuxfleurs.fr/documentation/operations/layout/) +- [Configuration reference](https://garagehq.deuxfleurs.fr/documentation/reference-manual/configuration/) +- [S3 compatibility matrix](https://garagehq.deuxfleurs.fr/documentation/reference-manual/s3-compatibility/) +- [Source code](https://git.deuxfleurs.fr/Deuxfleurs/garage) diff --git a/packs/garage-0.9.3/charts/garage-0.9.3.tgz b/packs/garage-0.9.3/charts/garage-0.9.3.tgz new file mode 100644 index 00000000..a14ba166 Binary files /dev/null and b/packs/garage-0.9.3/charts/garage-0.9.3.tgz differ diff --git a/packs/garage-0.9.3/charts/garage/.helmignore b/packs/garage-0.9.3/charts/garage/.helmignore new file mode 100644 index 00000000..0e8a0eb3 --- /dev/null +++ b/packs/garage-0.9.3/charts/garage/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/packs/garage-0.9.3/charts/garage/Chart.yaml b/packs/garage-0.9.3/charts/garage/Chart.yaml new file mode 100644 index 00000000..110ba8c7 --- /dev/null +++ b/packs/garage-0.9.3/charts/garage/Chart.yaml @@ -0,0 +1,18 @@ +apiVersion: v2 +name: garage +description: S3-compatible object store for small self-hosted geo-distributed deployments +type: application +version: 0.9.3 +appVersion: "v2.3.0" +home: https://garagehq.deuxfleurs.fr/ +icon: https://garagehq.deuxfleurs.fr/images/garage-logo.svg + +keywords: +- geo-distributed +- read-after-write-consistency +- s3-compatible + +sources: +- https://git.deuxfleurs.fr/Deuxfleurs/garage.git + +maintainers: [] diff --git a/packs/garage-0.9.3/charts/garage/README.md b/packs/garage-0.9.3/charts/garage/README.md new file mode 100644 index 00000000..1473e320 --- /dev/null +++ b/packs/garage-0.9.3/charts/garage/README.md @@ -0,0 +1,100 @@ +# garage + +![Version: 0.9.3](https://img.shields.io/badge/Version-0.9.3-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: v2.3.0](https://img.shields.io/badge/AppVersion-v2.3.0-informational?style=flat-square) + +S3-compatible object store for small self-hosted geo-distributed deployments + +**Homepage:** + +## Source Code + +* + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| affinity | object | `{}` | | +| commonLabels | object | `{}` | Extra labels for all resources | +| deployment.kind | string | `"StatefulSet"` | Switchable to DaemonSet | +| deployment.podManagementPolicy | string | `"OrderedReady"` | If using statefulset, allow Parallel or OrderedReady (default) | +| deployment.replicaCount | int | `3` | Number of StatefulSet replicas/garage nodes to start | +| environment | object | `{}` | | +| extraVolumeMounts | object | `{}` | | +| extraVolumes | object | `{}` | | +| fullnameOverride | string | `""` | | +| garage.blockSize | string | `"1048576"` | Defaults is 1MB An increase can result in better performance in certain scenarios https://garagehq.deuxfleurs.fr/documentation/reference-manual/configuration/#block_size | +| garage.bootstrapPeers | list | `[]` | This is not required if you use the integrated kubernetes discovery | +| garage.compressionLevel | string | `"1"` | zstd compression level of stored blocks https://garagehq.deuxfleurs.fr/documentation/reference-manual/configuration/#compression_level | +| garage.dbEngine | string | `"lmdb"` | Can be changed for better performance on certain systems https://garagehq.deuxfleurs.fr/documentation/reference-manual/configuration/#db_engine | +| garage.existingConfigMap | string | `""` | if not empty string, allow using an existing ConfigMap for the garage.toml, if set, ignores garage.toml | +| garage.garageTomlString | string | `""` | String Template for the garage configuration if set, ignores above values. Values can be templated, see https://garagehq.deuxfleurs.fr/documentation/reference-manual/configuration/ | +| garage.kubernetesSkipCrd | bool | `false` | Set to true if you want to use k8s discovery but install the CRDs manually outside of the helm chart, for example if you operate at namespace level without cluster resources | +| garage.replicationFactor | string | `"3"` | Default to 3 replicas, see the replication_factor section at https://garagehq.deuxfleurs.fr/documentation/reference-manual/configuration/#replication_factor | +| garage.consistencyMode | string | `"consistent"` | Default to read-after-write consistency, see the consistency_mode section at https://garagehq.deuxfleurs.fr/documentation/reference-manual/configuration/#consistency_mode | +| garage.metadataAutoSnapshotInterval | string | `""` | If this value is set, Garage will automatically take a snapshot of the metadata DB file at a regular interval and save it in the metadata directory. https://garagehq.deuxfleurs.fr/documentation/reference-manual/configuration/#metadata_auto_snapshot_interval | +| garage.admin.apiBindAddr | string | `"[::]:3903"` | | +| garage.rpcBindAddr | string | `"[::]:3901"` | | +| garage.rpcSecret | string | `""` | If not given, a random secret will be generated and stored in a Secret object | +| garage.s3.api.bindAddr | string | `"[::]:3900"` | | +| garage.s3.api.region | string | `"garage"` | | +| garage.s3.api.rootDomain | string | `".s3.garage.tld"` | | +| garage.s3.web.index | string | `"index.html"` | | +| garage.s3.web.bindAddr | string | `"[::]:3902"` | | +| garage.s3.web.rootDomain | string | `".web.garage.tld"` | | +| image.pullPolicy | string | `"IfNotPresent"` | | +| image.repository | string | `"dxflrs/amd64_garage"` | default to amd64 docker image | +| image.tag | string | `""` | set the image tag, please prefer using the chart version and not this to avoid compatibility issues | +| imagePullSecrets | list | `[]` | set if you need credentials to pull your custom image | +| ingress.s3.api.annotations | object | `{}` | Rely _either_ on the className or the annotation below but not both! If you want to use the className, set className: "nginx" and replace "nginx" by an Ingress controller name, examples [here](https://kubernetes.io/docs/concepts/services-networking/ingress-controllers). | +| ingress.s3.api.enabled | bool | `false` | | +| ingress.s3.api.hosts[0] | object | `{"host":"s3.garage.tld","paths":[{"path":"/","pathType":"Prefix"}]}` | garage S3 API endpoint, to be used with awscli for example | +| ingress.s3.api.hosts[1] | object | `{"host":"*.s3.garage.tld","paths":[{"path":"/","pathType":"Prefix"}]}` | garage S3 API endpoint, DNS style bucket access | +| ingress.s3.api.labels | object | `{}` | | +| ingress.s3.api.tls | list | `[]` | | +| ingress.s3.web.annotations | object | `{}` | Rely _either_ on the className or the annotation below but not both! If you want to use the className, set className: "nginx" and replace "nginx" by an Ingress controller name, examples [here](https://kubernetes.io/docs/concepts/services-networking/ingress-controllers). | +| ingress.s3.web.enabled | bool | `false` | | +| ingress.s3.web.hosts[0] | object | `{"host":"*.web.garage.tld","paths":[{"path":"/","pathType":"Prefix"}]}` | wildcard website access with bucket name prefix | +| ingress.s3.web.hosts[1] | object | `{"host":"mywebpage.example.com","paths":[{"path":"/","pathType":"Prefix"}]}` | specific bucket access with FQDN bucket | +| ingress.s3.web.labels | object | `{}` | | +| ingress.s3.web.tls | list | `[]` | | +| initImage.pullPolicy | string | `"IfNotPresent"` | | +| initImage.repository | string | `"busybox"` | | +| initImage.tag | string | `"stable"` | | +| livenessProbe | object | `{}` | Specifies a livenessProbe | +| monitoring.metrics.enabled | bool | `false` | If true, a service for monitoring is created with a prometheus.io/scrape annotation | +| monitoring.metrics.serviceMonitor.enabled | bool | `false` | If true, a ServiceMonitor CRD is created for a prometheus operator https://github.com/coreos/prometheus-operator | +| monitoring.metrics.serviceMonitor.interval | string | `"15s"` | | +| monitoring.metrics.serviceMonitor.labels | object | `{}` | | +| monitoring.metrics.serviceMonitor.path | string | `"/metrics"` | | +| monitoring.metrics.serviceMonitor.relabelings | list | `[]` | | +| monitoring.metrics.serviceMonitor.scheme | string | `"http"` | | +| monitoring.metrics.serviceMonitor.scrapeTimeout | string | `"10s"` | | +| monitoring.metrics.serviceMonitor.tlsConfig | object | `{}` | | +| monitoring.tracing.sink | string | `""` | specify a sink endpoint for OpenTelemetry Traces, eg. `http://localhost:4317` | +| nameOverride | string | `""` | | +| nodeSelector | object | `{}` | | +| persistence.data.hostPath | string | `"/var/lib/garage/data"` | | +| persistence.data.size | string | `"100Mi"` | | +| persistence.enabled | bool | `true` | | +| persistence.meta.hostPath | string | `"/var/lib/garage/meta"` | | +| persistence.meta.size | string | `"100Mi"` | | +| podAnnotations | object | `{}` | additional pod annotations | +| podSecurityContext.fsGroup | int | `1000` | | +| podSecurityContext.runAsGroup | int | `1000` | | +| podSecurityContext.runAsNonRoot | bool | `true` | | +| podSecurityContext.runAsUser | int | `1000` | | +| readinessProbe | object | `{}` | Specifies a readinessProbe | +| resources | object | `{}` | | +| securityContext.capabilities | object | `{"drop":["ALL"]}` | The default security context is heavily restricted, feel free to tune it to your requirements | +| securityContext.readOnlyRootFilesystem | bool | `true` | | +| service.s3.api.port | int | `3900` | | +| service.s3.web.port | int | `3902` | | +| service.type | string | `"ClusterIP"` | You can rely on any service to expose your cluster - ClusterIP (+ Ingress) - NodePort (+ Ingress) - LoadBalancer | +| serviceAccount.annotations | object | `{}` | Annotations to add to the service account | +| serviceAccount.create | bool | `true` | Specifies whether a service account should be created | +| serviceAccount.name | string | `""` | The name of the service account to use. If not set and create is true, a name is generated using the fullname template | +| tolerations | list | `[]` | | + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.14.2](https://github.com/norwoodj/helm-docs/releases/v1.14.2) diff --git a/packs/garage-0.9.3/charts/garage/templates/_helpers.tpl b/packs/garage-0.9.3/charts/garage/templates/_helpers.tpl new file mode 100644 index 00000000..4451840f --- /dev/null +++ b/packs/garage-0.9.3/charts/garage/templates/_helpers.tpl @@ -0,0 +1,98 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "garage.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 "garage.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 the name of the rpc secret +*/}} +{{- define "garage.rpcSecretName" -}} +{{- .Values.garage.existingRpcSecret | default (printf "%s-rpc-secret" (include "garage.fullname" .)) -}} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "garage.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "garage.labels" -}} +helm.sh/chart: {{ include "garage.chart" . }} +{{ include "garage.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- with .Values.commonLabels }} +{{- toYaml . | nindent 0 }} +{{- end }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "garage.selectorLabels" -}} +app.kubernetes.io/name: {{ include "garage.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "garage.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "garage.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +Extract the trailing port number from a bind address like [::]:3900 or 0.0.0.0:3900. +*/}} +{{- define "garage.portFromBindAddr" -}} +{{- regexFind "[0-9]+$" . -}} +{{- end }} + +{{/* + Returns given number of random Hex characters. + In practice, it generates up to 100 randAlphaNum strings + that are filtered from non-hex characters and augmented + to the resulting string that is finally trimmed down. +*/}} +{{- define "jupyterhub.randHex" -}} + {{- $result := "" }} + {{- range $i := until 100 }} + {{- if lt (len $result) . }} + {{- $rand_list := randAlphaNum . | splitList "" -}} + {{- $reduced_list := without $rand_list "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z" "A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S" "T" "U" "V" "W" "X" "Y" "Z" }} + {{- $rand_string := join "" $reduced_list }} + {{- $result = print $result $rand_string -}} + {{- end }} + {{- end }} + {{- $result | trunc . }} +{{- end }} diff --git a/packs/garage-0.9.3/charts/garage/templates/clusterrole.yaml b/packs/garage-0.9.3/charts/garage/templates/clusterrole.yaml new file mode 100644 index 00000000..3fb81af9 --- /dev/null +++ b/packs/garage-0.9.3/charts/garage/templates/clusterrole.yaml @@ -0,0 +1,30 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: manage-crds-{{ .Release.Namespace }}-{{ .Release.Name }} + labels: + {{- include "garage.labels" . | nindent 4 }} +rules: +{{- if eq .Values.garage.kubernetesSkipCrd false }} +- apiGroups: ["apiextensions.k8s.io"] + resources: ["customresourcedefinitions"] + verbs: ["get", "list", "watch", "create", "patch"] +{{ end }} +- apiGroups: ["deuxfleurs.fr"] + resources: ["garagenodes"] + verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: allow-crds-for-{{ .Release.Namespace }}-{{ .Release.Name }} + labels: + {{- include "garage.labels" . | nindent 4 }} +subjects: +- kind: ServiceAccount + name: {{ include "garage.serviceAccountName" . }} + namespace: {{ .Release.Namespace }} +roleRef: + kind: ClusterRole + name: manage-crds-{{ .Release.Namespace }}-{{ .Release.Name }} + apiGroup: rbac.authorization.k8s.io diff --git a/packs/garage-0.9.3/charts/garage/templates/configmap.yaml b/packs/garage-0.9.3/charts/garage/templates/configmap.yaml new file mode 100644 index 00000000..420f31da --- /dev/null +++ b/packs/garage-0.9.3/charts/garage/templates/configmap.yaml @@ -0,0 +1,62 @@ +{{- if not .Values.garage.existingConfigMap }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "garage.fullname" . }}-config +data: + garage.toml: |- + {{- if .Values.garage.garageTomlString }} + {{- tpl (index (index .Values.garage) "garageTomlString") $ | nindent 4 }} + {{- else }} + metadata_dir = "/mnt/meta" + data_dir = "/mnt/data" + + db_engine = "{{ .Values.garage.dbEngine }}" + + block_size = "{{ .Values.garage.blockSize }}" + + replication_factor = {{ .Values.garage.replicationFactor }} + consistency_mode = "{{ .Values.garage.consistencyMode }}" + + compression_level = {{ .Values.garage.compressionLevel }} + + {{- if .Values.garage.metadataAutoSnapshotInterval }} + metadata_auto_snapshot_interval = {{ .Values.garage.metadataAutoSnapshotInterval | quote }} + {{- end }} + + rpc_bind_addr = "{{ .Values.garage.rpcBindAddr }}" + # rpc_secret will be populated by the init container from a k8s secret object + rpc_secret = "__RPC_SECRET_REPLACE__" + + bootstrap_peers = [ + {{- range $index, $peer := .Values.garage.bootstrapPeers }} + {{- if $index}}, {{ end }}{{ $peer | quote }} + {{ end }} + ] + + {{- if .Values.garage.additionalTopLevelConfig }} + {{ .Values.garage.additionalTopLevelConfig | nindent 4 }} + {{- end }} + + [kubernetes_discovery] + namespace = "{{ .Release.Namespace }}" + service_name = "{{ include "garage.fullname" . }}" + skip_crd = {{ .Values.garage.kubernetesSkipCrd }} + + [s3_api] + s3_region = "{{ .Values.garage.s3.api.region }}" + api_bind_addr = "{{ .Values.garage.s3.api.bindAddr }}" + root_domain = "{{ .Values.garage.s3.api.rootDomain }}" + + [s3_web] + bind_addr = "{{ .Values.garage.s3.web.bindAddr }}" + root_domain = "{{ .Values.garage.s3.web.rootDomain }}" + index = "{{ .Values.garage.s3.web.index }}" + + [admin] + api_bind_addr = "{{ .Values.garage.admin.apiBindAddr }}" + {{- if .Values.monitoring.tracing.sink }} + trace_sink = "{{ .Values.monitoring.tracing.sink }}" + {{- end }} + {{- end }} +{{- end }} diff --git a/packs/garage-0.9.3/charts/garage/templates/ingress.yaml b/packs/garage-0.9.3/charts/garage/templates/ingress.yaml new file mode 100644 index 00000000..35225daa --- /dev/null +++ b/packs/garage-0.9.3/charts/garage/templates/ingress.yaml @@ -0,0 +1,129 @@ +{{- if .Values.ingress.s3.api.enabled -}} +{{- $fullName := include "garage.fullname" . -}} +{{- $svcPort := .Values.service.s3.api.port -}} +{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey .Values.ingress.s3.api.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .Values.ingress.s3.api.annotations "kubernetes.io/ingress.class" .Values.ingress.s3.api.className}} + {{- end }} +{{- end }} +{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }}-s3-api + labels: + {{- include "garage.labels" . | nindent 4 }} + {{- with .Values.ingress.s3.api.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.ingress.s3.api.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.ingress.s3.api.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ingress.s3.api.className }} + {{- end }} + {{- if .Values.ingress.s3.api.tls }} + tls: + {{- range .Values.ingress.s3.api.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.ingress.s3.api.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + {{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} + pathType: {{ .pathType }} + {{- end }} + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $fullName }} + port: + number: {{ $svcPort }} + {{- else }} + serviceName: {{ $fullName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- end }} + {{- end }} +{{- end }} +--- +{{- if .Values.ingress.s3.web.enabled -}} +{{- $fullName := include "garage.fullname" . -}} +{{- $svcPort := .Values.service.s3.web.port -}} +{{- if and .Values.ingress.s3.web.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey .Values.ingress.s3.web.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .Values.ingress.s3.web.annotations "kubernetes.io/ingress.class" .Values.ingress.s3.web.className}} + {{- end }} +{{- end }} +{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }}-s3-web + labels: + {{- include "garage.labels" . | nindent 4 }} + {{- with .Values.ingress.s3.web.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.ingress.s3.web.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.ingress.s3.web.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ingress.s3.web.className }} + {{- end }} + {{- if .Values.ingress.s3.web.tls }} + tls: + {{- range .Values.ingress.s3.web.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.ingress.s3.web.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + {{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} + pathType: {{ .pathType }} + {{- end }} + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $fullName }} + port: + number: {{ $svcPort }} + {{- else }} + serviceName: {{ $fullName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- end }} + {{- end }} +{{- end }} diff --git a/packs/garage-0.9.3/charts/garage/templates/secret.yaml b/packs/garage-0.9.3/charts/garage/templates/secret.yaml new file mode 100644 index 00000000..c0c45b93 --- /dev/null +++ b/packs/garage-0.9.3/charts/garage/templates/secret.yaml @@ -0,0 +1,16 @@ +{{- if not .Values.garage.existingRpcSecret }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "garage.rpcSecretName" . }} + labels: + {{- include "garage.labels" . | nindent 4 }} +type: Opaque +data: + {{/* retrieve the secret data using lookup function and when not exists, return an empty dictionary / map as result */}} + {{- $prevSecret := (lookup "v1" "Secret" .Release.Namespace (include "garage.rpcSecretName" .)) | default dict }} + {{- $prevSecretData := $prevSecret.data | default dict }} + {{- $prevRpcSecret := $prevSecretData.rpcSecret | default "" | b64dec }} + {{/* Priority is: 1. from values, 2. previous value, 3. generate random */}} + rpcSecret: {{ .Values.garage.rpcSecret | default $prevRpcSecret | default (include "jupyterhub.randHex" 64) | b64enc | quote }} +{{- end }} diff --git a/packs/garage-0.9.3/charts/garage/templates/service-headless.yaml b/packs/garage-0.9.3/charts/garage/templates/service-headless.yaml new file mode 100644 index 00000000..c6005cc3 --- /dev/null +++ b/packs/garage-0.9.3/charts/garage/templates/service-headless.yaml @@ -0,0 +1,22 @@ +{{- if eq .Values.deployment.kind "StatefulSet" -}} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "garage.fullname" . }}-headless + labels: + {{- include "garage.labels" . | nindent 4 }} +spec: + type: ClusterIP + clusterIP: None + ports: + - port: {{ .Values.service.s3.api.port }} + targetPort: {{ include "garage.portFromBindAddr" .Values.garage.s3.api.bindAddr | int }} + protocol: TCP + name: s3-api + - port: {{ .Values.service.s3.web.port }} + targetPort: {{ include "garage.portFromBindAddr" .Values.garage.s3.web.bindAddr | int }} + protocol: TCP + name: s3-web + selector: + {{- include "garage.selectorLabels" . | nindent 4 }} +{{- end }} diff --git a/packs/garage-0.9.3/charts/garage/templates/service.yaml b/packs/garage-0.9.3/charts/garage/templates/service.yaml new file mode 100644 index 00000000..cb4bc386 --- /dev/null +++ b/packs/garage-0.9.3/charts/garage/templates/service.yaml @@ -0,0 +1,44 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "garage.fullname" . }} + labels: + {{- include "garage.labels" . | nindent 4 }} + {{- with .Values.service.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.s3.api.port }} + targetPort: {{ include "garage.portFromBindAddr" .Values.garage.s3.api.bindAddr | int }} + protocol: TCP + name: s3-api + - port: {{ .Values.service.s3.web.port }} + targetPort: {{ include "garage.portFromBindAddr" .Values.garage.s3.web.bindAddr | int }} + protocol: TCP + name: s3-web + selector: + {{- include "garage.selectorLabels" . | nindent 4 }} +{{- if .Values.monitoring.metrics.enabled }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ include "garage.fullname" . }}-metrics + labels: + {{- include "garage.labels" . | nindent 4 }} + annotations: + prometheus.io/scrape: "true" +spec: + type: ClusterIP + clusterIP: None + ports: + - port: {{ include "garage.portFromBindAddr" .Values.garage.admin.apiBindAddr | int }} + targetPort: {{ include "garage.portFromBindAddr" .Values.garage.admin.apiBindAddr | int }} + protocol: TCP + name: metrics + selector: + {{- include "garage.selectorLabels" . | nindent 4 }} +{{- end }} diff --git a/packs/garage-0.9.3/charts/garage/templates/serviceaccount.yaml b/packs/garage-0.9.3/charts/garage/templates/serviceaccount.yaml new file mode 100644 index 00000000..a0a89a33 --- /dev/null +++ b/packs/garage-0.9.3/charts/garage/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "garage.serviceAccountName" . }} + labels: + {{- include "garage.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/packs/garage-0.9.3/charts/garage/templates/servicemonitor.yaml b/packs/garage-0.9.3/charts/garage/templates/servicemonitor.yaml new file mode 100644 index 00000000..6838d09f --- /dev/null +++ b/packs/garage-0.9.3/charts/garage/templates/servicemonitor.yaml @@ -0,0 +1,44 @@ +{{- if .Values.monitoring.metrics.serviceMonitor.enabled }} +--- +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "garage.fullname" . }} + {{- if .Values.monitoring.metrics.serviceMonitor.namespace }} + namespace: {{ tpl .Values.monitoring.metrics.serviceMonitor.namespace . }} + {{- else }} + namespace: {{ .Release.Namespace }} + {{- end }} + labels: + {{- include "garage.labels" . | nindent 4 }} + {{- with .Values.monitoring.metrics.serviceMonitor.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + endpoints: + - port: metrics + {{- with .Values.monitoring.metrics.serviceMonitor.interval }} + interval: {{ . }} + {{- end }} + {{- with .Values.monitoring.metrics.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ . }} + {{- end }} + honorLabels: true + path: {{ .Values.monitoring.metrics.serviceMonitor.path }} + scheme: {{ .Values.monitoring.metrics.serviceMonitor.scheme }} + {{- with .Values.monitoring.metrics.serviceMonitor.tlsConfig }} + tlsConfig: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.monitoring.metrics.serviceMonitor.relabelings }} + relabelings: + {{- toYaml . | nindent 6 }} + {{- end }} + jobLabel: "{{ .Release.Name }}" + selector: + matchLabels: + {{- include "garage.selectorLabels" . | nindent 6 }} + namespaceSelector: + matchNames: + - {{ .Release.Namespace }} +{{- end }} \ No newline at end of file diff --git a/packs/garage-0.9.3/charts/garage/templates/workload.yaml b/packs/garage-0.9.3/charts/garage/templates/workload.yaml new file mode 100644 index 00000000..1283d245 --- /dev/null +++ b/packs/garage-0.9.3/charts/garage/templates/workload.yaml @@ -0,0 +1,154 @@ +apiVersion: apps/v1 +kind: {{ .Values.deployment.kind }} +metadata: + name: {{ include "garage.fullname" . }} + labels: + {{- include "garage.labels" . | nindent 4 }} +spec: + selector: + matchLabels: + {{- include "garage.selectorLabels" . | nindent 6 }} + {{- if eq .Values.deployment.kind "StatefulSet" }} + replicas: {{ .Values.deployment.replicaCount }} + serviceName: {{ include "garage.fullname" . }}-headless + podManagementPolicy: {{ .Values.deployment.podManagementPolicy }} + {{- end }} + template: + metadata: + annotations: + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "garage.labels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "garage.serviceAccountName" . }} + {{- with .Values.priorityClassName }} + priorityClassName: {{ . }} + {{- end }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + initContainers: + # Copies garage.toml from configmap to temporary etc volume and replaces RPC secret placeholder + - name: {{ .Chart.Name }}-init + image: "{{ .Values.initImage.repository }}:{{ .Values.initImage.tag }}" + imagePullPolicy: {{ .Values.initImage.pullPolicy }} + command: ["sh", "-c", "sed \"s/__RPC_SECRET_REPLACE__/$RPC_SECRET/\" /mnt/garage.toml > /mnt/etc/garage.toml"] + env: + - name: RPC_SECRET + valueFrom: + secretKeyRef: + name: {{ include "garage.rpcSecretName" . }} + key: rpcSecret + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + volumeMounts: + - name: configmap + mountPath: /mnt/garage.toml + subPath: garage.toml + - name: etc + mountPath: /mnt/etc + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + ports: + - containerPort: {{ include "garage.portFromBindAddr" .Values.garage.s3.api.bindAddr | int }} + name: s3-api + - containerPort: {{ include "garage.portFromBindAddr" .Values.garage.s3.web.bindAddr | int }} + name: web-api + - containerPort: {{ include "garage.portFromBindAddr" .Values.garage.admin.apiBindAddr | int }} + name: admin + {{- with .Values.environment }} + env: + {{- toYaml . | nindent 12 }} + {{- end }} + volumeMounts: + - name: meta + mountPath: /mnt/meta + - name: data + mountPath: /mnt/data + - name: etc + mountPath: /etc/garage.toml + subPath: garage.toml + {{- with .Values.extraVolumeMounts }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.livenessProbe }} + livenessProbe: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.readinessProbe }} + readinessProbe: + {{- toYaml . | nindent 12 }} + {{- end }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + volumes: + - name: configmap + configMap: + name: {{ if .Values.garage.existingConfigMap }}{{ .Values.garage.existingConfigMap }}{{ else }}{{ include "garage.fullname" . }}-config{{ end }} + - name: etc + emptyDir: {} + {{- if .Values.persistence.enabled }} + {{- if eq .Values.deployment.kind "DaemonSet" }} + - name: meta + hostPath: + path: {{ .Values.persistence.meta.hostPath }} + type: DirectoryOrCreate + - name: data + hostPath: + path: {{ .Values.persistence.data.hostPath }} + type: DirectoryOrCreate + {{- end }} + {{- else }} + - name: meta + emptyDir: {} + - name: data + emptyDir: {} + {{- end }} + {{- with .Values.extraVolumes }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if and .Values.persistence.enabled (eq .Values.deployment.kind "StatefulSet") }} + volumeClaimTemplates: + - metadata: + name: meta + spec: + accessModes: [ "ReadWriteOnce" ] + {{- if hasKey .Values.persistence.meta "storageClass" }} + storageClassName: {{ .Values.persistence.meta.storageClass | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.persistence.meta.size | quote }} + - metadata: + name: data + spec: + accessModes: [ "ReadWriteOnce" ] + {{- if hasKey .Values.persistence.data "storageClass" }} + storageClassName: {{ .Values.persistence.data.storageClass | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.persistence.data.size | quote }} + {{- end }} diff --git a/packs/garage-0.9.3/charts/garage/values.yaml b/packs/garage-0.9.3/charts/garage/values.yaml new file mode 100644 index 00000000..a74faf3f --- /dev/null +++ b/packs/garage-0.9.3/charts/garage/values.yaml @@ -0,0 +1,273 @@ +# Default values for garage. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +# -- Additional labels to add to all resources created by this chart +commonLabels: {} +# app.kubernetes.io/part-of: storage +# team: platform + +# Garage configuration. These values go to garage.toml +garage: + # -- Can be changed for better performance on certain systems + # https://garagehq.deuxfleurs.fr/documentation/reference-manual/configuration/#db_engine + dbEngine: "lmdb" + + # -- Defaults is 1MB + # An increase can result in better performance in certain scenarios + # https://garagehq.deuxfleurs.fr/documentation/reference-manual/configuration/#block_size + blockSize: "1048576" + + # -- Default to 3 replicas, see the replication_factor section at + # https://garagehq.deuxfleurs.fr/documentation/reference-manual/configuration/#replication_factor + replicationFactor: "3" + + # -- By default, enable read-after-write consistency guarantees, see the consistency_mode section at + # https://garagehq.deuxfleurs.fr/documentation/reference-manual/configuration/#consistency_mode + consistencyMode: "consistent" + + # -- zstd compression level of stored blocks + # https://garagehq.deuxfleurs.fr/documentation/reference-manual/configuration/#compression_level + compressionLevel: "1" + + # -- If this value is set, Garage will automatically take a snapshot of the metadata DB file at a regular interval and save it in the metadata directory. + # https://garagehq.deuxfleurs.fr/documentation/reference-manual/configuration/#metadata_auto_snapshot_interval + metadataAutoSnapshotInterval: "" + + rpcBindAddr: "[::]:3901" + # -- If not given, a random secret will be generated and stored in a Secret object + rpcSecret: "" + # -- If you want to provide an rpcSecret within an existing k8s secret, + # specify the secret name here, and store the value under the secret key `rpcSecret` + # the default secret will not be created + existingRpcSecret: "" + # -- This is not required if you use the integrated kubernetes discovery + bootstrapPeers: [] + # -- Set to true if you want to use k8s discovery but install the CRDs manually outside + # of the helm chart, for example if you operate at namespace level without cluster resources + kubernetesSkipCrd: false + s3: + api: + bindAddr: "[::]:3900" + region: "garage" + rootDomain: ".s3.garage.tld" + web: + bindAddr: "[::]:3902" + rootDomain: ".web.garage.tld" + index: "index.html" + admin: + apiBindAddr: "[::]:3903" + + # -- Additional configuration to append to garage.toml. Use a multi-line string for custom config. + # Example: + # additionalTopLevelConfig: |- + # data_fsync = true + additionalTopLevelConfig: "" + + # -- if not empty string, allow using an existing ConfigMap for the garage.toml, + # if set, ignores garage.toml + existingConfigMap: "" + + # -- String Template for the garage configuration + # if set, ignores above values. + # Values can be templated, + # see https://garagehq.deuxfleurs.fr/documentation/reference-manual/configuration/ + garageTomlString: "" + +# Data persistence +persistence: + enabled: true + meta: + # storageClass: "fast-storage-class" + size: 100Mi + # used only for daemon sets + hostPath: /var/lib/garage/meta + data: + # storageClass: "slow-storage-class" + size: 100Mi + # used only for daemon sets + hostPath: /var/lib/garage/data + +# Deployment configuration +deployment: + # -- Switchable to DaemonSet + kind: StatefulSet + # -- Number of StatefulSet replicas/garage nodes to start + replicaCount: 3 + # -- If using statefulset, allow Parallel or OrderedReady (default) + podManagementPolicy: OrderedReady + +image: + # -- default to amd64 docker image + repository: dxflrs/amd64_garage + # -- set the image tag, please prefer using the chart version and not this + # to avoid compatibility issues + tag: "" + pullPolicy: IfNotPresent + +initImage: + repository: busybox + tag: stable + pullPolicy: IfNotPresent + +# -- set if you need credentials to pull your custom image +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + # -- Specifies whether a service account should be created + create: true + # -- Annotations to add to the service account + annotations: {} + # -- The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +# -- additional pod annotations +podAnnotations: {} + +podSecurityContext: + runAsUser: 1000 + runAsGroup: 1000 + fsGroup: 1000 + fsGroupChangePolicy: "OnRootMismatch" + runAsNonRoot: true + +securityContext: + # -- The default security context is heavily restricted, + # feel free to tune it to your requirements + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + +service: + # -- You can rely on any service to expose your cluster + # - ClusterIP (+ Ingress) + # - NodePort (+ Ingress) + # - LoadBalancer + type: ClusterIP + # -- Annotations to add to the service + annotations: {} + s3: + api: + port: 3900 + web: + port: 3902 + # NOTE: the admin API is excluded for now as it is not consistent across nodes + +ingress: + s3: + api: + enabled: false + # -- Rely _either_ on the className or the annotation below but not both! + # If you want to use the className, set + # className: "nginx" + # and replace "nginx" by an Ingress controller name, + # examples [here](https://kubernetes.io/docs/concepts/services-networking/ingress-controllers). + annotations: {} + # kubernetes.io/ingress.class: "nginx" + # kubernetes.io/tls-acme: "true" + labels: {} + hosts: + # -- garage S3 API endpoint, to be used with awscli for example + - host: "s3.garage.tld" + paths: + - path: / + pathType: Prefix + # -- garage S3 API endpoint, DNS style bucket access + - host: "*.s3.garage.tld" + paths: + - path: / + pathType: Prefix + tls: [] + # - secretName: my-garage-cluster-tls + # hosts: + # - kubernetes.docker.internal + web: + enabled: false + # -- Rely _either_ on the className or the annotation below but not both! + # If you want to use the className, set + # className: "nginx" + # and replace "nginx" by an Ingress controller name, + # examples [here](https://kubernetes.io/docs/concepts/services-networking/ingress-controllers). + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + labels: {} + hosts: + # -- wildcard website access with bucket name prefix + - host: "*.web.garage.tld" + paths: + - path: / + pathType: Prefix + # -- specific bucket access with FQDN bucket + - host: "mywebpage.example.com" + paths: + - path: / + pathType: Prefix + tls: [] + # - secretName: my-garage-cluster-tls + # hosts: + # - kubernetes.docker.internal + +resources: {} + # The following are indicative for a small-size deployment, for anything serious double them. + # limits: + # cpu: 100m + # memory: 1024Mi + # requests: + # cpu: 100m + # memory: 512Mi + +# -- Specifies a livenessProbe +livenessProbe: {} + #httpGet: + # path: /health + # port: 3903 # or the port from garage.admin.apiBindAddr + #initialDelaySeconds: 5 + #periodSeconds: 30 +# -- Specifies a readinessProbe +readinessProbe: {} + #httpGet: + # path: /health + # port: 3903 # or the port from garage.admin.apiBindAddr + #initialDelaySeconds: 5 + #periodSeconds: 30 + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +# -- Optional priority class name to assign to the pods. +# See https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/ +priorityClassName: "" + +environment: {} + +extraVolumes: {} + +extraVolumeMounts: {} + +monitoring: + metrics: + # -- If true, a service for monitoring is created with a prometheus.io/scrape annotation + enabled: false + serviceMonitor: + # -- If true, a ServiceMonitor CRD is created for a prometheus operator + # https://github.com/coreos/prometheus-operator + enabled: false + path: /metrics + # namespace: monitoring (defaults to use the namespace this chart is deployed to) + labels: {} + interval: 15s + scheme: http + tlsConfig: {} + scrapeTimeout: 10s + relabelings: [] + tracing: + # -- specify a sink endpoint for OpenTelemetry Traces, eg. `http://localhost:4317` + sink: "" diff --git a/packs/garage-0.9.3/logo.png b/packs/garage-0.9.3/logo.png new file mode 100644 index 00000000..2519e219 Binary files /dev/null and b/packs/garage-0.9.3/logo.png differ diff --git a/packs/garage-0.9.3/pack.json b/packs/garage-0.9.3/pack.json new file mode 100644 index 00000000..84d2fef4 --- /dev/null +++ b/packs/garage-0.9.3/pack.json @@ -0,0 +1,17 @@ +{ + "addonType": "system app", + "annotations": { + "source": "community", + "contributor" : "spectrocloud" + }, + "cloudTypes": [ + "all" + ], + "displayName": "garage", + "charts": [ + "charts/garage-0.9.3.tgz" + ], + "layer":"addon", + "name": "garage", + "version": "0.9.3" + } \ No newline at end of file diff --git a/packs/garage-0.9.3/values.yaml b/packs/garage-0.9.3/values.yaml new file mode 100644 index 00000000..4a408e2a --- /dev/null +++ b/packs/garage-0.9.3/values.yaml @@ -0,0 +1,281 @@ +pack: + spectrocloud.com/display-name: garage + releaseNameOverride: + garage: garage + namespace: garage + +charts: + garage: + # Default values for garage. + # This is a YAML-formatted file. + # Declare variables to be passed into your templates. + + # -- Additional labels to add to all resources created by this chart + commonLabels: {} + # app.kubernetes.io/part-of: storage + # team: platform + + # Garage configuration. These values go to garage.toml + garage: + # -- Can be changed for better performance on certain systems + # https://garagehq.deuxfleurs.fr/documentation/reference-manual/configuration/#db_engine + dbEngine: "lmdb" + + # -- Defaults is 1MB + # An increase can result in better performance in certain scenarios + # https://garagehq.deuxfleurs.fr/documentation/reference-manual/configuration/#block_size + blockSize: "1048576" + + # -- Default to 3 replicas, see the replication_factor section at + # https://garagehq.deuxfleurs.fr/documentation/reference-manual/configuration/#replication_factor + replicationFactor: "3" + + # -- By default, enable read-after-write consistency guarantees, see the consistency_mode section at + # https://garagehq.deuxfleurs.fr/documentation/reference-manual/configuration/#consistency_mode + consistencyMode: "consistent" + + # -- zstd compression level of stored blocks + # https://garagehq.deuxfleurs.fr/documentation/reference-manual/configuration/#compression_level + compressionLevel: "1" + + # -- If this value is set, Garage will automatically take a snapshot of the metadata DB file at a regular interval and save it in the metadata directory. + # https://garagehq.deuxfleurs.fr/documentation/reference-manual/configuration/#metadata_auto_snapshot_interval + metadataAutoSnapshotInterval: "" + + rpcBindAddr: "[::]:3901" + # -- If not given, a random secret will be generated and stored in a Secret object + rpcSecret: "" + # -- If you want to provide an rpcSecret within an existing k8s secret, + # specify the secret name here, and store the value under the secret key `rpcSecret` + # the default secret will not be created + existingRpcSecret: "" + # -- This is not required if you use the integrated kubernetes discovery + bootstrapPeers: [] + # -- Set to true if you want to use k8s discovery but install the CRDs manually outside + # of the helm chart, for example if you operate at namespace level without cluster resources + kubernetesSkipCrd: false + s3: + api: + bindAddr: "[::]:3900" + region: "garage" + rootDomain: ".s3.garage.tld" + web: + bindAddr: "[::]:3902" + rootDomain: ".web.garage.tld" + index: "index.html" + admin: + apiBindAddr: "[::]:3903" + + # -- Additional configuration to append to garage.toml. Use a multi-line string for custom config. + # Example: + # additionalTopLevelConfig: |- + # data_fsync = true + additionalTopLevelConfig: "" + + # -- if not empty string, allow using an existing ConfigMap for the garage.toml, + # if set, ignores garage.toml + existingConfigMap: "" + + # -- String Template for the garage configuration + # if set, ignores above values. + # Values can be templated, + # see https://garagehq.deuxfleurs.fr/documentation/reference-manual/configuration/ + garageTomlString: "" + + # Data persistence + persistence: + enabled: true + meta: + # storageClass: "fast-storage-class" + size: 100Mi + # used only for daemon sets + hostPath: /var/lib/garage/meta + data: + # storageClass: "slow-storage-class" + size: 100Mi + # used only for daemon sets + hostPath: /var/lib/garage/data + + # Deployment configuration + deployment: + # -- Switchable to DaemonSet + kind: StatefulSet + # -- Number of StatefulSet replicas/garage nodes to start + replicaCount: 3 + # -- If using statefulset, allow Parallel or OrderedReady (default) + podManagementPolicy: OrderedReady + + image: + # -- default to amd64 docker image + repository: dxflrs/amd64_garage + # -- set the image tag, please prefer using the chart version and not this + # to avoid compatibility issues + tag: "" + pullPolicy: IfNotPresent + + initImage: + repository: busybox + tag: stable + pullPolicy: IfNotPresent + + # -- set if you need credentials to pull your custom image + imagePullSecrets: [] + nameOverride: "" + fullnameOverride: "" + + serviceAccount: + # -- Specifies whether a service account should be created + create: true + # -- Annotations to add to the service account + annotations: {} + # -- The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + + # -- additional pod annotations + podAnnotations: {} + + podSecurityContext: + runAsUser: 1000 + runAsGroup: 1000 + fsGroup: 1000 + fsGroupChangePolicy: "OnRootMismatch" + runAsNonRoot: true + + securityContext: + # -- The default security context is heavily restricted, + # feel free to tune it to your requirements + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + + service: + # -- You can rely on any service to expose your cluster + # - ClusterIP (+ Ingress) + # - NodePort (+ Ingress) + # - LoadBalancer + type: ClusterIP + # -- Annotations to add to the service + annotations: {} + s3: + api: + port: 3900 + web: + port: 3902 + # NOTE: the admin API is excluded for now as it is not consistent across nodes + + ingress: + s3: + api: + enabled: false + # -- Rely _either_ on the className or the annotation below but not both! + # If you want to use the className, set + # className: "nginx" + # and replace "nginx" by an Ingress controller name, + # examples [here](https://kubernetes.io/docs/concepts/services-networking/ingress-controllers). + annotations: {} + # kubernetes.io/ingress.class: "nginx" + # kubernetes.io/tls-acme: "true" + labels: {} + hosts: + # -- garage S3 API endpoint, to be used with awscli for example + - host: "s3.garage.tld" + paths: + - path: / + pathType: Prefix + # -- garage S3 API endpoint, DNS style bucket access + - host: "*.s3.garage.tld" + paths: + - path: / + pathType: Prefix + tls: [] + # - secretName: my-garage-cluster-tls + # hosts: + # - kubernetes.docker.internal + web: + enabled: false + # -- Rely _either_ on the className or the annotation below but not both! + # If you want to use the className, set + # className: "nginx" + # and replace "nginx" by an Ingress controller name, + # examples [here](https://kubernetes.io/docs/concepts/services-networking/ingress-controllers). + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + labels: {} + hosts: + # -- wildcard website access with bucket name prefix + - host: "*.web.garage.tld" + paths: + - path: / + pathType: Prefix + # -- specific bucket access with FQDN bucket + - host: "mywebpage.example.com" + paths: + - path: / + pathType: Prefix + tls: [] + # - secretName: my-garage-cluster-tls + # hosts: + # - kubernetes.docker.internal + + resources: {} + # The following are indicative for a small-size deployment, for anything serious double them. + # limits: + # cpu: 100m + # memory: 1024Mi + # requests: + # cpu: 100m + # memory: 512Mi + + # -- Specifies a livenessProbe + livenessProbe: {} + #httpGet: + # path: /health + # port: 3903 # or the port from garage.admin.apiBindAddr + #initialDelaySeconds: 5 + #periodSeconds: 30 + # -- Specifies a readinessProbe + readinessProbe: {} + #httpGet: + # path: /health + # port: 3903 # or the port from garage.admin.apiBindAddr + #initialDelaySeconds: 5 + #periodSeconds: 30 + + nodeSelector: {} + + tolerations: [] + + affinity: {} + + # -- Optional priority class name to assign to the pods. + # See https://kubernetes.io/docs/concepts/scheduling-eviction/pod-priority-preemption/ + priorityClassName: "" + + environment: {} + + extraVolumes: {} + + extraVolumeMounts: {} + + monitoring: + metrics: + # -- If true, a service for monitoring is created with a prometheus.io/scrape annotation + enabled: false + serviceMonitor: + # -- If true, a ServiceMonitor CRD is created for a prometheus operator + # https://github.com/coreos/prometheus-operator + enabled: false + path: /metrics + # namespace: monitoring (defaults to use the namespace this chart is deployed to) + labels: {} + interval: 15s + scheme: http + tlsConfig: {} + scrapeTimeout: 10s + relabelings: [] + tracing: + # -- specify a sink endpoint for OpenTelemetry Traces, eg. `http://localhost:4317` + sink: ""