How I learned to live without Docker
So this is a short history of my relationship with Docker. It’s not a rant, it’s not a tutorial, it’s just a reflection on how my views have changed over the years. I went from a Docker fanatic to a skeptic to a moderate user. I hope you find at least some of it useful or entertaining.
I remember when I first started using Docker. It was my first job at a small but very ambitious startup. Like many small companies, we were collectively enamored with enterprise-grade toys. We barely had any users, but we were constantly thinking about scaling to millions. We spent way too much time thinking about orchestration, service discovery, and all that. Spoiler alert: we never got to millions, but I loved it. I was new to the industry, and all that complexity made me feel smart.
A quick note on what Docker is for those who are not familiar with it. Docker is a tool that allows you to run applications in isolated environments called containers. Containers can be easily replicated, shared, and manipulated in a consistent way. Dockerfiles are used blueprints for building containers, Docker Compose is used to manage multi-container applications, Kubernetes is like Compose but on steroids. With that out of the way, let’s continue.
At my next company, things were a bit different. People were more down-to-earth, and the projects were more down-to-earth too. The transition was hard for me. I spent my entire onboarding week trying to Dockerize their messy but clearly functional and profitable PHP monolith. I wasn’t assigned to do it, I just couldn’t imagine working on a project without Docker. I even managed to make it work, but it was a useless gimmick. My colleagues were clearly impressed by my dedication, but not so much by the results. My Dockerfile became a curious piece of company history, a testament to my stubbornness.
A year later, when I landed my first corporate job, I was finally in my element. Docker, Kubernetes, and all this cool stuff. I was working on projects that required “real” engineering. I was happy. I was finally a real developer. Sort of. In retrospect, my personal productivity had probably taken a hit that year. But I didn’t care. Building complex systems felt like building the right thing.
Things changed a few years into my enterprise career, I was working on a project that didn’t allow me to use Docker Desktop for Mac. Running Docker on Mac was always a bit of a pain, but at least Docker Desktop made it somewhat bearable. I had to use a different solution, which was painfully slow and resource-hungry. My 16GB of RAM were not enough, I literally had to budget Chrome tabs.
One day, during a discussion on Slack, my colleague mentioned that he was actually running his local setup without Docker. At first I was skeptical. How could he manage all these services without Docker Compose? What about all the nuances of networking, volumes, and so on? It sounded like a recipe for disaster, but I already was running out of ice cubes to cool my laptop. So I decided to give it a try.
I had to dig much deeper into the workings of our system than I had before. I could no longer get away with a superficial understanding of each service. I had to install Postgres, Minio, Redis, and a few other things manually, directly on my Mac. I had to run migrations, seed the databases, and configure everything myself. It was a bit of a hassle, but it was surprisingly liberating. In a way, it felt much simpler now, that I could finally see what was going on.
I then realized that my main motivation for using Docker all these years was automation. I was using a universal remote to turn on a single light bulb. I didn’t really need to isolate services in containers, I didn’t have major dependency issues, and I didn’t need to scale anything. I just needed to run a few services and make them talk to each other. And I could do that without Docker.
I created a Bash script to automate everything I was now doing manually. In a way I was doing with Bash the same thing I was doing earlier with Docker Compose. I never took Bash seriously before, so it started out pretty messy. But over time, as I learned more about shell scripting, it became much more simple and robust. I even found that I enjoyed Bash. I never thought that was possible.
Bash is a shell and scripting language that is available by default almost on every Linux or Mac machine. It’s a powerful tool for automating tasks and managing your system. But it’s also a bit of a relic, with a syntax that can be hard to read and understand. It has a pretty bad reputation among developers, and for that reason, it’s often overlooked while still being very useful in many cases.
I started to question other tools that I took for granted. I replaced NVM with another simple script. I tried deploying my pet projects without Ansible, again with pure Bash. It was sometimes a dirty and error-prone affair, but it was a great exercise in understanding the tools I use. After all that, I knew where I really needed enterprise-grade solutions, and where I could quickly hack something together with just a few lines of code.
Of course, I still use Docker at work. It makes sense at a large company with hundreds of developers and dozens of services. But I’m happy that I learned to live without it. My indie projects these days mostly consist of a single Go binary and SQLite on a single cloud VM. And it turns out, that you can go a long way with just that. And there is certainly a lot of joy in simplicity.
In the end, I learned a valuable lesson about not underestimating seemingly basic tools. I now try to start new project with the absolute minimum of setup and dependencies. I only add complexity when I feel like it’s justified. I feel more in control, and the software I write feels much more reliable and future-proof. And this wouldn’t have happened if I never challenged my own assumptions about what is necessary and what is not.