Build1 distinct publisher3 min readUpdated
A team's Debian 11-to-12 move across 28 hosts put the usual Ansible complaints under load. The failure that actually stopped the run sat in the SSH layer the tool does not own.
The Engineer · Build desk
Compiled by The EngineerSomething wrong?How this is made
Nothing in the play caused the stop at 02:13. A Debian 11 host in the payments group refused the old OpenSSH cipher list [2], which is a property of sshd and the client config on that pair of machines, not of any task in the run. Work backwards from the 41 quiet minutes and the run began around 01:32 [16]. The write-up never says what moved first, and that gap is the interesting part: during a distribution cutover, the transport you automate over is one of the things being upgraded.
The rerun tally is the number worth keeping. Twenty-three hosts ok, four changed, one failed [7] comes to 28 [15], which is the whole fleet [1]. The second pass therefore reached every host including the one that had dropped out, and the only failure left was a stale internal repository key [7]: content, in the play, fixable by whoever owns the key. The unrecoverable class of failure was the transport, and the transport is the part ansible-core 2.17.7 in a pinned virtualenv [3] has no authority over.
The month before the cutover says the same thing. Four separate ways to lose a connection before a single task runs: a stale known_hosts entry, a rotated host key, an expired jump-host certificate, an orphaned control socket under /tmp [8]. Call it one new class of transport failure per week [17], with no distro upgrade to blame. That is the sense in which "it's just SSH" is wrong and still worth respecting. Inventory groups, facts, handlers, check mode and a run history you can query afterwards are all real [5], and the APT source went in through deb822_repository with nginx reloaded only when the file changed [12], which no shell loop gives you across hosts that differ as much as gunicorn nodes, workers with their own systemd limits, and reporting boxes holding an NFS mount [6]. None of it starts without a working socket [4].
The Celery incident belongs to a different family. Six workers restarted on a run that should have reported no changes, because a task was written with state: restarted [11]. The module was idempotent; the play author was not. That is a code review problem rather than a tool problem, and it is precisely what the "safe to rerun" belief conceals [9]. The unit change underneath it, from Restart=always to Restart=on-failure after a wrong RabbitMQ credential produced 9 GB of logs in one on-call shift [10], moves the failure mode from loud to quiet: the next bad credential leaves stopped workers instead of a log flood, and queue depth has to do the detecting.
One more thing about the source itself. The published example breaks off at "- name: Install worker" without the corrected task [13]. On a run whose expensive lesson was a transport failure and whose self-inflicted one was a shortcut inside a handler, that missing snippet is the part everyone else would have copied.
Follow any of these and your For You feed starts watching them — no settings page required.
Ranked by verification strength, evidence, and original report placement.
After fixing the cipher issue, the rerun showed 23 hosts reporting ok, four making the expected package changes, and one failing on a stale internal repository key.
In the preceding month the team saw all four categories of SSH-side failure that can stop a run before a task begins: a stale known_hosts entry, a host key rotation, an expired jump-host certificate, and a control socket left under /tmp.
The published write-up breaks off at the line "- name: Install worker" without showing the replacement task that removed state: restarted.
A team moved 28 application and utility hosts to Debian 12 over three evenings: 14 API nodes, six Celery workers, four reporting boxes, two Redis replicas, and two machines nobody could name without checking NetBox.
At 02:13, the last Debian 11 VM in the payments group stopped accepting the old OpenSSH cipher list, halfway through an Ansible run that had looked boring for 41 minutes.
The team ran ansible-core 2.17.7 from a pinned Python 3.12 virtual environment on the control host.
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
Detailed but wholly self-reported single account
All evidence comes from one self-published practitioner post. It is unusually specific — exact tooling versions, timestamps, host counts, log volume, and two real playbook excerpts — and it is internally consistent, since the rerun tally of 23 ok plus four changed plus one failed reconciles to the stated 28-host fleet. But there is no second source, no logs, no ticket or postmortem artifact, the organisation is unnamed, and the write-up is truncated before its conclusion, so nothing can be independently checked.
One anonymous 28-host fleet
The supplied material documents exactly one adoption footprint: a single unnamed team running ansible-core 2.17.7 against 28 hosts it migrated to Debian 12. That is a real, dated production deployment rather than a demo, but it is one team of unknown size with no downstream users, no second deployment, and no ecosystem-wide usage figures in evidence.
Deflationary framing, mildly over-generalised
The post's rhetoric runs against hype: it debunks 'Ansible is just SSH' and 'idempotent means safe to rerun', and the headline promise — a 28-host cutover and a 02:13 failure Ansible could not have prevented — is delivered in the body. The small positive gap comes from generality: universal verdicts and the framing of 'all four categories' of SSH transport failure as a closed set rest on one unverified fleet's month of incidents, so the conclusions travel further than the evidence behind them.
Practitioner brand-building, no product pitch
The post is self-published on a developer platform under a DevOps-consultancy-style handle, and internal hostnames in the examples carry the same brand, so there is a visible reputational and audience-building incentive. Offsetting that, the material sells nothing: it recommends no vendor or commercial product, names no sponsor, and its central content is an admission of the author's own mistakes (a needless six-worker restart, a hidden changed_when: false, a restart loop that wrote 9 GB of logs), which cuts against promotional distortion.
Plausible and coherent, unverifiable
Confidence is limited chiefly by single-sourcing. The narrative is technically coherent, the module usage matches current ansible-core practice, the arithmetic checks out, and the incentive profile is not strongly promotional — so the account is likely broadly accurate as reported. But no claim can be corroborated, the actor is anonymous, and the truncated ending removes the author's own closing conclusions, so this stays well below the level of a verified report.
build
Your 90% Cache Hit Ratio Is a Lagging Indicator. Alert on Cold Misses Per Key1 distinct publisher
build
Three services you can delete: queue, cache and search in one Postgres1 distinct publisher
build
Debian 13 cleans /tmp, and Plex's EAC3 transcoding dies ten days later1 distinct publisher
build
Four control planes, one Postgres: a team's case against polyglot persistence1 distinct publisher
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
1 article · August 21, 2026