# 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 one `docker compose up` from 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](/architecture/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 — ```bash 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](/architecture/redis-resilience/), 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](/architecture/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](/architecture/rate-limiting/) 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` |