A local runtime for a Magento 2 store, in two shapes: a Kubernetes cluster and a Docker Compose stack. They deploy the same image, read the same configuration and the same generated credentials, and run the same install script. Anything that differs between them is a property of the runtime rather than of the application — which is the only reason having both is worth the cost.
Important
This is a workstation environment, not a production one. No cluster here serves traffic, the hardened overlay is called prod-shaped on purpose, and What this doesn't claim is a section rather than a footnote.
A Magento environment is around twenty containers: PHP-FPM, nginx, Varnish, MariaDB, OpenSearch, RabbitMQ, two Redis-compatible caches, six queue consumers and a cron loop. Getting one running is a day. Getting a second one running beside it, for a different branch or a different client, usually means copying the whole thing and then discovering the two stores are sharing a search index.
They share it because Magento's namespacing is spread across five unrelated settings, and four of the five fail silently when they collide. Two stores on one queue vhost consume each other's messages, and the only evidence is work that never happened.
Emporion is one description of a Magento environment with the runtime as a variable. make compose-up gives you a store in under a minute. make new-site SITE=second.test gives you another one, with its own database, cache keys, search index, queue vhost and mail, in about the time a database restore takes. And make up runs the same store on Kubernetes, when your question is about probes, claims or rollout rather than about Magento.
make compose-up && make compose-installThen https://vanilla.test/.
- The problem
- Documentation
- Which runtime, and when
- Requirements
- Two things to know before you start
- Decisions
- Scope
- Licence
| From nothing to a storefront | Start here if you have never run Magento. A bare machine to a working store, and the errors you'll actually meet |
| Getting started | What you need, bringing a store up, and how the install decides what to do |
| The two runtimes | Cluster or Compose, getting a code change into a running store, and the two cluster overlays |
| More than one store | A second storefront on demand, what keeps two stores apart, and snapshots |
| How it's put together | What the runtimes share, the four hard problems, and the layout |
| Running it | Commands, the checks, resource limits, and debugging |
| Examples | A recipe for each everyday task, the cluster explained in plain words, and the traps |
| Configuration | Every setting, which of the four places it lives in, and why |
| Decisions | Eight ADRs, each naming the alternative that nearly won |
| Contributing · Security · Changelog |
| Compose | kind cluster | |
|---|---|---|
| Start it | make compose-up |
make up |
| Time to a serving storefront | under a minute | several, plus a cluster |
| Application code | in the image, or bind-mounted | in the image, or a hostPath under the dev overlay |
| How many stores at once | as many as fit | one; there's no second port for a second host |
| Extra tooling needed | none | kind, kubectl |
| Good for | running the store, day to day | the orchestration questions — probes, claims, rollout, scaling |
Compose is the one to work in. The cluster is the one that answers questions Compose cannot be asked. Neither is a toy version of the other: they run the same image, and a bug that appears in one appears in both.
[!danger] The two runtimes must never run at the same time Both bind the same edge, and running them together means two MariaDB instances, two OpenSearch JVMs and two PHP pools each allowed 4 GiB. On a 31 GB workstation that reaches a load average in the hundreds with swap exhausted.
Both
uptargets refuse while the other runtime is present, and that refusal is the feature. Switching is meant to be cheap instead.This is about runtimes, not about stores. Several stores coexist on Compose because they share the expensive tier and only one does background work at a time. That's a different arrangement with its own guard — see More than one store.
- Docker, with BuildKit, and your reverse proxy's Docker network (below). That's the whole list for the Compose runtime.
- A Magento 2 tree at
MAGENTO_SRC, defaulting tocommerce-vanilla/beside this repository. Nothing here vendors Magento or installs it for you. kindandkubectlfor the cluster runtime only.make toolsinstalls both.- Wildcard DNS for
.testpointing at your Docker bridge, and a reverse proxy in front of it — dnsmasq and nginx-proxy here. The cluster runtime binds127.0.0.1and needs one/etc/hostsline instead. - The proxy's Docker network. The Compose runtime joins it by name and fails to start if it doesn't exist. Set
PROXY_NETWORKto your proxy's network (the default isproxy-dns_default), or, with no proxy at all, create an empty one:docker network create proxy-dns_default. mkcert, and a certificate per hostname inCERTS_HOME. There's no wildcard shortcut; see the callout in Getting started for why. If your setup needs a proxy reloaded after issuing, pointDEV_CERT_TOOLat your own wrapper and it will be called instead.envsubst, from GNU gettext, for the cluster runtime.
Adobe Commerce is licensed, and Magento Open Source is not. MAGENTO_SRC points at whichever tree you have, and nothing in this repository cares which. make sample-data is the one target that does: Adobe's sample data packages come from an authenticated repo.magento.com, so it checks for an auth.json and exits with a named error rather than half-running.
A store is machine state and git does not track it. Creating one writes a small env file and destroying it removes one, so those files are gitignored — with one exception the build needs. make sites reads the filesystem for the list, because which stores exist is a fact about your laptop rather than a claim this repository makes.
One file each, in docs/adr/. Each records the alternative that was nearly chosen and why it lost — that being the single most valuable line in an ADR and the one most often left out.
| # | Decision | The near miss |
|---|---|---|
| 001 | kind, single node | k3d — better on memory, lost on vocabulary |
| 002 | Kustomize over Helm | Helm — real hooks and loops, lost on indirection |
| 003 | Split the concerns; one single-node claim | Object storage — the right answer, not built |
| 004 | Multi-stage, exclusion made loud | Skip the compile — unpicks ADR-003 as a side effect |
| 005 | Varnish behind the edge | Varnish as a sidecar — N caches, one purge |
| 006 | The Magento tree is a build parameter | Vendoring it — tidy-looking, and licensed source in the history |
| 007 | Build both overlays | Drop the dev overlay — cleaner artifact, unusable environment |
| 008 | Compose beside the cluster, one image | Cluster only — one fewer thing, and a minute became several |
ADR-003 and ADR-005 both end with a limitation rather than a resolution. That's the state of the work, not a gap in the writing.
What is here:
- A multi-service Magento stack on Kubernetes and on Compose, from one image and one configuration source — StatefulSets with persistent claims, probes replacing startup ordering,
CronJoband consumer workloads, an ingress-to-Varnish edge. - The specific failure modes worked through and written down:
ReadWriteManyfor a shared webroot, build-time compilation for an immutable image, cache invalidation through an edge that's not the ingress. - Several stores on one machine, with the five namespaces that keep them apart.
What is deliberately not here:
- Any cloud component. Nothing targets EKS, GKE or AKS, and nothing has been run on them.
- Production. No cluster here serves traffic.
prod-shapedis a shape, and is named that way on purpose. - Cluster operations at scale — upgrades, capacity planning, operators, service mesh. A single-node local cluster is the wrong place to model any of them.
- Multi-tenancy, which is not a gap — it is out of scope and stays that way. Several stores share a data tier as a development convenience on one workstation. There's no isolation between them at the database, network or resource level, none is planned, and nothing here should grow toward it. Calling this tenancy would imply a security boundary that doesn't exist and was never wanted.
MIT — see LICENSE. It covers this repository only. Magento itself is not included and is licensed separately, Adobe Commerce commercially and Magento Open Source under OSL-3.0.