| name | adr-007-raw-yaml-over-helm-for-initial-development | |||
|---|---|---|---|---|
| description | Use raw Kubernetes YAML instead of Helm charts during initial development phase | |||
| triggers |
|
|||
| instructions | Use raw Kubernetes YAML for all infrastructure services in Tiltfile (CockroachDB, Redis, Kafka, Zookeeper). Defer Helm adoption until service topology stabilizes and multi-environment deployment becomes necessary. |
Date: 2025-10-29
Accepted
Meridian uses Kubernetes for deployment and Tilt for local development. The project needs to define backing services (CockroachDB, Redis, Kafka, Zookeeper) for local development.
The question: Should we use Helm charts or raw Kubernetes YAML for defining these services in the Tiltfile?
Helm is primarily a templating engine that allows:
Same Helm Chart + Different Values Files = Different Environments
The benefits are:
- Environment parity: Same chart for local/staging/prod with different values
- Dependency management: Charts can depend on other charts
- Versioning: Chart versions track configuration changes
- Community: Large ecosystem of pre-built charts
Using Helm introduces additional abstraction layers:
- Application code
- Container (Docker)
- Kubernetes primitives (Pods, Services, Deployments)
- Helm templates (Go templating over Kubernetes YAML)
- Helm values (configuration inputs to templates)
- Tilt (orchestrating everything)
When debugging a failing pod, you must reason through all six layers:
- Is my code wrong?
- Is the Dockerfile wrong?
- Is the Kubernetes YAML wrong?
- Did the Helm template render correctly?
- Are my values correct?
- Is Tilt configured properly?
This is particularly challenging when:
- Bootstrapping a new project with evolving infrastructure requirements
- Debugging service connectivity issues
- Rapidly iterating on infrastructure setup
- Maintaining transparency about what's actually running in the cluster
For initial development, use raw Kubernetes YAML instead of Helm charts:
- Use raw YAML for all backing services: CockroachDB, Redis, Kafka, and Zookeeper are all defined as inline YAML in the Tiltfile
- Keep configurations simple: Single-node deployments with minimal but complete configuration
- Defer Helm migration: Plan to migrate to Helm charts once service topology stabilizes and multi-environment deployment becomes necessary
This is a conscious architectural decision, not an oversight. We are explicitly choosing transparency and iteration velocity over environment abstraction during the bootstrap phase, prioritizing rapid development over premature optimization.
- Transparency: Direct visibility into deployed resources accelerates debugging and understanding
- Iteration speed: Faster feedback loops when configuration changes are immediately visible
- Reduced complexity: Minimize abstraction layers during bootstrap phase when requirements are evolving
- Service stability: Service topology is still evolving; premature abstraction creates unnecessary churn
- Deferred value: Helm's multi-environment capabilities aren't needed until we have multiple deployment targets
- Complete but minimal: Even complex services like Kafka can be configured simply for local development
- Transparent: What you see in the Tiltfile is what runs in Kubernetes
- Fast iteration: Direct YAML editing, no template rendering to debug
- Lower cognitive overhead: Fewer abstraction layers when troubleshooting
- Direct control: Explicit configuration without indirection through templating
- Simpler debugging: Fewer places for configuration to go wrong
- Environment-specific configuration: Will require separate YAML files for staging/prod
- No dependency management: Service startup order handled by Tilt, not Helm
- Manual version management: No chart versioning for infrastructure configuration
- Duplication: Some YAML patterns may be repeated across services
When service topology stabilizes, migrate to Helm:
-
Identify parameterization points: What differs between environments?
- Resource limits (CPU, memory)
- Storage (local vs cloud)
- Networking (NodePort vs LoadBalancer)
- Secrets (dev vs prod credentials)
-
Create Helm charts: Package stable service definitions
charts/meridian/- Main application chartcharts/backing-services/- Infrastructure services chart
-
Multi-environment values:
values-local.yaml- Minimal resources, NodePortvalues-stage.yaml- Moderate resources, cloud storagevalues-prod.yaml- HA, multiple replicas, production secrets
-
Update Tiltfile: Replace raw YAML with
helm_remote()calls -
Production deployment: Use Helm for staging and production environments
# Tiltfile
k8s_yaml(blob('''
apiVersion: v1
kind: Service
metadata:
name: redis
spec:
ports:
- port: 6379
selector:
app: redis
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
spec:
replicas: 1
template:
spec:
containers:
- name: redis
image: redis:7-alpine
resources:
limits:
memory: 512Mi
'''))Benefits: Direct visibility, easy to modify, clear what's deployed
# Tiltfile
helm_remote(
'redis',
repo_name='bitnami',
repo_url='https://charts.bitnami.com/bitnami',
values=['deployments/helm/redis-values-local.yaml']
)# deployments/helm/redis-values-local.yaml
replica:
replicaCount: 1
resources:
limits:
memory: 512MiBenefits: Environment abstraction, versioning, community support Costs: Additional file, template indirection, chart maintenance
- ADR-0006: Tilt for Local Kubernetes Development
- Future ADR: Multi-environment deployment strategy