Skip to content

Best Practices

This guide covers best practices for using frank effectively in production environments.

Configuration

1. Hierarchical Structure

Good - Clear hierarchy with inheritance:

config/
├── config.yaml              # Base: project_code, timeout
├── dev/
│   ├── config.yaml          # Override: context=dev
│   └── app.yaml             # App config
├── staging/
│   ├── config.yaml          # Override: context=staging
│   └── app.yaml             # App config
└── prod/
    ├── config.yaml          # Override: context=prod
    └── app.yaml             # App config

Avoid - Flat structure with duplication:

config/
├── dev-config.yaml
├── staging-config.yaml
├── prod-config.yaml
├── dev-app.yaml
├── staging-app.yaml
└── prod-app.yaml

2. Keep App Configs Simple

Good - Minimal app config:

manifest: app-deployment.jinja
app: web
version: 1.2.3

Avoid - Duplicating base config:

manifest: app-deployment.jinja
context: dev-cluster
project_code: myapp
namespace: myapp-dev
app: web
version: 1.2.3

3. Use Environment Variables for Secrets

Good - Use environment variables:

export DOCKER_REGISTRY_PASSWORD=secret123
export API_KEY=your-api-key

Avoid - Secrets in config files:

# config/prod/config.yaml
docker_registry_password: secret123  # DON'T DO THIS!
api_key: your-api-key                # DON'T DO THIS!

Template Design

1. Use Meaningful Variable Names

Good - Clear variable names:

image: {{ image }}:{{ version }}
replicas: {{ replicas | default(3) }}

Avoid - Unclear variable names:

image: {{ img }}:{{ v }}
replicas: {{ r | default(3) }}

2. Provide Sensible Defaults

Good - Always provide defaults:

replicas: {{ replicas | default(3) }}
port: {{ port | default(80) }}
memory: {{ memory | default('256Mi') }}

Avoid - No defaults:

replicas: {{ replicas }}  # Will error if not defined
port: {{ port }}          # Will error if not defined

3. Use Kubernetes Best Practice Labels

Good - Standard labels:

metadata:
  labels:
    app.kubernetes.io/name: {{ app_name }}
    app.kubernetes.io/version: {{ version }}

Avoid - Custom labels:

metadata:
  labels:
    myapp-name: {{ app_name }}
    myapp-version: {{ version }}
    managed-by: frank

4. Keep Templates Readable

Good - Clear structure:

spec:
  replicas: {{ replicas | default(3) }}
  selector:
    matchLabels:
      app.kubernetes.io/name: {{ app }}
  template:
    metadata:
      labels:
        app.kubernetes.io/name: {{ app }}

Avoid - Too much logic:

spec:
  replicas: {{ replicas if replicas else 3 if environment == 'prod' else 2 if environment == 'staging' else 1 }}

Deployment Strategies

1. Test in Dev First (Preferably locally)

Good - Progressive deployment:

$ frank apply dev

$ frank apply staging

$ frank apply prod

Avoid - Direct to production:

# DON'T DO THIS WITHOUT TESTING IN DEV FIRST!
$ frank apply prod

2. Use Stack Filtering

Good - Deploy specific applications:

$ frank apply dev/web
$ frank apply dev/api

Avoid - Deploy everything:

$ frank apply dev  # Unless you really need everything

3. Use Confirmation Prompts

Good - Always confirm before deploying:

$ frank apply  # Shows confirmation with scope

Avoid - Skip confirmation in development:

$ frank apply --yes  # Only in CI/CD

CI/CD Best Practices

1. Use Environment-Specific Configurations

Good - Different configs per environment:

# .github/workflows/deploy.yml
- name: Deploy to dev
  if: github.ref == 'refs/heads/develop'
  run: frank apply dev --yes

- name: Deploy to prod
  if: github.ref == 'refs/heads/main'
  run: frank apply prod --yes

2. Use Rollback Strategies

Good - Plan for rollbacks:

# Keep previous version available
$ kubectl get deployments -l app.kubernetes.io/name=web

# Rollback if needed
$ kubectl rollout undo deployment/web

Performance Optimization

1. Use Appropriate Timeouts

Good - Set reasonable timeouts:

# config/app.yaml
timeout: 10m  # 10 minutes for most apps

Avoid - Too high or too low:

timeout: 0    # No timeout - can hang forever
timeout: 1h   # Too high - slow feedback

2. Use Parallel Deployments

Good - Deploy multiple apps in parallel:

# frank handles this automatically
$ frank apply dev  # Deploys all dev apps in parallel

Troubleshooting

1. Use Debug Logging

Good - Enable debug when needed:

$ FRANK_LOG_LEVEL=debug frank apply dev

2. Monitor Resource Status

Good - Check resource status:

$ kubectl get pods -l app.kubernetes.io/managed-by=frank
$ kubectl describe deployment web

Common Anti-Patterns

1. Don't Put Secrets in Config Files

# DON'T DO THIS!
# config/prod/config.yaml
database_password: secret123
api_key: your-api-key

2. Don't Use Hardcoded Values

# DON'T DO THIS!
# manifests/app-deployment.yaml
spec:
  replicas: 5  # Hardcoded value
  image: nginx:1.20  # Hardcoded image

3. Don't Skip Testing

# DON'T DO THIS!
$ frank apply prod --yes  # Without testing first