Jak ustalić, czy proces działa w lxc / Docker?

172

Czy istnieje sposób, aby określić, czy proces (skrypt) działa w kontenerze LXC (środowisko wykonawcze ~ Docker)? Wiem, że niektóre programy są w stanie wykryć, czy działają w maszynie wirtualnej, czy coś podobnego jest dostępne dla lxc / docker?

Mate Varga
źródło
Może się to wydawać pedantyczne, ale najlepiej byłoby przeformułować pytanie, aby opisać problem, który masz, i zapytać, jak go rozwiązać - bez tego pytanie ma większą szansę na zamknięcie. W wielu przypadkach trudno jest dokonać takiej zmiany, ale w Twoim nie byłoby trudno po prostu przeformułować, jeśli chcesz.
mah
pojawia się interesująca odpowiedź podczas wydawania tego polecenia w kontenerze: uptime
Scott Stensland

Odpowiedzi:

169

Najbardziej niezawodnym sposobem jest sprawdzenie /proc/1/cgroup. Powie to grupy kontrola procesu init, a kiedy jesteś nie w pojemniku, który będzie /dla wszystkich hierarchiach. Gdy jesteś w kontenerze, zobaczysz nazwę punktu zakotwiczenia. W przypadku kontenerów LXC / Docker będzie to coś podobnego /lxc/<containerid>lub /docker/<containerid>odpowiednio.

jpetazzo
źródło
13
docker używa teraz dockerzamiast lxcw tych ścieżkach
Andy
4
Nie działa dla kontenerów LXD / LXC, ale stackoverflow.com/a/20010626/170230 tak.
Draco Ater
W późniejszych wersjach systemd wygląda na to, że nie można polegać na procesie 1 używającym /wszystkich cgroup; w moim systemie Debian 9 (Systemd 232) tylko trzy z dziesięciu cgroups ( 3:cpuset, 4:perf_eventi 7:freezer) są u nasady; reszta jest pod /init.scope. To powiedziawszy, myślę, że wyszukiwanie tego pliku :/docker/jest obecnie prawdopodobnie najbardziej niezawodną heurystyką.
cjs
2
grep 'docker\|lxc' /proc/1/cgroupdziała dla mnie na Dockerze 18.09.
rypel
1
Nie działa dla mnie. Host Ubuntu 19.04, gość Ubuntu 18.04 przy użyciu uprzywilejowanego kontenera LXC. / proc / 1 / cgroup NIE zawiera łańcucha lxc.
Gab
157

Docker tworzy .dockerenvplik w katalogu głównym drzewa katalogów wewnątrz kontenera. Możesz uruchomić ten skrypt, aby zweryfikować

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


WIĘCEJ: Ubuntu faktycznie ma skrypt bash: /bin/running-in-containeri faktycznie może zwrócić typ kontenera, w którym został wywołany. Może być pomocny. Nie wiem jednak o innych głównych dystrybucjach.

at0S
źródło
13
Ważna uwaga: .dockerinitplik został usunięty w ostatnich wersjach Dockera , więc ta metoda nie będzie już działać. W chwili pisania tego .dockerenvpliku plik jest nadal przechowywany, więc być może można go zamiast tego użyć.
Jason R
Na Debianie /bin/running-in-containerjest dostarczane przez upstart. Wraz z przejściem na systemd może to zniknąć. Mam nadzieję, że nie - to brzmi pożytecznie!
Max Murphy
co to znaczy „na szczycie drzewa katalogów”? gdzie to jest?
Alexander Mills,
3
Inni wskazywali, że sprawdzanie nie.dockerenv jest zalecane
Dave
1
Uwaga: testowanie dla .dockerenv działa tylko wtedy, gdy środowisko wykonawcze jest demonem Dockera. Jeśli używasz podmana lub czegoś innego, to się nie powiedzie.
Benjamin Kircher
22

W nowym systemie ubuntu 16.04, nowy systemd i lxc 2.0

sudo grep -qa container=lxc /proc/1/environ
larss
źródło
To działa dla mnie na Ubuntu focal 20.04. Żadna z odpowiedzi powyżej tego punktu nie odpowiadała.
Jonathan Hartley
16

Zwięzły sposób sprawdzenia, czy docker jest w skrypcie bash jest:

#!/bin/bash
if grep docker /proc/1/cgroup -qa; then
   echo I'm running on docker.
fi
WŁAŚCIWOŚCI
źródło
14

Poręczna funkcja Pythona do sprawdzenia, czy działa w Dockerze:

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
źródło
2
Ważna uwaga! Wygląda na to, że nie działa, gdy kontener działa w Kubernetes. Zamiast tego zamień ostatni wiersz na „kubepod” zamiast „docker”. (Lub umieść stwierdzenie „lub”, które sprawdza oba te elementy;))
JJC
1
To kubepodschyba.
rookie099
9

Używamy harmonogramu proc (/ proc / $ PID / schedule), aby wyodrębnić PID procesu. PID procesu wewnątrz kontenera będzie się różnił od jego PID na hoście (system niekontenerowy).

Na przykład wynik operacji / proc / 1 / schedule w kontenerze zwróci:

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

Na hoście innym niż kontener:

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

Pomaga to w rozróżnieniu, czy jesteś w kontenerze, czy nie.

Założyciel
źródło
W zależności od systemu operacyjnego, „init” może wymagać zastąpienia przez „systemd”. Więcej informacji o systemd tutaj .
BrianV
Tak, ale nie chodziło o nazwę procesu init, chodziło o numer procesu.
MillerGeek
Wydaje się, że działa tylko na platformie Docker. W kontenerze LXC Zwraca Systemd PID 1
MillerGeek
Teraz zwraca również 1 w dockerze. Zwykle jest shi nie initma, ale może to być prawie wszystko.
Jan Hudec
Pod dockerem tak już nie jest -bash-5.0# cat /proc/1/sched bash (1, #threads: 1)
shalomb
5

Najłatwiej byłoby sprawdzić otoczenie. Jeśli masz container=lxczmienną, jesteś w kontenerze.

W przeciwnym razie, jeśli jesteś rootem, możesz spróbować wykonać mknodlub wykonać mountoperację, jeśli to się nie powiedzie, najprawdopodobniej znajdziesz się w kontenerze z utraconymi możliwościami.

trzeszczenie
źródło
Ten działa nie tylko dla dockera (nie sprawdzałem tego), ale co ważniejsze dla kontenerów lxd / lxc (zaznaczone), gdzie /proc/1/cgroupnie pozwala ci tego wykryć.
Draco Ater
2
czy możesz edytować odpowiedź za pomocą kodu zamiast pseudokodu? „container = lxc”? nie jest niczym właściwym. czy masz na myśli coś takiego jak if [["lxc" = "$ kontener"]]?
Alexander Mills,
3
To znaczy ... to dziwne, zwykle zmienne env są we wszystkich wersalkach, więc szukam tutaj pewnej precyzji
Alexander Mills,
7
docker run alpine envnie daje niczego, co wygląda jak ta zmienna
Archimedes Trajano
3

Moja odpowiedź dotyczy tylko procesów Node.js, ale może być odpowiednia dla niektórych odwiedzających, którzy natkną się na to pytanie, szukając konkretnej odpowiedzi na Node.js.

Miałem ten sam problem i polegając na /proc/self/cgrouputworzeniu pakietu npm wyłącznie w tym celu - aby wykryć, czy proces Node.js działa w kontenerze Docker, czy nie.

Kontenerowy moduł npm pomoże Ci w Node.js. Obecnie nie jest testowany w Io.js, ale równie dobrze może tam działać.

Martin Tajur
źródło
Dzięki za ten moduł, wygląda na to, że czeka na Ciebie kilka otwartych poprawek - czy nadal to obsługujesz?
stevokk
2

Sprawdź wszystkie powyższe rozwiązania w Pythonie:

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())

Dowód koncepcji:

$ docker run --rm -it --mount type=bind,source=${PWD}/incontainer.py,target=/tmp/script.py python:3 python /tmp/script.py
True
blakev
źródło
To nie zadziałało dla mnie na kontenerze docker na Macu. Zwraca pusty. Docker w wersji 2.1.0.1 (37199).
splintercell
Ten zrobił: def is_non_docker(): return os.path.exists('/proc/1/cgroup')zgodnie z zaakceptowaną odpowiedzią tutaj stackoverflow.com/questions/20010199/…
splintercell
2
Otrzymasz nagrodę bezużytecznego wykorzystania kota. I bezużyteczne wykorzystanie podprocesu.
Jan Hudec
Tak, to zupełnie nowy poziom niepotrzebnych cat! Niezły :-D
Timmmm
Masz rację, zaktualizuję odpowiedź, mimo że nadal nie jest ona wyczerpująca. @JanHudec
blakev
1

Docker ewoluuje z dnia na dzień, więc nie możemy z całą pewnością stwierdzić, czy utrzymają się .dockerenv .dockerinitw przyszłości.

W większości odmian Linuksa initjest to pierwszy proces do uruchomienia. Ale w przypadku kontenerów to nieprawda.

#!/bin/bash
if ps -p1|grep -q init;then  
  echo "non-docker" 
else 
  echo "docker" 
fi
Govind Kailas
źródło
6
@RomanTrofimov LXC / Docker też nie. Co za zabawny komentarz.
abourget
1
Nie działa również w Centos 7. Kiedy uruchamiam się na moim komputerze głównym, pojawia się komunikat docker. Wygląda na to, że systemd działa jako proces o identyfikatorze 1
Venkateswara Rao
@VenkateswaraRao - To musi być uruchomione wewnątrz kontenera. Chodzi o to, aby dowiedzieć się, czy znajdujesz się w kontenerze docker, czy nie.
Govind Kailas
1
@GovindKailas: Problem polega na tym, że zakłada się, że normalny PID to init, co nie jest prawdą w systemach opartych systemdlub launchdopartych ...
Gert van den Berg
3
@SamThomas: launchd, upstart, Solaris SMF, systemd, init w stylu Sys V, init w stylu BSD (te dwa i kilka innych mogą jednak nazywać swój PID 1 init), OpenRC, initng, runit. Zobacz tutaj . Większość nowoczesnych systemów opartych na Linuksie systemdużywałaby, niektóre starsze, startowałyby ... Wszystkie nowoczesne systemy OS X by używałylaunchd
Gert van den Berg
0

Pytania i odpowiedzi dotyczące SO: „Dowiedz się, czy system operacyjny działa w środowisku wirtualnym” ; choć nie jest to to samo, co pytanie OP, faktycznie odpowiada na typowe przypadki znalezienia kontenera, w którym się znajdujesz (jeśli w ogóle).

W szczególności zainstaluj i przeczytaj kod tego skryptu bash, który wydaje się działać całkiem dobrze:

virt-what :

sudo apt install virt-what
kaiwan
źródło
Nie działa z virt-whatwersją 1.14-1 na Ubuntu 16.04. Potrzebuje poprawki.
Lucas
0

Przetłumaczyłem odpowiedź JJC na rubin

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
źródło
-1

W kontenerze Dockera wpisy /proc/self/cgroupsą montowane do cgroups na hoście.

np. w pojemniku

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

podczas gdy to samo na hoście

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

Używanie czegoś w powłoce do testu niskoprofilowego

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
źródło
Zwraca 1 w obu przypadkach.
sorin
-4

Może to załatwi sprawę:

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

Czy tego chcesz? Mam nadzieję, że to pomoże =)

Leonardo da Vinci
źródło
1
dockerOczywiście żaden plik binarny nie jest dostępny z wnętrza kontenera.
toriningen
3
Umm, to się nie powiedzie w sytuacjach (np. Gitlab docker-in-docker), w których kontrolujący kontener ma dockerdostęp do gniazda docker hosta .
shalomb
1
tak, masz rację, oczywiście, że nie ma ^^. Otrzymałem złą interpretację pytania w czasie, gdy je czytałem. Dziękuję, Shalomb.
Leonardo Da Vinci