How to determine if a process runs inside lxc/Docker?
LinuxBashDockerLinux Problem Overview
Is there any way to determine if a process (script) runs inside an lxc container (~ Docker runtime)? I know that some programs are able to detect whether they run inside a virtual machine, is something similar available for lxc/docker?
Linux Solutions
Solution 1 - Linux
Docker creates a .dockerenv
file at the root of the directory tree inside container. This can be seen by performing an ls -la /.dockerenv
to show that it is created on container startup.
You can run this script to verify:
#!/bin/bash
if [ -f /.dockerenv ]; then
echo "I'm inside matrix ;(";
else
echo "I'm living in real world!";
fi
MORE:
Ubuntu actually has a bash script: /bin/running-in-container
and it can return the type of container it has been invoked in. Might be helpful.
Don't know about other major distros though.
Solution 2 - Linux
The most reliable way is to check /proc/1/cgroup
. It will tell you the control groups of the init process, and when you are not in a container, that will be /
for all hierarchies. When you are inside a container, you will see the name of the anchor point. With LXC/Docker containers, it will be something like /lxc/<containerid>
or /docker/<containerid>
respectively.
Solution 3 - Linux
On a new ubuntu 16.04 system, new systemd & lxc 2.0
sudo grep -qa container=lxc /proc/1/environ
Solution 4 - Linux
A concise way to check for docker/lxc in a bash script is:
#!/bin/bash
if grep -sq 'docker\|lxc' /proc/1/cgroup; then
echo I'm running on docker.
fi
Solution 5 - Linux
Handy Python function to check if running in Docker:
def in_docker():
""" Returns: True if running in a Docker container, else False """
with open('/proc/1/cgroup', 'rt') as ifh:
return 'docker' in ifh.read()
Solution 6 - Linux
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.
Solution 7 - Linux
The easiest way would be to check the environment. If you have the container=lxc
variable, you are within a container.
Otherwise, if you are root, you can try to perform mknod
or mount
operation, if it fails, you are most likely in a container with dropped capabilities.
Solution 8 - Linux
My answer only applies for Node.js processes but may be relevant for some visitors who stumble to this question looking for a Node.js specific answer.
I had the same problem and relying on /proc/self/cgroup
I created an npm package for solely this purpose — to detect whether a Node.js process runs inside a Docker container or not.
The containerized npm module will help you out in Node.js. It is not currently tested in Io.js but may just as well work there too.
Solution 9 - Linux
Check for all the solutions above in Python:
import os
def in_container():
proc_1 = r'/proc/1/sched'
if os.path.exists(proc_1):
with open(proc_1, 'r') as fp:
out = fp.read()
else:
out = ''
checks = [
'docker' in out,
'/lxc/' in out,
out.split(' ')[0] not in ('systemd', 'init',),
os.path.exists('./dockerenv'),
os.path.exists('/.dockerinit'),
os.getenv('container') is not None
]
return any(checks)
if __name__ == '__main__':
print(in_container())
Proof of concept:
$ docker run --rm -it --mount type=bind,source=${PWD}/incontainer.py,target=/tmp/script.py python:3 python /tmp/script.py
True
Solution 10 - Linux
I have translated JJC's answer into ruby
def in_docker
File.open('/proc/1/cgroup', 'rt') do |f|
contents = f.read
return contents =~ /docker/i || contents =~ /kubepod/i
end
rescue StandardError => e
p 'Local development'
p e
false
end
Solution 11 - Linux
This is an old question, but a REALLY good one. :)
I've written some automation scripts that we run on baremetal, VM and in a docker container, with logic branching based on which platform the script is executing on. In my case I have the privilege of creating both the container and the docker image, so this solution will only work if you are in control of the entire stack:
Snippet of Dockerfile:
FROM ubuntu:18.04
ENV PLATFORM="docker"
RUN apt update; \
...
The script can then just check the value of $PLATFORM
for desired outcomes on each platform:
#!/bin/bash
# Check for executor specification in environment
case $PLATFORM in
docker)
# If running in Docker, do this stuff
echo "Running containerized, proceeding..."
;;
virtual)
# If running in a VM, do different stuff
echo "Running on a VM, loading VM stuff..."
modprobe some-kernel-module
;;
*)
echo "Unknown executor specified! Exiting..."
exit 1
;;
esac
I've omitted baremetal in the above code to keep it concise.
Solution 12 - Linux
This SO Q&A: "Find out if the OS is running in a virtual environment"; though not the same as the OP's question, it does indeed answer common cases of finding which container you're in (if at all).
In particular, install and read the code of this bash script which seems to work pretty well:
virt-what :
sudo apt install virt-what
Solution 13 - Linux
The golang code get pid container_id and you can get map container_id get docker image
func GetContainerID(pid int32) string {
cgroupPath := fmt.Sprintf("/proc/%s/cgroup", strconv.Itoa(int(pid)))
return getContainerID(cgroupPath)
}
func GetImage(containerId string) string {
if containerId == "" {
return ""
}
image, ok := containerImage[containerId]
if ok {
return image
} else {
return ""
}
}
func getContainerID(cgroupPath string) string {
containerID := ""
content, err := ioutil.ReadFile(cgroupPath)
if err != nil {
return containerID
}
lines := strings.Split(string(content), "\n")
for _, line := range lines {
field := strings.Split(line, ":")
if len(field) < 3 {
continue
}
cgroup_path := field[2]
if len(cgroup_path) < 64 {
continue
}
// Non-systemd Docker
//5:net_prio,net_cls:/docker/de630f22746b9c06c412858f26ca286c6cdfed086d3b302998aa403d9dcedc42
//3:net_cls:/kubepods/burstable/pod5f399c1a-f9fc-11e8-bf65-246e9659ebfc/9170559b8aadd07d99978d9460cf8d1c71552f3c64fefc7e9906ab3fb7e18f69
pos := strings.LastIndex(cgroup_path, "/")
if pos > 0 {
id_len := len(cgroup_path) - pos - 1
if id_len == 64 {
//p.InDocker = true
// docker id
containerID = cgroup_path[pos+1 : pos+1+64]
// logs.Debug("pid:%v in docker id:%v", pid, id)
return containerID
}
}
// systemd Docker
//5:net_cls:/system.slice/docker-afd862d2ed48ef5dc0ce8f1863e4475894e331098c9a512789233ca9ca06fc62.scope
docker_str := "docker-"
pos = strings.Index(cgroup_path, docker_str)
if pos > 0 {
pos_scope := strings.Index(cgroup_path, ".scope")
id_len := pos_scope - pos - len(docker_str)
if pos_scope > 0 && id_len == 64 {
containerID = cgroup_path[pos+len(docker_str) : pos+len(docker_str)+64]
return containerID
}
}
}
return containerID
}
Solution 14 - Linux
Docker is evolving day by day, so we can't say for sure if they are going to keep .dockerenv .dockerinit
in the future.
In most of the Linux flavours init
is the first process to start. But in case of containers this is not true.
#!/bin/bash
if ps -p1|grep -q init;then
echo "non-docker"
else
echo "docker"
fi
Solution 15 - Linux
In a docker container, entries /proc/self/cgroup
are mounted to cgroups on the host.
e.g. in a container
# awk -F: '/cpuset/' /proc/self/cgroup
3:cpuset:/docker/22bd0c154fb4e0d1b6c748faf1f1a12116acc21ce287618a115ad2bea41256b3
whereas, the same on the host
$ awk -F: '/cpuset/' /proc/self/cgroup
3:cpuset:/
Using something in the shell for a low profile test
is_running_in_container() {
awk -F: '/cpuset/ && $3 ~ /^\/$/{ c=1 } END { exit c }' /proc/self/cgroup
}
if is_running_in_container; then
echo "Aye!! I'm in a container"
else
echo "Nay!! I'm not in a container"
fi
Solution 16 - Linux
Here's a solution in Ruby,
# Usage: DockerHelper.running_in_docker?
module DockerHelper
extend self
def running_in_docker?
!!(File.read("/proc/1/cgroup") =~ %r[^\d+:\w+:/docker/]) # !! => true/false
rescue Errno::ENOENT
false
end
end
If you like tests with your code, here's a spec in the gist.
Solution 17 - Linux
As of 2022, with lxd v4.0+, none of the answers so far work for both docker and lxc.
- A
.dockerenv
file doesn't work for non-docker containers. - Checking that all hierarchies in
/proc/1/cgroup
are/
kinda maybe works. However, some hierarchies on non-containers are/init.scope
(Ubuntu 20.04 cgroup 0 and 1). So also not entirely reliable. - Checking for
container=lxc
in/proc/1/environ
works for lxc but not docker. Also, it requires root rights.
The only way I've found so far that works reliably on both CentOS and Ubuntu with lxc (4.0) containers and Docker, and also doesn't require root rights, is to check PID 2.
On all host systems, PID 2 is kthreadd
:
$ ps -p 2
PID TTY TIME CMD
2 ? 00:00:00 kthreadd
In containers, this PID either doesn't exist, or isn't kthreadd. Both docker and lxc show:
root@85396f8bce58:/# ps -p 2
PID TTY TIME CMD
root@85396f8bce58:/#
The best way seems to be to check /proc/2/status
:
$ head -n1 /proc/2/status
Name: kthreadd
So something like this seems to work:
if [ -n "$(grep 'kthreadd' /proc/2/status 2>/dev/null)" ]; then
echo "Not in container"
else
echo "In container";
fi
Solution 18 - Linux
Maybe this do the trick:
if [ -z $(docker ps -q) ]; then
echo "There is not process currently running"
else
echo "There are processes running"
fi
Is that what you want? Hope it helps =)