Introduction
Kamal manages not just your application containers but also supporting services like databases, caches, and search engines through accessories. Combined with secure secrets management, Kamal provides a complete deployment solution.
Key Concepts
- Accessory: A supporting service (PostgreSQL, Redis, etc.) that Kamal deploys and manages alongside your application.
- Secrets: Sensitive values stored in
.kamal/secretsand injected as environment variables at runtime — never committed to version control. - Destinations: Named deployment targets (staging, production) with different configurations.
Real World Context
Instead of manually installing PostgreSQL on your server and managing backups, Kamal accessories run the database as a Docker container with persistent volumes. One kamal accessory boot db command sets everything up.
Deep Dive
Accessories Configuration
yaml# config/deploy.yml accessories: db: image: postgres:17 host: 192.168.1.4 port: 5432 env: secret: - POSTGRES_PASSWORD volumes: - /data/postgres:/var/lib/postgresql/data search: image: elasticsearch:8.12.0 host: 192.168.1.4 port: 9200 env: clear: discovery.type: single-node xpack.security.enabled: "false" volumes: - /data/elasticsearch:/usr/share/elasticsearch/data
Managing Accessories
bashkamal accessory boot db # Start the database kamal accessory reboot db # Restart the database kamal accessory logs db # View database logs kamal accessory exec db 'psql' # Open psql shell
Secrets Management
bash# .kamal/secrets (never committed to git) KAMAL_REGISTRY_PASSWORD=ghp_xxxxxxxxxxxx RAILS_MASTER_KEY=abc123def456 DATABASE_URL=postgres://app:secret@db:5432/myapp_production POSTGRES_PASSWORD=very_secure_password
yaml# config/deploy.yml env: clear: RAILS_ENV: production SOLID_QUEUE_IN_PUMA: true secret: - RAILS_MASTER_KEY - DATABASE_URL
Destinations for Multi-Environment
yaml# config/deploy.staging.yml servers: web: hosts: - staging.example.com proxy: host: staging.myapp.com
bashkamal deploy --destination staging kamal deploy --destination production
Common Pitfalls
- Committing secrets to git — Add
.kamal/secretsto.gitignore. These contain passwords and API keys that must never be in version control. - Not using persistent volumes for databases — Without a volume mount, database data is lost when the container restarts.
Best Practices
- Use separate hosts for accessories in production — Running the database on the same server as the app means a server failure loses both.
- Use destinations for staging — Maintain separate deploy configurations so staging and production can't be confused.
Summary
- Accessories manage supporting services like databases alongside your app.
- Secrets are stored in
.kamal/secretsand injected as environment variables. - Use persistent volumes for any stateful service (databases, search).
- Destinations allow separate configurations for staging and production.
Code Examples
yaml
# config/deploy.yml — accessories section
accessories:
db:
image: postgres:17
host: 192.168.1.4
port: 5432
env:
secret:
- POSTGRES_PASSWORD
volumes:
- /data/postgres:/var/lib/postgresql/data
# Manage with:
# kamal accessory boot db
# kamal accessory logs db
# kamal accessory exec db 'psql -U postgres'