How to determine if a process runs inside lxc/Docker?

LinuxBashDocker

Linux 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 =)

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMate VargaView Question on Stackoverflow
Solution 1 - Linuxat0SView Answer on Stackoverflow
Solution 2 - LinuxjpetazzoView Answer on Stackoverflow
Solution 3 - LinuxlarssView Answer on Stackoverflow
Solution 4 - LinuxoNaiPsView Answer on Stackoverflow
Solution 5 - LinuxJJCView Answer on Stackoverflow
Solution 6 - LinuxFounderView Answer on Stackoverflow
Solution 7 - LinuxcreackView Answer on Stackoverflow
Solution 8 - LinuxMartin TajurView Answer on Stackoverflow
Solution 9 - LinuxblakevView Answer on Stackoverflow
Solution 10 - LinuxSouradeep NandaView Answer on Stackoverflow
Solution 11 - LinuxmainmachineView Answer on Stackoverflow
Solution 12 - LinuxkaiwanView Answer on Stackoverflow
Solution 13 - Linuxwcc526View Answer on Stackoverflow
Solution 14 - LinuxGovind KailasView Answer on Stackoverflow
Solution 15 - LinuxshalombView Answer on Stackoverflow
Solution 16 - LinuxtantrixView Answer on Stackoverflow
Solution 17 - LinuxFerry BoenderView Answer on Stackoverflow
Solution 18 - LinuxLeonardo Da VinciView Answer on Stackoverflow