diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..0051c2c --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,88 @@ +name: CI + +on: + pull_request: + branches: [main] + push: + branches: [main] + workflow_call: + +jobs: + lint: + name: Lint + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install Helm + uses: azure/setup-helm@v4 + with: + version: v3.16.0 + + - name: Lint chart + run: helm lint . + + - name: Validate JSON schema + run: | + if [ -f values.schema.json ]; then + python3 -m json.tool values.schema.json > /dev/null + echo "✅ values.schema.json is valid" + fi + + test: + name: Test + runs-on: ubuntu-latest + needs: lint + strategy: + fail-fast: false + matrix: + config: + - name: standalone-default + args: "" + - name: standalone-auth + args: "--set auth.enabled=true --set auth.password=test" + - name: standalone-metrics + args: "--set metrics.enabled=true" + - name: sentinel-mode + args: "--set architecture=sentinel --set auth.enabled=true --set auth.password=test" + - name: sentinel-metrics + args: "--set architecture=sentinel --set metrics.enabled=true" + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install Helm + uses: azure/setup-helm@v4 + with: + version: v3.16.0 + + - name: Test template - ${{ matrix.config.name }} + run: | + helm template test . ${{ matrix.config.args }} > output.yaml + + # Validate required resources + grep -q "kind: StatefulSet" output.yaml + grep -q "kind: Service" output.yaml + grep -q "kind: ConfigMap" output.yaml + + echo "✅ ${{ matrix.config.name }} passed" + + package: + name: Package + runs-on: ubuntu-latest + needs: test + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install Helm + uses: azure/setup-helm@v4 + with: + version: v3.16.0 + + - name: Package chart + run: | + helm package . + ls -la *.tgz + echo "✅ Package successful" diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml deleted file mode 100644 index 6282d40..0000000 --- a/.github/workflows/pages.yml +++ /dev/null @@ -1,234 +0,0 @@ -name: Deploy GitHub Pages - -on: - push: - branches: - - main - paths: - - 'Chart.yaml' - - 'README.md' - - 'artifacthub-repo.yml' - - '.github/workflows/pages.yml' - workflow_dispatch: - -# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages -permissions: - contents: read - pages: write - id-token: write - -# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. -# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. -concurrency: - group: "pages" - cancel-in-progress: false - -jobs: - # Build job - build: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - - name: Setup Pages - uses: actions/configure-pages@v4 - continue-on-error: true - - - name: Install Helm - uses: azure/setup-helm@v4 - with: - version: v3.12.1 - - - name: Create Helm repository index - run: | - # Create directories - mkdir -p .cr-release-packages - mkdir -p public - - # Download existing index.yaml and .tgz files to preserve history - echo "Downloading existing repository files..." - wget -q https://start-codex.github.io/valkey-helm-chart/index.yaml -O existing-index.yaml || echo "No existing index.yaml found" - - # Download existing .tgz files if index exists - if [ -f existing-index.yaml ]; then - echo "Parsing existing chart versions..." - # Extract URLs of existing chart packages from index.yaml and download to both directories - urls=$(grep -o 'https://start-codex.github.io/valkey-helm-chart/[^"]*\.tgz' existing-index.yaml || true) - if [ -n "$urls" ]; then - echo "$urls" | while read url; do - if [ -n "$url" ]; then - filename=$(basename "$url") - echo "Downloading existing chart: $filename" - # Download to both .cr-release-packages and public for efficiency - wget -q "$url" -O ".cr-release-packages/$filename" || echo "Failed to download $filename to .cr-release-packages" - wget -q "$url" -O "public/$filename" || echo "Failed to download $filename to public" - fi - done - else - echo "No existing chart packages found in index" - fi - - # Copy existing index to merge later - cp existing-index.yaml .cr-release-packages/ || true - fi - - # Package the current chart - helm package . -d .cr-release-packages - - # Create/update the index with existing and new charts - if [ -f .cr-release-packages/existing-index.yaml ]; then - echo "Merging with existing index..." - helm repo index .cr-release-packages --url https://start-codex.github.io/valkey-helm-chart --merge .cr-release-packages/existing-index.yaml - else - echo "Creating new index..." - helm repo index .cr-release-packages --url https://start-codex.github.io/valkey-helm-chart - fi - - # Copy new chart files to public directory - if ls .cr-release-packages/*.tgz 1> /dev/null 2>&1; then - cp .cr-release-packages/*.tgz public/ || true - fi - - # Copy the updated index - if [ -f .cr-release-packages/index.yaml ]; then - cp .cr-release-packages/index.yaml public/ - fi - - cp README.md public/ || true - cp artifacthub-repo.yml public/ || true - - # Verify what we have - echo "Contents of public directory:" - ls -la public/ - - # Show chart versions in the index - if [ -f public/index.yaml ]; then - echo "" - echo "Chart versions in repository:" - grep -A 2 "version:" public/index.yaml | grep "version:" | sort -V || echo "No versions found" - - echo "" - echo "Total charts in repository:" - grep "\.tgz" public/index.yaml | wc -l || echo "0" - fi - - # Create a simple index.html - cat > public/index.html << 'EOF' - - - - Valkey Helm Chart Repository - - - - - -
- -

Valkey Helm Chart Repository

-

Official Helm chart for Valkey - A high-performance data structure server

-
- -
-

🚀 Quick Start

-

Add this repository to your Helm:

-
helm repo add valkey https://start-codex.github.io/valkey-helm-chart
helm repo update
- -

Install Valkey:

-
helm install my-valkey valkey/valkey
-
- -
-

📦 Available Charts

- -
- -
-

🔧 Configuration

-

The chart supports both standalone and sentinel architectures:

-
# Standalone mode
helm install valkey valkey/valkey

# Sentinel mode
helm install valkey valkey/valkey --set architecture=sentinel
-
- -
-

📚 Documentation

-

For detailed configuration options and examples, visit:

- -
- -
-

📁 Repository Files

- -
- - - EOF - - - name: Upload artifact - uses: actions/upload-pages-artifact@v3 - with: - path: public - - # Deployment job - deploy: - environment: - name: github-pages - url: ${{ steps.deployment.outputs.page_url }} - runs-on: ubuntu-latest - needs: build - if: github.repository_owner != '' - steps: - - name: Deploy to GitHub Pages - id: deployment - uses: actions/deploy-pages@v4 - continue-on-error: true \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index b52ee1a..df414a1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,47 +1,205 @@ -name: Release Charts +name: Release on: + push: + branches: [main] + paths: + - 'Chart.yaml' + - 'values.yaml' + - 'values.schema.json' + - 'templates/**' + - 'public-key.asc' + - 'artifacthub-repo.yml' workflow_dispatch: +permissions: + contents: write + pages: write + id-token: write + +concurrency: + group: release + cancel-in-progress: false + jobs: + ci: + name: CI + uses: ./.github/workflows/ci.yml + release: - permissions: - contents: write + name: Release & Deploy runs-on: ubuntu-latest + needs: ci + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - - name: Configure Git - run: | - git config user.name "$GITHUB_ACTOR" - git config user.email "$GITHUB_ACTOR@users.noreply.github.com" + - name: Setup Pages + uses: actions/configure-pages@v4 - name: Install Helm uses: azure/setup-helm@v4 with: - version: v3.12.1 + version: v3.16.0 - - name: Add dependency chart repos + - name: Import GPG key + env: + GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} run: | - helm repo add bitnami https://charts.bitnami.com/bitnami + if [ -n "$GPG_PRIVATE_KEY" ]; then + echo "$GPG_PRIVATE_KEY" | gpg --batch --import + echo "allow-loopback-pinentry" >> ~/.gnupg/gpg-agent.conf + gpg-connect-agent reloadagent /bye || true + echo "GPG_AVAILABLE=true" >> $GITHUB_ENV + else + echo "GPG_AVAILABLE=false" >> $GITHUB_ENV + fi - - name: Run chart-releaser - uses: helm/chart-releaser-action@v1.6.0 - with: - charts_dir: . - skip_existing: true + - name: Package Chart env: - CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}" - CR_SKIP_EXISTING: true + GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} + run: | + mkdir -p .packages public + + # Download existing charts + wget -q https://start-codex.github.io/valkey-helm-chart/index.yaml -O existing-index.yaml 2>/dev/null || true + + if [ -f existing-index.yaml ]; then + grep -o 'https://start-codex.github.io/valkey-helm-chart/[^"]*\.tgz' existing-index.yaml | while read url; do + [ -n "$url" ] && wget -q "$url" -O "public/$(basename $url)" || true + done + cp existing-index.yaml .packages/ + fi + + # Package with signature if GPG available + if [ "$GPG_AVAILABLE" = "true" ] && [ -n "$GPG_PASSPHRASE" ]; then + echo "📦 Packaging with GPG signature..." + echo "$GPG_PASSPHRASE" | helm package . -d .packages \ + --sign --key "cloud@startcodex.com" --passphrase-file /dev/stdin \ + || helm package . -d .packages + else + echo "📦 Packaging without signature..." + helm package . -d .packages + fi + + # Generate index + if [ -f .packages/existing-index.yaml ]; then + helm repo index .packages --url https://start-codex.github.io/valkey-helm-chart --merge .packages/existing-index.yaml + else + helm repo index .packages --url https://start-codex.github.io/valkey-helm-chart + fi - - name: Trigger Pages Workflow - if: github.ref == 'refs/heads/main' + # Copy files to public + cp .packages/*.tgz public/ + cp .packages/*.prov public/ 2>/dev/null || true + cp .packages/index.yaml public/ + cp README.md artifacthub-repo.yml public-key.asc public/ + + - name: Generate index.html run: | - curl -X POST \ - -H "Accept: application/vnd.github.v3+json" \ - -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \ - https://api.github.com/repos/${{ github.repository }}/actions/workflows/pages.yml/dispatches \ - -d '{"ref":"main"}' \ No newline at end of file + VERSION=$(grep '^version:' Chart.yaml | awk '{print $2}') + cat > public/index.html << 'HTMLEOF' + + + + + + Valkey Helm Chart + + + +
+ Valkey +

Valkey Helm Chart

+

High-performance data structure server for Kubernetes

+
+ v${VERSION} + Signed +
+
+ +
+

Quick Start

+
helm repo add valkey https://start-codex.github.io/valkey-helm-chart
+          helm repo update
+          helm install my-valkey valkey/valkey
+
+ +
+

Installation Examples

+
# With authentication
+          helm install my-valkey valkey/valkey \
+            --set auth.enabled=true \
+            --set auth.password="your-password"
+
+          # High Availability (Sentinel)
+          helm install my-valkey valkey/valkey \
+            --set architecture=sentinel
+
+ +
+

Verify Signature

+
wget https://start-codex.github.io/valkey-helm-chart/public-key.asc
+          gpg --import public-key.asc
+          helm pull valkey/valkey --verify
+
+ +
+

Links

+ +
+ +
+

Files

+ +
+ + + + + HTMLEOF + sed -i "s/\${VERSION}/$VERSION/g" public/index.html + + - name: Upload Pages artifact + uses: actions/upload-pages-artifact@v3 + with: + path: public + + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml deleted file mode 100644 index 7b85b29..0000000 --- a/.github/workflows/test.yml +++ /dev/null @@ -1,60 +0,0 @@ -name: Test Chart - -on: - workflow_dispatch: - pull_request: - branches: [ main ] - push: - branches: [ main ] - -jobs: - test: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Install Helm - uses: azure/setup-helm@v4 - with: - version: v3.12.1 - - - name: Lint chart - run: | - helm lint . - echo "✅ Chart lint passed" - - - name: Test chart templates - run: | - echo "Testing standalone mode..." - helm template test . --set architecture=standalone > /dev/null - echo "✅ Standalone template generation passed" - - echo "Testing sentinel mode..." - helm template test . --set architecture=sentinel --set auth.enabled=true --set auth.password=test > /dev/null - echo "✅ Sentinel template generation passed" - - - name: Package chart - run: | - helm package . - ls -la *.tgz - echo "✅ Chart packaging passed" - - - name: Test installation (template only) - run: | - echo "Testing template generation with default values..." - helm template test-valkey . > /dev/null - echo "✅ Template generation with default values passed" - - echo "Testing template generation with custom values..." - cat > test-values.yaml << 'EOF' - architecture: standalone - auth: - enabled: true - password: "testpassword" - standalone: - persistence: - storageClass: "standard" - EOF - helm template test-valkey . -f test-values.yaml > /dev/null - echo "✅ Template generation with custom values passed" \ No newline at end of file diff --git a/.github/workflows/validate-configs.yml b/.github/workflows/validate-configs.yml deleted file mode 100644 index 9398a9e..0000000 --- a/.github/workflows/validate-configs.yml +++ /dev/null @@ -1,109 +0,0 @@ -name: Validate Chart Configurations - -on: - workflow_dispatch: - pull_request: - branches: [ main ] - push: - branches: [ main ] - -jobs: - validate-configs: - runs-on: ubuntu-latest - strategy: - matrix: - config: - - name: "standalone-no-auth" - values: | - architecture: standalone - auth: - enabled: false - - name: "standalone-with-auth" - values: | - architecture: standalone - auth: - enabled: true - password: "testpassword" - - name: "standalone-existing-secret" - values: | - architecture: standalone - auth: - enabled: true - existingSecret: "redis-secret" - - name: "standalone-with-persistence" - values: | - architecture: standalone - standalone: - persistence: - enabled: true - storageClass: "longhorn-simple" - size: "10Gi" - - name: "sentinel-mode" - values: | - architecture: sentinel - auth: - enabled: true - password: "testpassword" - sentinel: - replicaCount: 3 - - name: "with-metrics" - values: | - architecture: standalone - metrics: - enabled: true - - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Install Helm - uses: azure/setup-helm@v4 - with: - version: v3.12.1 - - - name: Create test values file - run: | - cat > test-values-${{ matrix.config.name }}.yaml << 'EOF' - ${{ matrix.config.values }} - EOF - - - name: Lint chart with ${{ matrix.config.name }} config - run: | - helm lint . -f test-values-${{ matrix.config.name }}.yaml - echo "✅ Lint passed for ${{ matrix.config.name }}" - - - name: Test template generation for ${{ matrix.config.name }} - run: | - helm template test-${{ matrix.config.name }} . -f test-values-${{ matrix.config.name }}.yaml > output-${{ matrix.config.name }}.yaml - echo "✅ Template generation passed for ${{ matrix.config.name }}" - - - name: Validate generated manifests - run: | - # Check that required resources are generated - if [ "${{ matrix.config.name }}" = "standalone-no-auth" ] || [ "${{ matrix.config.name }}" = "standalone-with-auth" ] || [ "${{ matrix.config.name }}" = "standalone-existing-secret" ] || [ "${{ matrix.config.name }}" = "standalone-with-persistence" ] || [ "${{ matrix.config.name }}" = "with-metrics" ]; then - grep -q "kind: StatefulSet" output-${{ matrix.config.name }}.yaml || (echo "❌ StatefulSet not found" && exit 1) - grep -q "kind: Service" output-${{ matrix.config.name }}.yaml || (echo "❌ Service not found" && exit 1) - grep -q "kind: ConfigMap" output-${{ matrix.config.name }}.yaml || (echo "❌ ConfigMap not found" && exit 1) - fi - - if [ "${{ matrix.config.name }}" = "sentinel-mode" ]; then - grep -q "kind: StatefulSet" output-${{ matrix.config.name }}.yaml || (echo "❌ StatefulSet not found" && exit 1) - # Should have master, replica, and sentinel services - SERVICE_COUNT=$(grep -c "kind: Service" output-${{ matrix.config.name }}.yaml) - if [ "$SERVICE_COUNT" -lt 3 ]; then - echo "❌ Expected at least 3 services for sentinel mode, found $SERVICE_COUNT" - exit 1 - fi - fi - - if [[ "${{ matrix.config.name }}" == *"persistence"* ]]; then - grep -q "volumeClaimTemplates" output-${{ matrix.config.name }}.yaml || (echo "❌ VolumeClaimTemplates not found when persistence enabled" && exit 1) - fi - - echo "✅ Manifest validation passed for ${{ matrix.config.name }}" - - - name: Upload generated manifests - uses: actions/upload-artifact@v4 - with: - name: manifests-${{ matrix.config.name }} - path: output-${{ matrix.config.name }}.yaml \ No newline at end of file diff --git a/Chart.yaml b/Chart.yaml index 54cfbba..fd3669c 100644 --- a/Chart.yaml +++ b/Chart.yaml @@ -5,7 +5,17 @@ type: application version: 0.1.24 appVersion: "9.0.0" annotations: - images: | + artifacthub.io/signKey: | + fingerprint: BD9C3A3FB5C152390B589739DA06B8958C5CE1D1 + url: https://start-codex.github.io/valkey-helm-chart/public-key.asc + artifacthub.io/category: database + artifacthub.io/license: Apache-2.0 + artifacthub.io/links: | + - name: Valkey Official + url: https://valkey.io/ + - name: Chart Source + url: https://github.com/start-codex/valkey-helm-chart + artifacthub.io/images: | - name: valkey image: docker.io/valkey/valkey:9.0.0 - name: os-shell @@ -14,8 +24,8 @@ annotations: image: docker.io/oliver006/redis_exporter:v1.80.0 - name: kubectl image: docker.io/alpine/k8s:1.31.13 - licenses: Apache-2.0 - category: database + artifacthub.io/containsSecurityUpdates: "false" + artifacthub.io/prerelease: "false" keywords: - valkey - redis diff --git a/public-key.asc b/public-key.asc new file mode 100644 index 0000000..6ac4192 --- /dev/null +++ b/public-key.asc @@ -0,0 +1,52 @@ +-----BEGIN PGP PUBLIC KEY BLOCK----- + +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 +9WC8JBHDuwy4luXYC9J80Vdmgn7k+zc8yeKO +=3bnc +-----END PGP PUBLIC KEY BLOCK----- diff --git a/values.schema.json b/values.schema.json new file mode 100644 index 0000000..6c5b159 --- /dev/null +++ b/values.schema.json @@ -0,0 +1,799 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "Valkey Helm Chart Values", + "type": "object", + "properties": { + "architecture": { + "type": "string", + "description": "Deployment architecture: standalone or sentinel", + "enum": ["standalone", "sentinel"], + "default": "standalone" + }, + "global": { + "type": "object", + "description": "Global parameters", + "properties": { + "imageRegistry": { + "type": "string", + "description": "Global Docker image registry" + }, + "imagePullSecrets": { + "type": "array", + "description": "Global Docker registry secret names", + "items": { + "type": "string" + } + }, + "storageClass": { + "type": "string", + "description": "Global StorageClass for Persistent Volume(s)" + } + } + }, + "clusterDomain": { + "type": "string", + "description": "Kubernetes cluster domain", + "default": "cluster.local" + }, + "image": { + "type": "object", + "description": "Valkey image configuration", + "properties": { + "registry": { + "type": "string", + "description": "Image registry", + "default": "docker.io" + }, + "repository": { + "type": "string", + "description": "Image repository", + "default": "valkey/valkey" + }, + "tag": { + "type": "string", + "description": "Image tag", + "default": "9.0.0" + }, + "pullPolicy": { + "type": "string", + "description": "Image pull policy", + "enum": ["Always", "IfNotPresent", "Never"], + "default": "IfNotPresent" + } + } + }, + "nameOverride": { + "type": "string", + "description": "String to partially override fullname template" + }, + "fullnameOverride": { + "type": "string", + "description": "String to fully override fullname template" + }, + "auth": { + "type": "object", + "description": "Authentication configuration", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable password authentication", + "default": false + }, + "password": { + "type": "string", + "description": "Valkey password (not recommended for production)" + }, + "existingSecret": { + "type": "string", + "description": "Name of existing secret containing the password" + }, + "existingSecretPasswordKey": { + "type": "string", + "description": "Key in existing secret containing the password", + "default": "password" + }, + "sentinel": { + "type": "boolean", + "description": "Enable authentication for Sentinel", + "default": false + } + } + }, + "networkPolicy": { + "type": "object", + "description": "Network Policy configuration", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable NetworkPolicy", + "default": false + }, + "allowExternal": { + "type": "boolean", + "description": "Allow external connections", + "default": true + }, + "ingressNSMatchLabels": { + "type": "object", + "description": "Namespace labels for ingress rules" + }, + "ingressNSPodMatchLabels": { + "type": "object", + "description": "Pod labels for ingress rules" + } + } + }, + "rbac": { + "type": "object", + "description": "RBAC configuration", + "properties": { + "create": { + "type": "boolean", + "description": "Create RBAC resources", + "default": false + } + } + }, + "serviceAccount": { + "type": "object", + "description": "Service Account configuration", + "properties": { + "create": { + "type": "boolean", + "description": "Create ServiceAccount", + "default": true + }, + "annotations": { + "type": "object", + "description": "ServiceAccount annotations" + }, + "name": { + "type": "string", + "description": "ServiceAccount name" + } + } + }, + "podSecurityContext": { + "type": "object", + "description": "Pod Security Context", + "properties": { + "fsGroup": { + "type": "integer", + "description": "Group ID for the filesystem", + "default": 999 + }, + "runAsUser": { + "type": "integer", + "description": "User ID for the container", + "default": 999 + }, + "runAsGroup": { + "type": "integer", + "description": "Group ID for the container", + "default": 999 + } + } + }, + "securityContext": { + "type": "object", + "description": "Container Security Context", + "properties": { + "allowPrivilegeEscalation": { + "type": "boolean", + "description": "Allow privilege escalation", + "default": false + }, + "capabilities": { + "type": "object", + "description": "Linux capabilities", + "properties": { + "drop": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "readOnlyRootFilesystem": { + "type": "boolean", + "description": "Read-only root filesystem", + "default": true + }, + "runAsNonRoot": { + "type": "boolean", + "description": "Run as non-root user", + "default": true + }, + "runAsUser": { + "type": "integer", + "description": "User ID for the container", + "default": 999 + } + } + }, + "commonAnnotations": { + "type": "object", + "description": "Annotations to add to all deployed objects" + }, + "commonLabels": { + "type": "object", + "description": "Labels to add to all deployed objects" + }, + "standalone": { + "type": "object", + "description": "Standalone mode configuration", + "properties": { + "replicaCount": { + "type": "integer", + "description": "Number of replicas", + "default": 1, + "minimum": 1 + }, + "resources": { + "type": "object", + "description": "Container resources", + "properties": { + "limits": { + "type": "object", + "properties": { + "memory": { + "type": "string" + }, + "cpu": { + "type": "string" + } + } + }, + "requests": { + "type": "object", + "properties": { + "memory": { + "type": "string" + }, + "cpu": { + "type": "string" + } + } + } + } + }, + "nodeSelector": { + "type": "object", + "description": "Node labels for pod assignment" + }, + "tolerations": { + "type": "array", + "description": "Tolerations for pod assignment", + "items": { + "type": "object" + } + }, + "affinity": { + "type": "object", + "description": "Affinity for pod assignment" + }, + "persistence": { + "type": "object", + "description": "Persistence configuration", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable persistence", + "default": true + }, + "storageClass": { + "type": "string", + "description": "StorageClass for PVC" + }, + "accessModes": { + "type": "array", + "description": "PVC access modes", + "items": { + "type": "string", + "enum": ["ReadWriteOnce", "ReadOnlyMany", "ReadWriteMany"] + }, + "default": ["ReadWriteOnce"] + }, + "size": { + "type": "string", + "description": "PVC size", + "default": "8Gi" + }, + "annotations": { + "type": "object", + "description": "PVC annotations" + } + } + }, + "service": { + "type": "object", + "description": "Service configuration", + "properties": { + "type": { + "type": "string", + "description": "Service type", + "enum": ["ClusterIP", "NodePort", "LoadBalancer"], + "default": "ClusterIP" + }, + "port": { + "type": "integer", + "description": "Service port", + "default": 6379 + }, + "targetPort": { + "type": "string", + "description": "Target port name", + "default": "valkey" + }, + "annotations": { + "type": "object", + "description": "Service annotations" + } + } + }, + "configuration": { + "type": "string", + "description": "Valkey configuration file content" + } + } + }, + "sentinel": { + "type": "object", + "description": "Sentinel configuration", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable Sentinel", + "default": false + }, + "replicaCount": { + "type": "integer", + "description": "Number of Sentinel replicas", + "default": 3, + "minimum": 1 + }, + "quorum": { + "type": "integer", + "description": "Quorum for Sentinel", + "default": 2, + "minimum": 1 + }, + "masterSet": { + "type": "string", + "description": "Name of the master set", + "default": "mymaster" + }, + "downAfterMilliseconds": { + "type": "integer", + "description": "Time in ms to consider a master down", + "default": 30000 + }, + "failoverTimeout": { + "type": "integer", + "description": "Failover timeout in ms", + "default": 180000 + }, + "parallelSyncs": { + "type": "integer", + "description": "Number of replicas to sync in parallel", + "default": 1 + }, + "image": { + "type": "object", + "description": "Sentinel image configuration", + "properties": { + "registry": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + }, + "pullPolicy": { + "type": "string", + "enum": ["Always", "IfNotPresent", "Never"] + } + } + }, + "resources": { + "type": "object", + "description": "Container resources" + }, + "service": { + "type": "object", + "description": "Sentinel service configuration", + "properties": { + "type": { + "type": "string", + "enum": ["ClusterIP", "NodePort", "LoadBalancer"] + }, + "port": { + "type": "integer", + "default": 26379 + } + } + } + } + }, + "master": { + "type": "object", + "description": "Master configuration (sentinel mode)", + "properties": { + "replicaCount": { + "type": "integer", + "description": "Number of master replicas", + "default": 1 + }, + "resources": { + "type": "object", + "description": "Container resources" + }, + "persistence": { + "type": "object", + "description": "Persistence configuration", + "properties": { + "enabled": { + "type": "boolean", + "default": true + }, + "storageClass": { + "type": "string" + }, + "accessModes": { + "type": "array", + "items": { + "type": "string" + } + }, + "size": { + "type": "string", + "default": "8Gi" + } + } + }, + "service": { + "type": "object", + "description": "Service configuration" + } + } + }, + "replica": { + "type": "object", + "description": "Replica configuration (sentinel mode)", + "properties": { + "replicaCount": { + "type": "integer", + "description": "Number of replica instances", + "default": 2, + "minimum": 0 + }, + "resources": { + "type": "object", + "description": "Container resources" + }, + "persistence": { + "type": "object", + "description": "Persistence configuration", + "properties": { + "enabled": { + "type": "boolean", + "default": true + }, + "storageClass": { + "type": "string" + }, + "accessModes": { + "type": "array", + "items": { + "type": "string" + } + }, + "size": { + "type": "string", + "default": "8Gi" + } + } + }, + "service": { + "type": "object", + "description": "Service configuration" + } + } + }, + "metrics": { + "type": "object", + "description": "Metrics exporter configuration", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable Prometheus metrics exporter", + "default": false + }, + "port": { + "type": "integer", + "description": "Metrics port", + "default": 9121 + }, + "image": { + "type": "object", + "description": "Metrics exporter image", + "properties": { + "registry": { + "type": "string", + "default": "docker.io" + }, + "repository": { + "type": "string", + "default": "oliver006/redis_exporter" + }, + "tag": { + "type": "string", + "default": "v1.80.0" + }, + "pullPolicy": { + "type": "string", + "enum": ["Always", "IfNotPresent", "Never"] + } + } + }, + "resources": { + "type": "object", + "description": "Container resources" + }, + "serviceMonitor": { + "type": "object", + "description": "Prometheus ServiceMonitor configuration", + "properties": { + "enabled": { + "type": "boolean", + "description": "Create ServiceMonitor", + "default": false + }, + "namespace": { + "type": "string", + "description": "ServiceMonitor namespace" + }, + "interval": { + "type": "string", + "description": "Scrape interval" + }, + "scrapeTimeout": { + "type": "string", + "description": "Scrape timeout" + } + } + }, + "podMonitor": { + "type": "object", + "description": "Prometheus PodMonitor configuration", + "properties": { + "enabled": { + "type": "boolean", + "description": "Create PodMonitor", + "default": false + } + } + }, + "prometheusRule": { + "type": "object", + "description": "Prometheus PrometheusRule configuration", + "properties": { + "enabled": { + "type": "boolean", + "description": "Create PrometheusRule", + "default": false + }, + "rules": { + "type": "array", + "description": "Prometheus rules", + "items": { + "type": "object" + } + } + } + } + } + }, + "preUpgradeHook": { + "type": "object", + "description": "Pre-upgrade hook configuration", + "properties": { + "image": { + "type": "object", + "description": "Hook image configuration", + "properties": { + "registry": { + "type": "string", + "default": "docker.io" + }, + "repository": { + "type": "string", + "default": "alpine/k8s" + }, + "tag": { + "type": "string", + "default": "1.31.13" + }, + "pullPolicy": { + "type": "string", + "enum": ["Always", "IfNotPresent", "Never"] + } + } + }, + "resources": { + "type": "object", + "description": "Container resources" + } + } + }, + "volumePermissions": { + "type": "object", + "description": "Volume permissions init container configuration", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable init container for volume permissions", + "default": false + }, + "image": { + "type": "object", + "description": "Init container image", + "properties": { + "registry": { + "type": "string" + }, + "repository": { + "type": "string" + }, + "tag": { + "type": "string" + }, + "pullPolicy": { + "type": "string" + } + } + }, + "resources": { + "type": "object", + "description": "Container resources" + } + } + }, + "sysctls": { + "type": "object", + "description": "Sysctls configuration", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable sysctls init container", + "default": false + } + } + }, + "existingConfigmap": { + "type": "string", + "description": "Name of existing ConfigMap with Valkey configuration" + }, + "extraEnvVars": { + "type": "array", + "description": "Extra environment variables", + "items": { + "type": "object" + } + }, + "extraVolumes": { + "type": "array", + "description": "Extra volumes", + "items": { + "type": "object" + } + }, + "extraVolumeMounts": { + "type": "array", + "description": "Extra volume mounts", + "items": { + "type": "object" + } + }, + "tls": { + "type": "object", + "description": "TLS configuration", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable TLS", + "default": false + }, + "port": { + "type": "integer", + "description": "TLS port", + "default": 6380 + }, + "existingSecret": { + "type": "string", + "description": "Name of existing secret with TLS certificates" + }, + "certFilename": { + "type": "string", + "description": "Certificate filename in secret", + "default": "tls.crt" + }, + "certKeyFilename": { + "type": "string", + "description": "Certificate key filename in secret", + "default": "tls.key" + }, + "caCertFilename": { + "type": "string", + "description": "CA certificate filename in secret", + "default": "ca.crt" + }, + "authClients": { + "type": "boolean", + "description": "Require client authentication", + "default": true + } + } + }, + "extraDeploy": { + "type": "array", + "description": "Extra Kubernetes resources to deploy", + "items": { + "type": "object" + } + }, + "serviceBinding": { + "type": "object", + "description": "Service Binding configuration", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable Service Binding", + "default": false + } + } + }, + "headlessService": { + "type": "object", + "description": "Headless service configuration", + "properties": { + "annotations": { + "type": "object", + "description": "Headless service annotations" + }, + "extraPorts": { + "type": "array", + "description": "Extra ports for headless service", + "items": { + "type": "object" + } + } + } + }, + "podSecurityPolicy": { + "type": "object", + "description": "Pod Security Policy configuration", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable Pod Security Policy", + "default": false + } + } + }, + "diagnosticMode": { + "type": "object", + "description": "Diagnostic mode configuration", + "properties": { + "enabled": { + "type": "boolean", + "description": "Enable diagnostic mode", + "default": false + } + } + } + } +}