Detect you are running in a docker container - buildx

I’m the maintainer of the dcli package which is intended to replace bash using dart as an alternate scripting language.

DCli has a feature that allow users to run privileged code by running sudo.

When running in a docker container we don’t need to use sudo (as it doesn’t exist anyway).

As such dcli needs a generic way to detect if it is running in a docker container.

Previously we have used the presence of ‘/.dockerenv’ to determine if we are in a docker container.

It however looks like that when running under buildx the .dockerenv file no longer exists.

As such I’m looking of a reliable way of detecting if dcli is running in a docker container.

The best I’ve seen is to look for :docker: in cgroups but this seems a little fraught.

Is there any official/correct way to determine if you are running in a docker container.

Usually we don’t want an application to be able to tell whether it is running in a container or not. There are some exceptions. For example Systemd. It is an exception, because systemd has to handle control groups and it is running as the first process to manage others. It can run in containers, but it was not originally designed for that. Then they introduced a way to tell if systemd is running in a Docker container. Setting an environment variable

ENV container=docker

So if you don’t want to check control groups, you could try this.

Or if you just want to do this because containers usually don’t have sudo, you could check if sudo command exists (/usr/bin/sudo)

Usually we don’t want an application to be able to tell whether it is running in a container or not.

hmm, we are going to have to agree to disagree on this one.
It can be useful for all sorts of reasons, which is why I’m surprised there isn’t some generic way to determine the case.

Additionally dcli is a library used by third parties, so the process I use needs to be generic, it needs to do the right things without them having to do anything special.
As such requiring an environment variable isn’t appropriate.

The test for sudo is an interesting idea but I don’t think its adequate as my code actually has other behaviour based on whether we are running in docker.
Additionally, I’m not certain if there are other environments where sudo wouldn’t be installed.

On top of that my published api has a method ‘isDocker’ which I need to continue to support.

It can be useful, I don’t disagree. And I also have to admit I didn’t really think the beginning of my previous reply through. I should have written we usually don’t need that, but I also know that it is indeed important for JVM to handle resources properly.

So you only want to support Docker containers? Should dcli be compatible with podman, LXC containers? Maybe Kubernetes?

I don’t know how JVM detects whether it is running in a container or not, but detecing it with Cgroup v1 and Cgroup v2 would be different if you rely on /proc so you wouldn’t find :docker: in cgroups when the host uses CGroup v2. Instead, you would probably find 0::/. I didn’t try what I would se if I had systemd running in the container for example.

Since containers doesn’t need to boot, checking whether /boot is empty or not could also reveal it is a container, but I could also mount that folder from the host so then it wouldn’t work.

I don’t know if there is a perfect way to detect it or if JVM can always detect it successfully or just very very likely to be right. I would think if Systemd could detect it perfectly, the tool that actually handles control groups, it wouldn’t have introduced the environment variable.

About JVM: Java 17: What’s new in OpenJDK's container awareness | Red Hat Developer

Since Java 14, the OperatingSystemMXBean uses the JDK’s internal, Linux-specific Metrics Java API to report system information. That means if cgroup limits are in place, the OperatingSystemMXBean reports those limits (as appropriate) over the container host system resources.

If I interpret it correctly, it works only if cgroup limits are set, but that is what it actually needs to know how much resources it could use.

You could check /proc/mounts too and find if “overlay /” can be find at the beginning like

overlay / overlay rw,relatime,lowerdir=/var/lib/docker/overlay2/l/4KALMRSIMIICBZ5KSWRXAWPBGQ:/var/lib/docker/overlay2/l/ZQKDNYTJGWWDLUEOUDS63QJEQW,upperdir=/var/lib/docker/overlay2/22c6cfac8b12bd659bf93af81a5988b0d49f1ba73bb6feb2467db35ecb0d93ff/diff,workdir=/var/lib/docker/overlay2/22c6cfac8b12bd659bf93af81a5988b0d49f1ba73bb6feb2467db35ecb0d93ff/work 0 0

but overlay is not the only storage driver.

As you, I always heard about checking control groups and I don’t know about any standard way that easily tells the process it is running in a container.

Since you understandably want to support isDocker, you could try one or multiple ways from above, but the fact that you see 0::/ in /proc/1/cgroup doesn’t tell you if it is a Docker container, it is just likely to be some kind of container.

Can you tell about those other behaviors? Regarding sudo, it wouldn’t tell you if it is running in a container, you want to know whether you can use sudo or you should use something else. And if you could detect if it is a container, you would assume you couldn’t use sudo, which is almost always true, but not necessarily. I would always try to detect what I could use rather than a specific environment assuming the rest. That way even if the environment changes and something becomes available or disappears, the app could adapt automatically.

Have you consididered supporting but also deprecating isDocker and introducing other methods that would support other container engines as well?

I’ve raised a feature request for this:

(post deleted by author)