Best practices for opam-derived Docker images

I’m using Docker images based on ocaml/opam, and I wonder if there are some “best practices” listed somewhere, or some example “official” Dockerfiles (e.g. @kit-ty-kate mentioned most of our CI projects start with…) that could serve as reference.

For instance, a common issue I have is that, for instance, the following Dockerfile does not work:

FROM ocaml/opam
RUN ocaml --version

I need to prefix such lines with eval $(opam env) && ...

This does not happen when using the image interactively (docker run -it ocaml/opam).

As I understand it, I could also add some ENV lines at the beginning of my Dockerfile to replace eval $(opam env), but they would be fairly long and with some hard-coded values (e.g. OCaml version).

The Docker documentation says that such ENV definitions are inherited, so I suppose this means the base images do not have such lines in them. Would adding them be a possibility?

There was also the opam version issue asked a few days ago.

Finally, I believe there must be several opam options and tricks related to general usage in Docker containers: adding --yes and/or using ENV OPAMYES, cleaning up opam’s caches to minimize image size, etc.

If there are already such examples, I’d like to know about them. Otherwise, this thread might be a place where to start such a list.

1 Like

It’s easier to use opam exec -- here (which is certainly a good general practice for these Dockerfiles - use the exec forms, rather than relying on the environment trickery which is really intended for interactive use).

When you run the image, it invokes a shell, which - as on a normal system - effectively invokes eval $(opam env)

The problem here is the principle of least surprise. The Dockerfiles could embed ENV clauses such that, say:

FROM ocaml/opam:ubuntu-24.04-ocaml-5.3
RUN ocaml --version

works as expected. But then you’ll end up writing something like:

FROM ocaml/opam:ubuntu-24.04-ocaml-5.3
RUN ocaml --version
RUN opam switch create 5.2 ocaml.5.2.0
RUN ocaml --version

and be surprised as to how the first ocaml --version works, but the next one doesn’t!

Note that all the ocaml/opam images have two Dockerfiles in the root: /Dockerfile.opam contains everything used to set-up the OS and opam itself and then /Dockerfile.ocaml is built on top of that and contains everything used to create the switch (which includes all the default environment variables). I certainly find the -opam images (e.g. ocaml/opam:ubuntu-24.04-opam) useful in all kinds of other contexts for getting quick development Dockerfiles up and running.