Why I think we should all use immutable Docker images
Docker is awesome. But the Docker technology can be used many different ways depending on the use case, the technology context and the developers or devops’ praxis.
In my point of view that containerisation technology requires most of us to change our mind on the way of seeing ops in our domain. In most of the use cases, there is a misunderstanding of the benefits of this technology if you are not using immutable images.
We probably have to change our mind
Except a very few like Google that runs containers since almost 10 years, we used to/are using a server or a VM to host our web applications. Simply ask (if it’s not you) the “system” or “devops” team to install and configure whatever it is needed to run that replaces with the language you like web application. Once they finished, we can now updates the source code deployed on the server by using Capistrano or any other deployment tool. The result is that the code is updated on the web server(s).
Then, the Docker popularity exploded. Everybody started to use it and most of us replicated the same logic: lets have a container running the web server and mount the source code from on the host or use a data-container. In that case, we are using Docker only to ease the server setup.
This setup is using what I name mutable images because if you change the contents of the mounted volume, then you change the behaviour of the container. That means that if you run that same image on another machine, then the container will potentially have a different behaviour than the one running on the other machine. We do have a kind of portability, but we don’t have the predictability at all.
Why immutable Docker images?
When we are talking about software design, the literature around immutable objects is vast. The devops culture is about joining the devs and the ops, so why not introducing immutability here too? An immutable image is an image that contains everything it needs to run the application, so obviously including your source code.
The “only” difference is that your
Dockerfile will copy your application code and eventually run any build process or dependencies installation. Using immutable images gives us many advantages but I would like to focus on two of them that are the portability and the predictability of the containers running from these images.
Because your container is self-sufficient, you will just have to run the container without caring about anything else like mounting volumes, etc… That means you can share your application with your users or partners in a more easy way. A good example is the Blackfire company that shares their agent in an image that you just have to
The direct consequence is that you can easily scale your system in an automated manner with tools such as Kubernetes that allows us to run set of containers on a set of machines, ie a cluster. You could even do that simply with Docker Swarm and Docker Compose.
The last main advantage of this portability is that it means we can also change the runtime dependencies (even of programmation language) between deployments. That can be extremely complicated to do with a legacy hosting infrastructure but is almost for free with a Docker container that simply runs by itself. In that example, if you are not using immutable containers, you will have to update the running containers on the server, not simply deploy your application as usual.
With immutable images, you can be sure that a given tag of that given image will always have the same behaviour because the code is contained in the image. That means a lot in terms of deployment and in the management of the application lifecycle.
Testing the application. Because we know we are deploying the tag
d1a8336, we can run unit and integration tests with a container that simply come from this image. That way we can ensure far more accurately that the application will run correctly also thanks to the portability of a Docker container.
Deployment and rollback. That’s an essential feature of your deployment pipeline, because sometimes, it fails. If you can just deploy another image version (whatever the kind of tooling changes you’ve done), then you can so easily rollback.
A/B testing and so on. While you couldn’t easily deploy different versions of your code at the same time with a code base shared via a volume, you can now easily run different version of your application and use them for A/B testing or even candidate testing.
Obviously, when we are talking about the development workflow, we definitely need this mutability to prevent to need of rebuilding the image all the time. But we can simply use an immutable image, and still override the volumes when running it with Docker’s -v option or Docker Compose’s volumes configuration.
This immutable approach to Docker containers changes the way of seeing application deployments, which are not code deployment anymore, but gives us so much more advantages than our “old way of doing” that you should definitely give a try!