Skip to content
5 min read

My Own Little Docker Swarm UI

My Own Little Docker Swarm UI

Recently, I left you with a bit of a cliffhanger in the end of this post, I know. It was about finding a better way to manage my Docker Swarm cluster. Well, here's where that story leads.

I am strongly considering migrating from Kubernetes back to Docker Swarm. But I hit a familiar wall. I needed (well, "wanted" is the better word) a management UI. Not because I can't use the terminal – I can, and do – but because when you're getting alerts on your phone while out and about, you want to be able to quickly check logs, restart a service, or diagnose an issue without pulling out your laptop.

For Kubernetes, I'm currently using Rancher. It's fantastic for k8s, but won't work for Docker Swarm. Previously, I'd used Portainer CE for Swarm management, and it worked well enough. But here's the thing: Portainer's CE version only supports up to 5 nodes. With the way Magic Pages is growing, I'd hit that limit soon. Then, I'll have to commit to some pretty expensive licensing.

Naturally, I looked for alternatives. For Docker Swarm there's basically Portainer and Swarmpit. But Swarmpit isn't maintained anymore 🤷

Then, two things converged at exactly the right moment:

  1. I wanted a Docker Swarm UI that wouldn't lock me in.
  2. I saw John O'Nolan rave about Claude Code on the social web.

But some context.

I recently listened to Arvid Kahl's podcast episode "From Code Writer to Code Editor", and it resonated deeply. I've been using LLMs for development work, but always with the intent to stay in control. I'm not a "vibe coder" – I want to understand every line of code in my projects and am aware of how LLMs work. They hallucinate and are not thinking. They just predict what the next "token" will be. And well. That can be wrong.

So far, I have used Cursor for assisted coding, but their recent pricing changes had me looking for alternatives. So when these needs aligned, I decided to run an experiment:

Could I build my own Docker Swarm UI using Claude Code?

Following Arvid's approach, I spent about 40% of my time carefully defining what I wanted, 20% waiting for Claude to generate code, and 40% reviewing and understanding the output.

The key was finding Dockerode – an excellent Node.js Docker client that made the entire project feasible.

GitHub - apocas/dockerode: Docker + Node = Dockerode (Node.js module for Docker’s Remote API)
Docker + Node = Dockerode (Node.js module for Docker’s Remote API) - apocas/dockerode

After a few days of pair programming with Claude, I had something that actually worked. My own Docker Swarm UI.

The UI is a full-stack application built with some pretty basic technologies. The frontend is using bare React with TailwindCSS (and the Flowbite UI kit).

The backend is just an Express.js server and a built-out Dockerode library that interacts with my Docker Swarm over its API.

The backend and frontend use websockets for live updates.

All some pretty basic technologies. Nothing fancy. And that was by design, to keep things maintainable. Yes, AI can generate code, but I would not trust it to maintain it, even with instructions. It's easier and faster to just do that myself.

Essentially, I build a UI that lets me manage Docker Swarm services (classic CRUD), lets me view logs, manage nodes, and more.

There is one page that really showed the constraints of LLMs: the monitoring page. I wanted to have an overview of the system information of the server nodes, so that I can see at one glance whether I need to add another server, or drain one.

Well, even though I gave Claude Code some pretty detailed instructions, it always took shortcuts. And this is where vibe coding breaks apart.

The internet barely talks about use cases like these. Docker Swarm is not dead, but it's also not as alive as Kubernetes. The first reflex an LLM will have is to use the Docker API to access docker stats. Well, plot twist, this will only show resource usage of well...Docker.

But I needed to see the entire system information, even the CPU and memory consumption outside of Docker.

I explained this to the LLM over and over again and ran multiple planning sessions. They all fell short. Even when I specifically spilled out what I wanted (deploy a global node-exporter service that runs one instance on every single Docker Swarm node, and then use their HTTP endpoints to accumulate information), it couldn't do it. The complexity was too big.

But, after I've implemented it "the old way", I had a beautiful monitoring page:

What's next?

For now, I'm using this internally at Magic Pages, while planning and testing the migration to Docker Swarm.

It's already proven its worth – being able to quickly check on a misbehaving Ghost site while running a few deployment tests has saved me quite some time. The interface is responsive, fast, and does exactly what I need it to do.

Eventually, I do want to open source this. The Docker Swarm community deserves more options for management UIs. But first, I need to gather more real-world experience with it, iron out any quirks, and ensure it's truly production-ready for others to use.

However, this experiment taught me something valuable: AI-assisted coding has its place. It lets us quickly spin up things that would have otherwise taken weeks. It needs guard rails and oversight. Just letting it run usually ends in disaster.

Or how one of my colleagues at my day job recently said: "Writing code has never been the problem – it's planning and reviewing.". He shared the following article, when somebody suggested to "do as much as possible with AI" and I think it fits my experience perfectly:

Writing Code Was Never The Bottleneck
LLMs make it easier to write code, but understanding, reviewing, and maintaining it still takes time, trust, and good judgment.