Ops: Deploy
Deploy the Rails application to remote environments.
Argument: $ARGUMENTS — environment (staging, production) and optional method (kamal, ci; default: kamal)
Safety
CRITICAL: Production deployments require explicit human confirmation before proceeding. Always ask for confirmation when $ARGUMENTS contains production.
Discovery
- Read
config/deploy.ymlto discover the Kamal configuration: service name, registry, image, servers, accessories - Read
config/deploy.staging.ymlandconfig/deploy.production.ymlfor environment-specific overrides - Verify the specific environment-variable keys needed for the deploy are present in
.env.staging/.env.production(or in SSM) without printing secret values - Read
Dockerfileto understand the Docker build stages
CI/CD Path (Preferred)
The standard deployment path is via CI/CD — pushing to environment branches triggers auto-deploy.
# Deploy to staging via CI/CD
git push origin HEAD:staging
# Deploy to production via CI/CD (requires human confirmation first)
git push origin HEAD:production
Monitor the deployment via GitHub Actions:
gh run list --branch {environment} --limit 3
gh run watch {run-id}
Kamal Deployment (Manual)
Pre-Deploy Checks
Verify Kamal is installed:
kamal versionVerify Docker builds locally:
docker build -t {app_name}:test .Check current deployment state:
kamal details -d {environment}Check for deploy lock:
kamal lock status -d {environment}If locked from a previous interrupted deploy:
kamal lock release -d {environment}
Deploy to Staging
kamal deploy -d staging
Deploy to Production
Requires explicit human confirmation.
kamal deploy -d production
Deploy with Specific Git Ref
kamal deploy -d {environment} --version {git-sha-or-tag}
Rollback
If a deploy causes issues, roll back to the previous version:
# List available versions
kamal app containers -d {environment}
# Rollback to previous version
kamal rollback {previous-version} -d {environment}
Post-Deploy Verification
After any deployment:
Health check the deployed environment:
curl -sf -o /dev/null -w "HTTP %{http_code} in %{time_total}s" https://{app_host}/upVerify ECS service stability (running count matches desired count):
aws ecs describe-services \ --cluster {cluster-name} \ --services {service-name} \ --region {aws-region} \ --query 'services[0].{Running:runningCount,Desired:desiredCount,Status:status}' \ --output tableCheck for migration status (if migrations were included):
kamal app exec --roles=web "bin/rails db:migrate:status" -d {environment}Check logs for errors in the first 5 minutes (use
ops-check-logsskill)Verify Solid Queue workers are running (use
ops-verify-jobsskill)Verify OpenTelemetry traces are being exported (use
ops-verify-telemetryskill)
Kamal Utility Commands
| Command | Purpose |
|---|---|
kamal details -d {env} |
Show current deployment details |
kamal app logs -d {env} |
Tail application logs |
kamal app exec --roles=web "bin/rails console" -d {env} |
Open Rails console on remote |
kamal audit -d {env} |
Show deploy audit log |
kamal env push -d {env} |
Push updated environment variables |
kamal lock status -d {env} |
Check deploy lock status |
kamal lock release -d {env} |
Release a stale deploy lock |
kamal traefik reboot -d {env} |
Restart the Traefik proxy |
Output Format
Report deployment result as a table:
| Target | Environment | Method | Status | Verification |
|---|---|---|---|---|
| Rails app | staging | Kamal | SUCCESS/FAIL | /up returns 200 |
| ECS tasks | staging | N/A | STABLE/UNSTABLE | running == desired |
| Solid Queue | staging | N/A | RUNNING/DOWN | workers have heartbeat |