← All projects

A platform for the application there was, and the ones coming next

Before · per application1
Now · shared3
nodes for all of them
Sector
Internal platform, on self-hosted servers
Duration
10 days · in use from the first month
Role
End-to-end design and execution

01Where it started

Everything lived on a single virtual machine: the application server, the database, and the files users upload, all three on the same disk. Any hardware failure took all three at once. The configuration was written inside the application and changes had been made by hand, leaving no record: if that machine were lost, nobody could put it back together the same way — it would have to be rebuilt by trial. And with a single instance, releasing a version meant shutting the service down, so releases happened at night, on Sundays, or not at all. But none of that is what settled the budget. What settled it is that this one was not alone. More applications were coming, starting with a website and a database of its own, and each would repeat the pattern — another virtual machine, hand-configured, with a single disk of its own.

02What could not move

  • One physical server: 30 GB of memory and 16 cores for everything.
  • The business code is not rewritten. Only how it is configured changes.
  • This is real data: zero rows lost, no exceptions.
  • What is not declared in the repository does not exist.

03The decision

A container platform across three nodes, with the application moved exactly as it was: the only change is where it reads its configuration from, hard-coded values becoming environment variables. The cheap alternative was weighed and discarded — two machines with a replicated database and a load balancer in front — and it has to be said that for a single application that was the right answer: fewer pieces, less to learn, fewer ways to break. A cluster for one application is over-engineering. The platform was chosen because it was not one application, it was the ones coming: the cost of building and learning it is paid once, and adding the second is adding a file to the repository rather than repeating the whole job, database replication included. It also settled two things the two-machine scheme leaves to you: the files, which need simultaneous read and write from any node and otherwise force you to stand up and maintain a separate file server; and automatic database failover with point-in-time recovery and backups declared alongside the database, which the other way round are scripts of your own to write, test and maintain. These are self-hosted servers with no option of renting a managed service, so the real alternative was always to build it yourself: the question was how much of what you build serves what comes next.

04The trade-off

What it cost
An application that used to live on one virtual machine now depends on four new pieces: distributed storage, a database operator, a deployment engine, and a secrets manager. Each has failure modes of its own and they have to be learnt. The platform consumes memory from the server before a single line of the application runs, and several components had to have their reservations tuned for it all to fit. On top of that, a badly reviewed deploy can now delete a volume with data in it: which is why all ten components were left on manual approval.
Why it was worth it
That price is paid once and spread across everything that comes after. The next application lands in minutes on the same storage, the same managed database, and the same deployment path. And the configuration stopped living in the memory of whoever built the server: it is in a repository, with history, and with every change laid out before it is applied.

05What went wrong

During the cutover the old application was shut down, and its virtual machine with it. A restart of the physical server, days later, handed the whole thing back: the machine had automatic start-up set on the hypervisor, one layer below where anyone had looked. It came back with the application running against the old database, ready to accept writes nobody would ever see. It was caught by comparing row counts across both environments, still identical, so nothing had diverged. The machine’s automatic start-up was removed, and the application’s nightly scheduled job switched off with it. Shutting something down is not taking it out of circulation, and in a migration the source has as many ways back as it has layers beneath it: the service, the machine and the hypervisor are three separate switches.

06What came of it

The cutover took 20 minutes, with row counts verified before freezing the source and after importing into the target: identical. The application was left with two replicas, the database with three copies and automatic failover, and the users’ files on storage reachable from any node. The whole platform, the engine that deploys it included, is declared in a repository, and the credentials travel encrypted inside that same repository. Adding the next application is no longer standing up another server: it is adding a file. The old machine was not decommissioned: it sits powered off and within reach, as the way back should the cluster fail. One limit was declared from day one: the three machines run on a single physical server, so the high availability is logical rather than physical — it covers the loss of a node or a disk, not of the server. The way to close it is known: a second box and off-site backups. The general rule: a declarative repository gives you back your configuration, never your data. They are two different problems, each needs its own answer, and treating them as one solved problem is the expensive mistake.

Something similar in front of you? Tell me what you are dealing with and I will reply, almost always within 24 hours.

Get in Touch