Kamal Deployment
Kamal is a zero-downtime deployment tool for containerized applications, originally built by 37signals for deploying Rails apps but works with any containerized web application.
Core Concepts
Philosophy: Kamal uses an imperative "push" model where you explicitly tell servers what to do, unlike declarative tools like Kubernetes. It combines SSH, Docker, and Kamal Proxy to achieve zero-downtime deployments.
Components:
-
SSH/SSHKit: Remote command execution
-
Docker: Container runtime and image management
-
Kamal Proxy: Reverse proxy for zero-downtime deployments (routes traffic between container versions)
-
Accessories: Supporting services (PostgreSQL, MySQL, Redis, etc.)
When to Use This Skill
Use this skill when you need to:
-
Set up Kamal for a new project
-
Configure config/deploy.yml or understand configuration options
-
Deploy applications or troubleshoot deployment failures
-
Manage multiple environments (staging, production)
-
Configure accessories (databases, Redis, etc.)
-
Debug deployment issues or container problems
-
Perform rollbacks or maintenance mode
-
Understand Kamal commands and workflows
-
Set up CI/CD pipelines with Kamal
Quick Start Workflow
Initial Setup
1. Install Kamal
gem install kamal
2. Initialize configuration
cd your-app kamal init
3. Edit config/deploy.yml
- Set service name and image
- Add server IP addresses
- Configure registry credentials
- Set environment variables
4. Configure secrets in .kamal/secrets
KAMAL_REGISTRY_PASSWORD=your-token RAILS_MASTER_KEY=your-key
5. Run initial setup (installs Docker, deploys everything)
kamal setup
Standard Deploy
kamal deploy # Build, push, deploy with zero downtime kamal deploy -d staging # Deploy to staging environment kamal app logs -f # Follow application logs
Common Operations
kamal app exec -i --reuse "bin/rails console" # Rails console kamal app logs -g "error" # Search logs kamal rollback <version> # Rollback kamal app maintenance # Maintenance mode kamal app live # Exit maintenance
Configuration Patterns
Basic deploy.yml Structure
service: myapp image: username/myapp
servers: web: - 192.168.1.10
registry: server: ghcr.io username: myuser password: - KAMAL_REGISTRY_PASSWORD
env: secret: - RAILS_MASTER_KEY clear: RAILS_ENV: production
proxy: ssl: true host: example.com
Multi-Server with Roles
servers: web: hosts: - 192.168.1.10 - 192.168.1.11 worker: hosts: - 192.168.1.12 cmd: bundle exec sidekiq
Accessories (Supporting Services)
accessories: postgres: image: postgres:15 host: 192.168.1.20 port: 5432 env: secret: - POSTGRES_PASSWORD clear: POSTGRES_DB: myapp_production directories: - data:/var/lib/postgresql/data
redis: image: redis:7 host: 192.168.1.21 directories: - data:/data
For comprehensive configuration options, see references/configuration.md.
Essential Commands
Deployment
-
kamal init
-
Initialize configuration files
-
kamal setup
-
First-time setup (installs Docker, deploys everything)
-
kamal deploy
-
Standard deploy with zero downtime
-
kamal redeploy
-
Fast redeploy (skips proxy setup)
-
kamal rollback VERSION
-
Rollback to previous version
Application Management
-
kamal app logs [-f]
-
View logs (follow with -f)
-
kamal app exec "COMMAND"
-
Run command in container
-
kamal app exec -i --reuse "bash"
-
Interactive shell
-
kamal app maintenance
-
Enable maintenance mode
-
kamal app live
-
Disable maintenance mode
-
kamal app containers
-
List all containers (for rollback)
-
kamal app version
-
Show deployed version
Accessories
-
kamal accessory boot NAME
-
Start accessory
-
kamal accessory logs NAME [-f]
-
View accessory logs
-
kamal accessory exec NAME "CMD"
-
Run command in accessory
Troubleshooting
-
kamal config
-
Show parsed configuration
-
kamal lock status
-
Check deployment lock
-
kamal lock release
-
Release stuck lock
-
kamal server exec "CMD"
-
Run command on host
Multiple Environments
-
kamal deploy -d staging
-
Deploy to staging
-
kamal deploy -h 192.168.1.10
-
Deploy to specific host
-
kamal deploy -r web
-
Deploy to specific role
For complete command reference, see references/commands.md.
Common Workflows
Deploy with Database Migration
Using pre-deploy hook (recommended):
Create .kamal/hooks/pre-deploy :
#!/bin/bash kamal app exec -p -q "bin/rails db:migrate"
chmod +x .kamal/hooks/pre-deploy kamal deploy
Rollback Workflow
Check what went wrong
kamal app logs
List available versions
kamal app containers
Rollback to previous version
kamal rollback abc123def
Debugging Failed Deployments
-
Check logs: kamal app logs -n 500
-
Check container status: kamal server exec "docker ps -a"
-
Test health endpoint: kamal app exec "curl localhost:3000/up"
-
Check configuration: kamal config
-
Release stuck locks: kamal lock release
Multiple Environments Pattern
Create environment-specific configs:
-
config/deploy.yml (production)
-
config/deploy.staging.yml
kamal setup -d staging kamal deploy -d staging kamal deploy # production
For detailed workflows, troubleshooting guides, and best practices, see references/workflows.md.
Database and Accessory Management
Running Commands in Accessories
PostgreSQL
kamal accessory exec postgres "psql -U myapp" kamal accessory exec postgres "pg_dump -U myapp myapp_production" > backup.sql
Redis
kamal accessory exec redis "redis-cli"
MySQL
kamal accessory exec mysql "mysql -u root -p myapp_production"
Litestream (SQLite Replication)
kamal accessory exec litestream "litestream generations /data/production.sqlite3" kamal accessory exec litestream "litestream restore /data/production.sqlite3"
Configuration for Common Scenarios
Custom SSH User/Port
ssh: user: deploy port: 2222
Custom Build Context
builder: context: . dockerfile: Dockerfile.production args: RUBY_VERSION: 3.2.0
Health Check Configuration
healthcheck: path: /up port: 3000 interval: 10 max_attempts: 7
Aliases for Common Commands
aliases: console: app exec --interactive --reuse "bin/rails console" shell: app exec --interactive --reuse "bash" logs: app logs -f
Use: kamal console instead of full command.
CI/CD Integration
GitHub Actions Example
- name: Deploy env: KAMAL_REGISTRY_PASSWORD: ${{ secrets.REGISTRY_TOKEN }} RAILS_MASTER_KEY: ${{ secrets.RAILS_MASTER_KEY }} run: | gem install kamal kamal deploy
Key Limitations
-
No automatic state reconciliation - Kamal won't automatically decommission containers if you remove them from config
-
No dynamic provisioning - Cannot auto-scale or provision servers on demand
-
Single-server load balancing only - Kamal Proxy balances containers on each server, not across servers (use external load balancer for that)
References
This skill includes comprehensive reference documentation:
-
configuration.md - Complete config/deploy.yml reference with all options, registry configurations, accessory setups, and example configurations
-
commands.md - Detailed command reference for all Kamal CLI commands with options and examples
-
workflows.md - Common deployment workflows, troubleshooting patterns, CI/CD integration, security best practices, and production guidelines
Read these references when you need detailed information about specific configuration options, commands, or deployment patterns.