feat/docker-deploy #105
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/docker-deploy"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
A two-stage image — a Debian bookworm builder for the four C dependencies (bcrypt, exqlite, crc, bzip2) and a hardened distroless runtime carrying ERTS, the release and libbz2 and nothing else. 104 MB, no Mix, no Elixir, no toolchain, uid 65532. The cache is never in it: operators supply their own and it is bind-mounted read-only, as the BYO-cache rule requires. The larger half of this is a config restructure, and it was not optional. `config.exs` read the environment with `System.get_env/2`, and that file is evaluated when the tree is BUILT — inside the builder container, for a release — so every value would have been frozen into the image and no `docker run -e` could have moved it. `config/runtime.exs` is now the one file that touches the environment, evaluated at boot under `mix run`, `mix test` and the release alike. Two things stay behind on purpose: `config_env()`, and the database adapter, which `use Ecto.Repo` bakes into generated code and which is therefore a build ARG. That move repaired three faults that had nothing to do with containers: * the SQLite default expanded to `Path.expand("../priv/repository/…")`, which under a release is the BUILDER's source tree — a path absent from the image; * `pool_size` was `System.schedulers_online()` evaluated at build, baking the build machine's core count into the deployment; * a variable set to the empty string was not the same as an unset one, and Compose substitutes an unset `${VAR:-}` to `""` rather than omitting the key — so an optional `REVENANT_ADMIN_PORT` would have reached `String.to_integer/1` and taken the boot down. Blank now counts as absent everywhere. `.env` is read by the server itself as well as by Compose, so a bare-metal run behaves like a container. The real environment always wins over the file. Eight `config.exs` blocks setting keys nothing in this project reads are gone — those variables are read by the converter in its own project. Their prose is kept as a comment block beside the tables they produce. `elixirc_paths/1` no longer compiles `lib/mix` outside dev and test. A Mix task has no business in a release: `:mix` is not an application it carries, and the bench task calls `:eprof`, which `profiling_apps/1` keeps out of :prod deliberately and which warned on every release build. No migration step is sequenced anywhere, because `Database.Migrator` brings the schema current at boot. The panel is off unless `REVENANT_ADMIN_PORT` names a port, binds 0.0.0.0 inside the container because Docker forwards a published port to eth0 rather than loopback, and is published to the HOST loopback only — an SSH tunnel is how it is reached. The forge builds and pushes the image when main advances. What a green run there proves is narrower than it looks and the workflow says so: the image is never started, because without a cache the application does not boot and no workflow file may name a place to get one. Verified by building and running it: the world comes up against the real rev-149 cache — collision decoded, 17,906 NPCs, listener on 43594 — the panel answers 401 without a credential, 401 with a wrong one and 200 with the right one, the schema is created in the mounted volume, and SIGTERM unwinds the tree in 1.3s. One trap is recorded in the compose file because it cost a boot: a bind mount copies a symlink AS a symlink and resolves it inside the container, so a linked cache directory arrives dangling and the server reports "No index file(s) present" having found the directory perfectly well.