Skip to main content
Version: 0.4 (Next)

Catalog Examples

Real-world catalog examples demonstrating common patterns and best practices.

YAML Catalog Example: Prometheus Monitoring

Deploy a complete Prometheus monitoring stack with Grafana dashboards.

Directory Structure:

catalog/prometheus-monitoring/
├── Chart.yaml
├── values.yaml
└── templates/
└── application.yaml

Chart.yaml:

apiVersion: v2
name: prometheus-monitoring
description: Prometheus monitoring stack with Grafana dashboards
type: application
version: 0.2.0
appVersion: "2.45.0"

values.yaml:

# @input.type: string
# @input.description: Target cluster name
# @input.required: true
clusterName: my-cluster

# @input.type: string
# @input.description: Namespace for monitoring stack
# @input.required: true
# @input.default: monitoring
namespace: monitoring

# @input.type: enum
# @input.description: Enable Grafana dashboards
# @input.options: true,false
# @input.required: true
# @input.default: true
grafanaEnabled: true

# @input.type: string
# @input.description: Data retention period (e.g., 15d, 30d)
# @input.required: false
# @input.default: 15d
retentionPeriod: 15d

# @input.type: enum
# @input.description: Enable alerting rules
# @input.options: true,false
# @input.required: false
# @input.default: true
alertingEnabled: true

# @input.type: secret
# @input.description: Grafana admin password
# @input.required: true
# @input.secretKey: admin-password
# @input.secretEnv: GRAFANA_ADMIN_PASSWORD
# @input.secretBackend: vault
# @input.secretPath: /prometheus-monitoring
grafanaAdminPassword: ""

# Standard values
# @input.type: string
# @input.description: Target cluster destination
# @input.required: true
# @input.default: in-cluster
clusterDestination: in-cluster

# @input.type: string
# @input.description: ArgoCD project
# @input.required: true
# @input.default: platform
project: platform

templates/application.yaml:

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: {{ .Values.clusterName }}-prometheus
namespace: argocd
annotations:
kubefirst.konstruct.io/application-name: prometheus-monitoring
kubefirst.konstruct.io/source: catalog-templates
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
destination:
namespace: {{ .Values.namespace }}
name: {{ .Values.clusterDestination }}
project: {{ .Values.project }}
source:
chart: kube-prometheus-stack
repoURL: https://prometheus-community.github.io/helm-charts
targetRevision: "48.3.1"
helm:
releaseName: prometheus
values: |
prometheus:
prometheusSpec:
retention: {{ .Values.retentionPeriod }}
{{- if .Values.alertingEnabled }}
enableAlertmanager: true
{{- end }}
grafana:
enabled: {{ .Values.grafanaEnabled }}
{{- if .Values.grafanaEnabled }}
adminPassword:
valueFrom:
secretKeyRef:
name: grafana-secret
key: admin-password
{{- end }}
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true

IAC Catalog Example: RDS PostgreSQL Database

Provision a production-ready PostgreSQL database with security best practices.

Directory Structure:

rds-postgres/
├── provider
├── main.tf
├── variables.tf
└── outputs.tf

provider:

terraform {
backend "s3" {
bucket = "<BUCKET_NAME>"
key = "registry/clusters/<NAME>/infrastructure/rds-postgres/terraform.tfstate"
region = "<REGION>"
encrypt = true
}
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.30.0, < 6.0.0"
}
random = {
source = "hashicorp/random"
version = ">= 3.6.0, < 4.0.0"
}
}
}

provider "aws" {
region = "<REGION>"
allowed_account_ids = ["<ACCOUNT_ID>"]
assume_role_with_web_identity {
session_name = "kubefirst-pro"
role_arn = "<ROLE_ARN>"
web_identity_token_file = "/var/run/secrets/eks.amazonaws.com/serviceaccount/token"
}
}

main.tf:

resource "random_password" "db_password" {
length = 32
special = true
}

resource "aws_db_subnet_group" "main" {
name = "${var.database_name}-subnet-group"
subnet_ids = var.subnet_ids

tags = {
Name = "${var.database_name}-subnet-group"
}
}

resource "aws_security_group" "db" {
name = "${var.database_name}-sg"
description = "Security group for ${var.database_name} RDS instance"
vpc_id = var.vpc_id

ingress {
from_port = 5432
to_port = 5432
protocol = "tcp"
cidr_blocks = var.allowed_cidrs
}

egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}

tags = {
Name = "${var.database_name}-sg"
}
}

resource "aws_db_instance" "postgres" {
identifier = var.database_name
engine = "postgres"
engine_version = var.postgres_version
instance_class = var.instance_class
allocated_storage = var.allocated_storage
storage_encrypted = true
db_name = replace(var.database_name, "-", "_")
username = "postgres"
password = random_password.db_password.result
db_subnet_group_name = aws_db_subnet_group.main.name
vpc_security_group_ids = [aws_security_group.db.id]
skip_final_snapshot = var.skip_final_snapshot
backup_retention_period = var.backup_retention_days
multi_az = var.multi_az
publicly_accessible = false

tags = {
Name = var.database_name
Environment = var.environment
ManagedBy = "Terraform"
}
}

resource "aws_secretsmanager_secret" "db_credentials" {
name = "${var.database_name}-credentials"
}

resource "aws_secretsmanager_secret_version" "db_credentials" {
secret_id = aws_secretsmanager_secret.db_credentials.id
secret_string = jsonencode({
username = aws_db_instance.postgres.username
password = random_password.db_password.result
endpoint = aws_db_instance.postgres.endpoint
port = aws_db_instance.postgres.port
database = aws_db_instance.postgres.db_name
})
}

variables.tf:

variable "database_name" {
description = "Name of the database instance"
type = string
}

variable "postgres_version" {
description = "PostgreSQL version"
type = string
default = "15.3"
}

variable "instance_class" {
description = "RDS instance class"
type = string
default = "db.t3.micro"
}

variable "allocated_storage" {
description = "Allocated storage in GB"
type = number
default = 20
}

variable "vpc_id" {
description = "VPC ID for security group"
type = string
}

variable "subnet_ids" {
description = "List of subnet IDs for DB subnet group"
type = list(string)
}

variable "allowed_cidrs" {
description = "List of CIDR blocks allowed to connect"
type = list(string)
}

variable "skip_final_snapshot" {
description = "Skip final snapshot on deletion"
type = bool
default = false
}

variable "backup_retention_days" {
description = "Number of days to retain backups"
type = number
default = 7
}

variable "multi_az" {
description = "Enable multi-AZ deployment"
type = bool
default = false
}

variable "environment" {
description = "Environment name"
type = string
}

outputs.tf:

output "db_instance_endpoint" {
description = "Database instance endpoint"
value = aws_db_instance.postgres.endpoint
}

output "db_instance_arn" {
description = "Database instance ARN"
value = aws_db_instance.postgres.arn
}

output "db_instance_port" {
description = "Database port"
value = aws_db_instance.postgres.port
}

output "db_name" {
description = "Database name"
value = aws_db_instance.postgres.db_name
}

output "secret_arn" {
description = "ARN of secrets manager secret with credentials"
value = aws_secretsmanager_secret.db_credentials.arn
}

output "security_group_id" {
description = "Security group ID for database"
value = aws_security_group.db.id
}

Hybrid Catalog Example: Redis with Management UI

Provision Redis ElastiCache and deploy RedisInsight management UI.

This example combines:

  • IAC: AWS ElastiCache Redis cluster
  • YAML: RedisInsight management application

Key Files (Condensed):

values.yaml (Combined):

# Application parameters
# @input.type: string
# @input.description: Application name
# @input.required: true
appName: redis-insight

# @input.type: string
# @input.description: Namespace
# @input.required: true
# @input.default: redis
namespace: redis

# Infrastructure parameters
# @input.type: string
# @input.description: Redis cluster name
# @input.required: true
redisClusterName: my-redis

# @input.type: enum
# @input.description: Redis node type
# @input.options: cache.t3.micro,cache.t3.small,cache.m5.large
# @input.required: true
# @input.default: cache.t3.micro
redisNodeType: cache.t3.micro

# @input.type: string
# @input.description: Number of cache nodes
# @input.required: true
# @input.default: 1
numCacheNodes: 1

# @input.type: string
# @input.description: Redis engine version
# @input.required: true
# @input.default: 7.0
redisVersion: 7.0

# Standard values
# @input.type: string
# @input.description: VPC ID
# @input.required: true
vpcId: vpc-xxxxx

# @input.type: string
# @input.description: Subnet IDs (comma-separated)
# @input.required: true
subnetIds: subnet-xxxxx,subnet-yyyyy

main.tf (Redis ElastiCache):

resource "aws_elasticache_subnet_group" "redis" {
name = "${var.redis_cluster_name}-subnet-group"
subnet_ids = split(",", var.subnet_ids)
}

resource "aws_security_group" "redis" {
name = "${var.redis_cluster_name}-sg"
description = "Security group for Redis cluster"
vpc_id = var.vpc_id

ingress {
from_port = 6379
to_port = 6379
protocol = "tcp"
cidr_blocks = ["10.0.0.0/8"]
}
}

resource "aws_elasticache_cluster" "redis" {
cluster_id = var.redis_cluster_name
engine = "redis"
engine_version = var.redis_version
node_type = var.redis_node_type
num_cache_nodes = var.num_cache_nodes
parameter_group_name = "default.redis7"
subnet_group_name = aws_elasticache_subnet_group.redis.name
security_group_ids = [aws_security_group.redis.id]

tags = {
Name = var.redis_cluster_name
}
}

templates/application.yaml (RedisInsight UI):

apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: {{ .Values.clusterName }}-{{ .Values.appName }}
namespace: argocd
spec:
destination:
namespace: {{ .Values.namespace }}
name: {{ .Values.clusterDestination }}
project: {{ .Values.project }}
source:
chart: redisinsight
repoURL: https://charts.redis.com
targetRevision: "1.0.0"
helm:
values: |
redis:
host: {{ .Values.redisEndpoint }}
port: 6379
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true

Common Patterns

Pattern 1: External Secrets Integration

Use External Secrets to fetch infrastructure credentials:

apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: {{ .Values.appName }}-secrets
namespace: {{ .Values.namespace }}
spec:
secretStoreRef:
name: aws-secrets-manager
kind: SecretStore
target:
name: app-secrets
data:
- secretKey: database-url
remoteRef:
key: {{ .Values.secretArn }}
property: endpoint

Pattern 2: Multi-Environment Configuration

Use environment-specific values:

# @input.type: enum
# @input.description: Deployment environment
# @input.options: dev,staging,prod
# @input.required: true
environment: dev

# @input.type: string
# @input.description: Instance size (varies by environment)
# @input.required: true
# @input.default: small
instanceSize: {{ if eq .Values.environment "prod" }}large{{ else }}small{{ end }}

Pattern 3: Conditional Resource Deployment

Deploy resources based on flags:

{{- if .Values.monitoringEnabled }}
---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: {{ .Values.clusterName }}-monitoring
# ... monitoring application
{{- end }}

What's Next?