How to check if a process is running inside docker container?
Solution 1
To check inside a Docker container if you are inside a Docker container or not can be done via /proc/1/cgroup
. As this post suggests you can to the following:
Outside a docker container all entries in /proc/1/cgroup
end on /
as you can see here:
vagrant@ubuntu-13:~$ cat /proc/1/cgroup
11:name=systemd:/
10:hugetlb:/
9:perf_event:/
8:blkio:/
7:freezer:/
6:devices:/
5:memory:/
4:cpuacct:/
3:cpu:/
2:cpuset:/
Inside a Docker container some of the control groups will belong to Docker (or LXC):
vagrant@ubuntu-13:~$ docker run busybox cat /proc/1/cgroup
11:name=systemd:/
10:hugetlb:/
9:perf_event:/
8:blkio:/
7:freezer:/
6:devices:/docker/3601745b3bd54d9780436faa5f0e4f72bb46231663bb99a6bb892764917832c2
5:memory:/
4:cpuacct:/
3:cpu:/docker/3601745b3bd54d9780436faa5f0e4f72bb46231663bb99a6bb892764917832c2
2:cpuset:/
Solution 2
Docker creates .dockerenv
and (removed in v1.11) files at the top of the container's directory tree so you might want to check if those exist..dockerinit
Something like this should work.
#!/bin/bash
if [ -f /.dockerenv ]; then
echo "I'm inside matrix ;(";
else
echo "I'm living in real world!";
fi
Solution 3
We use the proc's sched (/proc/$PID/sched) to extract the PID of the process. The process's PID inside the container will differ then it's PID on the host (a non-container system).
For example, the output of /proc/1/sched on a container will return:
root@33044d65037c:~# cat /proc/1/sched | head -n 1
bash (5276, #threads: 1)
While on a non-container host:
$ cat /proc/1/sched | head -n 1
init (1, #threads: 1)
This helps to differentiate if you are in a container or not. eg you can do:
if [[ ! $(cat /proc/1/sched | head -n 1 | grep init) ]]; then {
echo in docker
} else {
echo not in docker
} fi
Solution 4
Thomas' solution as code:
running_in_docker() {
(awk -F/ '$2 == "docker"' /proc/self/cgroup | read non_empty_input)
}
Note
The read
with a dummy variable is a simple idiom for Does this produce any output?. It's a compact method for turning a possibly verbose grep
or awk
into a test of a pattern.
Solution 5
Using Environment Variables
For my money, I prefer to set an environment variable inside the docker image that can then be detected by the application.
For example, this is the start of a demo Dockerfile
config:
FROM node:12.20.1 as base
ENV DOCKER_RUNNING=true
RUN yarn install --production
RUN yarn build
The second line sets an envar called DOCKER_RUNNING
that is then easy to detect. The issue with this is that in a multi-stage build, you will have to repeat the ENV
line every time you FROM
off of an external image. For example, you can see that I FROM
off of node:12.20.1
, which includes a lot of extra stuff (git, for example). Later on in my Dockerfile
I then COPY
things over to a new image based on node:12.20.1-slim
, which is much smaller:
FROM node:12.20.1-slim as server
ENV DOCKER_RUNNING=true
EXPOSE 3000
COPY --from=base /build /build
CMD ["node", "server.js"]
Even though this image target server
is in the same Dockerfile
, it requires the ENV var to be defined again because it has a different base image.
If you make use of Docker-Compose, you could instead easily define an envar there. For example, your docker-compose.yml
file could look like this:
version: "3.8"
services:
nodeserver:
image: michaeloryl/stackdemo
environment:
- NODE_ENV=production
- DOCKER_RUNNING=true
Related videos on Youtube
Comments
-
harryz about 2 years
[Updated1] I have a shell which will change TCP kernel parameters in some functions, but now I need to make this shell run in Docker container, that means, the shell need to know it is running inside a container and stop configuring the kernel.
Now I'm not sure how to achieve that, here is the contents of
/proc/self/cgroup
inside the container:9:hugetlb:/ 8:perf_event:/ 7:blkio:/ 6:freezer:/ 5:devices:/ 4:memory:/ 3:cpuacct:/ 2:cpu:/docker/25ef774c390558ad8c4e9a8590b6a1956231aae404d6a7aba4dde320ff569b8b 1:cpuset:/
Any flags above can I use to figure out if this process is running inside a container?
[Updated2]: I have also noticed Determining if a process runs inside lxc/Docker, but it seems not working in this case, the content in
/proc/1/cgroup
of my container is:8:perf_event:/ 7:blkio:/ 6:freezer:/ 5:devices:/ 4:memory:/ 3:cpuacct:/ 2:cpu:/docker/25ef774c390558ad8c4e9a8590b6a1956231aae404d6a7aba4dde320ff569b8b 1:cpuset:/
No /lxc/containerid
-
Henk Langeveld about 10 yearsNot a very clear question. Why do you need this?
-
Johannes 'fish' Ziemke about 10 yearsDuplicate of stackoverflow.com/questions/20010199/…
-
harryz about 10 years@fish no /lxc/<containerid> in my case, see update
-
harryz about 10 years@HenkLangeveld kernel parameters is read-only in Docker container,so I need to know if my shell is running inside containers and disable kernel functions in my shell. see update.
-
Henk Langeveld about 10 yearsSome steps in the script try to modify kernel parameters, and need to be skipped when running in Docker. Clear.
-
-
larsks about 9 yearsExcept...this will fail in some envrionments, because, e.g.,
3:cpu,cpuacct:/system.slice/docker-1ce79a0dec4a2084d54acf187a1e177e0339dc90d0218b48b4456576ecaf291e.scope
would not match. Simpler togrep -q docker /proc/1/cgroup
; the result code from that should also be sufficient. -
Daniel Alder over 8 years
read
might work forbash
, but in the most useddash
shell you have to use eitherread dummy
(or similar) or use a construct like[ -n "$(command)" ]
-
Henk Langeveld over 8 years@DanielAlder Good catch, Daniel. I will update the text.
-
Henk Langeveld over 8 yearsPreviously this claimed that any Bourne compatible shell supports the plain
read
without variable name. This is only true for bash and ksh93. The Opengroup only specifiesread var
and does not mentionread
behaviour without at least one variable. In bash and ksh93, if no var is given, read uses the shell variableREPLY
. -
sosiouxme over 8 yearsUnless, of course, you or someone else has created
/.dockerinit
on your host (perhaps by accident), in which case it will be wrong outside a container. -
automationleg over 8 yearsIf somebody else made it in / then they are root and you've got worse problems than knowing whether you are in docker or no.
-
Paul almost 8 years@HenkLangeveld This would fix your solution: (awk -F: '$3 ~ /docker/' /proc/self/cgroup | read non_empty_input)
-
Fabian Lange almost 8 yearsthis is actually quite a valuable information. thanks
-
ReactiveRaven over 7 yearsBeware relying on
/.dockerenv
in the long term. It is not intended to be used this way. -
BrianV almost 7 yearsDepending on the OS, "init" might need to be replaced with "systemd". More information on systemd here.
-
Shubham Chaudhary almost 7 yearsAs mentioned by @BrianV, this doesn't work for me too.
-
Shubham Chaudhary almost 7 yearsWhy can't we just use
awk -F: '$3 ~ /docker/' /proc/self/cgroup | read
? Works for me. -
Stefan Majewsky over 6 yearsIn a Docker container running on a k8s cluster,
head -n1 /proc/1/sched
returnsdumb-init (1, #threads: 1)
, so the check suggested in this answer fails. (Also, contrary to what the answer suggests, the PID is shown as "1" in that line although I'm doing this in a container.) -
Stefan Majewsky over 6 yearsDoes not work for me. From within a k8s-scheduled Docker container,
readlink /proc/self/ns/pid
andreadlink /proc/1/ns/pid
produce the same output. -
Greg Bray over 6 years@StefanMajewsky Might want to try using github.com/jessfraz/amicontained to see what features are enabled in the container runtime.
-
samfr about 6 yearsit is not strictly true that "Outside a docker container all entries in /proc/1/cgroup end on /". On ubuntu 16.04 for example I have:
12:perf_event:/ 11:blkio:/init.scope 10:cpuset:/ 9:devices:/init.scope 8:hugetlb:/ 7:cpu,cpuacct:/init.scope 6:net_cls,net_prio:/ 5:memory:/init.scope 4:pids:/init.scope 3:rdma:/ 2:freezer:/ 1:name=systemd:/init.scope
-
Christian over 4 yearsThis pretty much only works on Linux, not on Darwin or other BSDs that don't even use a procfs.
-
Robert Lacroix over 4 years@Christian Docker/LXC are Linux only things, so that's fine, right :)?
-
Christian over 4 years@RobertLacroix so you're saying if you don't find a procfs, you're not in Docker? Well, that's fair enough I guess...
-
Beni Cherniavsky-Paskin about 4 yearsfwiw, Podman does not create
/.dockerenv
. It does create/run/.containerenv
but by similar logic, sounds like implementation detail not to be relied upon. See github.com/containers/libpod/issues/3586 for some podman-specific alternatives. -
frakman1 about 4 years@larsks Indeed,
grep
is simpler. However, using-q
didn't work on my docker container (command returned nothing) so it's better to omit it. -
larsks about 4 years@frakman1 the
grep -q
command is not expected to return anything. See thegrep(1)
man page. -
jpkotta about 4 yearsThis is definitely not a universal solution. You can (sort of) use whatever you want for a container's PID 1. E.g. if you do
docker run --init ...
it will bedocker-init
. If you do e.g.docker run ... head -n 1 /proc/1/sched
it will behead
. -
truthadjustr almost 4 yearsThis method is not durable.
-
bo0k almost 4 yearsin MSYS2 ls -ali / | sed '2!d' |awk {'print $1'} 232779805740174872
-
yurenchen over 3 yearssame as
ls -di /
? seems inode num not reliable on different platform -
Michael Altfield over 3 yearsthis is the only thing that worked for me to differentiate between a Xen domU host and its docker container
-
Nick Ribal over 3 yearsHere's a shorter version and without violating any shellcheck rules:
EXECUTABLE_NAME=$(if head -n 1 /proc/1/sched | grep -q 'tini'; then echo "docker run [name of this container]"; else echo "${0}"; fi)
. This assumes that you're using tini in your container, of course. -
Kokos about 3 yearsThis answer is the only one that still works for Docker v20. Simplest code to wrap it (exit code 0 if running with different init than systemd or init:
awk '{exit ($1 ~ /^init|systemd$/)}' /proc/1/sched
-
Eric almost 3 yearscare to explain what the code does? Thank you.
-
four43 almost 3 yearsThis is great, just being explicit
-
Neil Mayhew almost 3 years
stat -c %i
is simpler thanls -ali / | sed '2!d' |awk {'print $1'}
-
Prosunjit Biswas about 2 yearsjust an alternative way of writing the above test
test -f /.dockerenv && echo inside docker || echo not inside docker
-
Wolfram Rösler about 2 yearsInstead of
cat /proc/1/sched | head -n 1
you can simply usehead -n 1 /proc/1/sched
. -
Wolfram Rösler about 2 years
/proc/1/cgroup
exists in Linux hosts as well, not only in containers -
cowlinator almost 2 yearsDoes this work in windows container?
-
Ott Toomet almost 2 yearsBeware that some programs do purge environment when starting (e.g shiny server). The variables are there if you open a shell, but empty within the program. In that case check out how to configure those vars for that particular software.