¿Cómo determinar si un proceso se ejecuta dentro de lxc / Docker?

172

¿Hay alguna manera de determinar si un proceso (script) se ejecuta dentro de un contenedor lxc (~ Docker runtime)? Sé que algunos programas pueden detectar si se ejecutan dentro de una máquina virtual, ¿hay algo similar disponible para lxc / docker?

Mate Varga
fuente
Puede parecer pedante, pero sería mejor reformular su pregunta para describir un problema que tiene y preguntar cómo resolverlo; sin eso, la pregunta tiene una mayor probabilidad de ser cerrada. En muchos casos es difícil hacer ese cambio, pero en el tuyo no sería difícil reformularlo simplemente si lo deseas.
mah
hay una respuesta interesante al emitir este comando dentro de un contenedor: tiempo de actividad
Scott Stensland

Respuestas:

170

La forma más confiable es verificar /proc/1/cgroup. Se le dirá que los grupos de control del proceso init, y cuando estás no en un contenedor, que será /para todas las jerarquías. Cuando esté dentro de un contenedor, verá el nombre del punto de anclaje. Con los contenedores LXC / Docker, será algo así /lxc/<containerid>o /docker/<containerid>respectivamente.

jpetazzo
fuente
13
docker ahora usa en dockerlugar de lxcen esos caminos
Andy
44
No funciona para contenedores lxd / lxc, pero stackoverflow.com/a/20010626/170230 sí.
Draco Ater
Con versiones posteriores de systemd, parece que no puede confiar en el proceso 1 /para todos los cgroups; en mi sistema Debian 9 (systemd 232) solo tres de los diez grupos c ( 3:cpuset, 4:perf_eventy 7:freezer) están en la raíz; El resto está debajo /init.scope. Dicho esto, creo que buscar ese archivo :/docker/es probablemente la heurística más confiable en este momento.
cjs
2
grep 'docker\|lxc' /proc/1/cgroupfunciona para mí en Docker 18.09.
rypel
1
No funciona para mi Host Ubuntu 19.04, invitado Ubuntu 18.04 usando el contenedor privilegiado LXC. / proc / 1 / cgroup NO contiene la cadena lxc.
Gab
158

Docker crea un .dockerenvarchivo en la raíz del árbol de directorios dentro del contenedor. Puede ejecutar este script para verificar

#!/bin/bash
if [ -f /.dockerenv ]; then
    echo "I'm inside matrix ;(";
else
    echo "I'm living in real world!";
fi


MÁS: Ubuntu en realidad tiene un script bash: /bin/running-in-containery en realidad puede devolver el tipo de contenedor en el que se ha invocado. Podría ser útil. Sin embargo, no sé sobre otras distribuciones importantes.

at0S
fuente
13
Nota importante: el .dockerinitarchivo se ha eliminado en versiones recientes de Docker , por lo que este método ya no funcionará. Al momento de escribir esto, el .dockerenvarchivo todavía se mantiene, por lo que quizás podría usarse en su lugar.
Jason R
En Debian /bin/running-in-containeres proporcionado por upstart. Con la transición a systemd, podría desaparecer. Espero que no, ¡suena útil!
Max Murphy
"en la parte superior del árbol de directorios", ¿qué significa eso? ¿donde es eso?
Alexander Mills
3
Otros han señalado que la comprobación .dockerenvse no se recomienda
David
1
Nota: las pruebas para .dockerenv solo funcionan si el tiempo de ejecución es docker daemon. Si está utilizando podman o algo más, esto falla.
Benjamin Kircher
22

En un nuevo sistema ubuntu 16.04, nuevo systemd y lxc 2.0

sudo grep -qa container=lxc /proc/1/environ
larss
fuente
Esto funciona para mí en Ubuntu focal 20.04. Ninguna de las respuestas sobre este punto sí.
Jonathan Hartley
16

Una forma concisa de verificar el acoplador en un script bash es:

#!/bin/bash
if grep docker /proc/1/cgroup -qa; then
   echo I'm running on docker.
fi
oNaiPs
fuente
14

Práctica función de Python para verificar si se ejecuta en 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()
JJC
fuente
2
¡Nota IMPORTANTE! Esto no parece funcionar cuando el contenedor se ejecuta en kubernetes. En su lugar, reemplace la última línea con 'kubepod' en lugar de 'docker'. (O, ponga una declaración "o" que verifique ambos;))
JJC
1
Es, kubepodssupongo.
rookie099
9

Usamos el programado del proceso (/ proc / $ PID / sched) para extraer el PID del proceso. El PID del proceso dentro del contenedor será diferente, entonces es PID en el host (un sistema sin contenedor).

Por ejemplo, la salida de / proc / 1 / sched en un contenedor devolverá:

root@33044d65037c:~# cat /proc/1/sched | head -n 1
bash (5276, #threads: 1)

Mientras esté en un host que no sea contenedor:

$ cat /proc/1/sched  | head -n 1
init (1, #threads: 1)

Esto ayuda a diferenciar si estás en un contenedor o no.

Fundador
fuente
Dependiendo del sistema operativo, "init" podría necesitar ser reemplazado por "systemd". Más información sobre systemd aquí .
BrianV
Sí, pero el punto no era el nombre del proceso init, el punto era el número del proceso.
MillerGeek
Esto parece funcionar solo en Docker. En un contenedor LXC Está regresando Systemd PID 1
MillerGeek
Ahora también está devolviendo 1 en Docker. Por lo general, está shy no está initallí, pero puede ser casi cualquier cosa.
Jan Hudec
Bajo Docker, este ya no es el casobash-5.0# cat /proc/1/sched bash (1, #threads: 1)
Shalomb
5

La forma más fácil sería verificar el entorno. Si tiene la container=lxcvariable, está dentro de un contenedor.

De lo contrario, si es root, puede intentar realizar mknodu mountoperar, si falla, lo más probable es que se encuentre en un contenedor con capacidades caídas.

crujir
fuente
Este funciona no solo para la ventana acoplable (no lo comprobé), sino más importante aún para los contenedores lxd / lxc (comprobado), donde /proc/1/cgroupno le permite detectar eso.
Draco Ater
2
¿Puedes editar la respuesta con código en lugar de pseudocódigo? "container = lxc"? no es apropiado nada. ¿te refieres a algo como si [["lxc" = "$ container"]]?
Alexander Mills
3
Quiero decir ... es extraño, por lo general, las variables env están en mayúsculas, por lo que buscar un poco de precisión aquí
Alexander Mills
77
docker run alpine envno da nada que se parezca a esa variable
Archimedes Trajano
3

Mi respuesta solo se aplica a los procesos Node.js pero puede ser relevante para algunos visitantes que tropiezan con esta pregunta en busca de una respuesta específica de Node.js.

Tuve el mismo problema y confiando en /proc/self/cgroupque creé un paquete npm solo para este propósito: detectar si un proceso Node.js se ejecuta dentro de un contenedor Docker o no.

El módulo npm contenedorizado lo ayudará en Node.js. Actualmente no está probado en Io.js, pero también podría funcionar allí.

Martin Tajur
fuente
Gracias por este módulo, parece que hay un par de correcciones pendientes pendientes. ¿Sigue manteniendo esto?
stevokk
2

Verifique todas las soluciones anteriores en 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())

Prueba de concepto:

$ docker run --rm -it --mount type=bind,source=${PWD}/incontainer.py,target=/tmp/script.py python:3 python /tmp/script.py
True
blakev
fuente
Esto no funcionó para mí en el contenedor de Docker basado en Mac. Devoluciones vacías Docker versión 2.1.0.1 (37199).
splintercell
Éste lo hizo: def is_non_docker(): return os.path.exists('/proc/1/cgroup')según la respuesta aceptada aquí stackoverflow.com/questions/20010199/…
splintercell
2
Obtienes un Premio de Uso Inútil del Gato. E inútil uso del subproceso uno.
Jan Hudec
Sí, este es un nivel completamente nuevo de innecesario cat! Nice one :-D
Timmmm
Tienes razón, actualizaré la respuesta a pesar de que todavía no lo abarca todo. @ JanHudec
blakev
1

Docker está evolucionando día a día, por lo que no podemos decir con certeza si se mantendrán .dockerenv .dockeriniten el futuro.

En la mayoría de los sabores de Linux inites el primer proceso en comenzar. Pero en el caso de los contenedores esto no es cierto.

#!/bin/bash
if ps -p1|grep -q init;then  
  echo "non-docker" 
else 
  echo "docker" 
fi
Govind Kailas
fuente
66
@RomanTrofimov LXC / Docker tampoco. Que comentario más gracioso.
Abourget
1
Tampoco funciona en centos 7. Cuando ejecuto en mi máquina host dice Docker. Parece que systemd se está ejecutando como ID de proceso 1
Venkateswara Rao
@VenkateswaraRao: debe ejecutarse dentro del contenedor. La intención es averiguar si estás dentro de un contenedor acoplable o no.
Govind Kailas
1
@GovindKailas: El problema es que esto supone que el PID normal es init , que no es cierto en systemdo launchdsistemas basados ...
Gert Van den Berg
3
@SamThomas: launchd, upstart, Solaris SMF, systemd, Sys V style init, BSD style init (estos dos y otros pueden llamar a su PID 1 init), OpenRC, initng, runit. Vea aquí . La mayoría de los sistemas modernos basados ​​en Linux usarían systemd, algunos más antiguos, nuevos ... Todos los sistemas OS X modernos usaríanlaunchd
Gert van den Berg
0

Estas preguntas y respuestas sobre SO: "Averigüe si el sistema operativo se ejecuta en un entorno virtual" ; aunque no es lo mismo que la pregunta del OP, de hecho responde a casos comunes de encontrar en qué contenedor se encuentra (si es que lo hace).

En particular, instale y lea el código de este script bash que parece funcionar bastante bien:

virt-what :

sudo apt install virt-what
kaiwan
fuente
No funciona con la virt-whatversión 1.14-1 en Ubuntu 16.04. Necesita parche.
Lucas
0

He traducido la respuesta de JJC al rubí

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
Souradeep Nanda
fuente
-1

En un contenedor acoplable, las entradas /proc/self/cgroupse montan en cgroups en el host.

por ejemplo, en un contenedor

# awk -F: '/cpuset/' /proc/self/cgroup
3:cpuset:/docker/22bd0c154fb4e0d1b6c748faf1f1a12116acc21ce287618a115ad2bea41256b3

mientras que, lo mismo en el host

$ awk -F: '/cpuset/' /proc/self/cgroup
3:cpuset:/

Usar algo en el shell para una prueba de bajo perfil

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
shalomb
fuente
Devuelve 1 en ambos.
Sorin
-4

Tal vez esto haga el truco:

if [ -z $(docker ps -q) ]; then
    echo "There is not process currently running"
else
    echo "There are processes running"
fi

¿Es eso lo que quieres? Espero que ayude =)

Leonardo Da Vinci
fuente
1
No hay dockerbinarios disponibles desde el interior del contenedor, obviamente.
toriningen
3
Umm, esto fallaría en situaciones (por ejemplo, gitlab docker-in-docker) en las que el contenedor de control tiene dockeracceso al zócalo docker de los hosts.
shalomb
1
Sí, tienes razón, por supuesto que no hay ^^. Obtuve la interpretación incorrecta sobre la pregunta en el momento en que la leí. Gracias Shalomb.
Leonardo Da Vinci