This may seem like a controversial statement, considering Docker is widely believed to speed up the development process. However, when not used thoughtfully, it can lead to many hours of wasted time—a mistake I’ve observed several times.
The scenario is this: Your teams create software containers in Kubernetes clusters for several cloud or on-prem environments. But during the development phase on local machines, they rely on Docker. This seems manageable for small-scale projects with few containers. But as teams start creating complex docker-compose files to emulate more substantial environments, inefficiencies begin to surface. These compose files, packed with custom configurations, shared storage requirements, and environment variables, soon become a support nightmare. They bear no resemblance to the Kubernetes environments where the containers will eventually be deployed, leading to a significant disconnect in processes and a drain on productivity. At this point using docker-compose is doing nothing but slowing down the development and impacting the productivity and delivery of the project.
Lack of understanding of Docker often compounds this too. A common misstep involves deploying multiple containers with HTTP endpoints on different ports—a needless complexity in both Docker and Kubernetes. Properly configuring layer 7 routing and HTTP reverse proxies like Nginx and Traefik should negate this need, but adding a reverse proxy to the compose file just adds another layer of complexity, and I think it is debatable whether this is further divergence from the Kubernetes environment, or bringing you closer to it.
So what should I do
It surprises me that in this day and age this practice has become so prolific given that the good practices around continuous delivery have been established for so long. In the 2011 book “Continuous Delivery” by Jez Humble and David Farley it states:
It is essential to use the same process to deploy to every environment – whether a developer or analyst’s workstation, a testing environment, or production – in order to ensure that the build and deployment process is tested effectively
“Continuous Delivery” by Jez Humble and David Farley (P. 117)
Yet so many teams are deploying to docker on their workstations, only to commit their code to a automated pipeline that immediately deploys to a Kubernetes cluster and then fails due to some configuration issue. How can we resolve this?
A simple solution is at hand: Docker Desktop’s Kubernetes mode. This feature allows the use of kubectl to deploy manifests just like in a cloud-hosted cluster. Kustomize and Helm charts can further streamline the process, ensuring consistency between your local and cloud environments.The issue with this then becomes one of resources on your workstation. A problem that exists regardless of whether you are using kubernetes of Docker. But it is a good step in the right direction and I would love to see more teams set up this way.
Moving to the edge
The resources question also has solutions. The traditional answer, and the one I would always advocate first is to build small components that can be run and tested in isolation without the need for extreme resources on your workstation. And Besides may of us have huge machines these days that are more than capable or running a vast amount of software. Well built software with well defined contracts that are well tested can be deployed to integration environments to ensure that everything is running together smoothly.
But what if there is another approach? Have you considered developing on the edge? How many of us software developers have old laptops, spare computers or collections of Raspberry Pis kicking around that could be used to host a kubernetes cluster on our local networks only one hop away? If you have read other posts on this blog you will know that is exactly what I do. I have a 10 node Raspberry Pi cluster in my home office that runs everything including my test environments, my Gitlab instance, openproject and more. It is an environment that accurately replicates the production cloud providers that I ultimately deploy my software to.
What about debugging
Depending on the language that you use debugging an application in kubernetes will be a little different. In essence though the basic idea is to deploy a new ephemeral debug container into the same process namespace as the running process you want to debug. This new ephemeral container can contain the debugger utility plus any required debug symbols. Once you have the container deployed you can use kubernetes port forwarding to allow your debug client to attach to the debugger and step through the code. Here are a few resources you might want to look at to get a good grasp of this.
- https://skaffold.dev/
- https://www.youtube.com/watch?v=8_Ozfa7JLEs&t=0s
- https://squash.solo.io/
- https://www.youtube.com/watch?v=nByB9rVLF7U
- https://www.youtube.com/watch?v=g38S–qYbWY
Conclusion
In summary, while Docker and Kubernetes are powerful tools in the software development lifecycle, their effectiveness hinges on thoughtful and consistent usage. The disparity between development environments using Docker-compose and deployment in Kubernetes can lead to significant inefficiencies and challenges. By embracing solutions such as Docker Desktop’s Kubernetes mode on and edge or remote cluster, we can create a more unified and streamlined workflow. Moreover, exploring edge computing opens up innovative avenues for development and testing. The key takeaway is the need for a paradigm shift in how we approach these tools – refocusing on consistency to enhance our development practices. Let this be a call to action for developers and teams: re-evaluate and refine your use of Docker and Kubernetes to realise the full potential in your software development.