Come determinare se un processo viene eseguito all'interno di lxc / Docker?


172

Esiste un modo per determinare se un processo (script) viene eseguito all'interno di un contenitore lxc (~ Docker runtime)? So che alcuni programmi sono in grado di rilevare se funzionano all'interno di una macchina virtuale, è disponibile qualcosa di simile per lxc / docker?


Potrebbe sembrare pedante, ma sarebbe meglio riformulare la tua domanda per descrivere un problema che stai riscontrando e chiedere come risolverlo - senza di ciò, la domanda ha maggiori possibilità di essere chiusa. In molti casi è difficile apportare quel cambiamento, ma nel tuo non sarebbe difficile riformulare semplicemente se lo desideri.
Mah,

c'è una risposta interessante quando si emette questo comando all'interno di un container: uptime
Scott Stensland

Risposte:


170

Il modo più affidabile è verificare /proc/1/cgroup. Essa vi dirà i gruppi di controllo del processo init, e quando si è non è in un contenitore, che sarà /per tutte le gerarchie. Quando ti trovi in un contenitore, vedrai il nome del punto di ancoraggio. Con i contenitori LXC / Docker, sarà qualcosa di simile /lxc/<containerid>o /docker/<containerid>rispettivamente.


13
la finestra mobile ora utilizza dockerinvece di lxcquei percorsi
Andy,

4
Non funziona per i contenitori lxd / lxc, ma stackoverflow.com/a/20010626/170230 funziona.
Draco Ater,

Con le versioni successive di systemd sembra che non si possa fare affidamento sul processo 1 usando /per tutti i cgroups; sul mio sistema Debian 9 (systemd 232) solo tre dei dieci cgroups ( 3:cpuset, 4:perf_evente 7:freezer) sono alla radice; il resto è sotto /init.scope. Detto questo, penso che cercare quel file :/docker/sia probabilmente l'euristica più affidabile al momento.
cjs,

2
grep 'docker\|lxc' /proc/1/cgroupfunziona per me su Docker 18.09.
rypel,

1
Non funziona per me. Ospita Ubuntu 19.04, guest Ubuntu 18.04 usando il contenitore privilegiato LXC. / proc / 1 / cgroup NON contiene la stringa lxc.
Gab

158

Docker crea un .dockerenvfile nella radice dell'albero delle directory all'interno del contenitore. È possibile eseguire questo script per verificare

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


ALTRO: Ubuntu in realtà ha uno script bash: /bin/running-in-containere in realtà può restituire il tipo di contenitore in cui è stato invocato. Potrebbe essere utile. Non so di altre grandi distro però.


13
Nota importante: il .dockerinitfile è stato rimosso nelle versioni recenti di Docker , quindi questo metodo non funzionerà più. Al momento della stesura di questo documento, il .dockerenvfile è ancora conservato, quindi forse potrebbe essere utilizzato al suo posto.
Jason R,

Su Debian /bin/running-in-containerè fornito da upstart. Con il passaggio a systemd potrebbe andare via. Spero di no - sembra utile!
Max Murphy,

"in cima all'albero delle directory", cosa significa? dov'è?
Alexander Mills,

3
Altri hanno sottolineato che il controllo non.dockerenv è raccomandato
Dave,

1
Nota: il test per .dockerenv funziona solo se il runtime è un demone docker. Se stai usando podman o qualcos'altro questo non riesce.
Benjamin Kircher,

22

Su un nuovo sistema Ubuntu 16.04, nuovo systemd & lxc 2.0

sudo grep -qa container=lxc /proc/1/environ

Questo funziona per me su Ubuntu focal 20.04. Nessuna delle risposte sopra questo punto ha fatto.
Jonathan Hartley,

16

Un modo conciso per controllare la finestra mobile in uno script bash è:

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

14

Comoda funzione Python per verificare se in esecuzione 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()

2
Nota importante! Ciò non sembra funzionare quando il contenitore è in esecuzione in kubernetes. Sostituisci invece l'ultima riga con 'kubepod' al posto di 'docker'. (Oppure, inserisci un'istruzione "o" che controlli entrambi;))
JJC

1
E ' kubepodsCredo.
novellino

9

Usiamo il proc proc sched (/ proc / $ PID / sched) per estrarre il PID del processo. Il PID del processo all'interno del contenitore sarà diverso, quindi è PID sull'host (un sistema non contenitore).

Ad esempio, l'output di / proc / 1 / sched su un contenitore restituirà:

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

In un host non contenitore:

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

Questo aiuta a distinguere se ci si trova in un contenitore o meno.


A seconda del sistema operativo, potrebbe essere necessario sostituire "init" con "systemd". Maggiori informazioni su systemd qui .
BrianV,

Sì, ma il punto non era il nome del processo init, il punto era il numero del processo.
MillerGeek,

Questo sembra funzionare solo su Docker. In un contenitore LXC
Restituisce Systemd

Ora sta restituendo anche 1 nella finestra mobile. Di solito è lì she non è initlì, ma può essere quasi tutto in entrambi.
Jan Hudec,

Sotto la finestra mobile, questo non è più il casobash-5.0# cat /proc/1/sched bash (1, #threads: 1)
Shalomb

5

Il modo più semplice sarebbe controllare l'ambiente. Se hai ilcontainer=lxc variabile, ti trovi in ​​un contenitore.

Altrimenti, se sei root, puoi provare a eseguire mknodo mountoperare, se fallisce, molto probabilmente ti trovi in ​​un contenitore con capacità rilasciate.


Questo funziona non solo per la finestra mobile (non l'ho verificato), ma soprattutto per i contenitori lxd / lxc (controllato), dove /proc/1/cgroupnon è possibile rilevarlo.
Draco Ater,

2
puoi modificare la risposta con il codice anziché con lo pseudocodice? "container = lxc"? non è proprio niente. intendi qualcosa come if [["lxc" = "$ container"]]?
Alexander Mills,

3
Voglio dire ... è strano, di solito le variabili env sono tutte in maiuscolo, quindi cerco una certa precisione qui
Alexander Mills

7
docker run alpine envnon fornisce nulla che assomigli a quella variabile
Archimede Trajano

3

La mia risposta vale solo per i processi Node.js ma può essere pertinente per alcuni visitatori che si imbattono in questa domanda alla ricerca di una risposta specifica Node.js.

Ho avuto lo stesso problema e basandomi su /proc/self/cgroupho creato un pacchetto npm esclusivamente per questo scopo, per rilevare se un processo Node.js viene eseguito all'interno di un contenitore Docker o meno.

Il modulo containerizzato npm ti aiuterà in Node.js. Al momento non è testato in Io.js ma potrebbe funzionare anche lì.


Grazie per questo modulo, sembrano esserci un paio di correzioni aperte in sospeso - lo stai ancora mantenendo?
Stevokk,

2

Controlla tutte le soluzioni sopra 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())

Verifica teorica:

$ docker run --rm -it --mount type=bind,source=${PWD}/incontainer.py,target=/tmp/script.py python:3 python /tmp/script.py
True

Questo non ha funzionato per me sul contenitore docker basato su Mac. Restituisce vuoto. Docker versione 2.1.0.1 (37199).
splintercell

Questo ha fatto: def is_non_docker(): return os.path.exists('/proc/1/cgroup')secondo la risposta accettata qui stackoverflow.com/questions/20010199/…
splintercell

2
Ottieni un uso inutile del premio Cat. E l'uso inutile del sottoprocesso.
Jan Hudec,

Sì, questo è un livello completamente nuovo di inutili cat! Bello uno :-D
Timmmm

Hai ragione, aggiornerò la risposta anche se non è ancora onnicomprensiva. @JanHudec
blakev

1

Docker si sta evolvendo di giorno in giorno, quindi non possiamo dire con certezza se rimarranno .dockerenv .dockerinitin futuro.

Nella maggior parte dei gusti Linux initè il primo processo da avviare. Ma nel caso di contenitori questo non è vero.

#!/bin/bash
if ps -p1|grep -q init;then  
  echo "non-docker" 
else 
  echo "docker" 
fi

6
Nemmeno @RomanTrofimov LXC / Docker. Che commento divertente.
abourget,

1
Non funziona anche in centos 7. Quando corro nella mia macchina host dice docker. Sembra che systemd sia in esecuzione come ID processo 1
Venkateswara Rao,

@VenkateswaraRao - Deve essere eseguito all'interno del contenitore. L'intento è scoprire se ci si trova all'interno di un container docker o meno.
Govind Kailas,

1
@GovindKailas: Il problema è che questo presuppone che sia quello normale PID init, che non è vero sui sistemi systemdo launchdbasati su ...
Gert van den Berg

3
@SamThomas: launchd, upstart, Solaris SMF, systemd, Sys V style init, BSD style init (questi due e alcuni altri potrebbero chiamare il loro PID 1 initperò), OpenRC, initng, runit. Vedi qui . La maggior parte dei moderni sistemi basati su Linux userebbe systemd, alcuni più vecchi, in partenza ... Tutti i moderni sistemi OS X userebberolaunchd
Gert van den Berg

0

Domande e risposte SO: "Scopri se il sistema operativo è in esecuzione in un ambiente virtuale" ; sebbene non coincida con la domanda del PO, in effetti risponde a casi comuni di ricerca in quale contenitore ci si trova (se non del tutto).

In particolare, installa e leggi il codice di questo script bash che sembra funzionare abbastanza bene:

virt-what :

sudo apt install virt-what

Non funziona con la virt-whatversione 1.14-1 su Ubuntu 16.04. Ha bisogno di patch.
Lucas,

0

Ho tradotto la risposta di JJC in rubino

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

-1

In un contenitore finestra mobile, le voci /proc/self/cgroupsono montate su cgroups sull'host.

ad es. in un contenitore

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

mentre lo stesso sull'host

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

Usare qualcosa nella shell per un test di basso profilo

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

Restituisce 1 su entrambi.
sorin,

-4

Forse questo fa il trucco:

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

È questo che vuoi? Spero che aiuti =)


1
dockerOvviamente non è disponibile alcun file binario dall'interno del contenitore.
Toriningen,

3
Umm, questo fallirebbe in situazioni (es. Gitlab docker-in-docker) in cui il container di controllo ha dockere accesso al socket docker degli host.
Shalomb,

1
sì, hai ragione, certo che non c'è ^^. Ho avuto un'interpretazione sbagliata sulla domanda nel momento in cui l'ho letta. Grazie Shalomb.
Leonardo Da Vinci,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.