Examples
Real-world examples and use cases
This page provides real-world examples of using the DB Query Operator for various scenarios.
Multi-Tenant ConfigMaps
Manage per-tenant configuration from a central database.
Database Setup
CREATE TABLE tenants (
tenant_id TEXT PRIMARY KEY,
config_json JSONB NOT NULL,
enabled BOOLEAN DEFAULT true
);
INSERT INTO tenants VALUES
('acme-corp', '{"api_url": "https://acme.api.com", "max_requests": 1000}', true),
('globex', '{"api_url": "https://globex.api.com", "max_requests": 500}', true);DatabaseQueryResource
apiVersion: konnektr.io/v1alpha1
kind: DatabaseQueryResource
metadata:
name: tenant-configs
namespace: tenants-system
spec:
pollInterval: "2m"
prune: true
database:
type: postgres
connectionSecretRef:
name: postgres-credentials
namespace: tenants-system
uriKey: fqdn-uri # CloudNativePG
query: |
SELECT tenant_id, config_json
FROM tenants
WHERE enabled = true
template: |
apiVersion: v1
kind: ConfigMap
metadata:
name: tenant-{{ .Row.tenant_id }}-config
namespace: tenants-system
labels:
tenant: {{ .Row.tenant_id | quote }}
data:
config.json: {{ .Row.config_json | toJson | quote }}Result: Creates tenant-acme-corp-config and tenant-globex-config ConfigMaps automatically.
ArgoCD Application Management
Deploy ArgoCD Applications dynamically based on database records.
Database Setup
CREATE TABLE applications (
app_name TEXT PRIMARY KEY,
repo_url TEXT NOT NULL,
target_revision TEXT DEFAULT 'main',
path TEXT NOT NULL,
namespace TEXT NOT NULL,
project TEXT DEFAULT 'default',
auto_sync BOOLEAN DEFAULT true,
created_at TIMESTAMP DEFAULT NOW()
);
INSERT INTO applications (app_name, repo_url, path, namespace) VALUES
('app-digitaltwins-env-dbqr-test',
'https://github.com/my-org/manifests',
'apps/digitaltwins/test',
'digitaltwins-test');DatabaseQueryResource
apiVersion: konnektr.io/v1alpha1
kind: DatabaseQueryResource
metadata:
name: argocd-apps
namespace: argocd
spec:
pollInterval: "1m"
prune: true
database:
type: postgres
connectionSecretRef:
name: postgres-creds
uriKey: fqdn-uri
query: |
SELECT app_name, repo_url, target_revision, path, namespace, project, auto_sync
FROM applications
WHERE created_at IS NOT NULL
template: |
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: {{ .Row.app_name }}
namespace: {{ .Metadata.Namespace }}
spec:
project: {{ .Row.project }}
source:
repoURL: {{ .Row.repo_url | quote }}
targetRevision: {{ .Row.target_revision | quote }}
path: {{ .Row.path | quote }}
destination:
server: https://kubernetes.default.svc
namespace: {{ .Row.namespace }}
{{- if .Row.auto_sync }}
syncPolicy:
automated:
prune: true
selfHeal: true
{{- end }}Use case: Centrally manage ArgoCD Application deployment from a database interface or API.
Dynamic Deployments
Create Kubernetes Deployments from database specifications.
Database Setup
CREATE TABLE services (
service_name TEXT PRIMARY KEY,
image TEXT NOT NULL,
replicas INT DEFAULT 1,
port INT DEFAULT 80,
env_vars JSONB DEFAULT '{}',
namespace TEXT NOT NULL
);
INSERT INTO services VALUES
('api-server', 'nginx:1.25', 2, 8080, '{"LOG_LEVEL": "info"}', 'production');DatabaseQueryResource
apiVersion: konnektr.io/v1alpha1
kind: DatabaseQueryResource
metadata:
name: dynamic-deployments
namespace: apps-system
spec:
pollInterval: "5m"
prune: false # Keep deployments even if removed from DB
database:
type: postgres
connectionSecretRef:
name: db-secret
uriKey: fqdn-uri
query: |
SELECT service_name, image, replicas, port, env_vars, namespace
FROM services
template: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Row.service_name }}
namespace: {{ .Row.namespace }}
spec:
replicas: {{ .Row.replicas }}
selector:
matchLabels:
app: {{ .Row.service_name }}
template:
metadata:
labels:
app: {{ .Row.service_name }}
spec:
containers:
- name: {{ .Row.service_name }}
image: {{ .Row.image | quote }}
ports:
- containerPort: {{ .Row.port }}
env:
{{- range $key, $value := (.Row.env_vars | fromJson) }}
- name: {{ $key }}
value: {{ $value | quote }}
{{- end }}Status Updates with Two-Way Sync
Update database when Kubernetes resources change state.
Database Setup
CREATE TABLE deployments (
deployment_name TEXT PRIMARY KEY,
image TEXT NOT NULL,
namespace TEXT NOT NULL,
ready_replicas INT DEFAULT 0,
last_updated TIMESTAMP DEFAULT NOW()
);DatabaseQueryResource
apiVersion: konnektr.io/v1alpha1
kind: DatabaseQueryResource
metadata:
name: deployment-sync
namespace: sync-system
spec:
pollInterval: "1m"
prune: true
database:
type: postgres
connectionSecretRef:
name: db-creds
uriKey: fqdn-uri
query: |
SELECT deployment_name, image, namespace
FROM deployments
template: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ .Row.deployment_name }}
namespace: {{ .Row.namespace }}
spec:
replicas: 2
selector:
matchLabels:
app: {{ .Row.deployment_name }}
template:
metadata:
labels:
app: {{ .Row.deployment_name }}
spec:
containers:
- name: app
image: {{ .Row.image | quote }}
# Update database with current ready replicas
statusUpdateQueryTemplate: |
UPDATE deployments
SET ready_replicas = {{ .Status.readyReplicas | default 0 }},
last_updated = NOW()
WHERE deployment_name = {{ .Metadata.Name | squote }}
AND namespace = {{ .Metadata.Namespace | squote }}Result: Deployment status in Kubernetes is continuously synced back to the database.
Change Detection for Large Tables
Only query database when data actually changes.
Database Setup
CREATE TABLE configs (
config_id TEXT PRIMARY KEY,
data JSONB NOT NULL,
updated_at TIMESTAMP DEFAULT NOW()
);
-- Trigger to update timestamp
CREATE OR REPLACE FUNCTION update_updated_at()
RETURNS TRIGGER AS $$
BEGIN
NEW.updated_at = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER configs_updated_at
BEFORE UPDATE ON configs
FOR EACH ROW
EXECUTE FUNCTION update_updated_at();DatabaseQueryResource
apiVersion: konnektr.io/v1alpha1
kind: DatabaseQueryResource
metadata:
name: efficient-configs
namespace: default
spec:
pollInterval: "30s" # Check frequently but only query if changed
prune: true
database:
type: postgres
connectionSecretRef:
name: db-secret
uriKey: fqdn-uri
changeDetection:
enabled: true
tableName: "configs"
timestampColumn: "updated_at"
query: |
SELECT config_id, data
FROM configs
template: |
apiVersion: v1
kind: ConfigMap
metadata:
name: config-{{ .Row.config_id }}
data:
config.json: {{ .Row.data | toJson | quote }}Benefit: With 30s polling, change detection reduces database load significantly by only executing the main query when updated_at changes.
Cross-Namespace Resource Management
Manage resources across multiple namespaces from a single DBQR.
apiVersion: konnektr.io/v1alpha1
kind: DatabaseQueryResource
metadata:
name: cross-namespace-secrets
namespace: secrets-controller
spec:
pollInterval: "5m"
prune: true
database:
type: postgres
connectionSecretRef:
name: db-creds
uriKey: fqdn-uri
query: |
SELECT secret_name, target_namespace, secret_data
FROM shared_secrets
WHERE enabled = true
template: |
apiVersion: v1
kind: Secret
metadata:
name: {{ .Row.secret_name }}
namespace: {{ .Row.target_namespace }} # Target namespace from database
type: Opaque
stringData:
data: {{ .Row.secret_data | quote }}RBAC Requirement: The operator ServiceAccount needs permissions in target namespaces.
Next Steps
- See Advanced Topics for change detection implementation details
- Check Configuration Reference for all CRD fields
- Review Troubleshooting for common issues