Deployment
The platform is containerized and deployed with Kamal, Rails’ own zero-downtime deploy tool. The goal is a production setup one engineer can run and reason about — no Kubernetes control plane to babysit.
Containers
Everything is defined in Docker:
Dockerfile— the production image: a slim, multi-stage build with assets precompiled and Thruster in front for asset compression and HTTP caching.Dockerfile.dev+docker-compose.yml— the local stack: the app, PostgreSQL, and Redis, so a new developer is onedocker compose upfrom a running store.
The running app is several processes from the same image: the Puma web server, a Solid Queue worker, and a Sidekiq worker — see Background Jobs.
Deploying with Kamal
Kamal builds the image, pushes it to a registry, and rolls it out across hosts
with a health-checked, zero-downtime swap. Production configuration lives in
config/deploy.yml.
Redis runs as a Kamal accessory (ecommerce_app-redis) on the shared
kamal network. Operational note: rebooting it —
export KAMAL_REGISTRY_PASSWORD=... # required first
kamal accessory reboot redis
— needs the registry password exported, because .kamal/secrets references it.
And because Redis is a fail-open dependency,
that reboot degrades the site rather than downing it.
Health checks
Two endpoints serve two audiences:
/up— a pure boot check; “is the process alive?” Used by the orchestrator at start-up./health— a deeper check reporting database, Redis, and queue status. It deliberately returns HTTP 200 even when Redis is degraded, so the load balancer never pulls a node that is still serving shoppers. See Redis Resilience for why.
Observability
- Prometheus — metrics exported from the app, including queue depth and request timings.
- Sentry — exception tracking, wired so production errors (including reported Redis failures) surface immediately.
- Mission Control — Jobs — a dashboard over both job backends.
Configuration
Configuration is environment-driven. env.example and
.env.production.example document every variable — database URLs, Redis pool
sizing, SES credentials, payment-gateway keys, and the RACK_ATTACK_*
rate-limit knobs — so a new environment is a
matter of filling in values, not reading source.
Key files
| Concern | Files |
|---|---|
| Images | Dockerfile, Dockerfile.dev, docker-compose.yml |
| Deploy | config/deploy.yml, .kamal/, bin/kamal |
| Health | HealthController — /up, /health |
| Config | env.example, .env.production.example |