LinearB On-Prem Agent - Ingress Usage Scenarios
This guide covers different ingress configuration scenarios for the LinearB On-Prem Agent (v4.0.11+).
Overview
Starting from version 4.0.11, the LinearB On-Prem Agent provides flexible ingress configuration options to support various deployment scenarios:
- Install ingress controller with the agent (default behavior)
- Use an existing ingress controller in your namespace
- Disable ingress entirely and use LoadBalancer service
- Multi-host configuration with single or multiple hostnames
- TLS/HTTPS configuration with certificate management
- Chart-specific ingress override for granular control per subchart
The global.RECEIVER_INGRESS flag is still supported for backward compatibility with existing installations.
Configuration Options
Ingress Configuration Parameters
Add these parameters to your local-values.yaml file:
global:
# Legacy flag (still supported for backward compatibility)
# Controls both ingress controller installation and Ingress resource creation
RECEIVER_INGRESS: true|false
# Global ingress control (new in v4.0.11+)
ingress:
# Whether to install the ingress-nginx controller
# Condition priority: ingress.installController > global.ingress.installController > global.RECEIVER_INGRESS
installController: true|false
ingress:
# Input for optional ingress-nginx chart
controller:
# IngressClass name that the controller watches
ingressClass: "linearb-opa-ingress-class"
ingressClassResource:
# IngressClass resource name to create
name: "linearb-opa-ingress-class"
onprem-receiver:
ingress:
# Whether to create Ingress resource for onprem-receiver
# Priority: global.RECEIVER_INGRESS (if defined) > onprem-receiver.ingress.enabled
enabled: true|false
# IngressClass name for the Ingress resource (spec.ingressClassName)
# Falls back to controller.ingressClass if not specified
className: "linearb-opa-ingress-class"
Usage Scenarios
Scenario 1: Default Installation (Install Ingress Controller)
Use case: You don't have an ingress controller in your namespace and want the agent to install one.
Configuration:
Or using the new parameters (v4.0.11+):
global:
ingress:
installController: true # Install ingress-nginx controller
# ... other global settings
ingress:
installController: true # Can also be set here (takes priority over global)
controller:
ingressClass: "linearb-opa-ingress-class"
ingressClassResource:
name: "linearb-opa-ingress-class"
onprem-receiver:
ingress:
enabled: true
className: "linearb-opa-ingress-class"
What happens: - The agent installs ingress-nginx controller in your namespace - The controller watches for Ingress resources with ingressClassName: "linearb-opa-ingress-class" - Creates an Ingress resource for the onprem-receiver service with the specified className - Service type is set to ClusterIP
Scenario 2: Use Existing Ingress Controller
Use case: Your cluster or namespace already has an ingress controller installed, and you want to use it instead of installing a new one.
Configuration:
global:
RECEIVER_INGRESS: "true" # Enable Ingress resource creation
ingress:
installController: false # Don't install ingress-nginx controller
# ... other global settings
ingress:
installController: false # Don't install ingress-nginx controller (takes priority over global)
onprem-receiver:
ingress:
enabled: true
className: "nginx" # Or your existing ingress class name (e.g., "traefik", "haproxy")
What happens: - The agent does NOT install a new ingress controller - Creates an Ingress resource for the onprem-receiver service with ingressClassName: "nginx" - The existing ingress controller in your namespace handles the traffic based on the className - Service type is set to ClusterIP
Important notes: - Make sure your existing ingress controller is configured to watch the namespace where the agent is deployed - Update className to match your existing ingress controller's IngressClass name - If using a non-nginx ingress controller, you may need to adjust ingress annotations in helm/onprem-receiver/values.yaml
Scenario 3: Disable Ingress (Use LoadBalancer)
Use case: You don't want to use ingress and prefer to expose the service via LoadBalancer or NodePort.
Configuration:
Or using the new parameters:
global:
ingress:
installController: false # Don't install ingress controller
# ... other global settings
onprem-receiver:
ingress:
enabled: false # Don't create Ingress resource
What happens: - No ingress controller is installed - No Ingress resource is created for onprem-receiver - Service type is set to LoadBalancer
Scenario 4: Multi-Host Configuration
Use case: You want to expose the onprem-receiver service on multiple hostnames (e.g., for different domains or environments).
Configuration:
global:
RECEIVER_INGRESS: "true"
ingress:
installController: true # Install ingress controller (or false if using existing)
onprem-receiver:
ingress:
enabled: true
className: "linearb-opa-ingress-class"
hosts:
# Option 1: Single host
- host: "on-prem-api.example.com"
paths:
- path: /
pathType: Prefix
backend:
service:
name: on-prem-agent-onprem-receiver
# Option 2: Multiple hosts
# - host: "on-prem-api.example.org"
# paths:
# - path: /
# pathType: Prefix
# backend:
# service:
# name: on-prem-agent-onprem-receiver
# Option 3: No host specified (accepts all hosts)
# - paths:
# - path: /
# pathType: Prefix
# backend:
# service:
# name: on-prem-agent-onprem-receiver
What happens: - Ingress routes traffic from specified host(s) to the onprem-receiver service - You can define multiple hosts with different paths - If no host is specified, the ingress accepts all hosts (default behavior)
Scenario 5: TLS/HTTPS Configuration
Use case: You want to secure your ingress with TLS certificates.
Configuration:
global:
RECEIVER_INGRESS: "true"
ingress:
installController: true # Install ingress controller (or false if using existing)
onprem-receiver:
ingress:
enabled: true
className: "linearb-opa-ingress-class"
hosts:
- host: "on-prem-api.example.com"
paths:
- path: /
pathType: Prefix
backend:
service:
name: on-prem-agent-onprem-receiver
# TLS configuration
tls:
- hosts:
- "on-prem-api.example.com"
secretName: on-prem-tls
# Multiple certificates for multiple hosts
# - hosts:
# - "on-prem-api.example.org"
# secretName: on-prem-tls-org
What happens: - Ingress terminates TLS using the certificate from the specified Kubernetes secret - The secret must exist in the same namespace as the ingress - Multiple TLS configurations can reference different secrets for different hosts
Creating the TLS secret:
# Create TLS secret from certificate files
kubectl create secret tls on-prem-tls \
--cert=path/to/tls.crt \
--key=path/to/tls.key \
-n linearb
# Or for cert-manager (automatic certificate provisioning)
# Create a Certificate resource that references your Issuer
Scenario 6: Chart-Specific Ingress Override
Use case: You want to control ingress at the subchart level when global.RECEIVER_INGRESS is not set.
Configuration:
# Option 1: Enable ingress via subchart setting (when RECEIVER_INGRESS is not set)
global:
# RECEIVER_INGRESS is not defined
ingress:
installController: true # Install ingress controller
onprem-receiver:
ingress:
enabled: true # Enable ingress for this chart
className: "linearb-opa-ingress-class"
Or:
# Option 2: Disable ingress via subchart setting (when RECEIVER_INGRESS is not set)
global:
# RECEIVER_INGRESS is not defined
ingress:
installController: false # Don't install ingress controller
onprem-receiver:
ingress:
enabled: false # Disable ingress for this chart
What happens: - When global.RECEIVER_INGRESS is not defined, the onprem-receiver.ingress.enabled setting controls ingress creation - If you do set global.RECEIVER_INGRESS, it will take precedence over the subchart setting
Priority order: - For Ingress resource creation: global.RECEIVER_INGRESS (if defined) > onprem-receiver.ingress.enabled - For controller installation: ingress.installController > global.ingress.installController > global.RECEIVER_INGRESS
Backward Compatibility
Automatic className Detection on Upgrade
Starting from v4.0.11, the agent automatically detects and preserves the existing ingress className during upgrades:
- On upgrade: If an existing Ingress resource with
className: "nginx"is found, it will be automatically preserved - On fresh install: New installations will use
className: "linearb-opa-ingress-class"by default
This means you can upgrade from v4.0.10 or earlier without any configuration changes, and your existing ingress will continue to work.
Legacy RECEIVER_INGRESS Flag
The legacy global.RECEIVER_INGRESS flag is fully supported for backward compatibility:
| RECEIVER_INGRESS | Behavior |
|---|---|
"true" | Installs ingress controller + creates Ingress |
"false" | No ingress controller, uses LoadBalancer service |
If global.RECEIVER_INGRESS is defined, it takes precedence over onprem-receiver.ingress.enabled. To use subchart-level control, leave global.RECEIVER_INGRESS undefined.
Migration Examples
Migrating from global.RECEIVER_INGRESS to new parameters
Before (v4.0.10 and earlier):
After (v4.0.11+, no changes needed):
global:
RECEIVER_INGRESS: "true" # Keep this - className "nginx" will be auto-detected and preserved
Or explicitly migrate to the new parameters with your existing className:
global:
ingress:
installController: true
className: "nginx" # Fallback className for Ingress resources
onprem-receiver:
ingress:
enabled: true
className: "nginx" # Explicitly maintain existing className
Or migrate to the new default className (requires updating your DNS/ingress configuration):
global:
ingress:
installController: true
className: "linearb-opa-ingress-class" # New installations default
onprem-receiver:
ingress:
enabled: true
className: "linearb-opa-ingress-class"
Troubleshooting
Ingress controller not receiving traffic
-
Verify the ingress controller is running in your namespace:
-
Check the Ingress resource:
-
Verify the ingress class matches your controller:
Upgrade fails with "x509: certificate signed by unknown authority"
Symptom: UPGRADE FAILED: failed calling webhook "validate.nginx.ingress.kubernetes.io": ... tls: failed to verify certificate: x509: certificate signed by unknown authority
Cause: The ValidatingWebhookConfiguration for the nginx-ingress admission webhook has a stale caBundle from a previous installation. On upgrade, the nginx-ingress controller gets fresh self-signed certs, but the webhook config still holds the old CA — so the Kubernetes API server can't verify the webhook's TLS certificate.
Fix: Delete the stale webhook configuration and re-run the upgrade:
kubectl delete validatingwebhookconfiguration on-prem-agent-ingress-admission
helm upgrade --install -n linearb on-prem-agent oci://<registry>/on-prem-agent \
--values local-values.yaml --version <version>
The certgen job on the next upgrade will recreate the ValidatingWebhookConfiguration with the correct caBundle.
Service is LoadBalancer instead of ClusterIP
This usually means ingress is disabled. Check your configuration:
Customizing Container Registry
Overview
The LinearB On-Prem Agent uses a centralized registry configuration that allows you to customize which container registry to pull images from. This is useful when: - You want to use a private mirror/proxy registry - You have corporate policies requiring images to come from specific registries - You're running in an air-gapped environment
Default Registry Configuration
By default, the agent uses the following registry:
Architecture
The agent uses a hybrid approach for registry configuration:
- External subcharts (minio, rabbitmq, redis, datadog, fluent-bit): Use YAML anchors to reference the registry
- Internal charts (agent-api, scheduler, sensors, etc.): Can use Helm templating helpers to dynamically build registry paths
Overriding the Registry
Option 1: Override global.JFROG_HOST Only
For services that use the registry split (like rabbitmq, redis):
# my-custom-values.yaml
global:
JFROG_HOST: "my-custom-registry.io/artifactory/custom-path"
# These services automatically use the JFROG_HOST reference
rabbitmq:
image:
registry: *jfrog_registry # Automatically uses global.JFROG_HOST
repository: image-dependencies/rabbitmq
redis:
image:
registry: *jfrog_registry # Automatically uses global.JFROG_HOST
repository: image-dependencies/redis
Important: YAML anchors only work within the default values.yaml file and cannot be used in override files.
Option 2: Full Override for External Subcharts
For external subcharts that require full repository paths (like minio):
# my-custom-values.yaml
global:
JFROG_HOST: "my-custom-registry.io/artifactory/custom-path"
minio:
image:
repository: "my-custom-registry.io/artifactory/custom-path/image-dependencies/minio"
mcImage:
repository: "my-custom-registry.io/artifactory/custom-path/image-dependencies/mc"
datadog-agent:
registry: "my-custom-registry.io/artifactory/custom-path"
fluent-bit:
image:
registry: "my-custom-registry.io/artifactory/custom-path"
socat:
image:
registry: "my-custom-registry.io/artifactory/custom-path"
Option 3: Using --set Flags
helm upgrade my-release ./helm/on-prem-agent \
--set global.JFROG_HOST="my-custom-registry.io/artifactory/custom-path" \
--set minio.image.repository="my-custom-registry.io/artifactory/custom-path/image-dependencies/minio" \
--set minio.mcImage.repository="my-custom-registry.io/artifactory/custom-path/image-dependencies/mc" \
--set datadog-agent.registry="my-custom-registry.io/artifactory/custom-path"
Complete Override Example
Here's a complete example for switching to a custom registry:
# custom-registry-values.yaml
global:
JFROG_HOST: "harbor.mycompany.com/linearb-mirror"
JFROG_USER: "myuser"
JFROG_KEY: "mypassword"
# External charts requiring full paths
minio:
image:
repository: "harbor.mycompany.com/linearb-mirror/image-dependencies/minio"
mcImage:
repository: "harbor.mycompany.com/linearb-mirror/image-dependencies/mc"
rabbitmq:
image:
registry: "harbor.mycompany.com/linearb-mirror"
repository: image-dependencies/rabbitmq
redis:
image:
registry: "harbor.mycompany.com/linearb-mirror"
repository: image-dependencies/redis
datadog-agent:
registry: "harbor.mycompany.com/linearb-mirror"
fluent-bit:
image:
registry: "harbor.mycompany.com/linearb-mirror"
socat:
image:
registry: "harbor.mycompany.com/linearb-mirror"
ingress:
global:
registry: "harbor.mycompany.com/linearb-mirror"
defaultBackend:
image:
registry: "harbor.mycompany.com/linearb-mirror"
controller:
image:
registry: "harbor.mycompany.com/linearb-mirror"
admissionWebhooks:
patch:
image:
registry: "harbor.mycompany.com/linearb-mirror"
Important Notes
-
YAML Anchor Limitation: YAML anchors (like
*jfrog_registry) only work within a single YAML file. When you provide override values in a custom file or via--set, you must provide complete, fully-qualified values. -
Registry Authentication: Update
global.JFROG_USERandglobal.JFROG_KEYif your custom registry requires authentication. -
Image Pull Secrets: Ensure your
imagePullSecretsare configured correctly for your custom registry: -
Chart Dependencies: Don't forget to update the registry for chart dependencies in
Chart.yamlif you're also mirroring Helm charts.
Testing Registry Configuration
After applying custom registry values, verify the configuration:
# Check the rendered templates
helm template on-prem-agent ./helm/on-prem-agent -f custom-registry-values.yaml | grep -i "repository:\|registry:"
# Check running pods
kubectl get pods -n linearb -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.spec.containers[*].image}{"\n"}{end}'
Worker Pod Scheduling Configuration
Overview
The LinearB On-Prem Agent dynamically creates worker pods for various jobs (linta, pm-connectors, sensors). You can control where these pods are scheduled in your Kubernetes cluster using nodeSelector and affinity configurations.
Important: This configuration applies to dynamically created worker pods only. For regular deployments (scheduler, agent-api, sensors, etc.), use the standard per-service configuration in each chart's values.yaml (e.g., scheduler.nodeSelector, agent-api.affinity). See the "Scheduling for Deployments vs Worker Pods" section below for details.
This is useful when: - You want to dedicate specific nodes for LinearB worker pods - You need to avoid certain nodes (e.g., system nodes, nodes with limited resources) - You want to ensure pods run on nodes with specific hardware (e.g., amd64 architecture) - You need to comply with organizational policies about workload placement
Configuration Parameters
Add these parameters to your local-values.yaml file:
global:
workerPods:
# NodeSelector - simple key-value node labels for pod placement
nodeSelector:
kubernetes.io/arch: amd64
node-type: worker
# Affinity - advanced pod scheduling rules
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- node1
- node2
Use Cases
Use Case 1: Schedule on Specific Architecture
Scenario: Ensure all worker pods run on amd64 nodes only.
Configuration:
Use Case 2: Dedicate Specific Nodes
Scenario: Run worker pods only on nodes labeled as node-type: linearb-worker.
Configuration:
Prepare your nodes:
# Label nodes for LinearB workloads
kubectl label nodes node1 node-type=linearb-worker
kubectl label nodes node2 node-type=linearb-worker
Use Case 3: Avoid Specific Nodes
Scenario: Prevent worker pods from running on nodes with the label node-role=system.
Configuration:
global:
workerPods:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node-role
operator: NotIn
values:
- system
Use Case 4: Preferred Node Scheduling
Scenario: Prefer high-performance nodes but allow scheduling on other nodes if unavailable.
Configuration:
global:
workerPods:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: node-type
operator: In
values:
- high-performance
Use Case 5: Combined NodeSelector and Affinity
Scenario: Require amd64 architecture, prefer specific nodes.
Configuration:
global:
workerPods:
nodeSelector:
kubernetes.io/arch: amd64
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
preference:
matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- node1
- node2
Important Notes
-
Optional Configuration: If you don't configure
workerPods, pods will be scheduled normally without constraints (default Kubernetes scheduling behavior). -
Node Labels: Ensure your nodes have the appropriate labels before applying nodeSelector or affinity rules:
-
Applies to All Worker Pods: The configuration affects all dynamically created worker pods:
- Linta jobs (Git analysis)
- PM-Connectors jobs (Jira sync)
-
Sensors jobs (data collection)
-
Testing Configuration: After applying the configuration, verify that pods are scheduled correctly:
-
Troubleshooting: If pods are not being scheduled:
Differences Between NodeSelector and Affinity
| Feature | NodeSelector | Affinity |
|---|---|---|
| Complexity | Simple key-value matching | Advanced rules with operators |
| Required vs Preferred | Always required | Supports both required and preferred |
| Operators | Exact match only | In, NotIn, Exists, DoesNotExist, Gt, Lt |
| Multiple Conditions | AND logic only | Complex AND/OR logic |
| Use Case | Simple node targeting | Complex scheduling requirements |
Recommendation: Use nodeSelector for simple cases, and affinity for advanced scheduling requirements.
Scheduling for Deployments vs Worker Pods
The LinearB On-Prem Agent consists of two types of workloads with different scheduling configuration methods:
1. Regular Deployments (Long-Running Services)
These are standard Kubernetes Deployments that run continuously: - scheduler, job-lifecycle-manager - agent-api, agent-poller, agent-cli - sensors, onprem-receiver - jobs-suite-dispatcher, jobs-suite-worker
Configuration Method: Use per-service values in your local-values.yaml:
# Example: Configure scheduling for the scheduler deployment
scheduler:
nodeSelector:
node-type: control-plane
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: node-role
operator: In
values:
- management
# Example: Configure scheduling for agent-api
agent-api:
nodeSelector:
node-type: api-tier
2. Dynamic Worker Pods (Job Execution)
These are pods created on-demand by the scheduler to execute jobs: - Linta jobs - Git repository analysis - PM-Connectors jobs - Jira/project management data sync - Sensors jobs - Data collection tasks
Configuration Method: Use the global.workerPods section (as documented above):
global:
workerPods:
nodeSelector:
node-type: worker
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: workload-type
operator: In
values:
- batch-jobs
Why the Difference?
- Deployments use Helm's standard templating, so each chart can have its own
nodeSelectorandaffinityconfiguration in its values.yaml - Dynamic worker pods are created programmatically by Python code in the scheduler service, so they read their configuration from the
common-chart-valuesConfigMap at runtime
Complete Example: Separating Control Plane and Worker Nodes
global:
# Worker pods go to dedicated worker nodes
workerPods:
nodeSelector:
node-type: batch-worker
kubernetes.io/arch: amd64
# Scheduler deployments go to control plane nodes
scheduler:
nodeSelector:
node-type: control-plane
# API services go to API tier nodes
agent-api:
nodeSelector:
node-type: api-tier
sensors:
nodeSelector:
node-type: api-tier
This separation allows you to: - Place long-running services on stable, always-available nodes - Direct short-lived batch jobs to nodes optimized for burst workloads - Implement different resource limits and priorities for each tier
Redis Memory Configuration
Overview
Redis is used by the LinearB On-Prem Agent for caching and session management. Proper memory configuration is critical for stability. These values must be adjusted based on the number of repositories tracked and the activity level in those repositories.
Understanding Memory Units (Critical!)
IMPORTANT: Kubernetes and Redis use different memory unit systems, and this correlation is tricky:
| Unit | System | Example | Actual Bytes |
|---|---|---|---|
| Mi (Mebibytes) | Binary (base 2) | 400Mi | 400 × 1,048,576 = 419,430,400 bytes (~419.43 MB) |
| mb (Megabytes) | Decimal (base 10) | 350mb | 350 × 1,000,000 = 350,000,000 bytes (~333.79 MiB) |
Key Point: When you set a Kubernetes memory limit of 400Mi, you're allocating ~419.43 MB. If you set Redis maxmemory 350mb, Redis uses 350 MB, leaving ~70MB overhead for Redis operations.
Default Configuration
redis:
commonConfiguration: |-
# Memory management: 350mb provides ~70MB overhead for Redis operations
# Container limit is 400Mi (419MB), leaving 16.5% buffer for safety
maxmemory 350mb
maxmemory-policy volatile-lru
resources:
limits:
memory: 400Mi
requests:
cpu: 30m
memory: 200Mi
Calculation: - Container limit: 400Mi = 419.43 MB - Redis maxmemory: 350mb = 350 MB - Overhead: 419.43 - 350 = 69.43 MB (16.5% buffer)
This 16.5% buffer is critical - it provides space for: - Redis internal operations and metadata - Connection overhead - Memory fragmentation - OS-level buffers
When to Scale Up Memory
You need to increase Redis memory if: - Redis pod gets OOM-killed (Out of Memory) - You're tracking more repositories or repositories with high activity - High eviction rate (evicted_keys metric increasing rapidly) - Performance degradation (slow Git operations, frequent cache misses)
Scaling Guidelines
When increasing memory, always maintain the ~16.5% buffer between Redis maxmemory and container limit:
Calculation Formula: 1. Determine your container limit (e.g., 800Mi) 2. Convert to MB: Multiply Mi by 1.048576 (e.g., 800Mi × 1.048576 = 838.86 MB) 3. Calculate maxmemory: Use 83.5% of the MB value (e.g., 838.86 × 0.835 = 700.45 MB) 4. Round down: Use safe value like 700mb
Example scaling configurations:
# Small deployment (default)
redis:
commonConfiguration: |-
maxmemory 350mb
resources:
limits:
memory: 400Mi
# Medium deployment (more repos/activity)
redis:
commonConfiguration: |-
maxmemory 700mb
resources:
limits:
memory: 800Mi
# Large deployment (many repos/high activity)
redis:
commonConfiguration: |-
maxmemory 1800mb
resources:
limits:
memory: 2Gi
Monitoring Redis Memory
Check if your configuration is appropriate:
# Connect to Redis pod
kubectl exec -it $(kubectl get pod -n linearb -l app.kubernetes.io/name=on-prem-agent-redis -o jsonpath='{.items[0].metadata.name}') -n linearb -- redis-cli
# Check memory usage
INFO memory
# Key metrics:
# - used_memory: Current memory used
# - maxmemory: Your configured limit
# - mem_fragmentation_ratio: Should be ~1.0 (if >1.5, increase memory)
# - evicted_keys: Number of evicted keys (if high, increase memory)
Troubleshooting OOM Issues
Problem: Redis pod gets OOM-killed
Check pod events:
Solution: Increase both values proportionally while maintaining buffer:
redis:
commonConfiguration: |-
# Increased from 350mb to 700mb
maxmemory 700mb
maxmemory-policy volatile-lru
resources:
limits:
memory: 800Mi # Increased from 400Mi
requests:
cpu: 50m # Scale CPU with memory
memory: 400Mi # Increased from 200Mi
Important Notes
- Unit mismatch is intentional: Using
mbfor Redis andMifor Kubernetes is correct - don't change both to the same unit - Always maintain buffer: Don't set maxmemory too close to container limit or Redis will be OOM-killed
- Scale CPU with memory: Increase CPU requests/limits proportionally when increasing memory
- Monitor before scaling: Use
kubectl top podto check actual memory usage before increasing limits - Memory policy:
volatile-lruevicts least recently used keys with TTL set - appropriate for cache data
Storage Class Configuration for Minio
Overview
The LinearB On-Prem Agent uses Minio for integration credential storage. Minio requires a PersistentVolumeClaim (PVC), and the storage class backing that PVC depends on your Kubernetes platform. The global.K8S_PLATFORM value controls how the PVC is provisioned.
Supported Platforms
K8S_PLATFORM | Storage Behavior |
|---|---|
k3d | Creates a hostPath-backed PV + PVC |
eks | Creates a StorageClass backed by AWS EBS (gp2) and a PVC using it |
aks | Creates a PVC using the managed-premium Azure storage class (or MINIO_STORAGE_CLASS if set) |
default | Creates a PVC with no storageClassName, using the cluster's default storage class (or MINIO_STORAGE_CLASS if set) |
Scenario 1: Azure Kubernetes Service (AKS)
Use case: Deploying on AKS with the managed-premium storage class.
Configuration:
What happens: - A PVC named minio-pvc is created using storageClassName: managed-premium - Azure Disk is provisioned automatically by the AKS storage class
Custom storage class override:
global:
K8S_PLATFORM: "aks"
MINIO_STORAGE_CLASS: "managed-csi-premium" # Override the default managed-premium
PV_SIZE: "200Gi"
Scenario 2: Default Storage Class (Any Platform)
Use case: Your cluster has a default storage class configured and you want Minio to use it — for example, on GKE, OpenShift, or any generic K8s environment.
Configuration:
What happens: - A PVC named minio-pvc is created with no explicit storageClassName - Kubernetes binds the PVC to a PV provisioned by whichever storage class is annotated as the cluster default
Scenario 3: Pre-Existing / Custom Storage Class
Use case: You have a specific storage class already configured in your cluster and want Minio to use it explicitly (e.g., fast-ssd, nfs-storage, etc.).
Configuration:
What happens: - A PVC is created with storageClassName: fast-ssd - Any pre-existing storage class in the cluster can be used — no new StorageClass resource is created
Configuration Reference
global:
# Kubernetes platform — controls how the Minio PVC is provisioned
# Supported values: k3d, eks, aks, default
K8S_PLATFORM: "default"
# Persistent volume size for Minio
PV_SIZE: "200Gi"
# Optional: override the storage class used for the Minio PVC.
# When K8S_PLATFORM is 'aks', defaults to 'managed-premium' if not set.
# When K8S_PLATFORM is 'default', omitting this uses the cluster's default storage class.
# MINIO_STORAGE_CLASS: "my-storage-class"
Important Notes
-
Data persistence: The
minio-pvcPVC is created withhelm.sh/resource-policy: keep, meaning it will not be deleted onhelm uninstall. This prevents accidental data loss of stored credentials. -
k3d is for local development only: The
k3dplatform uses ahostPathvolume tied to a single node. It is not suitable for production environments. -
eks creates a StorageClass: Unlike the other platforms,
ekscreates a newStorageClassresource namedminio(backed by AWS EBSgp2) in addition to the PVC. If this StorageClass already exists in your cluster, it will not be recreated. -
Verify your storage class exists:
-
PVC is immutable after creation: Changing
MINIO_STORAGE_CLASSorPV_SIZEafter the initial install has no effect on the existing PVC. To change storage configuration, the PVC must be manually deleted and recreated (requires Minio downtime and a data migration plan).
Additional Resources
For questions or issues, please contact LinearB support.