Bake the codebase into production images Bake the codebase into production images docker docker

Bake the codebase into production images


Binding source code onto the container, is usually done to have a quick feedback loop while developing. This is achieved by avoiding rebuilding the image once code changes as done. This technique is mostly useful for local development purposes. For production environments this technique should not be used.

Docker images are designed to be self-contained. All the dependencies that an image needs should be packaged inside the image. Relying on bind mounts to provide the source code or dependencies is not recommended as the resulting Docker image is not portable. Whenever you switch to a new machine, you need to transfer that source code and dependencies to that new machine.

Thus adding the source code into the image is the recommended approach. You should also benefit from the standard Docker workflow, where you build the image giving it a specific tag (usually the version), and pushit into a Docker repository. From there on, you only pull the image and start it on any machine that you have.

As for the versioning: When building the image you tag it with the source code version(or git tag or commit id).

docker build -t <image-name>:<version> .

And you also pull a specific version using docker pull <image-name>:<version>. Using this technique, you can always revert back to any version of the image.


docker-compose is one orchestration tool for docker, but there others like kubernetes or docker swarm. You should check them out for yourself, considering where you can use these tools.

To version your images you can tag them (with -t ). So you will be able to roll out specific version my.registry.net:5000/my/app:1.1.0, etc.

The build can be done locally on your machine or automated in a CI/CD pipeline.

Docker does not pull the codebase, only layers with files. If you compile your program, only the the binary should be added and some assets. Layers are cached and only pulled on when needed.

If you want to minimize the images in your registry, you can use multi stage builds in docker. This uses multiple stages to build the last container, which only serves your app, and therefore needs less files. E.g. you can compile your binary in one stage with javac, compile the assets in another stage with nodejs and webpack and copy those resulting files to the last container which only has the java runtime and the static, generated assets. The official docs are here: https://docs.docker.com/develop/develop-images/multistage-build/


You're right, your approach has a number of issues, including:

  • Your containers are not ephemeral
  • Each instance of your application has to wait for the build to complete before starting
  • What happens if your build fails? Excluding manual testing, you only know for failures at "deploy time"
  • The build process will produce the same artifact on each run (provided you did not change the source). Why waste time repeating this process?

Instead of baking the source code of your app inside the container and rebuilding your app on each deploy, you could just build your app (maybe inside another "build" container if you want to make the build environment portable too, i.e. a container used just for building) and add the artifacts that your build produced in another image that will be deployed in your production environment (after testing and QA, because you do have multiple environments, right? :).

Docker image tagging could work this way: build an image on each commit (maybe under the latest image tag) and on each git tag (under the corresponding image tag). Example: for each commit on your master branch you "update" your-image:latest and when you tag the 1.0.0 version you produce the your-image:1.0.0.

If you have a CI service of sorts you may also automate this procedure.

Note that using the latest tag in production may lead to unstable environments because you don't know which version you are deploying. Use another more-specific tag.

UPDATE: as others have been pointing out, putting your sources inside the container is a strategy that you can apply to the development phase. But it's not your case, because I am assuming you are talking about (pre-)production deplyoments.