mirror of
https://github.com/lukaszraczylo/helm-charts.git
synced 2026-07-03 05:30:47 +00:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 089daf15f2 | |||
| a14cfff75f | |||
|
5afe124e2c
|
@@ -45,11 +45,18 @@ jobs:
|
||||
echo "chart_path=${{ inputs.chart_path }}" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Checkout helm-charts repo
|
||||
- name: Checkout helm-charts repo (gh-pages)
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: gh-pages
|
||||
fetch-depth: 0
|
||||
submodules: false
|
||||
|
||||
- name: Clean up any leftover source-repo
|
||||
run: |
|
||||
rm -rf source-repo
|
||||
# Remove from git index if it exists as submodule
|
||||
git rm -rf --cached source-repo 2>/dev/null || true
|
||||
|
||||
- name: Checkout source repo
|
||||
uses: actions/checkout@v4
|
||||
@@ -78,7 +85,7 @@ jobs:
|
||||
sed -i "s/^appVersion:.*/appVersion: \"${VERSION}\"/" "source-repo/${CHART_PATH}/Chart.yaml"
|
||||
|
||||
# Update values.yaml tag if it exists
|
||||
if grep -q "^ tag:" "source-repo/${CHART_PATH}/values.yaml" 2>/dev/null; then
|
||||
if grep -q "tag:" "source-repo/${CHART_PATH}/values.yaml" 2>/dev/null; then
|
||||
sed -i "s/tag:.*/tag: \"${VERSION}\"/" "source-repo/${CHART_PATH}/values.yaml"
|
||||
fi
|
||||
|
||||
@@ -109,10 +116,15 @@ jobs:
|
||||
|
||||
cp /tmp/helm-packages/index.yaml index.yaml
|
||||
|
||||
- name: Commit and push
|
||||
- name: Commit and push to gh-pages
|
||||
run: |
|
||||
# Remove source-repo before committing (it's a temp checkout)
|
||||
rm -rf source-repo
|
||||
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git add -A
|
||||
|
||||
# Only add specific paths, not source-repo
|
||||
git add charts/ index.yaml
|
||||
git diff --staged --quiet || git commit -m "Release ${{ steps.inputs.outputs.chart_name }} ${{ steps.inputs.outputs.version }}"
|
||||
git push
|
||||
git push origin gh-pages
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
chart-releaser.yaml
|
||||
@@ -1,11 +0,0 @@
|
||||
CHART := charts/jobs-manager-operator
|
||||
|
||||
copy-charts:
|
||||
cp -R ../jmo-current/charts/jobs-manager-operator/* $(CHART)/.
|
||||
|
||||
release-charts:
|
||||
cd $(CHART); cr package --config ../../chart-releaser.yaml;
|
||||
git add -A charts/packages; git fix; git push;
|
||||
cd $(CHART); cr upload --config ../../chart-releaser.yaml --skip-existing;
|
||||
cd $(CHART); cr index --config ../../chart-releaser.yaml;
|
||||
cd $(CHART); cp .cr-index/index.yaml ../../index.yaml
|
||||
@@ -1,33 +0,0 @@
|
||||
## Helm Charts for Kubernetes
|
||||
|
||||
This repository contains Helm charts for Kubernetes.
|
||||
|
||||
## Installation
|
||||
|
||||
Add the repository to Helm:
|
||||
|
||||
```bash
|
||||
helm repo add raczylo https://lukaszraczylo.github.io/helm-charts/
|
||||
helm repo update
|
||||
```
|
||||
|
||||
## List available charts
|
||||
|
||||
```bash
|
||||
helm search repo raczylo
|
||||
```
|
||||
|
||||
## Chart installation
|
||||
|
||||
```
|
||||
helm install <chart-name> raczylo/<chart-name>
|
||||
```
|
||||
|
||||
## Currently available charts
|
||||
|
||||
| Chart | Description |
|
||||
| ----- | ----------- |
|
||||
| [jobs-manager](https://github.com/lukaszraczylo/jobs-manager-operator) | Kubernetes Operator for managing and scheduling Jobs |
|
||||
| [kube-images-sync](https://github.com/lukaszraczylo/kubernetes-images-sync-operator) | Kubernetes Operator for storing images pre-impex |
|
||||
| [kubemirror](https://github.com/lukaszraczylo/kubemirror) | Kubernetes Operator for mirroring Kubernetes resources across namespaces |
|
||||
| ----- | ----------- |
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
repositoryID: 2b92d5b8-cc60-4cf9-9e42-4b5c96ea2fe5
|
||||
owners:
|
||||
- name: lukasz
|
||||
email: lukasz@raczylo.com
|
||||
@@ -1,22 +0,0 @@
|
||||
apiVersion: v2
|
||||
name: gohoarder
|
||||
description: A universal package cache proxy supporting npm, PyPI, and Go modules with security scanning
|
||||
type: application
|
||||
version: 0.1.144
|
||||
appVersion: "0.1.144"
|
||||
keywords:
|
||||
- package-manager
|
||||
- cache
|
||||
- proxy
|
||||
- npm
|
||||
- pypi
|
||||
- go-modules
|
||||
- security
|
||||
- vulnerability-scanning
|
||||
home: https://github.com/lukaszraczylo/gohoarder
|
||||
sources:
|
||||
- https://github.com/lukaszraczylo/gohoarder
|
||||
maintainers:
|
||||
- name: Lukasz Raczylo
|
||||
email: lukasz@raczylo.com
|
||||
# icon: https://raw.githubusercontent.com/lukaszraczylo/gohoarder/main/docs/logo.png # TODO: Add logo
|
||||
@@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 Lukasz Raczylo
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -1,499 +0,0 @@
|
||||
# GoHoarder Helm Chart
|
||||
|
||||
A universal package cache proxy supporting npm, PyPI, and Go modules with integrated security scanning.
|
||||
|
||||
## Features
|
||||
|
||||
- **Multi-Registry Support**: Proxy for npm, PyPI, and Go modules
|
||||
- **Security Scanning**: Integrated vulnerability scanning with multiple scanners
|
||||
- **Flexible Storage**: Support for filesystem, S3, and SMB storage backends
|
||||
- **Metadata Storage**: SQLite or PostgreSQL for metadata
|
||||
- **Auto-Configuration**: Generates configuration from Helm values
|
||||
- **Production Ready**: Includes health checks, resource limits, and security contexts
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Kubernetes 1.19+
|
||||
- Helm 3.0+
|
||||
- PV provisioner support in the underlying infrastructure (for persistent storage)
|
||||
|
||||
## Installation
|
||||
|
||||
### Add Helm Repository
|
||||
|
||||
```bash
|
||||
helm repo add gohoarder https://lukaszraczylo.github.io/gohoarder
|
||||
helm repo update
|
||||
```
|
||||
|
||||
### Install Chart
|
||||
|
||||
```bash
|
||||
# Install with default values
|
||||
helm install gohoarder gohoarder/gohoarder
|
||||
|
||||
# Install with custom values
|
||||
helm install gohoarder gohoarder/gohoarder -f values.yaml
|
||||
|
||||
# Install in a specific namespace
|
||||
helm install gohoarder gohoarder/gohoarder -n gohoarder --create-namespace
|
||||
```
|
||||
|
||||
## Quick Start Examples
|
||||
|
||||
### Minimal Installation
|
||||
|
||||
```bash
|
||||
helm install gohoarder gohoarder/gohoarder \
|
||||
--set global.domain=example.com \
|
||||
--set ingress.enabled=true
|
||||
```
|
||||
|
||||
### With Security Scanning
|
||||
|
||||
```bash
|
||||
helm install gohoarder gohoarder/gohoarder \
|
||||
--set security.enabled=true \
|
||||
--set security.scanners.trivy.enabled=true \
|
||||
--set security.scanners.osv.enabled=true
|
||||
```
|
||||
|
||||
### With S3 Storage
|
||||
|
||||
```bash
|
||||
helm install gohoarder gohoarder/gohoarder \
|
||||
--set storage.backend=s3 \
|
||||
--set storage.s3.bucket=my-bucket \
|
||||
--set storage.s3.region=us-east-1 \
|
||||
--set storage.s3.accessKeyId=AKIAIOSFODNN7EXAMPLE \
|
||||
--set storage.s3.secretAccessKey=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
|
||||
```
|
||||
|
||||
### With Private Container Registry
|
||||
|
||||
If using images from a private registry, create an image pull secret and reference it:
|
||||
|
||||
```bash
|
||||
# Create a Docker registry secret
|
||||
kubectl create secret docker-registry ghcr-secret \
|
||||
--docker-server=ghcr.io \
|
||||
--docker-username=<your-username> \
|
||||
--docker-password=<your-token> \
|
||||
--docker-email=<your-email> \
|
||||
-n gohoarder
|
||||
|
||||
# Install with the secret
|
||||
helm install gohoarder gohoarder/gohoarder \
|
||||
--set global.imagePullSecrets[0].name=ghcr-secret \
|
||||
-n gohoarder
|
||||
```
|
||||
|
||||
Or using a values file to reference existing secrets:
|
||||
|
||||
```yaml
|
||||
global:
|
||||
imagePullSecrets:
|
||||
- name: ghcr-secret
|
||||
- name: dockerhub-secret # Multiple secrets supported
|
||||
```
|
||||
|
||||
**Auto-create secrets** (chart will create them for you):
|
||||
|
||||
```yaml
|
||||
imageCredentials:
|
||||
ghcr-secret:
|
||||
registry: ghcr.io
|
||||
username: myusername
|
||||
password: mytoken
|
||||
email: myemail@example.com
|
||||
|
||||
global:
|
||||
imagePullSecrets:
|
||||
- name: ghcr-secret
|
||||
```
|
||||
|
||||
> **Note**: Storing credentials in values files is less secure than creating secrets manually. Consider using external secret management solutions like Sealed Secrets or External Secrets Operator for production.
|
||||
|
||||
## Configuration Methods
|
||||
|
||||
GoHoarder supports two configuration methods that can be used together:
|
||||
|
||||
### 1. ConfigMap (Default)
|
||||
|
||||
The chart automatically generates a `config.yaml` from Helm values and mounts it as a ConfigMap. This is the default approach and works out of the box.
|
||||
|
||||
### 2. Environment Variables
|
||||
|
||||
You can override any configuration using environment variables with the format `GOHOARDER_<CONFIG_KEY>` where dots are replaced with underscores.
|
||||
|
||||
**Example using values file:**
|
||||
|
||||
```yaml
|
||||
server:
|
||||
env:
|
||||
- name: GOHOARDER_STORAGE_BACKEND
|
||||
value: "s3"
|
||||
- name: GOHOARDER_STORAGE_S3_BUCKET
|
||||
value: "my-bucket"
|
||||
# Reference secrets for sensitive data
|
||||
- name: GOHOARDER_STORAGE_S3_SECRET_ACCESS_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: aws-credentials
|
||||
key: secret-access-key
|
||||
- name: GOHOARDER_METADATA_POSTGRESQL_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: postgres-secret
|
||||
key: password
|
||||
```
|
||||
|
||||
**Example using command line:**
|
||||
|
||||
```bash
|
||||
helm install gohoarder gohoarder/gohoarder \
|
||||
--set server.env[0].name=GOHOARDER_STORAGE_BACKEND \
|
||||
--set server.env[0].value=s3 \
|
||||
--set server.env[1].name=GOHOARDER_LOGGING_LEVEL \
|
||||
--set server.env[1].value=debug
|
||||
```
|
||||
|
||||
**Benefits of environment variables:**
|
||||
- Better integration with Kubernetes secrets
|
||||
- Override specific values without modifying ConfigMap
|
||||
- Support for secret references (no plain-text passwords)
|
||||
- Compatible with external secret management (External Secrets Operator, Sealed Secrets)
|
||||
|
||||
**Common environment variable mappings:**
|
||||
|
||||
| Config Path | Environment Variable |
|
||||
|-------------|---------------------|
|
||||
| `storage.backend` | `GOHOARDER_STORAGE_BACKEND` |
|
||||
| `storage.s3.bucket` | `GOHOARDER_STORAGE_S3_BUCKET` |
|
||||
| `storage.s3.region` | `GOHOARDER_STORAGE_S3_REGION` |
|
||||
| `storage.s3.access_key_id` | `GOHOARDER_STORAGE_S3_ACCESS_KEY_ID` |
|
||||
| `storage.s3.secret_access_key` | `GOHOARDER_STORAGE_S3_SECRET_ACCESS_KEY` |
|
||||
| `metadata.backend` | `GOHOARDER_METADATA_BACKEND` |
|
||||
| `metadata.postgresql.host` | `GOHOARDER_METADATA_POSTGRESQL_HOST` |
|
||||
| `metadata.postgresql.password` | `GOHOARDER_METADATA_POSTGRESQL_PASSWORD` |
|
||||
| `security.enabled` | `GOHOARDER_SECURITY_ENABLED` |
|
||||
| `security.scanners.trivy.enabled` | `GOHOARDER_SECURITY_SCANNERS_TRIVY_ENABLED` |
|
||||
| `logging.level` | `GOHOARDER_LOGGING_LEVEL` |
|
||||
| `logging.format` | `GOHOARDER_LOGGING_FORMAT` |
|
||||
|
||||
## Configuration Reference
|
||||
|
||||
The following table lists the configurable parameters and their default values.
|
||||
|
||||
### Global Parameters
|
||||
|
||||
| Parameter | Description | Default |
|
||||
|-----------|-------------|---------|
|
||||
| `nameOverride` | Override the name of the chart | `""` |
|
||||
| `fullnameOverride` | Override the full name of the chart | `""` |
|
||||
| `global.domain` | Base domain for the deployment | `gohoarder.local` |
|
||||
| `global.imagePullSecrets` | Image pull secrets (reference existing) | `[]` |
|
||||
| `imageCredentials` | Auto-create image pull secrets from credentials | `{}` |
|
||||
|
||||
### Replica Count
|
||||
|
||||
| Parameter | Description | Default |
|
||||
|-----------|-------------|---------|
|
||||
| `replicaCount.server` | Number of server replicas | `1` |
|
||||
| `replicaCount.frontend` | Number of frontend replicas | `1` |
|
||||
| `replicaCount.scanner` | Number of scanner replicas | `1` |
|
||||
|
||||
### Image Configuration
|
||||
|
||||
| Parameter | Description | Default |
|
||||
|-----------|-------------|---------|
|
||||
| `image.server.repository` | Server image repository | `ghcr.io/lukaszraczylo/gohoarder-server` |
|
||||
| `image.server.tag` | Server image tag | `latest` |
|
||||
| `image.server.pullPolicy` | Server image pull policy | `IfNotPresent` |
|
||||
| `image.frontend.repository` | Frontend image repository | `ghcr.io/lukaszraczylo/gohoarder-frontend` |
|
||||
| `image.frontend.tag` | Frontend image tag | `latest` |
|
||||
| `image.frontend.pullPolicy` | Frontend image pull policy | `IfNotPresent` |
|
||||
| `image.scanner.repository` | Scanner image repository | `ghcr.io/lukaszraczylo/gohoarder-scanner` |
|
||||
| `image.scanner.tag` | Scanner image tag | `latest` |
|
||||
| `image.scanner.pullPolicy` | Scanner image pull policy | `IfNotPresent` |
|
||||
|
||||
### Environment Variables
|
||||
|
||||
| Parameter | Description | Default |
|
||||
|-----------|-------------|---------|
|
||||
| `server.env` | Additional environment variables for server | `[]` |
|
||||
| `frontend.env` | Additional environment variables for frontend | `[]` |
|
||||
| `scanner.env` | Additional environment variables for scanner | `[]` |
|
||||
|
||||
### Storage Configuration
|
||||
|
||||
| Parameter | Description | Default |
|
||||
|-----------|-------------|---------|
|
||||
| `storage.backend` | Storage backend (filesystem, s3, smb) | `filesystem` |
|
||||
| `storage.filesystem.storageClass` | Storage class for PVC | `""` |
|
||||
| `storage.filesystem.size` | Storage size | `100Gi` |
|
||||
| `storage.filesystem.useHostPath` | Use hostPath instead of PVC | `false` |
|
||||
| `storage.filesystem.hostPath` | Host path for storage | `/var/lib/gohoarder` |
|
||||
| `storage.s3.endpoint` | S3 endpoint | `s3.amazonaws.com` |
|
||||
| `storage.s3.bucket` | S3 bucket name | `gohoarder-cache` |
|
||||
| `storage.s3.region` | S3 region | `us-east-1` |
|
||||
|
||||
### Metadata Configuration
|
||||
|
||||
| Parameter | Description | Default |
|
||||
|-----------|-------------|---------|
|
||||
| `metadata.backend` | Metadata backend (sqlite, postgresql) | `sqlite` |
|
||||
| `metadata.sqlite.persistence.enabled` | Enable persistence for SQLite | `true` |
|
||||
| `metadata.sqlite.persistence.size` | SQLite storage size | `10Gi` |
|
||||
| `metadata.postgresql.host` | PostgreSQL host | `localhost` |
|
||||
| `metadata.postgresql.database` | PostgreSQL database | `gohoarder` |
|
||||
|
||||
### Security Configuration
|
||||
|
||||
| Parameter | Description | Default |
|
||||
|-----------|-------------|---------|
|
||||
| `security.enabled` | Enable security scanning | `false` |
|
||||
| `security.blockOnSeverity` | Block packages on severity | `high` |
|
||||
| `security.scanners.trivy.enabled` | Enable Trivy scanner | `false` |
|
||||
| `security.scanners.osv.enabled` | Enable OSV scanner | `false` |
|
||||
| `security.scanners.grype.enabled` | Enable Grype scanner | `false` |
|
||||
|
||||
### Authentication
|
||||
|
||||
| Parameter | Description | Default |
|
||||
|-----------|-------------|---------|
|
||||
| `auth.enabled` | Enable authentication | `true` |
|
||||
| `auth.adminApiKey` | Admin API key (auto-generated if empty) | `""` |
|
||||
| `auth.existingSecret` | Use existing secret for admin key | `""` |
|
||||
|
||||
### Ingress
|
||||
|
||||
| Parameter | Description | Default |
|
||||
|-----------|-------------|---------|
|
||||
| `ingress.enabled` | Enable ingress | `false` |
|
||||
| `ingress.className` | Ingress class name | `nginx` |
|
||||
| `ingress.frontend.enabled` | Enable frontend ingress | `true` |
|
||||
| `ingress.frontend.host` | Frontend hostname | `gohoarder.local` |
|
||||
| `ingress.frontend.tls.enabled` | Enable TLS for frontend | `false` |
|
||||
|
||||
## High Availability & Scaling
|
||||
|
||||
### Running Multiple Server Replicas
|
||||
|
||||
GoHoarder can run with multiple server replicas for high availability and load distribution, but the configuration must be set correctly to avoid data inconsistency.
|
||||
|
||||
#### ✅ Compatible Configurations (Safe for Multiple Replicas)
|
||||
|
||||
**Storage:**
|
||||
- ✅ **S3** - Fully compatible, recommended for production HA setups
|
||||
- ✅ **SMB** - Compatible, shared network storage
|
||||
- ✅ **Filesystem with RWX** - Compatible when using ReadWriteMany storage classes
|
||||
- ✅ Examples: Longhorn RWX, NFS, CephFS, GlusterFS, Azure Files
|
||||
- ✅ Uses atomic rename operations for safe concurrent writes
|
||||
- ✅ Packages are static/immutable - perfect for shared storage
|
||||
- ❌ Not compatible with local storage or ReadWriteOnce (RWO) PVCs
|
||||
|
||||
**Metadata:**
|
||||
- ✅ **PostgreSQL** - Fully compatible, handles concurrent writes, recommended for HA
|
||||
- ⚠️ **SQLite** - Limited compatibility:
|
||||
- Uses WAL mode which supports concurrent reads
|
||||
- Multiple writers can cause lock contention
|
||||
- Works but may have performance issues under high concurrency
|
||||
- Only if using shared storage (NFS, etc.)
|
||||
|
||||
#### 📋 Recommended HA Configurations
|
||||
|
||||
**Option 1: Cloud Storage (S3)**
|
||||
|
||||
Best for cloud deployments, object storage:
|
||||
|
||||
```yaml
|
||||
replicaCount:
|
||||
server: 3
|
||||
|
||||
storage:
|
||||
backend: s3
|
||||
s3:
|
||||
endpoint: s3.amazonaws.com
|
||||
region: us-east-1
|
||||
bucket: gohoarder-cache
|
||||
|
||||
metadata:
|
||||
backend: postgresql
|
||||
postgresql:
|
||||
host: postgres.database.svc.cluster.local
|
||||
database: gohoarder
|
||||
|
||||
podDisruptionBudget:
|
||||
enabled: true
|
||||
minAvailable: 1
|
||||
```
|
||||
|
||||
**Option 2: Shared Filesystem (Longhorn/NFS)**
|
||||
|
||||
Best for on-premises or self-hosted Kubernetes:
|
||||
|
||||
```yaml
|
||||
replicaCount:
|
||||
server: 3
|
||||
|
||||
storage:
|
||||
backend: filesystem
|
||||
filesystem:
|
||||
# Use RWX storage class (Longhorn, NFS, CephFS, etc.)
|
||||
storageClass: "longhorn" # or "nfs-client", "cephfs", etc.
|
||||
size: "500Gi"
|
||||
accessMode: "ReadWriteMany" # RWX - Critical for multiple replicas!
|
||||
|
||||
metadata:
|
||||
backend: postgresql # Or SQLite with RWX storage
|
||||
postgresql:
|
||||
host: postgres.database.svc.cluster.local
|
||||
database: gohoarder
|
||||
|
||||
podDisruptionBudget:
|
||||
enabled: true
|
||||
minAvailable: 1
|
||||
```
|
||||
|
||||
**Why Filesystem with RWX Works:**
|
||||
- Packages are immutable once cached (static files)
|
||||
- Filesystem backend uses atomic `rename()` operations
|
||||
- Race condition safe: If two replicas cache same package, one wins
|
||||
- Performance: Local filesystem often faster than object storage for reads
|
||||
|
||||
#### ⚠️ What Won't Work with Multiple Replicas
|
||||
|
||||
**Filesystem storage with local volumes:**
|
||||
```yaml
|
||||
# ❌ DON'T DO THIS with multiple replicas
|
||||
storage:
|
||||
backend: filesystem
|
||||
filesystem:
|
||||
useHostPath: true # Each replica gets different storage
|
||||
```
|
||||
|
||||
**SQLite with local storage:**
|
||||
```yaml
|
||||
# ⚠️ AVOID with multiple replicas
|
||||
metadata:
|
||||
backend: sqlite
|
||||
sqlite:
|
||||
persistence:
|
||||
enabled: true # Each replica gets its own database
|
||||
```
|
||||
|
||||
#### 🔄 How It Works
|
||||
|
||||
**Request Deduplication:**
|
||||
- Single replica: Uses `singleflight` to prevent duplicate upstream fetches
|
||||
- Multiple replicas: Each replica may fetch the same package independently
|
||||
- **Mitigation**: Package metadata in shared database prevents duplicate downloads once one replica completes
|
||||
|
||||
**Cache Consistency:**
|
||||
- Storage backend (S3/SMB) ensures all replicas see the same cached packages
|
||||
- Metadata database ensures consistent package information across replicas
|
||||
- First replica to cache a package wins, others will use the cached version
|
||||
|
||||
**Session Affinity:**
|
||||
- Not required - GoHoarder is stateless
|
||||
- Load balancer can distribute requests randomly
|
||||
|
||||
**Scanner Replicas:**
|
||||
- Scanner can run as a single replica or multiple
|
||||
- If multiple scanners enabled, they share work through the metadata database
|
||||
- Package scans are deduplicated via database state
|
||||
|
||||
#### 🔬 Technical Details: Concurrent Write Safety
|
||||
|
||||
**Filesystem Backend with RWX Storage:**
|
||||
|
||||
The filesystem storage backend uses a **temp-file + atomic rename** pattern:
|
||||
|
||||
```go
|
||||
1. Write package to: /cache/npm/package@1.0.0.tmp
|
||||
2. Calculate checksums (MD5, SHA256)
|
||||
3. Atomic rename: .tmp → /cache/npm/package@1.0.0
|
||||
```
|
||||
|
||||
**Why this is safe for concurrent writes:**
|
||||
- `os.Rename()` is atomic on POSIX filesystems
|
||||
- If two replicas cache the same package simultaneously:
|
||||
- Both write to separate `.tmp` files
|
||||
- Both attempt atomic rename
|
||||
- One succeeds, one gets "file exists" error
|
||||
- Result: Same file content, no corruption
|
||||
|
||||
**Package immutability:**
|
||||
- Packages are versioned and immutable (npm/pypi/go semantics)
|
||||
- Same package@version always has identical content
|
||||
- Concurrent writes produce identical results
|
||||
- No risk of partial/corrupted files
|
||||
|
||||
**Quota tracking:**
|
||||
- Per-process mutex (minor inaccuracy across replicas)
|
||||
- Conservative: May undercount slightly
|
||||
- Not critical for operation
|
||||
|
||||
## Uninstallation
|
||||
|
||||
```bash
|
||||
helm uninstall gohoarder -n gohoarder
|
||||
```
|
||||
|
||||
## Upgrading
|
||||
|
||||
```bash
|
||||
helm upgrade gohoarder gohoarder/gohoarder -f values.yaml
|
||||
```
|
||||
|
||||
## Package Manager Configuration
|
||||
|
||||
After installation, configure your package managers to use GoHoarder:
|
||||
|
||||
### NPM
|
||||
|
||||
```bash
|
||||
npm config set registry http://<gohoarder-url>/npm/
|
||||
```
|
||||
|
||||
### Go
|
||||
|
||||
```bash
|
||||
export GOPROXY=http://<gohoarder-url>/go,direct
|
||||
```
|
||||
|
||||
### PyPI
|
||||
|
||||
```bash
|
||||
pip config set global.index-url http://<gohoarder-url>/pypi/simple
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Check Pod Status
|
||||
|
||||
```bash
|
||||
kubectl get pods -n gohoarder
|
||||
kubectl logs -n gohoarder <pod-name>
|
||||
```
|
||||
|
||||
### Verify Configuration
|
||||
|
||||
```bash
|
||||
kubectl get configmap -n gohoarder <release-name>-gohoarder-config -o yaml
|
||||
```
|
||||
|
||||
### Get Admin API Key
|
||||
|
||||
```bash
|
||||
kubectl get secret -n gohoarder <release-name>-gohoarder-auth -o jsonpath='{.data.admin-api-key}' | base64 -d
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome! Please visit [GitHub](https://github.com/lukaszraczylo/gohoarder) for more information.
|
||||
|
||||
## License
|
||||
|
||||
See the [LICENSE](https://github.com/lukaszraczylo/gohoarder/blob/main/LICENSE) file.
|
||||
@@ -1,70 +0,0 @@
|
||||
** GoHoarder has been installed! **
|
||||
|
||||
1. Get the application URL by running these commands:
|
||||
{{- if .Values.ingress.enabled }}
|
||||
{{- if .Values.ingress.frontend.enabled }}
|
||||
http{{ if .Values.ingress.frontend.tls.enabled }}s{{ end }}://{{ .Values.ingress.frontend.host | default (printf "%s.%s" "gohoarder" .Values.global.domain) }}
|
||||
{{- end }}
|
||||
{{- else if contains "NodePort" .Values.frontend.service.type }}
|
||||
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "gohoarder.fullname" . }}-frontend)
|
||||
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
|
||||
echo http://$NODE_IP:$NODE_PORT
|
||||
{{- else if contains "LoadBalancer" .Values.frontend.service.type }}
|
||||
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
|
||||
You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "gohoarder.fullname" . }}-frontend'
|
||||
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "gohoarder.fullname" . }}-frontend --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
|
||||
echo http://$SERVICE_IP:{{ .Values.frontend.service.port }}
|
||||
{{- else if contains "ClusterIP" .Values.frontend.service.type }}
|
||||
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "gohoarder.name" . }},app.kubernetes.io/instance={{ .Release.Name }},app.kubernetes.io/component=frontend" -o jsonpath="{.items[0].metadata.name}")
|
||||
export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
|
||||
echo "Visit http://127.0.0.1:8080 to use your application"
|
||||
kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT
|
||||
{{- end }}
|
||||
|
||||
2. Admin API Key:
|
||||
{{- if .Values.auth.enabled }}
|
||||
{{- if .Values.auth.existingSecret }}
|
||||
The admin API key is stored in the existing secret: {{ .Values.auth.existingSecret }}
|
||||
|
||||
To retrieve it:
|
||||
kubectl get secret {{ .Values.auth.existingSecret }} -n {{ .Release.Namespace }} -o jsonpath='{.data.{{ .Values.auth.secretKey }}}' | base64 -d
|
||||
{{- else if .Values.auth.adminApiKey }}
|
||||
The admin API key you provided: {{ .Values.auth.adminApiKey }}
|
||||
{{- else }}
|
||||
A random admin API key has been generated. To retrieve it:
|
||||
kubectl get secret {{ include "gohoarder.fullname" . }}-auth -n {{ .Release.Namespace }} -o jsonpath='{.data.{{ .Values.auth.secretKey }}}' | base64 -d
|
||||
{{- end }}
|
||||
{{- else }}
|
||||
Authentication is disabled.
|
||||
{{- end }}
|
||||
|
||||
3. Configuration:
|
||||
- Storage backend: {{ .Values.storage.backend }}
|
||||
- Metadata backend: {{ .Values.metadata.backend }}
|
||||
- Security scanning: {{ if .Values.security.enabled }}enabled{{ else }}disabled{{ end }}
|
||||
{{- if .Values.security.enabled }}
|
||||
- Active scanners:
|
||||
{{- range $scanner, $config := .Values.security.scanners }}
|
||||
{{- if $config.enabled }}
|
||||
* {{ $scanner }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
4. Package Proxies:
|
||||
Configure your package managers to use GoHoarder:
|
||||
|
||||
NPM:
|
||||
npm config set registry http://{{ include "gohoarder.fullname" . }}-server.{{ .Release.Namespace }}.svc.cluster.local/npm/
|
||||
|
||||
Go:
|
||||
export GOPROXY=http://{{ include "gohoarder.fullname" . }}-server.{{ .Release.Namespace }}.svc.cluster.local/go,direct
|
||||
|
||||
PyPI:
|
||||
pip config set global.index-url http://{{ include "gohoarder.fullname" . }}-server.{{ .Release.Namespace }}.svc.cluster.local/pypi/simple
|
||||
|
||||
5. Health Checks:
|
||||
- Server health: http://{{ include "gohoarder.fullname" . }}-server.{{ .Release.Namespace }}.svc.cluster.local/health
|
||||
- Server ready: http://{{ include "gohoarder.fullname" . }}-server.{{ .Release.Namespace }}.svc.cluster.local/health/ready
|
||||
|
||||
For more information, visit: https://github.com/lukaszraczylo/gohoarder
|
||||
@@ -1,188 +0,0 @@
|
||||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "gohoarder.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
*/}}
|
||||
{{- define "gohoarder.fullname" -}}
|
||||
{{- if .Values.fullnameOverride }}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride }}
|
||||
{{- if contains $name .Release.Name }}
|
||||
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create chart name and version as used by the chart label.
|
||||
*/}}
|
||||
{{- define "gohoarder.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Common labels
|
||||
*/}}
|
||||
{{- define "gohoarder.labels" -}}
|
||||
helm.sh/chart: {{ include "gohoarder.chart" . }}
|
||||
{{ include "gohoarder.selectorLabels" . }}
|
||||
{{- if .Chart.AppVersion }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||
{{- end }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Selector labels
|
||||
*/}}
|
||||
{{- define "gohoarder.selectorLabels" -}}
|
||||
app.kubernetes.io/name: {{ include "gohoarder.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Server labels
|
||||
*/}}
|
||||
{{- define "gohoarder.server.labels" -}}
|
||||
{{ include "gohoarder.labels" . }}
|
||||
app.kubernetes.io/component: server
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Server selector labels
|
||||
*/}}
|
||||
{{- define "gohoarder.server.selectorLabels" -}}
|
||||
{{ include "gohoarder.selectorLabels" . }}
|
||||
app.kubernetes.io/component: server
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Frontend labels
|
||||
*/}}
|
||||
{{- define "gohoarder.frontend.labels" -}}
|
||||
{{ include "gohoarder.labels" . }}
|
||||
app.kubernetes.io/component: frontend
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Frontend selector labels
|
||||
*/}}
|
||||
{{- define "gohoarder.frontend.selectorLabels" -}}
|
||||
{{ include "gohoarder.selectorLabels" . }}
|
||||
app.kubernetes.io/component: frontend
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Scanner labels
|
||||
*/}}
|
||||
{{- define "gohoarder.scanner.labels" -}}
|
||||
{{ include "gohoarder.labels" . }}
|
||||
app.kubernetes.io/component: scanner
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Scanner selector labels
|
||||
*/}}
|
||||
{{- define "gohoarder.scanner.selectorLabels" -}}
|
||||
{{ include "gohoarder.selectorLabels" . }}
|
||||
app.kubernetes.io/component: scanner
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create the name of the service account to use
|
||||
*/}}
|
||||
{{- define "gohoarder.serviceAccountName" -}}
|
||||
{{- if .Values.serviceAccount.create }}
|
||||
{{- default (include "gohoarder.fullname" .) .Values.serviceAccount.name }}
|
||||
{{- else }}
|
||||
{{- default "default" .Values.serviceAccount.name }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Generate admin API key
|
||||
*/}}
|
||||
{{- define "gohoarder.adminApiKey" -}}
|
||||
{{- if .Values.auth.adminApiKey }}
|
||||
{{- .Values.auth.adminApiKey }}
|
||||
{{- else }}
|
||||
{{- randAlphaNum 32 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Storage volume configuration
|
||||
*/}}
|
||||
{{- define "gohoarder.storageVolume" -}}
|
||||
{{- if eq .Values.storage.backend "filesystem" }}
|
||||
{{- if .Values.storage.filesystem.useHostPath }}
|
||||
- name: storage
|
||||
hostPath:
|
||||
path: {{ .Values.storage.filesystem.hostPath }}
|
||||
type: DirectoryOrCreate
|
||||
{{- else if .Values.storage.filesystem.existingClaim }}
|
||||
- name: storage
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ .Values.storage.filesystem.existingClaim }}
|
||||
{{- else }}
|
||||
- name: storage
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ include "gohoarder.fullname" . }}-storage
|
||||
{{- end }}
|
||||
{{- else }}
|
||||
- name: storage
|
||||
emptyDir: {}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Metadata volume configuration
|
||||
*/}}
|
||||
{{- define "gohoarder.metadataVolume" -}}
|
||||
{{- if and (eq .Values.metadata.backend "sqlite") .Values.metadata.sqlite.persistence.enabled }}
|
||||
{{- if .Values.metadata.sqlite.persistence.existingClaim }}
|
||||
- name: metadata
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ .Values.metadata.sqlite.persistence.existingClaim }}
|
||||
{{- else }}
|
||||
- name: metadata
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ include "gohoarder.fullname" . }}-metadata
|
||||
{{- end }}
|
||||
{{- else }}
|
||||
- name: metadata
|
||||
emptyDir: {}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Trivy cache volume configuration
|
||||
*/}}
|
||||
{{- define "gohoarder.trivyCacheVolume" -}}
|
||||
{{- if .Values.security.scanners.trivy.enabled }}
|
||||
- name: trivy-cache
|
||||
emptyDir: {}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Validate SQLite configuration - SQLite cannot be used with SMB/NFS network storage
|
||||
*/}}
|
||||
{{- define "gohoarder.validateSQLiteConfig" -}}
|
||||
{{- if eq .Values.metadata.backend "sqlite" }}
|
||||
{{- if .Values.metadata.sqlite.persistence.enabled }}
|
||||
{{- $storageClass := .Values.metadata.sqlite.persistence.storageClass | default .Values.storage.storageClass }}
|
||||
{{- if or (contains "smb" ($storageClass | lower)) (contains "cifs" ($storageClass | lower)) (contains "nfs" ($storageClass | lower)) }}
|
||||
{{- fail "\n\n❌ ERROR: SQLite cannot be used with SMB/CIFS/NFS network storage!\n\nSQLite requires POSIX file locking which is not reliably supported over network filesystems.\nThis will cause 'database is locked' errors and data corruption.\n\nPlease choose ONE of the following solutions:\n\n1. Use PostgreSQL for network storage (RECOMMENDED for production):\n metadata:\n backend: postgresql\n postgresql:\n host: your-postgres-host\n ...\n\n2. Use MySQL/MariaDB for network storage (alternative to PostgreSQL):\n metadata:\n backend: mysql\n mysql:\n host: your-mysql-host\n ...\n\n3. Use local storage for SQLite (OK for development):\n metadata:\n sqlite:\n persistence:\n enabled: true\n storageClass: local-path # or another local storage class\n\n4. Disable persistence (data will be lost on pod restart):\n metadata:\n sqlite:\n persistence:\n enabled: false\n\nFor more information, see: https://www.sqlite.org/lockingv3.html\n" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -1,174 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: {{ include "gohoarder.fullname" . }}-config
|
||||
labels:
|
||||
{{- include "gohoarder.labels" . | nindent 4 }}
|
||||
data:
|
||||
config.yaml: |
|
||||
server:
|
||||
host: {{ .Values.server.host | quote }}
|
||||
port: {{ .Values.server.port }}
|
||||
read_timeout: {{ .Values.server.readTimeout | quote }}
|
||||
write_timeout: {{ .Values.server.writeTimeout | quote }}
|
||||
idle_timeout: {{ .Values.server.idleTimeout | quote }}
|
||||
tls:
|
||||
enabled: false
|
||||
|
||||
storage:
|
||||
backend: {{ .Values.storage.backend | quote }}
|
||||
{{- if eq .Values.storage.backend "filesystem" }}
|
||||
path: "/var/cache/gohoarder"
|
||||
filesystem:
|
||||
base_path: "/var/cache/gohoarder"
|
||||
{{- else if eq .Values.storage.backend "s3" }}
|
||||
s3:
|
||||
endpoint: {{ .Values.storage.s3.endpoint | quote }}
|
||||
region: {{ .Values.storage.s3.region | quote }}
|
||||
bucket: {{ .Values.storage.s3.bucket | quote }}
|
||||
{{- if .Values.storage.s3.existingSecret }}
|
||||
access_key_id: "${S3_ACCESS_KEY_ID}"
|
||||
secret_access_key: "${S3_SECRET_ACCESS_KEY}"
|
||||
{{- else }}
|
||||
access_key_id: {{ .Values.storage.s3.accessKeyId | quote }}
|
||||
secret_access_key: {{ .Values.storage.s3.secretAccessKey | quote }}
|
||||
{{- end }}
|
||||
use_ssl: {{ .Values.storage.s3.useSSL }}
|
||||
{{- else if eq .Values.storage.backend "smb" }}
|
||||
smb:
|
||||
host: {{ .Values.storage.smb.host | quote }}
|
||||
share: {{ .Values.storage.smb.share | quote }}
|
||||
{{- if .Values.storage.smb.existingSecret }}
|
||||
username: "${SMB_USERNAME}"
|
||||
password: "${SMB_PASSWORD}"
|
||||
{{- else }}
|
||||
username: {{ .Values.storage.smb.username | quote }}
|
||||
password: {{ .Values.storage.smb.password | quote }}
|
||||
{{- end }}
|
||||
domain: {{ .Values.storage.smb.domain | quote }}
|
||||
{{- end }}
|
||||
|
||||
metadata:
|
||||
backend: {{ .Values.metadata.backend | quote }}
|
||||
{{- if eq .Values.metadata.backend "sqlite" }}
|
||||
connection: "file:/var/lib/gohoarder/metadata/gohoarder.db?cache=shared&mode=rwc"
|
||||
sqlite:
|
||||
path: "/var/lib/gohoarder/metadata/gohoarder.db"
|
||||
wal_mode: {{ .Values.metadata.sqlite.walMode }}
|
||||
{{- else if eq .Values.metadata.backend "postgresql" }}
|
||||
postgresql:
|
||||
host: {{ .Values.metadata.postgresql.host | quote }}
|
||||
port: {{ .Values.metadata.postgresql.port }}
|
||||
database: {{ .Values.metadata.postgresql.database | quote }}
|
||||
{{- if .Values.metadata.postgresql.existingSecret }}
|
||||
user: "${POSTGRES_USER}"
|
||||
password: "${POSTGRES_PASSWORD}"
|
||||
{{- else }}
|
||||
user: {{ .Values.metadata.postgresql.username | quote }}
|
||||
password: {{ .Values.metadata.postgresql.password | quote }}
|
||||
{{- end }}
|
||||
ssl_mode: {{ .Values.metadata.postgresql.sslMode | quote }}
|
||||
{{- end }}
|
||||
|
||||
cache:
|
||||
default_ttl: {{ .Values.cache.defaultTTL | quote }}
|
||||
cleanup_interval: {{ .Values.cache.cleanupInterval | quote }}
|
||||
max_size_bytes: {{ .Values.cache.maxSizeBytes }}
|
||||
per_project_quota: {{ .Values.cache.perProjectQuota }}
|
||||
ttl_overrides:
|
||||
{{- range $key, $value := .Values.cache.ttlOverrides }}
|
||||
{{ $key }}: {{ $value | quote }}
|
||||
{{- end }}
|
||||
|
||||
security:
|
||||
enabled: {{ .Values.security.enabled }}
|
||||
block_on_severity: {{ .Values.security.blockOnSeverity | quote }}
|
||||
scan_on_download: {{ .Values.security.scanOnDownload }}
|
||||
rescan_interval: {{ .Values.security.rescanInterval | quote }}
|
||||
update_db_on_startup: {{ .Values.security.updateDbOnStartup }}
|
||||
block_thresholds:
|
||||
critical: {{ .Values.security.blockThresholds.critical }}
|
||||
high: {{ .Values.security.blockThresholds.high }}
|
||||
medium: {{ .Values.security.blockThresholds.medium }}
|
||||
low: {{ .Values.security.blockThresholds.low }}
|
||||
scanners:
|
||||
trivy:
|
||||
# Disabled in server config (no trivy binary), enabled via env var in scanner pod
|
||||
enabled: false
|
||||
timeout: {{ .Values.security.scanners.trivy.timeout | quote }}
|
||||
cache_db: {{ .Values.security.scanners.trivy.cacheDb | quote }}
|
||||
osv:
|
||||
# API-based scanner - works in both server and scanner pods
|
||||
enabled: {{ .Values.security.scanners.osv.enabled }}
|
||||
api_url: {{ .Values.security.scanners.osv.apiUrl | quote }}
|
||||
timeout: {{ .Values.security.scanners.osv.timeout | quote }}
|
||||
grype:
|
||||
# Disabled in server config (no grype binary), enabled via env var in scanner pod
|
||||
enabled: false
|
||||
timeout: {{ .Values.security.scanners.grype.timeout | quote }}
|
||||
govulncheck:
|
||||
# Disabled in server config (no go/govulncheck binary), enabled via env var in scanner pod
|
||||
enabled: false
|
||||
timeout: {{ .Values.security.scanners.govulncheck.timeout | quote }}
|
||||
npm_audit:
|
||||
# Disabled in server config (no npm binary), enabled via env var in scanner pod
|
||||
enabled: false
|
||||
timeout: {{ .Values.security.scanners.npmAudit.timeout | quote }}
|
||||
pip_audit:
|
||||
# Disabled in server config (no pip binary), enabled via env var in scanner pod
|
||||
enabled: false
|
||||
timeout: {{ .Values.security.scanners.pipAudit.timeout | quote }}
|
||||
ghsa:
|
||||
enabled: {{ .Values.security.scanners.ghsa.enabled }}
|
||||
timeout: {{ .Values.security.scanners.ghsa.timeout | quote }}
|
||||
{{- if or .Values.security.scanners.ghsa.token .Values.security.scanners.ghsa.existingSecret }}
|
||||
token: "${GHSA_TOKEN}"
|
||||
{{- end }}
|
||||
static:
|
||||
enabled: {{ .Values.security.scanners.static.enabled }}
|
||||
max_package_size: {{ .Values.security.scanners.static.maxPackageSize }}
|
||||
check_checksums: {{ .Values.security.scanners.static.checkChecksums }}
|
||||
block_suspicious: {{ .Values.security.scanners.static.blockSuspicious }}
|
||||
|
||||
auth:
|
||||
enabled: {{ .Values.auth.enabled }}
|
||||
key_expiration: {{ .Values.auth.keyExpiration | quote }}
|
||||
bcrypt_cost: {{ .Values.auth.bcryptCost }}
|
||||
audit_log: {{ .Values.auth.auditLog }}
|
||||
|
||||
network:
|
||||
connect_timeout: {{ .Values.network.connectTimeout | quote }}
|
||||
read_timeout: {{ .Values.network.readTimeout | quote }}
|
||||
write_timeout: {{ .Values.network.writeTimeout | quote }}
|
||||
max_idle_conns: {{ .Values.network.maxIdleConns }}
|
||||
max_conns_per_host: {{ .Values.network.maxConnsPerHost }}
|
||||
rate_limit:
|
||||
per_api_key: {{ .Values.network.rateLimit.perApiKey }}
|
||||
per_ip: {{ .Values.network.rateLimit.perIp }}
|
||||
burst_size: {{ .Values.network.rateLimit.burstSize }}
|
||||
circuit_breaker:
|
||||
threshold: {{ .Values.network.circuitBreaker.threshold }}
|
||||
timeout: {{ .Values.network.circuitBreaker.timeout | quote }}
|
||||
reset_interval: {{ .Values.network.circuitBreaker.resetInterval | quote }}
|
||||
retry:
|
||||
max_attempts: {{ .Values.network.retry.maxAttempts }}
|
||||
initial_backoff: {{ .Values.network.retry.initialBackoff | quote }}
|
||||
max_backoff: {{ .Values.network.retry.maxBackoff | quote }}
|
||||
|
||||
logging:
|
||||
level: {{ .Values.logging.level | quote }}
|
||||
format: {{ .Values.logging.format | quote }}
|
||||
|
||||
handlers:
|
||||
go:
|
||||
enabled: {{ .Values.handlers.go.enabled }}
|
||||
upstream_proxy: {{ .Values.handlers.go.upstreamProxy | quote }}
|
||||
checksum_db: {{ .Values.handlers.go.checksumDb | quote }}
|
||||
verify_checksums: {{ .Values.handlers.go.verifyChecksums }}
|
||||
npm:
|
||||
enabled: {{ .Values.handlers.npm.enabled }}
|
||||
upstream_registry: {{ .Values.handlers.npm.upstreamRegistry | quote }}
|
||||
pypi:
|
||||
enabled: {{ .Values.handlers.pypi.enabled }}
|
||||
upstream_url: {{ .Values.handlers.pypi.upstreamUrl | quote }}
|
||||
simple_api_url: {{ .Values.handlers.pypi.simpleApiUrl | quote }}
|
||||
@@ -1,124 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "gohoarder.fullname" . }}-frontend
|
||||
labels:
|
||||
{{- include "gohoarder.frontend.labels" . | nindent 4 }}
|
||||
spec:
|
||||
{{- if not .Values.autoscaling.enabled }}
|
||||
replicas: {{ .Values.replicaCount.frontend }}
|
||||
{{- end }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "gohoarder.frontend.selectorLabels" . | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
{{- with .Values.podAnnotations }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "gohoarder.frontend.selectorLabels" . | nindent 8 }}
|
||||
spec:
|
||||
{{- with .Values.global.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
serviceAccountName: {{ include "gohoarder.serviceAccountName" . }}
|
||||
securityContext:
|
||||
fsGroup: 101
|
||||
runAsNonRoot: true
|
||||
runAsUser: 101
|
||||
initContainers:
|
||||
- name: copy-static-files
|
||||
image: "{{ .Values.image.frontend.repository }}:{{ .Values.image.frontend.tag | default .Chart.AppVersion }}"
|
||||
command: ['sh', '-c']
|
||||
args:
|
||||
- |
|
||||
# Copy built frontend files to writable volume
|
||||
cp -rp /usr/share/nginx/html/* /html/
|
||||
# Copy nginx config to writable volume
|
||||
cp -rp /etc/nginx/conf.d/* /conf/
|
||||
volumeMounts:
|
||||
- name: nginx-html
|
||||
mountPath: /html
|
||||
- name: nginx-conf
|
||||
mountPath: /conf
|
||||
securityContext:
|
||||
runAsUser: 101
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
containers:
|
||||
- name: frontend
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
readOnlyRootFilesystem: false
|
||||
runAsUser: 101
|
||||
image: "{{ .Values.image.frontend.repository }}:{{ .Values.image.frontend.tag | default .Chart.AppVersion }}"
|
||||
imagePullPolicy: {{ .Values.image.frontend.pullPolicy }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 80
|
||||
protocol: TCP
|
||||
env:
|
||||
- name: API_BASE_URL
|
||||
value: {{ .Values.frontend.backendUrl | default "/api" | quote }}
|
||||
- name: APP_VERSION
|
||||
value: {{ .Chart.AppVersion | quote }}
|
||||
- name: APP_NAME
|
||||
value: "GoHoarder"
|
||||
# Backend proxy configuration (frontend now includes reverse proxy)
|
||||
- name: BACKEND_HOST
|
||||
value: {{ include "gohoarder.fullname" . }}-server
|
||||
- name: BACKEND_PORT
|
||||
value: {{ .Values.server.service.port | quote }}
|
||||
- name: SERVER_NAME
|
||||
value: {{ .Values.frontend.serverName | default "_" | quote }}
|
||||
{{- with .Values.frontend.env }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
livenessProbe:
|
||||
{{- toYaml .Values.frontend.livenessProbe | nindent 12 }}
|
||||
readinessProbe:
|
||||
{{- toYaml .Values.frontend.readinessProbe | nindent 12 }}
|
||||
resources:
|
||||
{{- toYaml .Values.frontend.resources | nindent 12 }}
|
||||
volumeMounts:
|
||||
- name: tmp
|
||||
mountPath: /tmp
|
||||
- name: nginx-cache
|
||||
mountPath: /var/cache/nginx
|
||||
- name: nginx-run
|
||||
mountPath: /var/run
|
||||
- name: nginx-html
|
||||
mountPath: /usr/share/nginx/html
|
||||
- name: nginx-conf
|
||||
mountPath: /etc/nginx/conf.d
|
||||
volumes:
|
||||
- name: tmp
|
||||
emptyDir: {}
|
||||
- name: nginx-cache
|
||||
emptyDir: {}
|
||||
- name: nginx-run
|
||||
emptyDir: {}
|
||||
- name: nginx-html
|
||||
emptyDir: {}
|
||||
- name: nginx-conf
|
||||
emptyDir: {}
|
||||
{{- with .Values.frontend.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.frontend.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.frontend.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
@@ -1,222 +0,0 @@
|
||||
{{- if .Values.security.enabled }}
|
||||
{{- include "gohoarder.validateSQLiteConfig" . }}
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "gohoarder.fullname" . }}-scanner
|
||||
labels:
|
||||
{{- include "gohoarder.scanner.labels" . | nindent 4 }}
|
||||
spec:
|
||||
replicas: {{ .Values.replicaCount.scanner }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "gohoarder.scanner.selectorLabels" . | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
|
||||
checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }}
|
||||
{{- with .Values.podAnnotations }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "gohoarder.scanner.selectorLabels" . | nindent 8 }}
|
||||
spec:
|
||||
{{- with .Values.global.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
serviceAccountName: {{ include "gohoarder.serviceAccountName" . }}
|
||||
securityContext:
|
||||
{{- toYaml .Values.podSecurityContext | nindent 8 }}
|
||||
{{- if .Values.migration.enabled }}
|
||||
initContainers:
|
||||
# Wait for database to be ready
|
||||
- name: wait-for-db
|
||||
image: busybox:1.36
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- |
|
||||
echo "Waiting for database..."
|
||||
{{- if eq .Values.metadata.backend "postgresql" }}
|
||||
until nc -z {{ .Values.metadata.postgresql.host }} {{ .Values.metadata.postgresql.port }}; do
|
||||
echo " PostgreSQL not ready, retrying in 2s..."
|
||||
sleep 2
|
||||
done
|
||||
echo "✓ PostgreSQL is ready"
|
||||
{{- else if eq .Values.metadata.backend "mysql" }}
|
||||
until nc -z {{ .Values.metadata.mysql.host }} {{ .Values.metadata.mysql.port }}; do
|
||||
echo " MySQL not ready, retrying in 2s..."
|
||||
sleep 2
|
||||
done
|
||||
echo "✓ MySQL is ready"
|
||||
{{- else }}
|
||||
echo "✓ SQLite (no wait needed)"
|
||||
{{- end }}
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1000
|
||||
resources:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 64Mi
|
||||
requests:
|
||||
cpu: 10m
|
||||
memory: 32Mi
|
||||
# Run database migrations
|
||||
- name: migrate
|
||||
image: "{{ .Values.migration.image.repository }}:{{ .Values.migration.image.tag | default .Chart.AppVersion }}"
|
||||
imagePullPolicy: {{ .Values.migration.image.pullPolicy }}
|
||||
env:
|
||||
- name: DB_DRIVER
|
||||
value: {{ .Values.metadata.backend | quote }}
|
||||
{{- if eq .Values.metadata.backend "postgresql" }}
|
||||
- name: DATABASE_URL
|
||||
value: "postgresql://{{ .Values.metadata.postgresql.username }}:{{ .Values.metadata.postgresql.password }}@{{ .Values.metadata.postgresql.host }}:{{ .Values.metadata.postgresql.port }}/{{ .Values.metadata.postgresql.database }}?sslmode={{ .Values.metadata.postgresql.sslMode }}"
|
||||
{{- else if eq .Values.metadata.backend "mysql" }}
|
||||
- name: DATABASE_URL
|
||||
value: "{{ .Values.metadata.mysql.username }}:{{ .Values.metadata.mysql.password }}@tcp({{ .Values.metadata.mysql.host }}:{{ .Values.metadata.mysql.port }})/{{ .Values.metadata.mysql.database }}?charset={{ .Values.metadata.mysql.charset }}&parseTime={{ .Values.metadata.mysql.parseTime }}"
|
||||
{{- else }}
|
||||
- name: DATABASE_URL
|
||||
value: "/var/lib/gohoarder/metadata/gohoarder.db"
|
||||
{{- end }}
|
||||
args:
|
||||
- --driver=$(DB_DRIVER)
|
||||
- --dsn=$(DATABASE_URL)
|
||||
- --action=migrate
|
||||
- --log-level={{ .Values.migration.logLevel | default "info" }}
|
||||
- --timeout={{ .Values.migration.timeout | default "5m" }}
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1000
|
||||
resources:
|
||||
{{- toYaml .Values.migration.resources | nindent 10 }}
|
||||
{{- if eq .Values.metadata.backend "sqlite" }}
|
||||
volumeMounts:
|
||||
- name: metadata
|
||||
mountPath: /var/lib/gohoarder/metadata
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
containers:
|
||||
- name: scanner
|
||||
securityContext:
|
||||
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||
image: "{{ .Values.image.scanner.repository }}:{{ .Values.image.scanner.tag | default .Chart.AppVersion }}"
|
||||
imagePullPolicy: {{ .Values.image.scanner.pullPolicy }}
|
||||
env:
|
||||
- name: CONFIG_FILE
|
||||
value: /etc/gohoarder/config.yaml
|
||||
# Enable tool-based scanners only in scanner pod (server doesn't have the tools)
|
||||
- name: GOHOARDER_SECURITY_SCANNERS_TRIVY_ENABLED
|
||||
value: "{{ .Values.security.scanners.trivy.enabled }}"
|
||||
- name: GOHOARDER_SECURITY_SCANNERS_GRYPE_ENABLED
|
||||
value: "{{ .Values.security.scanners.grype.enabled }}"
|
||||
- name: GOHOARDER_SECURITY_SCANNERS_GOVULNCHECK_ENABLED
|
||||
value: "{{ .Values.security.scanners.govulncheck.enabled }}"
|
||||
- name: GOHOARDER_SECURITY_SCANNERS_NPM_AUDIT_ENABLED
|
||||
value: "{{ .Values.security.scanners.npmAudit.enabled }}"
|
||||
- name: GOHOARDER_SECURITY_SCANNERS_PIP_AUDIT_ENABLED
|
||||
value: "{{ .Values.security.scanners.pipAudit.enabled }}"
|
||||
{{- if and (eq .Values.metadata.backend "postgresql") .Values.metadata.postgresql.existingSecret }}
|
||||
- name: POSTGRES_USER
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.metadata.postgresql.existingSecret }}
|
||||
key: username
|
||||
- name: POSTGRES_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.metadata.postgresql.existingSecret }}
|
||||
key: password
|
||||
{{- else if and (eq .Values.metadata.backend "postgresql") .Values.metadata.postgresql.username }}
|
||||
- name: POSTGRES_USER
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "gohoarder.fullname" . }}-postgresql
|
||||
key: username
|
||||
- name: POSTGRES_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "gohoarder.fullname" . }}-postgresql
|
||||
key: password
|
||||
{{- end }}
|
||||
{{- if and (or (eq .Values.metadata.backend "mysql") (eq .Values.metadata.backend "mariadb")) .Values.metadata.mysql.existingSecret }}
|
||||
- name: MYSQL_USER
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.metadata.mysql.existingSecret }}
|
||||
key: username
|
||||
- name: MYSQL_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.metadata.mysql.existingSecret }}
|
||||
key: password
|
||||
{{- else if and (or (eq .Values.metadata.backend "mysql") (eq .Values.metadata.backend "mariadb")) .Values.metadata.mysql.username }}
|
||||
- name: MYSQL_USER
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "gohoarder.fullname" . }}-mysql
|
||||
key: username
|
||||
- name: MYSQL_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "gohoarder.fullname" . }}-mysql
|
||||
key: password
|
||||
{{- end }}
|
||||
{{- if and .Values.security.scanners.ghsa.enabled .Values.security.scanners.ghsa.existingSecret }}
|
||||
- name: GHSA_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.security.scanners.ghsa.existingSecret }}
|
||||
key: token
|
||||
{{- else if and .Values.security.scanners.ghsa.enabled .Values.security.scanners.ghsa.token }}
|
||||
- name: GHSA_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "gohoarder.fullname" . }}-ghsa
|
||||
key: token
|
||||
{{- end }}
|
||||
{{- with .Values.scanner.env }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
resources:
|
||||
{{- toYaml .Values.scanner.resources | nindent 12 }}
|
||||
volumeMounts:
|
||||
- name: config
|
||||
mountPath: /etc/gohoarder
|
||||
readOnly: true
|
||||
- name: storage
|
||||
mountPath: /var/cache/gohoarder
|
||||
- name: metadata
|
||||
mountPath: /var/lib/gohoarder/metadata
|
||||
{{- if .Values.security.scanners.trivy.enabled }}
|
||||
- name: trivy-cache
|
||||
mountPath: {{ .Values.security.scanners.trivy.cacheDb }}
|
||||
{{- end }}
|
||||
- name: tmp
|
||||
mountPath: /tmp
|
||||
volumes:
|
||||
- name: config
|
||||
configMap:
|
||||
name: {{ include "gohoarder.fullname" . }}-config
|
||||
{{- include "gohoarder.storageVolume" . | nindent 6 }}
|
||||
{{- include "gohoarder.metadataVolume" . | nindent 6 }}
|
||||
{{- include "gohoarder.trivyCacheVolume" . | nindent 6 }}
|
||||
- name: tmp
|
||||
emptyDir: {}
|
||||
{{- with .Values.scanner.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.scanner.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.scanner.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -1,273 +0,0 @@
|
||||
{{- include "gohoarder.validateSQLiteConfig" . }}
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "gohoarder.fullname" . }}-server
|
||||
labels:
|
||||
{{- include "gohoarder.server.labels" . | nindent 4 }}
|
||||
spec:
|
||||
{{- if not .Values.autoscaling.enabled }}
|
||||
replicas: {{ .Values.replicaCount.server }}
|
||||
{{- end }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "gohoarder.server.selectorLabels" . | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }}
|
||||
checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }}
|
||||
{{- with .Values.podAnnotations }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "gohoarder.server.selectorLabels" . | nindent 8 }}
|
||||
spec:
|
||||
{{- with .Values.global.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
serviceAccountName: {{ include "gohoarder.serviceAccountName" . }}
|
||||
securityContext:
|
||||
{{- toYaml .Values.podSecurityContext | nindent 8 }}
|
||||
{{- if .Values.migration.enabled }}
|
||||
initContainers:
|
||||
# Wait for database to be ready
|
||||
- name: wait-for-db
|
||||
image: busybox:1.36
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- |
|
||||
echo "Waiting for database..."
|
||||
{{- if eq .Values.metadata.backend "postgresql" }}
|
||||
until nc -z {{ .Values.metadata.postgresql.host }} {{ .Values.metadata.postgresql.port }}; do
|
||||
echo " PostgreSQL not ready, retrying in 2s..."
|
||||
sleep 2
|
||||
done
|
||||
echo "✓ PostgreSQL is ready"
|
||||
{{- else if eq .Values.metadata.backend "mysql" }}
|
||||
until nc -z {{ .Values.metadata.mysql.host }} {{ .Values.metadata.mysql.port }}; do
|
||||
echo " MySQL not ready, retrying in 2s..."
|
||||
sleep 2
|
||||
done
|
||||
echo "✓ MySQL is ready"
|
||||
{{- else }}
|
||||
echo "✓ SQLite (no wait needed)"
|
||||
{{- end }}
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1000
|
||||
resources:
|
||||
limits:
|
||||
cpu: 100m
|
||||
memory: 64Mi
|
||||
requests:
|
||||
cpu: 10m
|
||||
memory: 32Mi
|
||||
# Run database migrations
|
||||
- name: migrate
|
||||
image: "{{ .Values.migration.image.repository }}:{{ .Values.migration.image.tag | default .Chart.AppVersion }}"
|
||||
imagePullPolicy: {{ .Values.migration.image.pullPolicy }}
|
||||
env:
|
||||
- name: DB_DRIVER
|
||||
value: {{ .Values.metadata.backend | quote }}
|
||||
{{- if eq .Values.metadata.backend "postgresql" }}
|
||||
- name: DATABASE_URL
|
||||
value: "postgresql://{{ .Values.metadata.postgresql.username }}:{{ .Values.metadata.postgresql.password }}@{{ .Values.metadata.postgresql.host }}:{{ .Values.metadata.postgresql.port }}/{{ .Values.metadata.postgresql.database }}?sslmode={{ .Values.metadata.postgresql.sslMode }}"
|
||||
{{- else if eq .Values.metadata.backend "mysql" }}
|
||||
- name: DATABASE_URL
|
||||
value: "{{ .Values.metadata.mysql.username }}:{{ .Values.metadata.mysql.password }}@tcp({{ .Values.metadata.mysql.host }}:{{ .Values.metadata.mysql.port }})/{{ .Values.metadata.mysql.database }}?charset={{ .Values.metadata.mysql.charset }}&parseTime={{ .Values.metadata.mysql.parseTime }}"
|
||||
{{- else }}
|
||||
- name: DATABASE_URL
|
||||
value: "/var/lib/gohoarder/metadata/gohoarder.db"
|
||||
{{- end }}
|
||||
args:
|
||||
- --driver=$(DB_DRIVER)
|
||||
- --dsn=$(DATABASE_URL)
|
||||
- --action=migrate
|
||||
- --log-level={{ .Values.migration.logLevel | default "info" }}
|
||||
- --timeout={{ .Values.migration.timeout | default "5m" }}
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1000
|
||||
resources:
|
||||
{{- toYaml .Values.migration.resources | nindent 10 }}
|
||||
{{- if eq .Values.metadata.backend "sqlite" }}
|
||||
volumeMounts:
|
||||
- name: metadata
|
||||
mountPath: /var/lib/gohoarder/metadata
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
containers:
|
||||
- name: server
|
||||
securityContext:
|
||||
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||
image: "{{ .Values.image.server.repository }}:{{ .Values.image.server.tag | default .Chart.AppVersion }}"
|
||||
imagePullPolicy: {{ .Values.image.server.pullPolicy }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: {{ .Values.server.port }}
|
||||
protocol: TCP
|
||||
env:
|
||||
- name: CONFIG_FILE
|
||||
value: /etc/gohoarder/config.yaml
|
||||
{{- if and .Values.auth.enabled .Values.auth.existingSecret }}
|
||||
- name: ADMIN_API_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.auth.existingSecret }}
|
||||
key: {{ .Values.auth.secretKey }}
|
||||
{{- else if .Values.auth.enabled }}
|
||||
- name: ADMIN_API_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "gohoarder.fullname" . }}-auth
|
||||
key: {{ .Values.auth.secretKey }}
|
||||
{{- end }}
|
||||
{{- if and (eq .Values.storage.backend "s3") .Values.storage.s3.existingSecret }}
|
||||
- name: S3_ACCESS_KEY_ID
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.storage.s3.existingSecret }}
|
||||
key: access-key-id
|
||||
- name: S3_SECRET_ACCESS_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.storage.s3.existingSecret }}
|
||||
key: secret-access-key
|
||||
{{- else if and (eq .Values.storage.backend "s3") .Values.storage.s3.accessKeyId }}
|
||||
- name: S3_ACCESS_KEY_ID
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "gohoarder.fullname" . }}-s3
|
||||
key: access-key-id
|
||||
- name: S3_SECRET_ACCESS_KEY
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "gohoarder.fullname" . }}-s3
|
||||
key: secret-access-key
|
||||
{{- end }}
|
||||
{{- if and (eq .Values.storage.backend "smb") .Values.storage.smb.existingSecret }}
|
||||
- name: SMB_USERNAME
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.storage.smb.existingSecret }}
|
||||
key: username
|
||||
- name: SMB_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.storage.smb.existingSecret }}
|
||||
key: password
|
||||
{{- else if and (eq .Values.storage.backend "smb") .Values.storage.smb.username }}
|
||||
- name: SMB_USERNAME
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "gohoarder.fullname" . }}-smb
|
||||
key: username
|
||||
- name: SMB_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "gohoarder.fullname" . }}-smb
|
||||
key: password
|
||||
{{- end }}
|
||||
{{- if and (eq .Values.metadata.backend "postgresql") .Values.metadata.postgresql.existingSecret }}
|
||||
- name: POSTGRES_USER
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.metadata.postgresql.existingSecret }}
|
||||
key: username
|
||||
- name: POSTGRES_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.metadata.postgresql.existingSecret }}
|
||||
key: password
|
||||
{{- else if and (eq .Values.metadata.backend "postgresql") .Values.metadata.postgresql.username }}
|
||||
- name: POSTGRES_USER
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "gohoarder.fullname" . }}-postgresql
|
||||
key: username
|
||||
- name: POSTGRES_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "gohoarder.fullname" . }}-postgresql
|
||||
key: password
|
||||
{{- end }}
|
||||
{{- if and (or (eq .Values.metadata.backend "mysql") (eq .Values.metadata.backend "mariadb")) .Values.metadata.mysql.existingSecret }}
|
||||
- name: MYSQL_USER
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.metadata.mysql.existingSecret }}
|
||||
key: username
|
||||
- name: MYSQL_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.metadata.mysql.existingSecret }}
|
||||
key: password
|
||||
{{- else if and (or (eq .Values.metadata.backend "mysql") (eq .Values.metadata.backend "mariadb")) .Values.metadata.mysql.username }}
|
||||
- name: MYSQL_USER
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "gohoarder.fullname" . }}-mysql
|
||||
key: username
|
||||
- name: MYSQL_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "gohoarder.fullname" . }}-mysql
|
||||
key: password
|
||||
{{- end }}
|
||||
{{- if and .Values.security.scanners.ghsa.enabled .Values.security.scanners.ghsa.existingSecret }}
|
||||
- name: GHSA_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ .Values.security.scanners.ghsa.existingSecret }}
|
||||
key: token
|
||||
{{- else if and .Values.security.scanners.ghsa.enabled .Values.security.scanners.ghsa.token }}
|
||||
- name: GHSA_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "gohoarder.fullname" . }}-ghsa
|
||||
key: token
|
||||
{{- end }}
|
||||
{{- with .Values.server.env }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
livenessProbe:
|
||||
{{- toYaml .Values.server.livenessProbe | nindent 12 }}
|
||||
readinessProbe:
|
||||
{{- toYaml .Values.server.readinessProbe | nindent 12 }}
|
||||
resources:
|
||||
{{- toYaml .Values.server.resources | nindent 12 }}
|
||||
volumeMounts:
|
||||
- name: config
|
||||
mountPath: /etc/gohoarder
|
||||
readOnly: true
|
||||
- name: storage
|
||||
mountPath: /var/cache/gohoarder
|
||||
- name: metadata
|
||||
mountPath: /var/lib/gohoarder/metadata
|
||||
- name: tmp
|
||||
mountPath: /tmp
|
||||
volumes:
|
||||
- name: config
|
||||
configMap:
|
||||
name: {{ include "gohoarder.fullname" . }}-config
|
||||
{{- include "gohoarder.storageVolume" . | nindent 6 }}
|
||||
{{- include "gohoarder.metadataVolume" . | nindent 6 }}
|
||||
- name: tmp
|
||||
emptyDir: {}
|
||||
{{- with .Values.server.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.server.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.server.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
@@ -1,14 +0,0 @@
|
||||
{{- if .Values.imageCredentials }}
|
||||
{{- range $name, $config := .Values.imageCredentials }}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ $name }}
|
||||
labels:
|
||||
{{- include "gohoarder.labels" $ | nindent 4 }}
|
||||
type: kubernetes.io/dockerconfigjson
|
||||
data:
|
||||
.dockerconfigjson: {{ printf "{\"auths\":{\"%s\":{\"username\":\"%s\",\"password\":\"%s\",\"email\":\"%s\",\"auth\":\"%s\"}}}" $config.registry $config.username $config.password $config.email (printf "%s:%s" $config.username $config.password | b64enc) | b64enc }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -1,34 +0,0 @@
|
||||
{{- if .Values.ingress.enabled -}}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ include "gohoarder.fullname" . }}
|
||||
labels:
|
||||
{{- include "gohoarder.labels" . | nindent 4 }}
|
||||
{{- with .Values.ingress.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if .Values.ingress.className }}
|
||||
ingressClassName: {{ .Values.ingress.className }}
|
||||
{{- end }}
|
||||
{{- if .Values.ingress.tls.enabled }}
|
||||
tls:
|
||||
- hosts:
|
||||
- {{ .Values.ingress.host | default (printf "%s.%s" "gohoarder" .Values.global.domain) | quote }}
|
||||
secretName: {{ .Values.ingress.tls.secretName }}
|
||||
{{- end }}
|
||||
rules:
|
||||
- host: {{ .Values.ingress.host | default (printf "%s.%s" "gohoarder" .Values.global.domain) | quote }}
|
||||
http:
|
||||
paths:
|
||||
# Route all traffic to frontend (which now includes reverse proxy to backend)
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: {{ include "gohoarder.fullname" . }}-frontend
|
||||
port:
|
||||
number: {{ .Values.frontend.service.port }}
|
||||
{{- end }}
|
||||
@@ -1,37 +0,0 @@
|
||||
{{- if and (eq .Values.storage.backend "filesystem") (not .Values.storage.filesystem.useHostPath) (not .Values.storage.filesystem.existingClaim) }}
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: {{ include "gohoarder.fullname" . }}-storage
|
||||
labels:
|
||||
{{- include "gohoarder.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: storage
|
||||
spec:
|
||||
accessModes:
|
||||
- {{ .Values.storage.filesystem.accessMode }}
|
||||
{{- if .Values.storage.filesystem.storageClass }}
|
||||
storageClassName: {{ .Values.storage.filesystem.storageClass | quote }}
|
||||
{{- end }}
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.storage.filesystem.size | quote }}
|
||||
{{- end }}
|
||||
---
|
||||
{{- if and (eq .Values.metadata.backend "sqlite") .Values.metadata.sqlite.persistence.enabled (not .Values.metadata.sqlite.persistence.existingClaim) }}
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: {{ include "gohoarder.fullname" . }}-metadata
|
||||
labels:
|
||||
{{- include "gohoarder.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: metadata
|
||||
spec:
|
||||
accessModes:
|
||||
- {{ .Values.metadata.sqlite.persistence.accessMode }}
|
||||
{{- if .Values.metadata.sqlite.persistence.storageClass }}
|
||||
storageClassName: {{ .Values.metadata.sqlite.persistence.storageClass | quote }}
|
||||
{{- end }}
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.metadata.sqlite.persistence.size | quote }}
|
||||
{{- end }}
|
||||
@@ -1,79 +0,0 @@
|
||||
{{- if and .Values.auth.enabled (not .Values.auth.existingSecret) }}
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ include "gohoarder.fullname" . }}-auth
|
||||
labels:
|
||||
{{- include "gohoarder.labels" . | nindent 4 }}
|
||||
type: Opaque
|
||||
data:
|
||||
{{- if .Values.auth.adminApiKey }}
|
||||
{{ .Values.auth.secretKey }}: {{ .Values.auth.adminApiKey | b64enc | quote }}
|
||||
{{- else }}
|
||||
{{ .Values.auth.secretKey }}: {{ include "gohoarder.adminApiKey" . | b64enc | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
---
|
||||
{{- if and (eq .Values.storage.backend "s3") (not .Values.storage.s3.existingSecret) .Values.storage.s3.accessKeyId }}
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ include "gohoarder.fullname" . }}-s3
|
||||
labels:
|
||||
{{- include "gohoarder.labels" . | nindent 4 }}
|
||||
type: Opaque
|
||||
data:
|
||||
access-key-id: {{ .Values.storage.s3.accessKeyId | b64enc | quote }}
|
||||
secret-access-key: {{ .Values.storage.s3.secretAccessKey | b64enc | quote }}
|
||||
{{- end }}
|
||||
---
|
||||
{{- if and (eq .Values.storage.backend "smb") (not .Values.storage.smb.existingSecret) .Values.storage.smb.username }}
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ include "gohoarder.fullname" . }}-smb
|
||||
labels:
|
||||
{{- include "gohoarder.labels" . | nindent 4 }}
|
||||
type: Opaque
|
||||
data:
|
||||
username: {{ .Values.storage.smb.username | b64enc | quote }}
|
||||
password: {{ .Values.storage.smb.password | b64enc | quote }}
|
||||
{{- end }}
|
||||
---
|
||||
{{- if and (eq .Values.metadata.backend "postgresql") (not .Values.metadata.postgresql.existingSecret) .Values.metadata.postgresql.username }}
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ include "gohoarder.fullname" . }}-postgresql
|
||||
labels:
|
||||
{{- include "gohoarder.labels" . | nindent 4 }}
|
||||
type: Opaque
|
||||
data:
|
||||
username: {{ .Values.metadata.postgresql.username | b64enc | quote }}
|
||||
password: {{ .Values.metadata.postgresql.password | b64enc | quote }}
|
||||
{{- end }}
|
||||
---
|
||||
{{- if and (or (eq .Values.metadata.backend "mysql") (eq .Values.metadata.backend "mariadb")) (not .Values.metadata.mysql.existingSecret) .Values.metadata.mysql.username }}
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ include "gohoarder.fullname" . }}-mysql
|
||||
labels:
|
||||
{{- include "gohoarder.labels" . | nindent 4 }}
|
||||
type: Opaque
|
||||
data:
|
||||
username: {{ .Values.metadata.mysql.username | b64enc | quote }}
|
||||
password: {{ .Values.metadata.mysql.password | b64enc | quote }}
|
||||
{{- end }}
|
||||
---
|
||||
{{- if and .Values.security.scanners.ghsa.enabled (not .Values.security.scanners.ghsa.existingSecret) .Values.security.scanners.ghsa.token }}
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ include "gohoarder.fullname" . }}-ghsa
|
||||
labels:
|
||||
{{- include "gohoarder.labels" . | nindent 4 }}
|
||||
type: Opaque
|
||||
data:
|
||||
token: {{ .Values.security.scanners.ghsa.token | b64enc | quote }}
|
||||
{{- end }}
|
||||
@@ -1,39 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "gohoarder.fullname" . }}-server
|
||||
labels:
|
||||
{{- include "gohoarder.server.labels" . | nindent 4 }}
|
||||
{{- with .Values.server.service.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
type: {{ .Values.server.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.server.service.port }}
|
||||
targetPort: http
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
{{- include "gohoarder.server.selectorLabels" . | nindent 4 }}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "gohoarder.fullname" . }}-frontend
|
||||
labels:
|
||||
{{- include "gohoarder.frontend.labels" . | nindent 4 }}
|
||||
{{- with .Values.frontend.service.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
type: {{ .Values.frontend.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.frontend.service.port }}
|
||||
targetPort: http
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
{{- include "gohoarder.frontend.selectorLabels" . | nindent 4 }}
|
||||
@@ -1,12 +0,0 @@
|
||||
{{- if .Values.serviceAccount.create -}}
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ include "gohoarder.serviceAccountName" . }}
|
||||
labels:
|
||||
{{- include "gohoarder.labels" . | nindent 4 }}
|
||||
{{- with .Values.serviceAccount.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -1,539 +0,0 @@
|
||||
# Default values for gohoarder
|
||||
# This is a YAML-formatted file.
|
||||
# Declare variables to be passed into your templates.
|
||||
|
||||
# Override the name of the chart
|
||||
nameOverride: ""
|
||||
# Override the full name of the chart
|
||||
fullnameOverride: ""
|
||||
|
||||
# Global configuration
|
||||
global:
|
||||
# Base domain for the deployment
|
||||
domain: "gohoarder.local"
|
||||
|
||||
# Image pull secrets for private registries
|
||||
# Reference existing secrets by name:
|
||||
# imagePullSecrets:
|
||||
# - name: ghcr-secret
|
||||
# - name: dockerhub-secret
|
||||
imagePullSecrets: []
|
||||
|
||||
# Auto-create image pull secrets from credentials (optional)
|
||||
# If you want the chart to create the secrets for you, use this instead:
|
||||
# imageCredentials:
|
||||
# ghcr-secret:
|
||||
# registry: ghcr.io
|
||||
# username: myusername
|
||||
# password: mytoken
|
||||
# email: myemail@example.com
|
||||
# dockerhub-secret:
|
||||
# registry: https://index.docker.io/v1/
|
||||
# username: myusername
|
||||
# password: mytoken
|
||||
# email: myemail@example.com
|
||||
# Then reference them in global.imagePullSecrets:
|
||||
# - name: ghcr-secret
|
||||
imageCredentials: {}
|
||||
|
||||
# Deployment replicas
|
||||
# NOTE: When running multiple server replicas (>1):
|
||||
# - Use S3 or SMB for storage.backend (not filesystem with local storage)
|
||||
# - Use PostgreSQL for metadata.backend (SQLite has limited concurrency)
|
||||
# - See "High Availability & Scaling" section in README
|
||||
replicaCount:
|
||||
server: 1
|
||||
frontend: 1
|
||||
scanner: 1
|
||||
|
||||
# Image configuration
|
||||
image:
|
||||
server:
|
||||
repository: ghcr.io/lukaszraczylo/gohoarder-server
|
||||
pullPolicy: IfNotPresent
|
||||
tag: "0.1.144"
|
||||
|
||||
frontend:
|
||||
repository: ghcr.io/lukaszraczylo/gohoarder-frontend
|
||||
pullPolicy: IfNotPresent
|
||||
tag: "0.1.144"
|
||||
|
||||
scanner:
|
||||
repository: ghcr.io/lukaszraczylo/gohoarder-scanner
|
||||
pullPolicy: IfNotPresent
|
||||
tag: "0.1.144"
|
||||
|
||||
# Service Account
|
||||
serviceAccount:
|
||||
create: true
|
||||
annotations: {}
|
||||
name: ""
|
||||
|
||||
# Pod annotations
|
||||
podAnnotations: {}
|
||||
|
||||
# Pod security context
|
||||
podSecurityContext:
|
||||
fsGroup: 1000
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1000
|
||||
|
||||
# Container security context
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
readOnlyRootFilesystem: true
|
||||
|
||||
# Server configuration
|
||||
server:
|
||||
host: "0.0.0.0"
|
||||
port: 8080
|
||||
readTimeout: "5m"
|
||||
writeTimeout: "5m"
|
||||
idleTimeout: "2m"
|
||||
|
||||
# Additional environment variables for server container
|
||||
# Use this to override config via environment variables
|
||||
# Format: GOHOARDER_<CONFIG_KEY> (dots replaced with underscores)
|
||||
# Examples:
|
||||
# GOHOARDER_STORAGE_BACKEND: s3
|
||||
# GOHOARDER_METADATA_BACKEND: postgresql
|
||||
# env:
|
||||
# - name: GOHOARDER_STORAGE_BACKEND
|
||||
# value: "s3"
|
||||
# - name: GOHOARDER_STORAGE_S3_BUCKET
|
||||
# value: "my-bucket"
|
||||
# - name: GOHOARDER_METADATA_POSTGRESQL_PASSWORD
|
||||
# valueFrom:
|
||||
# secretKeyRef:
|
||||
# name: postgres-secret
|
||||
# key: password
|
||||
env: []
|
||||
|
||||
# Service configuration
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 80
|
||||
targetPort: 8080
|
||||
annotations: {}
|
||||
|
||||
# Resource limits
|
||||
resources:
|
||||
limits:
|
||||
cpu: 2000m
|
||||
memory: 2Gi
|
||||
requests:
|
||||
cpu: 500m
|
||||
memory: 512Mi
|
||||
|
||||
# Liveness and readiness probes
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
port: http
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 3
|
||||
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /health/ready
|
||||
port: http
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 5
|
||||
timeoutSeconds: 3
|
||||
failureThreshold: 3
|
||||
|
||||
# Node selector
|
||||
nodeSelector: {}
|
||||
|
||||
# Tolerations
|
||||
tolerations: []
|
||||
|
||||
# Affinity
|
||||
affinity: {}
|
||||
|
||||
# Frontend configuration
|
||||
frontend:
|
||||
# Backend URL for API calls
|
||||
backendUrl: "" # Auto-configured if empty
|
||||
|
||||
# Additional environment variables for frontend container
|
||||
# env:
|
||||
# - name: API_BASE_URL
|
||||
# value: "https://api.example.com"
|
||||
env: []
|
||||
|
||||
# Service configuration
|
||||
service:
|
||||
type: ClusterIP
|
||||
port: 80
|
||||
targetPort: 80
|
||||
annotations: {}
|
||||
|
||||
# Resource limits
|
||||
resources:
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 512Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
|
||||
# Liveness and readiness probes
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: http
|
||||
initialDelaySeconds: 30
|
||||
periodSeconds: 10
|
||||
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: http
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 5
|
||||
|
||||
nodeSelector: {}
|
||||
tolerations: []
|
||||
affinity: {}
|
||||
|
||||
# Scanner configuration
|
||||
scanner:
|
||||
# Additional environment variables for scanner container
|
||||
# env:
|
||||
# - name: GOHOARDER_SECURITY_SCANNERS_TRIVY_ENABLED
|
||||
# value: "true"
|
||||
env: []
|
||||
|
||||
# Resource limits
|
||||
resources:
|
||||
limits:
|
||||
cpu: 2000m
|
||||
memory: 4Gi
|
||||
requests:
|
||||
cpu: 500m
|
||||
memory: 1Gi
|
||||
|
||||
nodeSelector: {}
|
||||
tolerations: []
|
||||
affinity: {}
|
||||
|
||||
# Storage configuration
|
||||
storage:
|
||||
# Storage backend: filesystem, s3, smb
|
||||
# For multiple server replicas:
|
||||
# - S3 or SMB (recommended)
|
||||
# - Filesystem with ReadWriteMany (RWX) storage class (Longhorn, NFS, CephFS)
|
||||
# - NOT filesystem with ReadWriteOnce (RWO) or local storage
|
||||
backend: "filesystem"
|
||||
|
||||
# Filesystem storage
|
||||
filesystem:
|
||||
# Storage class for PVC
|
||||
# For multiple replicas: use RWX-capable storage class (longhorn, nfs-client, cephfs, etc.)
|
||||
storageClass: ""
|
||||
# Storage size
|
||||
size: "100Gi"
|
||||
# Access mode:
|
||||
# ReadWriteOnce (RWO) - Single replica only
|
||||
# ReadWriteMany (RWX) - Multiple replicas (requires RWX storage class)
|
||||
accessMode: "ReadWriteOnce"
|
||||
# Use hostPath instead of PVC (for single-node testing only)
|
||||
useHostPath: false
|
||||
hostPath: "/var/lib/gohoarder"
|
||||
# Existing PVC name (if you want to use existing PVC)
|
||||
existingClaim: ""
|
||||
|
||||
# S3 storage
|
||||
s3:
|
||||
endpoint: "s3.amazonaws.com"
|
||||
region: "us-east-1"
|
||||
bucket: "gohoarder-cache"
|
||||
accessKeyId: ""
|
||||
secretAccessKey: ""
|
||||
# Use existing secret for S3 credentials
|
||||
existingSecret: ""
|
||||
useSSL: true
|
||||
|
||||
# SMB storage
|
||||
smb:
|
||||
host: ""
|
||||
share: ""
|
||||
username: ""
|
||||
password: ""
|
||||
domain: ""
|
||||
# Use existing secret for SMB credentials
|
||||
existingSecret: ""
|
||||
|
||||
# Metadata storage configuration
|
||||
metadata:
|
||||
# Backend: sqlite, postgresql, mysql
|
||||
#
|
||||
# IMPORTANT: SQLite CANNOT be used with SMB/CIFS/NFS network storage!
|
||||
# SQLite requires POSIX file locking which causes "database is locked" errors on network filesystems.
|
||||
#
|
||||
# Choose your configuration:
|
||||
# 1. SQLite with local storage (development/single-node only)
|
||||
# - Set backend: sqlite
|
||||
# - Set sqlite.persistence.storageClass to a LOCAL storage class (e.g., "local-path")
|
||||
# - OR set sqlite.persistence.enabled: false to use emptyDir (data lost on pod restart)
|
||||
#
|
||||
# 2. PostgreSQL with any storage (RECOMMENDED for production)
|
||||
# - Set backend: postgresql
|
||||
# - Configure postgresql settings below
|
||||
# - Works with any storage including SMB/NFS
|
||||
# - Supports multiple replicas and high availability
|
||||
#
|
||||
# 3. MySQL/MariaDB with any storage (alternative to PostgreSQL)
|
||||
# - Set backend: mysql
|
||||
# - Configure mysql settings below
|
||||
# - Works with any storage including SMB/NFS
|
||||
#
|
||||
backend: "sqlite"
|
||||
|
||||
# SQLite configuration
|
||||
# WARNING: Do NOT use SMB/CIFS/NFS storage classes with SQLite!
|
||||
sqlite:
|
||||
# Use PVC for SQLite database
|
||||
# IMPORTANT: storageClass must be LOCAL storage, NOT network storage (smb/nfs)
|
||||
persistence:
|
||||
enabled: false # Changed to false by default - use emptyDir unless you have local storage
|
||||
storageClass: "" # Must be local-path or similar LOCAL storage class if enabled
|
||||
size: "10Gi"
|
||||
accessMode: "ReadWriteOnce"
|
||||
existingClaim: ""
|
||||
# WAL mode provides better concurrency but doesn't work on network filesystems (SMB, NFS)
|
||||
# Set to false when using network storage for the metadata volume
|
||||
walMode: false
|
||||
|
||||
# PostgreSQL configuration
|
||||
# Works with any storage including SMB/NFS
|
||||
# Recommended for production deployments
|
||||
postgresql:
|
||||
# Use bundled PostgreSQL (sets up postgresql subchart)
|
||||
enabled: false
|
||||
host: "localhost"
|
||||
port: 5432
|
||||
database: "gohoarder"
|
||||
username: "gohoarder"
|
||||
password: ""
|
||||
sslMode: "disable" # disable, require, verify-ca, verify-full
|
||||
# Use existing secret for PostgreSQL credentials
|
||||
existingSecret: ""
|
||||
|
||||
# MySQL/MariaDB configuration
|
||||
# Works with any storage including SMB/NFS
|
||||
# Alternative to PostgreSQL for production deployments
|
||||
mysql:
|
||||
host: "localhost"
|
||||
port: 3306
|
||||
database: "gohoarder"
|
||||
username: "gohoarder"
|
||||
password: ""
|
||||
charset: "utf8mb4"
|
||||
parseTime: true
|
||||
# Use existing secret for MySQL credentials
|
||||
existingSecret: ""
|
||||
|
||||
# GORM connection pool settings (applies to all database backends)
|
||||
# These settings control database connection pooling and performance
|
||||
maxOpenConns: 25 # Maximum number of open connections to the database
|
||||
maxIdleConns: 5 # Maximum number of idle connections in the pool
|
||||
connMaxLifetime: 3600 # Maximum lifetime of a connection in seconds (1 hour)
|
||||
logLevel: "warn" # GORM log level: silent, error, warn, info
|
||||
|
||||
# Database migration configuration
|
||||
migration:
|
||||
# Enable automatic database migrations via init containers
|
||||
# When enabled, each pod will run migrations before starting the main container
|
||||
# Gormigrate handles concurrency automatically - safe for multiple pods
|
||||
enabled: true
|
||||
|
||||
# Migration image configuration
|
||||
image:
|
||||
repository: ghcr.io/lukaszraczylo/gohoarder-migrate
|
||||
pullPolicy: IfNotPresent
|
||||
tag: "0.1.144"
|
||||
|
||||
# Migration settings
|
||||
logLevel: "info" # debug, info, warn, error
|
||||
timeout: "5m" # Maximum time for migrations to complete
|
||||
|
||||
# Resource limits for migration init container
|
||||
resources:
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 256Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
|
||||
# Cache configuration
|
||||
cache:
|
||||
defaultTTL: "168h" # 7 days
|
||||
cleanupInterval: "1h"
|
||||
maxSizeBytes: 536870912000 # 500GB
|
||||
perProjectQuota: 53687091200 # 50GB
|
||||
ttlOverrides:
|
||||
npm: "168h"
|
||||
pip: "168h"
|
||||
go: "168h"
|
||||
|
||||
# Security scanning configuration
|
||||
security:
|
||||
enabled: false
|
||||
blockOnSeverity: "high" # none, low, medium, high, critical
|
||||
scanOnDownload: true
|
||||
rescanInterval: "24h"
|
||||
updateDbOnStartup: false
|
||||
|
||||
blockThresholds:
|
||||
critical: 0
|
||||
high: -1
|
||||
medium: -1
|
||||
low: -1
|
||||
|
||||
scanners:
|
||||
trivy:
|
||||
enabled: false
|
||||
timeout: "5m"
|
||||
cacheDb: "/var/lib/trivy"
|
||||
|
||||
osv:
|
||||
enabled: false
|
||||
apiUrl: "https://api.osv.dev"
|
||||
timeout: "30s"
|
||||
|
||||
grype:
|
||||
enabled: false
|
||||
timeout: "5m"
|
||||
|
||||
govulncheck:
|
||||
enabled: false
|
||||
timeout: "5m"
|
||||
|
||||
npmAudit:
|
||||
enabled: false
|
||||
timeout: "2m"
|
||||
|
||||
pipAudit:
|
||||
enabled: false
|
||||
timeout: "2m"
|
||||
|
||||
ghsa:
|
||||
enabled: false
|
||||
timeout: "30s"
|
||||
# GitHub token for higher rate limits
|
||||
token: ""
|
||||
existingSecret: ""
|
||||
|
||||
static:
|
||||
enabled: true
|
||||
maxPackageSize: 2147483648 # 2GB
|
||||
checkChecksums: true
|
||||
blockSuspicious: false
|
||||
|
||||
# Authentication configuration
|
||||
auth:
|
||||
enabled: true
|
||||
keyExpiration: "0" # Never expire
|
||||
bcryptCost: 10
|
||||
auditLog: true
|
||||
|
||||
# Admin API key - will be auto-generated if not provided
|
||||
adminApiKey: ""
|
||||
# Use existing secret for admin API key
|
||||
existingSecret: ""
|
||||
# Secret key name for admin API key
|
||||
secretKey: "admin-api-key"
|
||||
|
||||
# Network configuration
|
||||
network:
|
||||
connectTimeout: "10s"
|
||||
readTimeout: "5m"
|
||||
writeTimeout: "5m"
|
||||
maxIdleConns: 100
|
||||
maxConnsPerHost: 10
|
||||
|
||||
rateLimit:
|
||||
perApiKey: 1000
|
||||
perIp: 100
|
||||
burstSize: 50
|
||||
|
||||
circuitBreaker:
|
||||
threshold: 5
|
||||
timeout: "30s"
|
||||
resetInterval: "60s"
|
||||
|
||||
retry:
|
||||
maxAttempts: 3
|
||||
initialBackoff: "1s"
|
||||
maxBackoff: "30s"
|
||||
|
||||
# Logging configuration
|
||||
logging:
|
||||
level: "info" # debug, info, warn, error
|
||||
format: "json" # json, pretty
|
||||
|
||||
# Package handlers configuration
|
||||
handlers:
|
||||
go:
|
||||
enabled: true
|
||||
upstreamProxy: "https://proxy.golang.org"
|
||||
checksumDb: "https://sum.golang.org"
|
||||
verifyChecksums: true
|
||||
|
||||
npm:
|
||||
enabled: true
|
||||
upstreamRegistry: "https://registry.npmjs.org"
|
||||
|
||||
pypi:
|
||||
enabled: true
|
||||
upstreamUrl: "https://pypi.org"
|
||||
simpleApiUrl: "https://pypi.org/simple"
|
||||
|
||||
# Ingress configuration
|
||||
ingress:
|
||||
enabled: false
|
||||
className: "nginx"
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: "letsencrypt-prod"
|
||||
nginx.ingress.kubernetes.io/proxy-body-size: "2048m"
|
||||
nginx.ingress.kubernetes.io/proxy-read-timeout: "300"
|
||||
nginx.ingress.kubernetes.io/proxy-send-timeout: "300"
|
||||
|
||||
# Single ingress routes all traffic to frontend
|
||||
# Frontend now includes reverse proxy to backend (merged gateway functionality)
|
||||
host: "gohoarder.local"
|
||||
tls:
|
||||
enabled: false
|
||||
secretName: "gohoarder-tls"
|
||||
|
||||
# Autoscaling configuration
|
||||
autoscaling:
|
||||
enabled: false
|
||||
minReplicas: 1
|
||||
maxReplicas: 10
|
||||
targetCPUUtilizationPercentage: 80
|
||||
targetMemoryUtilizationPercentage: 80
|
||||
|
||||
# Pod Disruption Budget
|
||||
podDisruptionBudget:
|
||||
enabled: false
|
||||
minAvailable: 1
|
||||
|
||||
# Network Policy
|
||||
networkPolicy:
|
||||
enabled: false
|
||||
# Allow external access to server
|
||||
ingress:
|
||||
- from:
|
||||
- namespaceSelector: {}
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 8080
|
||||
@@ -1,23 +0,0 @@
|
||||
# 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/
|
||||
@@ -1,37 +0,0 @@
|
||||
apiVersion: v2
|
||||
name: jobs-manager
|
||||
description: Kubernetes jobs manager operator for orchestrating workflow-based job execution with dependency management
|
||||
type: application
|
||||
version: 0.1.15
|
||||
appVersion: "0.1.15"
|
||||
keywords:
|
||||
- operator
|
||||
- jobs
|
||||
- tasks
|
||||
- workflow
|
||||
- kubernetes
|
||||
- batch
|
||||
home: https://raczylo.com
|
||||
sources:
|
||||
- https://github.com/lukaszraczylo/jobs-manager-operator
|
||||
maintainers:
|
||||
- name: lukaszraczylo
|
||||
email: job-manager-operator@raczylo.com
|
||||
annotations:
|
||||
artifacthub.io/changes: |
|
||||
- kind: added
|
||||
description: Prometheus metrics support (jobs created/succeeded/failed, active jobs, reconciliation duration)
|
||||
- kind: added
|
||||
description: Configurable leader election ID via --leader-election-id flag
|
||||
- kind: added
|
||||
description: Configurable development logging mode via --dev-mode flag
|
||||
- kind: added
|
||||
description: LOG_LEVEL environment variable support
|
||||
- kind: added
|
||||
description: Finalizers for proper resource cleanup
|
||||
- kind: added
|
||||
description: Resource limits support for job containers
|
||||
- kind: added
|
||||
description: Reconciliation backoff/requeue logic
|
||||
- kind: changed
|
||||
description: O(1) dependency lookup performance optimization
|
||||
@@ -1,62 +0,0 @@
|
||||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "chart.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
If release name contains chart name it will be used as a full name.
|
||||
*/}}
|
||||
{{- define "chart.fullname" -}}
|
||||
{{- if .Values.fullnameOverride }}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride }}
|
||||
{{- if contains $name .Release.Name }}
|
||||
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create chart name and version as used by the chart label.
|
||||
*/}}
|
||||
{{- define "chart.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Common labels
|
||||
*/}}
|
||||
{{- define "chart.labels" -}}
|
||||
helm.sh/chart: {{ include "chart.chart" . }}
|
||||
{{ include "chart.selectorLabels" . }}
|
||||
{{- if .Chart.AppVersion }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||
{{- end }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Selector labels
|
||||
*/}}
|
||||
{{- define "chart.selectorLabels" -}}
|
||||
app.kubernetes.io/name: {{ include "chart.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create the name of the service account to use
|
||||
*/}}
|
||||
{{- define "chart.serviceAccountName" -}}
|
||||
{{- if .Values.serviceAccount.create }}
|
||||
{{- default (include "chart.fullname" .) .Values.serviceAccount.name }}
|
||||
{{- else }}
|
||||
{{- default "default" .Values.serviceAccount.name }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -1,82 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "chart.fullname" . }}-controller-manager
|
||||
labels:
|
||||
app.kubernetes.io/component: manager
|
||||
app.kubernetes.io/created-by: jobs-manager-operator
|
||||
app.kubernetes.io/part-of: jobs-manager-operator
|
||||
control-plane: controller-manager
|
||||
{{- include "chart.labels" . | nindent 4 }}
|
||||
spec:
|
||||
replicas: {{ .Values.controllerManager.replicas }}
|
||||
selector:
|
||||
matchLabels:
|
||||
control-plane: controller-manager
|
||||
{{- include "chart.selectorLabels" . | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
{{- include "chart.selectorLabels" . | nindent 8 }}
|
||||
annotations:
|
||||
kubectl.kubernetes.io/default-container: manager
|
||||
spec:
|
||||
affinity:
|
||||
nodeAffinity:
|
||||
requiredDuringSchedulingIgnoredDuringExecution:
|
||||
nodeSelectorTerms:
|
||||
- matchExpressions:
|
||||
- key: kubernetes.io/arch
|
||||
operator: In
|
||||
values:
|
||||
- amd64
|
||||
- arm64
|
||||
- ppc64le
|
||||
- s390x
|
||||
- key: kubernetes.io/os
|
||||
operator: In
|
||||
values:
|
||||
- linux
|
||||
containers:
|
||||
- args:
|
||||
{{- toYaml .Values.controllerManager.manager.args | nindent 8 }}
|
||||
{{- if .Values.controllerManager.manager.leaderElectionId }}
|
||||
- --leader-election-id={{ .Values.controllerManager.manager.leaderElectionId }}
|
||||
{{- end }}
|
||||
{{- if .Values.controllerManager.manager.devMode }}
|
||||
- --dev-mode
|
||||
{{- end }}
|
||||
command:
|
||||
- /manager
|
||||
env:
|
||||
- name: KUBERNETES_CLUSTER_DOMAIN
|
||||
value: {{ quote .Values.kubernetesClusterDomain }}
|
||||
{{- if .Values.controllerManager.manager.env.LOG_LEVEL }}
|
||||
- name: LOG_LEVEL
|
||||
value: {{ quote .Values.controllerManager.manager.env.LOG_LEVEL }}
|
||||
{{- end }}
|
||||
image: {{ .Values.controllerManager.manager.image.repository }}:{{ .Values.controllerManager.manager.image.tag | default .Chart.AppVersion }}
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 8081
|
||||
initialDelaySeconds: 15
|
||||
periodSeconds: 20
|
||||
name: manager
|
||||
ports:
|
||||
- containerPort: 8443
|
||||
name: https
|
||||
protocol: TCP
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /readyz
|
||||
port: 8081
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
resources: {{- toYaml .Values.controllerManager.manager.resources | nindent 10 }}
|
||||
securityContext: {{- toYaml .Values.controllerManager.manager.containerSecurityContext | nindent 10 }}
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
serviceAccountName: {{ include "chart.fullname" . }}-controller-manager
|
||||
terminationGracePeriodSeconds: 10
|
||||
@@ -1,59 +0,0 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: {{ include "chart.fullname" . }}-leader-election-role
|
||||
labels:
|
||||
app.kubernetes.io/component: rbac
|
||||
app.kubernetes.io/created-by: jobs-manager-operator
|
||||
app.kubernetes.io/part-of: jobs-manager-operator
|
||||
{{- include "chart.labels" . | nindent 4 }}
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- configmaps
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- patch
|
||||
- delete
|
||||
- apiGroups:
|
||||
- coordination.k8s.io
|
||||
resources:
|
||||
- leases
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- patch
|
||||
- delete
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- events
|
||||
verbs:
|
||||
- create
|
||||
- patch
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: {{ include "chart.fullname" . }}-leader-election-rolebinding
|
||||
labels:
|
||||
app.kubernetes.io/component: rbac
|
||||
app.kubernetes.io/created-by: jobs-manager-operator
|
||||
app.kubernetes.io/part-of: jobs-manager-operator
|
||||
{{- include "chart.labels" . | nindent 4 }}
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: '{{ include "chart.fullname" . }}-leader-election-role'
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: '{{ include "chart.fullname" . }}-controller-manager'
|
||||
namespace: '{{ .Release.Namespace }}'
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,75 +0,0 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: {{ include "chart.fullname" . }}-manager-role
|
||||
labels:
|
||||
{{- include "chart.labels" . | nindent 4 }}
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- events
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- batch
|
||||
resources:
|
||||
- jobs
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- jobsmanager.raczylo.com
|
||||
resources:
|
||||
- managedjobs
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- jobsmanager.raczylo.com
|
||||
resources:
|
||||
- managedjobs/finalizers
|
||||
verbs:
|
||||
- update
|
||||
- apiGroups:
|
||||
- jobsmanager.raczylo.com
|
||||
resources:
|
||||
- managedjobs/status
|
||||
verbs:
|
||||
- get
|
||||
- patch
|
||||
- update
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: {{ include "chart.fullname" . }}-manager-rolebinding
|
||||
labels:
|
||||
app.kubernetes.io/component: rbac
|
||||
app.kubernetes.io/created-by: jobs-manager-operator
|
||||
app.kubernetes.io/part-of: jobs-manager-operator
|
||||
{{- include "chart.labels" . | nindent 4 }}
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: '{{ include "chart.fullname" . }}-manager-role'
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: '{{ include "chart.fullname" . }}-controller-manager'
|
||||
namespace: '{{ .Release.Namespace }}'
|
||||
@@ -1,14 +0,0 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: {{ include "chart.fullname" . }}-metrics-reader
|
||||
labels:
|
||||
app.kubernetes.io/component: manager
|
||||
app.kubernetes.io/created-by: jobs-manager-operator
|
||||
app.kubernetes.io/part-of: jobs-manager-operator
|
||||
{{- include "chart.labels" . | nindent 4 }}
|
||||
rules:
|
||||
- nonResourceURLs:
|
||||
- /metrics
|
||||
verbs:
|
||||
- get
|
||||
@@ -1,17 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "chart.fullname" . }}-controller-manager-metrics-service
|
||||
labels:
|
||||
app.kubernetes.io/component: manager
|
||||
app.kubernetes.io/created-by: jobs-manager-operator
|
||||
app.kubernetes.io/part-of: jobs-manager-operator
|
||||
control-plane: controller-manager
|
||||
{{- include "chart.labels" . | nindent 4 }}
|
||||
spec:
|
||||
type: {{ .Values.metricsService.type }}
|
||||
selector:
|
||||
control-plane: controller-manager
|
||||
{{- include "chart.selectorLabels" . | nindent 4 }}
|
||||
ports:
|
||||
{{- .Values.metricsService.ports | toYaml | nindent 2 -}}
|
||||
@@ -1,40 +0,0 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: {{ include "chart.fullname" . }}-proxy-role
|
||||
labels:
|
||||
app.kubernetes.io/component: manager
|
||||
app.kubernetes.io/created-by: jobs-manager-operator
|
||||
app.kubernetes.io/part-of: jobs-manager-operator
|
||||
{{- include "chart.labels" . | nindent 4 }}
|
||||
rules:
|
||||
- apiGroups:
|
||||
- authentication.k8s.io
|
||||
resources:
|
||||
- tokenreviews
|
||||
verbs:
|
||||
- create
|
||||
- apiGroups:
|
||||
- authorization.k8s.io
|
||||
resources:
|
||||
- subjectaccessreviews
|
||||
verbs:
|
||||
- create
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: {{ include "chart.fullname" . }}-proxy-rolebinding
|
||||
labels:
|
||||
app.kubernetes.io/component: manager
|
||||
app.kubernetes.io/created-by: jobs-manager-operator
|
||||
app.kubernetes.io/part-of: jobs-manager-operator
|
||||
{{- include "chart.labels" . | nindent 4 }}
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: '{{ include "chart.fullname" . }}-proxy-role'
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: '{{ include "chart.fullname" . }}-controller-manager'
|
||||
namespace: '{{ .Release.Namespace }}'
|
||||
@@ -1,11 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ include "chart.fullname" . }}-controller-manager
|
||||
labels:
|
||||
app.kubernetes.io/component: rbac
|
||||
app.kubernetes.io/created-by: jobs-manager-operator
|
||||
app.kubernetes.io/part-of: jobs-manager-operator
|
||||
{{- include "chart.labels" . | nindent 4 }}
|
||||
annotations:
|
||||
{{- toYaml .Values.controllerManager.serviceAccount.annotations | nindent 4 }}
|
||||
@@ -1,31 +0,0 @@
|
||||
{{- if .Values.serviceMonitor.enabled }}
|
||||
apiVersion: monitoring.coreos.com/v1
|
||||
kind: ServiceMonitor
|
||||
metadata:
|
||||
name: {{ include "chart.fullname" . }}-metrics
|
||||
{{- if .Values.serviceMonitor.namespace }}
|
||||
namespace: {{ .Values.serviceMonitor.namespace }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "chart.labels" . | nindent 4 }}
|
||||
{{- with .Values.serviceMonitor.labels }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
endpoints:
|
||||
- path: /metrics
|
||||
port: https
|
||||
scheme: https
|
||||
interval: {{ .Values.serviceMonitor.interval }}
|
||||
scrapeTimeout: {{ .Values.serviceMonitor.scrapeTimeout }}
|
||||
tlsConfig:
|
||||
insecureSkipVerify: true
|
||||
bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
|
||||
namespaceSelector:
|
||||
matchNames:
|
||||
- {{ .Release.Namespace }}
|
||||
selector:
|
||||
matchLabels:
|
||||
control-plane: controller-manager
|
||||
{{- include "chart.selectorLabels" . | nindent 6 }}
|
||||
{{- end }}
|
||||
@@ -1,57 +0,0 @@
|
||||
controllerManager:
|
||||
manager:
|
||||
# Command line arguments for the manager
|
||||
args:
|
||||
- --health-probe-bind-address=:8081
|
||||
- --metrics-bind-address=:8443
|
||||
- --metrics-secure
|
||||
- --leader-elect
|
||||
# Leader election ID - customize for multi-tenant clusters
|
||||
leaderElectionId: "jobsmanager.raczylo.com"
|
||||
# Enable development mode with verbose logging (console format)
|
||||
devMode: false
|
||||
# Environment variables for the manager container
|
||||
env:
|
||||
# Set to "debug" to enable verbose logging
|
||||
LOG_LEVEL: ""
|
||||
containerSecurityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
image:
|
||||
repository: ghcr.io/lukaszraczylo/jobs-manager-operator
|
||||
tag: "0.1.15"
|
||||
resources:
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 128Mi
|
||||
requests:
|
||||
cpu: 10m
|
||||
memory: 64Mi
|
||||
replicas: 1
|
||||
serviceAccount:
|
||||
annotations: {}
|
||||
|
||||
kubernetesClusterDomain: cluster.local
|
||||
|
||||
# Metrics service configuration
|
||||
metricsService:
|
||||
ports:
|
||||
- name: https
|
||||
port: 8443
|
||||
protocol: TCP
|
||||
targetPort: https
|
||||
type: ClusterIP
|
||||
|
||||
# ServiceMonitor for Prometheus Operator integration
|
||||
serviceMonitor:
|
||||
enabled: false
|
||||
# Namespace where ServiceMonitor will be created (defaults to release namespace)
|
||||
namespace: ""
|
||||
# Additional labels for ServiceMonitor
|
||||
labels: {}
|
||||
# Scrape interval
|
||||
interval: 30s
|
||||
# Scrape timeout
|
||||
scrapeTimeout: 10s
|
||||
@@ -1,21 +0,0 @@
|
||||
apiVersion: v2
|
||||
name: kube-images-sync
|
||||
description: |
|
||||
A Helm chart for Kubernetes Images Sync Operator.
|
||||
Kubernetes Images Sync Operator is responsible for backing up and restoring images from a Kubernetes cluster.
|
||||
Its ultimate goal is to provide synchronization of images between multiple environments, quite often air-gapped.
|
||||
It compiles the list of images currently present in the cluster and uploads them to the specified storage.
|
||||
Whenever a new CRD is created - it will try to figure out which images were already uploaded and which are new and
|
||||
upload only the new ones to avoid repetition.
|
||||
|
||||
type: application
|
||||
|
||||
version: 0.5.57
|
||||
|
||||
appVersion: "0.5.57"
|
||||
|
||||
home: https://github.com/lukaszraczylo/kubernetes-images-sync-operator
|
||||
|
||||
maintainers:
|
||||
- name: lukaszraczylo
|
||||
email: github-enquiries@raczylo.com
|
||||
@@ -1,58 +0,0 @@
|
||||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "chart.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
If release name contains chart name it will be used as a full name.
|
||||
*/}}
|
||||
{{- define "chart.fullname" -}}
|
||||
{{- if .Values.fullnameOverride }}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride }}
|
||||
{{- if contains $name .Release.Name }}
|
||||
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create chart name and version as used by the chart label.
|
||||
*/}}
|
||||
{{- define "chart.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Common labels
|
||||
*/}}
|
||||
{{- define "chart.labels" -}}
|
||||
helm.sh/chart: {{ include "chart.chart" . }}
|
||||
{{ include "chart.selectorLabels" . }}
|
||||
{{- if .Chart.AppVersion }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||
{{- end }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Selector labels
|
||||
*/}}
|
||||
{{- define "chart.selectorLabels" -}}
|
||||
app.kubernetes.io/name: {{ include "chart.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Get the worker image
|
||||
*/}}
|
||||
{{- define "chart.workerImage" -}}
|
||||
{{- printf "%s:%s" .Values.images.worker.repository .Values.images.worker.tag }}
|
||||
{{- end }}
|
||||
@@ -1,126 +0,0 @@
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: clusterimages.raczylo.com
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.17.1
|
||||
labels:
|
||||
{{- include "chart.labels" . | nindent 4 }}
|
||||
spec:
|
||||
group: raczylo.com
|
||||
names:
|
||||
kind: ClusterImage
|
||||
listKind: ClusterImageList
|
||||
plural: clusterimages
|
||||
singular: clusterimage
|
||||
scope: Namespaced
|
||||
versions:
|
||||
- additionalPrinterColumns:
|
||||
- jsonPath: .spec.exportName
|
||||
name: Ref
|
||||
type: string
|
||||
- jsonPath: .spec.image
|
||||
name: Image
|
||||
type: string
|
||||
- jsonPath: .spec.tag
|
||||
name: Tag
|
||||
type: string
|
||||
- jsonPath: .spec.sha
|
||||
name: SHA
|
||||
type: string
|
||||
- jsonPath: .spec.storage
|
||||
name: Storage
|
||||
type: string
|
||||
- jsonPath: .spec.exportPath
|
||||
name: Path
|
||||
type: string
|
||||
- jsonPath: .status.progress
|
||||
name: Progress
|
||||
type: string
|
||||
- jsonPath: .status.retryCount
|
||||
name: Retries
|
||||
type: integer
|
||||
- jsonPath: .metadata.creationTimestamp
|
||||
name: Age
|
||||
type: date
|
||||
name: v1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: ClusterImage is the Schema for the clusterimages API
|
||||
properties:
|
||||
apiVersion:
|
||||
description: |-
|
||||
APIVersion defines the versioned schema of this representation of an object.
|
||||
Servers should convert recognized schemas to the latest internal value, and
|
||||
may reject unrecognized values.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||
type: string
|
||||
kind:
|
||||
description: |-
|
||||
Kind is a string value representing the REST resource this object represents.
|
||||
Servers may infer this from the endpoint the client submits requests to.
|
||||
Cannot be updated.
|
||||
In CamelCase.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: ClusterImageSpec defines the desired state of ClusterImage
|
||||
properties:
|
||||
exportName:
|
||||
type: string
|
||||
exportPath:
|
||||
type: string
|
||||
fullName:
|
||||
type: string
|
||||
image:
|
||||
type: string
|
||||
imageNamespace:
|
||||
type: string
|
||||
imagePullSecrets:
|
||||
items:
|
||||
description: |-
|
||||
LocalObjectReference contains enough information to let you locate the
|
||||
referenced object inside the same namespace.
|
||||
properties:
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
type: string
|
||||
type: object
|
||||
x-kubernetes-map-type: atomic
|
||||
type: array
|
||||
jobAnnotations:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
sha:
|
||||
type: string
|
||||
storage:
|
||||
type: string
|
||||
tag:
|
||||
type: string
|
||||
required:
|
||||
- exportName
|
||||
type: object
|
||||
status:
|
||||
description: ClusterImageStatus defines the observed state of ClusterImage
|
||||
properties:
|
||||
progress:
|
||||
type: string
|
||||
retryCount:
|
||||
default: 0
|
||||
description: default value is 0
|
||||
type: integer
|
||||
type: object
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
subresources:
|
||||
status: {}
|
||||
@@ -1,186 +0,0 @@
|
||||
apiVersion: apiextensions.k8s.io/v1
|
||||
kind: CustomResourceDefinition
|
||||
metadata:
|
||||
name: clusterimageexports.raczylo.com
|
||||
annotations:
|
||||
controller-gen.kubebuilder.io/version: v0.17.1
|
||||
labels:
|
||||
{{- include "chart.labels" . | nindent 4 }}
|
||||
spec:
|
||||
group: raczylo.com
|
||||
names:
|
||||
kind: ClusterImageExport
|
||||
listKind: ClusterImageExportList
|
||||
plural: clusterimageexports
|
||||
singular: clusterimageexport
|
||||
scope: Namespaced
|
||||
versions:
|
||||
- additionalPrinterColumns:
|
||||
- jsonPath: .spec.basePath
|
||||
name: BasePath
|
||||
type: string
|
||||
- jsonPath: .spec.storage.target
|
||||
name: Storage
|
||||
type: string
|
||||
- jsonPath: .status.progress
|
||||
name: Progress
|
||||
type: string
|
||||
- jsonPath: .status.completedImages
|
||||
name: Images
|
||||
type: string
|
||||
- jsonPath: .status.totalImages
|
||||
name: Total
|
||||
type: string
|
||||
- jsonPath: .metadata.creationTimestamp
|
||||
name: Age
|
||||
type: date
|
||||
name: v1
|
||||
schema:
|
||||
openAPIV3Schema:
|
||||
description: ClusterImageExport is the Schema for the clusterimageexports
|
||||
API
|
||||
properties:
|
||||
apiVersion:
|
||||
description: |-
|
||||
APIVersion defines the versioned schema of this representation of an object.
|
||||
Servers should convert recognized schemas to the latest internal value, and
|
||||
may reject unrecognized values.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
|
||||
type: string
|
||||
kind:
|
||||
description: |-
|
||||
Kind is a string value representing the REST resource this object represents.
|
||||
Servers may infer this from the endpoint the client submits requests to.
|
||||
Cannot be updated.
|
||||
In CamelCase.
|
||||
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
|
||||
type: string
|
||||
metadata:
|
||||
type: object
|
||||
spec:
|
||||
description: ClusterImageExportSpec defines the desired state of ClusterImageExport
|
||||
properties:
|
||||
additionalImages:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
basePath:
|
||||
description: Base path for the export - both file and S3
|
||||
maxLength: 255
|
||||
minLength: 1
|
||||
type: string
|
||||
createdAt:
|
||||
format: date-time
|
||||
type: string
|
||||
excludedNamespaces:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
excludes:
|
||||
description: Exclude images which contain these strings
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
imagePullSecrets:
|
||||
items:
|
||||
description: |-
|
||||
LocalObjectReference contains enough information to let you locate the
|
||||
referenced object inside the same namespace.
|
||||
properties:
|
||||
name:
|
||||
default: ""
|
||||
description: |-
|
||||
Name of the referent.
|
||||
This field is effectively required, but due to backwards compatibility is
|
||||
allowed to be empty. Instances of this type with an empty value here are
|
||||
almost certainly wrong.
|
||||
More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names
|
||||
type: string
|
||||
type: object
|
||||
x-kubernetes-map-type: atomic
|
||||
type: array
|
||||
includes:
|
||||
description: Include only images which contain these strings
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
jobAnnotations:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
maxConcurrentJobs:
|
||||
default: 5
|
||||
maximum: 100
|
||||
minimum: 1
|
||||
type: integer
|
||||
name:
|
||||
type: string
|
||||
namespaces:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
storage:
|
||||
description: ClusterImageStorageSpec defines the desired state of
|
||||
ClusterImageStorage
|
||||
properties:
|
||||
s3:
|
||||
properties:
|
||||
accessKey:
|
||||
description: S3 bucket credentials
|
||||
type: string
|
||||
bucket:
|
||||
description: Bucket name
|
||||
type: string
|
||||
endpoint:
|
||||
description: |-
|
||||
Defines the endpoint for the S3 storage
|
||||
If none specified - default AWS endpoint will be used
|
||||
type: string
|
||||
region:
|
||||
type: string
|
||||
roleARN:
|
||||
description: RoleARN is the ARN of the role to be used for
|
||||
the deployment
|
||||
type: string
|
||||
secretKey:
|
||||
type: string
|
||||
secretName:
|
||||
description: Defines the secret name for credentials
|
||||
type: string
|
||||
useRole:
|
||||
type: boolean
|
||||
required:
|
||||
- bucket
|
||||
- region
|
||||
type: object
|
||||
target:
|
||||
enum:
|
||||
- FILE
|
||||
- S3
|
||||
type: string
|
||||
required:
|
||||
- target
|
||||
type: object
|
||||
required:
|
||||
- basePath
|
||||
- maxConcurrentJobs
|
||||
- name
|
||||
- storage
|
||||
type: object
|
||||
status:
|
||||
description: ClusterImageExportStatus defines the observed state of ClusterImageExport
|
||||
properties:
|
||||
completedImages:
|
||||
description: Number of images that have completed export
|
||||
type: integer
|
||||
progress:
|
||||
type: string
|
||||
totalImages:
|
||||
description: Total number of images to be exported
|
||||
type: integer
|
||||
type: object
|
||||
type: object
|
||||
served: true
|
||||
storage: true
|
||||
subresources:
|
||||
status: {}
|
||||
@@ -1,83 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "chart.fullname" . }}-controller-manager
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
{{- include "chart.labels" . | nindent 4 }}
|
||||
spec:
|
||||
replicas: {{ .Values.controllerManager.replicas }}
|
||||
selector:
|
||||
matchLabels:
|
||||
control-plane: controller-manager
|
||||
{{- include "chart.selectorLabels" . | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
{{- include "chart.selectorLabels" . | nindent 8 }}
|
||||
annotations:
|
||||
kubectl.kubernetes.io/default-container: manager
|
||||
spec:
|
||||
affinity:
|
||||
nodeAffinity:
|
||||
requiredDuringSchedulingIgnoredDuringExecution:
|
||||
nodeSelectorTerms:
|
||||
- matchExpressions:
|
||||
- key: kubernetes.io/arch
|
||||
operator: In
|
||||
values:
|
||||
- amd64
|
||||
- arm64
|
||||
- key: kubernetes.io/os
|
||||
operator: In
|
||||
values:
|
||||
- linux
|
||||
containers:
|
||||
- args:
|
||||
{{- toYaml .Values.controllerManager.manager.args | nindent 8 }}
|
||||
command:
|
||||
- /manager
|
||||
env:
|
||||
- name: POD_NAME
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.name
|
||||
- name: POD_NAMESPACE
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: metadata.namespace
|
||||
- name: POD_SERVICE_ACCOUNT
|
||||
valueFrom:
|
||||
fieldRef:
|
||||
fieldPath: spec.serviceAccountName
|
||||
- name: WORKER_IMAGE
|
||||
value: {{ quote .Values.controllerManager.manager.env.workerImage }}
|
||||
- name: KUBERNETES_CLUSTER_DOMAIN
|
||||
value: {{ quote .Values.kubernetesClusterDomain }}
|
||||
image: {{ .Values.controllerManager.manager.image.repository }}:{{ .Values.controllerManager.manager.image.tag | default .Chart.AppVersion }}
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: 8081
|
||||
initialDelaySeconds: 15
|
||||
periodSeconds: 20
|
||||
name: manager
|
||||
ports:
|
||||
- containerPort: 8443
|
||||
name: https
|
||||
protocol: TCP
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /readyz
|
||||
port: 8081
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
resources:
|
||||
{{- toYaml .Values.controllerManager.manager.resources | nindent 10 }}
|
||||
securityContext:
|
||||
{{- toYaml .Values.controllerManager.manager.containerSecurityContext | nindent 10 }}
|
||||
securityContext:
|
||||
{{- toYaml .Values.controllerManager.podSecurityContext | nindent 8 }}
|
||||
serviceAccountName: {{ include "chart.fullname" . }}-controller-manager
|
||||
terminationGracePeriodSeconds: 10
|
||||
@@ -1,74 +0,0 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: {{ include "chart.fullname" . }}-impex-mgr
|
||||
labels:
|
||||
{{- include "chart.labels" . | nindent 4 }}
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- pods
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- apps
|
||||
resources:
|
||||
- daemonsets
|
||||
- deployments
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- batch
|
||||
resources:
|
||||
- cronjobs
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- batch
|
||||
resources:
|
||||
- jobs
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- raczylo.com
|
||||
resources:
|
||||
- '*'
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- raczylo.com
|
||||
resources:
|
||||
- '*/finalizers'
|
||||
verbs:
|
||||
- update
|
||||
- apiGroups:
|
||||
- raczylo.com
|
||||
resources:
|
||||
- '*/status'
|
||||
verbs:
|
||||
- get
|
||||
- patch
|
||||
- update
|
||||
@@ -1,14 +0,0 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: {{ include "chart.fullname" . }}-impex-mgrbinding
|
||||
labels:
|
||||
{{- include "chart.labels" . | nindent 4 }}
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: '{{ include "chart.fullname" . }}-impex-mgr'
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: '{{ include "chart.fullname" . }}-controller-manager'
|
||||
namespace: '{{ .Release.Namespace }}'
|
||||
@@ -1,19 +0,0 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: {{ include "chart.fullname" . }}-metrics-auth-raczylo
|
||||
labels:
|
||||
{{- include "chart.labels" . | nindent 4 }}
|
||||
rules:
|
||||
- apiGroups:
|
||||
- authentication.k8s.io
|
||||
resources:
|
||||
- tokenreviews
|
||||
verbs:
|
||||
- create
|
||||
- apiGroups:
|
||||
- authorization.k8s.io
|
||||
resources:
|
||||
- subjectaccessreviews
|
||||
verbs:
|
||||
- create
|
||||
@@ -1,14 +0,0 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: {{ include "chart.fullname" . }}-metrics-auth-raczylobinding
|
||||
labels:
|
||||
{{- include "chart.labels" . | nindent 4 }}
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: '{{ include "chart.fullname" . }}-metrics-auth-raczylo'
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: '{{ include "chart.fullname" . }}-controller-manager'
|
||||
namespace: '{{ .Release.Namespace }}'
|
||||
@@ -1,11 +0,0 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: {{ include "chart.fullname" . }}-metrics-raczylo
|
||||
labels:
|
||||
{{- include "chart.labels" . | nindent 4 }}
|
||||
rules:
|
||||
- nonResourceURLs:
|
||||
- /metrics
|
||||
verbs:
|
||||
- get
|
||||
@@ -1,38 +0,0 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: Role
|
||||
metadata:
|
||||
name: {{ include "chart.fullname" . }}-raczylo-com-leader
|
||||
labels:
|
||||
{{- include "chart.labels" . | nindent 4 }}
|
||||
rules:
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- configmaps
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- patch
|
||||
- delete
|
||||
- apiGroups:
|
||||
- coordination.k8s.io
|
||||
resources:
|
||||
- leases
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- patch
|
||||
- delete
|
||||
- apiGroups:
|
||||
- ""
|
||||
resources:
|
||||
- events
|
||||
verbs:
|
||||
- create
|
||||
- patch
|
||||
@@ -1,14 +0,0 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: RoleBinding
|
||||
metadata:
|
||||
name: {{ include "chart.fullname" . }}-raczylo-com-leaderbinding
|
||||
labels:
|
||||
{{- include "chart.labels" . | nindent 4 }}
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: Role
|
||||
name: '{{ include "chart.fullname" . }}-raczylo-com-leader'
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: '{{ include "chart.fullname" . }}-controller-manager'
|
||||
namespace: '{{ .Release.Namespace }}'
|
||||
@@ -1,28 +0,0 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: {{ include "chart.fullname" . }}-raczylo.com-clusterimage-editor-role
|
||||
labels:
|
||||
{{- include "chart.labels" . | nindent 4 }}
|
||||
rules:
|
||||
- apiGroups:
|
||||
- raczylo.com
|
||||
resources:
|
||||
- clusterimages
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- raczylo.com
|
||||
resources:
|
||||
- clusterimages/status
|
||||
verbs:
|
||||
- get
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
@@ -1,22 +0,0 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: {{ include "chart.fullname" . }}-raczylo.com-clusterimage-viewer-role
|
||||
labels:
|
||||
{{- include "chart.labels" . | nindent 4 }}
|
||||
rules:
|
||||
- apiGroups:
|
||||
- raczylo.com
|
||||
resources:
|
||||
- clusterimages
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- apiGroups:
|
||||
- raczylo.com
|
||||
resources:
|
||||
- clusterimages/status
|
||||
verbs:
|
||||
- get
|
||||
- watch
|
||||
-28
@@ -1,28 +0,0 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: {{ include "chart.fullname" . }}-raczylo.com-clusterimageexport-editor-role
|
||||
labels:
|
||||
{{- include "chart.labels" . | nindent 4 }}
|
||||
rules:
|
||||
- apiGroups:
|
||||
- raczylo.com
|
||||
resources:
|
||||
- clusterimageexports
|
||||
verbs:
|
||||
- create
|
||||
- delete
|
||||
- get
|
||||
- list
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
- apiGroups:
|
||||
- raczylo.com
|
||||
resources:
|
||||
- clusterimageexports/status
|
||||
verbs:
|
||||
- get
|
||||
- patch
|
||||
- update
|
||||
- watch
|
||||
-16
@@ -1,16 +0,0 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: {{ include "chart.fullname" . }}-raczylo.com-clusterimageexport-viewer-role
|
||||
labels:
|
||||
{{- include "chart.labels" . | nindent 4 }}
|
||||
rules:
|
||||
- apiGroups:
|
||||
- raczylo.com
|
||||
resources:
|
||||
- clusterimageexports
|
||||
- clusterimageexports/status
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
@@ -1,14 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "chart.fullname" . }}-metrics-service
|
||||
labels:
|
||||
control-plane: controller-manager
|
||||
{{- include "chart.labels" . | nindent 4 }}
|
||||
spec:
|
||||
type: {{ .Values.metricsService.type }}
|
||||
selector:
|
||||
control-plane: controller-manager
|
||||
{{- include "chart.selectorLabels" . | nindent 4 }}
|
||||
ports:
|
||||
{{- .Values.metricsService.ports | toYaml | nindent 2 }}
|
||||
@@ -1,8 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ include "chart.fullname" . }}-controller-manager
|
||||
labels:
|
||||
{{- include "chart.labels" . | nindent 4 }}
|
||||
annotations:
|
||||
{{- toYaml .Values.controllerManager.serviceAccount.annotations | nindent 4 }}
|
||||
@@ -1,31 +0,0 @@
|
||||
{{- if .Values.serviceMonitor.enabled }}
|
||||
apiVersion: monitoring.coreos.com/v1
|
||||
kind: ServiceMonitor
|
||||
metadata:
|
||||
name: {{ include "chart.fullname" . }}-metrics
|
||||
{{- if .Values.serviceMonitor.namespace }}
|
||||
namespace: {{ .Values.serviceMonitor.namespace }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "chart.labels" . | nindent 4 }}
|
||||
{{- with .Values.serviceMonitor.labels }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
endpoints:
|
||||
- path: /metrics
|
||||
port: https
|
||||
scheme: https
|
||||
interval: {{ .Values.serviceMonitor.interval }}
|
||||
scrapeTimeout: {{ .Values.serviceMonitor.scrapeTimeout }}
|
||||
tlsConfig:
|
||||
insecureSkipVerify: true
|
||||
bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
|
||||
namespaceSelector:
|
||||
matchNames:
|
||||
- {{ .Release.Namespace }}
|
||||
selector:
|
||||
matchLabels:
|
||||
control-plane: controller-manager
|
||||
{{- include "chart.selectorLabels" . | nindent 6 }}
|
||||
{{- end }}
|
||||
@@ -1,53 +0,0 @@
|
||||
kubernetesClusterDomain: cluster.local
|
||||
|
||||
controllerManager:
|
||||
manager:
|
||||
# Command line arguments for the manager
|
||||
args:
|
||||
- --metrics-bind-address=:8443
|
||||
- --metrics-secure
|
||||
- --leader-elect
|
||||
- --health-probe-bind-address=:8081
|
||||
containerSecurityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
env:
|
||||
workerImage: ghcr.io/lukaszraczylo/kubernetes-images-sync-worker:0.5.54
|
||||
image:
|
||||
repository: ghcr.io/lukaszraczylo/kubernetes-images-sync-operator
|
||||
tag: "0.5.57"
|
||||
resources:
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 128Mi
|
||||
requests:
|
||||
cpu: 10m
|
||||
memory: 64Mi
|
||||
podSecurityContext:
|
||||
runAsNonRoot: true
|
||||
replicas: 1
|
||||
serviceAccount:
|
||||
annotations: {}
|
||||
|
||||
# Metrics service configuration
|
||||
metricsService:
|
||||
ports:
|
||||
- name: https
|
||||
port: 8443
|
||||
protocol: TCP
|
||||
targetPort: 8443
|
||||
type: ClusterIP
|
||||
|
||||
# ServiceMonitor for Prometheus Operator integration
|
||||
serviceMonitor:
|
||||
enabled: false
|
||||
# Namespace where ServiceMonitor will be created (defaults to release namespace)
|
||||
namespace: ""
|
||||
# Additional labels for ServiceMonitor
|
||||
labels: {}
|
||||
# Scrape interval
|
||||
interval: 30s
|
||||
# Scrape timeout
|
||||
scrapeTimeout: 10s
|
||||
@@ -1,18 +0,0 @@
|
||||
apiVersion: v2
|
||||
name: kubemirror
|
||||
description: Kubernetes controller for mirroring resources across namespaces
|
||||
type: application
|
||||
version: 0.9.22
|
||||
appVersion: "0.9.22"
|
||||
keywords:
|
||||
- kubernetes
|
||||
- controller
|
||||
- mirror
|
||||
- secrets
|
||||
- configmaps
|
||||
home: https://github.com/lukaszraczylo/kubemirror
|
||||
sources:
|
||||
- https://github.com/lukaszraczylo/kubemirror
|
||||
maintainers:
|
||||
- name: Lukasz Raczylo
|
||||
email: lukasz@raczylo.com
|
||||
@@ -1,36 +0,0 @@
|
||||
Thank you for installing {{ .Chart.Name }}.
|
||||
|
||||
Your release is named {{ .Release.Name }}.
|
||||
|
||||
To learn more about the release, try:
|
||||
|
||||
$ helm status {{ .Release.Name }} -n {{ .Release.Namespace }}
|
||||
$ helm get all {{ .Release.Name }} -n {{ .Release.Namespace }}
|
||||
|
||||
KubeMirror is now running and will automatically mirror resources across namespaces.
|
||||
|
||||
To mirror a Secret or ConfigMap, add this LABEL and ANNOTATIONS:
|
||||
|
||||
# Label (required for server-side filtering):
|
||||
kubemirror.raczylo.com/enabled: "true"
|
||||
|
||||
# Annotations:
|
||||
kubemirror.raczylo.com/sync: "true"
|
||||
kubemirror.raczylo.com/target-namespaces: "namespace1,namespace2"
|
||||
|
||||
Or use "all" to mirror to all namespaces with the allow-mirrors label:
|
||||
|
||||
kubemirror.raczylo.com/target-namespaces: "all"
|
||||
|
||||
To allow a namespace to receive mirrored resources, add this label:
|
||||
|
||||
kubemirror.raczylo.com/allow-mirrors: "true"
|
||||
|
||||
View controller logs:
|
||||
|
||||
$ kubectl logs -n {{ .Release.Namespace }} -l app.kubernetes.io/name={{ include "kubemirror.name" . }}
|
||||
|
||||
Check metrics:
|
||||
|
||||
$ kubectl port-forward -n {{ .Release.Namespace }} svc/{{ include "kubemirror.fullname" . }}-metrics {{ .Values.service.metricsPort }}:{{ .Values.service.metricsPort }}
|
||||
$ curl http://localhost:{{ .Values.service.metricsPort }}/metrics
|
||||
@@ -1,60 +0,0 @@
|
||||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "kubemirror.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
*/}}
|
||||
{{- define "kubemirror.fullname" -}}
|
||||
{{- if .Values.fullnameOverride }}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride }}
|
||||
{{- if contains $name .Release.Name }}
|
||||
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create chart name and version as used by the chart label.
|
||||
*/}}
|
||||
{{- define "kubemirror.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Common labels
|
||||
*/}}
|
||||
{{- define "kubemirror.labels" -}}
|
||||
helm.sh/chart: {{ include "kubemirror.chart" . }}
|
||||
{{ include "kubemirror.selectorLabels" . }}
|
||||
{{- if .Chart.AppVersion }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||
{{- end }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Selector labels
|
||||
*/}}
|
||||
{{- define "kubemirror.selectorLabels" -}}
|
||||
app.kubernetes.io/name: {{ include "kubemirror.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create the name of the service account to use
|
||||
*/}}
|
||||
{{- define "kubemirror.serviceAccountName" -}}
|
||||
{{- if .Values.serviceAccount.create }}
|
||||
{{- default (include "kubemirror.fullname" .) .Values.serviceAccount.name }}
|
||||
{{- else }}
|
||||
{{- default "default" .Values.serviceAccount.name }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -1,57 +0,0 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: {{ include "kubemirror.fullname" . }}
|
||||
labels:
|
||||
{{- include "kubemirror.labels" . | nindent 4 }}
|
||||
rules:
|
||||
# Discovery - read access to all API groups for resource discovery
|
||||
# This is required for auto-discovering available resource types
|
||||
- apiGroups: ["*"]
|
||||
resources: ["*"]
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
|
||||
# Full access to all mirrorable resources
|
||||
# Required for creating, updating, and deleting mirrors across all resource types
|
||||
# The controller will only mirror resources that are explicitly marked with
|
||||
# kubemirror.raczylo.com/enabled label and kubemirror.raczylo.com/sync annotation
|
||||
- apiGroups: ["*"]
|
||||
resources: ["*"]
|
||||
verbs:
|
||||
- create
|
||||
- update
|
||||
- patch
|
||||
- delete
|
||||
|
||||
# Namespaces - read only (for listing and filtering)
|
||||
- apiGroups: [""]
|
||||
resources:
|
||||
- namespaces
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
|
||||
# Leader election - coordination.k8s.io/v1
|
||||
- apiGroups: ["coordination.k8s.io"]
|
||||
resources:
|
||||
- leases
|
||||
verbs:
|
||||
- get
|
||||
- list
|
||||
- watch
|
||||
- create
|
||||
- update
|
||||
- patch
|
||||
- delete
|
||||
|
||||
# Events - for creating events about mirroring operations
|
||||
- apiGroups: [""]
|
||||
resources:
|
||||
- events
|
||||
verbs:
|
||||
- create
|
||||
- patch
|
||||
@@ -1,14 +0,0 @@
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: {{ include "kubemirror.fullname" . }}
|
||||
labels:
|
||||
{{- include "kubemirror.labels" . | nindent 4 }}
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: {{ include "kubemirror.fullname" . }}
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: {{ include "kubemirror.serviceAccountName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
@@ -1,103 +0,0 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "kubemirror.fullname" . }}
|
||||
labels:
|
||||
{{- include "kubemirror.labels" . | nindent 4 }}
|
||||
spec:
|
||||
replicas: {{ .Values.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "kubemirror.selectorLabels" . | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
{{- toYaml .Values.podAnnotations | nindent 8 }}
|
||||
labels:
|
||||
{{- include "kubemirror.selectorLabels" . | nindent 8 }}
|
||||
spec:
|
||||
{{- with .Values.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
serviceAccountName: {{ include "kubemirror.serviceAccountName" . }}
|
||||
securityContext:
|
||||
{{- toYaml .Values.podSecurityContext | nindent 8 }}
|
||||
{{- with .Values.priorityClassName }}
|
||||
priorityClassName: {{ . }}
|
||||
{{- end }}
|
||||
containers:
|
||||
- name: controller
|
||||
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
|
||||
imagePullPolicy: {{ .Values.image.pullPolicy }}
|
||||
command:
|
||||
- /kubemirror
|
||||
args:
|
||||
- --metrics-bind-address={{ .Values.controller.metricsBindAddress }}
|
||||
- --health-probe-bind-address={{ .Values.controller.healthProbeBindAddress }}
|
||||
{{- if .Values.controller.leaderElect }}
|
||||
- --leader-elect
|
||||
{{- end }}
|
||||
- --leader-election-id={{ .Values.controller.leaderElectionID }}
|
||||
- --max-targets={{ .Values.controller.maxTargets }}
|
||||
- --worker-threads={{ .Values.controller.workerThreads }}
|
||||
- --rate-limit-qps={{ .Values.controller.rateLimitQPS }}
|
||||
- --rate-limit-burst={{ .Values.controller.rateLimitBurst }}
|
||||
{{- if .Values.controller.verifySourceFreshness }}
|
||||
- --verify-source-freshness=true
|
||||
{{- end }}
|
||||
{{- if .Values.controller.lazyWatcherInit }}
|
||||
- --lazy-watcher-init=true
|
||||
{{- end }}
|
||||
- --watcher-scan-interval={{ .Values.controller.watcherScanInterval }}
|
||||
{{- if .Values.controller.excludedNamespaces }}
|
||||
- --excluded-namespaces={{ .Values.controller.excludedNamespaces }}
|
||||
{{- end }}
|
||||
{{- if .Values.controller.includedNamespaces }}
|
||||
- --included-namespaces={{ .Values.controller.includedNamespaces }}
|
||||
{{- end }}
|
||||
{{- if .Values.controller.resourceTypes }}
|
||||
- --resource-types={{ join "," .Values.controller.resourceTypes }}
|
||||
{{- end }}
|
||||
- --discovery-interval={{ .Values.controller.discoveryInterval }}
|
||||
- --resync-period={{ .Values.controller.resyncPeriod }}
|
||||
ports:
|
||||
- name: metrics
|
||||
containerPort: 8080
|
||||
protocol: TCP
|
||||
- name: health
|
||||
containerPort: 8081
|
||||
protocol: TCP
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /healthz
|
||||
port: health
|
||||
initialDelaySeconds: 15
|
||||
periodSeconds: 20
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 3
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /readyz
|
||||
port: health
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 3
|
||||
resources:
|
||||
{{- toYaml .Values.resources | nindent 12 }}
|
||||
securityContext:
|
||||
{{- toYaml .Values.securityContext | nindent 12 }}
|
||||
terminationGracePeriodSeconds: 10
|
||||
{{- with .Values.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
@@ -1,19 +0,0 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "kubemirror.fullname" . }}-metrics
|
||||
labels:
|
||||
{{- include "kubemirror.labels" . | nindent 4 }}
|
||||
spec:
|
||||
type: {{ .Values.service.type }}
|
||||
ports:
|
||||
- name: metrics
|
||||
port: {{ .Values.service.metricsPort }}
|
||||
targetPort: metrics
|
||||
protocol: TCP
|
||||
- name: health
|
||||
port: {{ .Values.service.healthPort }}
|
||||
targetPort: health
|
||||
protocol: TCP
|
||||
selector:
|
||||
{{- include "kubemirror.selectorLabels" . | nindent 4 }}
|
||||
@@ -1,12 +0,0 @@
|
||||
{{- if .Values.serviceAccount.create -}}
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ include "kubemirror.serviceAccountName" . }}
|
||||
labels:
|
||||
{{- include "kubemirror.labels" . | nindent 4 }}
|
||||
{{- with .Values.serviceAccount.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -1,113 +0,0 @@
|
||||
replicaCount: 1
|
||||
|
||||
image:
|
||||
repository: ghcr.io/lukaszraczylo/kubemirror
|
||||
pullPolicy: IfNotPresent
|
||||
tag: "0.9.22"
|
||||
|
||||
imagePullSecrets: []
|
||||
nameOverride: ""
|
||||
fullnameOverride: ""
|
||||
|
||||
serviceAccount:
|
||||
create: true
|
||||
annotations: {}
|
||||
name: ""
|
||||
|
||||
podAnnotations:
|
||||
prometheus.io/scrape: "true"
|
||||
prometheus.io/port: "8080"
|
||||
prometheus.io/path: "/metrics"
|
||||
|
||||
podSecurityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 65532
|
||||
fsGroup: 65532
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
readOnlyRootFilesystem: true
|
||||
runAsNonRoot: true
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
|
||||
controller:
|
||||
# Metrics and health endpoints
|
||||
metricsBindAddress: ":8080"
|
||||
healthProbeBindAddress: ":8081"
|
||||
|
||||
# Leader election
|
||||
leaderElect: true
|
||||
leaderElectionID: "kubemirror-controller-leader"
|
||||
|
||||
# Resource types to mirror
|
||||
# Examples: ["Secret.v1", "ConfigMap.v1", "Ingress.v1.networking.k8s.io", "Middleware.v1alpha1.traefik.io"]
|
||||
# If empty, auto-discovery will find all mirrorable resources
|
||||
# MEMORY TIP: Specifying exact types reduces memory by 70-80% vs auto-discovery
|
||||
# Common types: Secret.v1, ConfigMap.v1
|
||||
resourceTypes: []
|
||||
|
||||
# Auto-discovery interval (only used when resourceTypes is empty)
|
||||
# How often to rediscover available resources in the cluster
|
||||
discoveryInterval: "5m"
|
||||
|
||||
# Cache resync period - how often to refresh all cached resources
|
||||
# Higher values reduce memory churn and API load
|
||||
# Default: 10m (was 30s in earlier versions)
|
||||
resyncPeriod: "10m"
|
||||
|
||||
# Resource limits
|
||||
maxTargets: 100
|
||||
workerThreads: 5
|
||||
|
||||
# API rate limiting
|
||||
rateLimitQPS: 50.0
|
||||
rateLimitBurst: 100
|
||||
|
||||
# Cache freshness verification
|
||||
# Compares cache with direct API read to detect informer cache lag
|
||||
# Prevents mirroring stale data but adds extra API call when cache is stale
|
||||
# Recommended: false for most deployments (eventual consistency is acceptable)
|
||||
verifySourceFreshness: false
|
||||
|
||||
# Lazy watcher initialization (RECOMMENDED for production)
|
||||
# Only creates informers for resource types that actually have resources marked for mirroring
|
||||
# Dramatically reduces memory usage - e.g., if you have 204 available resource types but only
|
||||
# 2 types with marked resources, this creates only 2 watchers instead of 204
|
||||
# Memory savings: typically 70-90% compared to eager initialization
|
||||
# Default: false (user opt-in)
|
||||
lazyWatcherInit: false
|
||||
|
||||
# Watcher scan interval (lazy-watcher-init mode only)
|
||||
# How often to scan the cluster for new resource types that need watchers
|
||||
# If you add a new resource type to mirror, it will be detected within this interval
|
||||
# Default: 5m
|
||||
watcherScanInterval: "5m"
|
||||
|
||||
# Namespace filtering
|
||||
excludedNamespaces: ""
|
||||
includedNamespaces: ""
|
||||
|
||||
service:
|
||||
type: ClusterIP
|
||||
metricsPort: 8080
|
||||
healthPort: 8081
|
||||
|
||||
resources:
|
||||
limits:
|
||||
cpu: 500m
|
||||
memory: 512Mi
|
||||
requests:
|
||||
cpu: 100m
|
||||
memory: 128Mi
|
||||
|
||||
nodeSelector: {}
|
||||
|
||||
tolerations: []
|
||||
|
||||
affinity: {}
|
||||
|
||||
priorityClassName: ""
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user