Jak sprawdzić, czy proces działa w kontenerze Dockera


86

[Zaktualizowano1] Mam powłokę, która zmieni parametry jądra TCP w niektórych funkcjach, ale teraz muszę uruchomić tę powłokę w kontenerze Dockera, co oznacza, że ​​powłoka musi wiedzieć, że działa w kontenerze i przestać konfigurować jądro.

Teraz nie jestem pewien, jak to osiągnąć, oto zawartość /proc/self/cgroupwnętrza pojemnika:

9:hugetlb:/
8:perf_event:/
7:blkio:/
6:freezer:/
5:devices:/
4:memory:/
3:cpuacct:/
2:cpu:/docker/25ef774c390558ad8c4e9a8590b6a1956231aae404d6a7aba4dde320ff569b8b
1:cpuset:/

Jakiekolwiek flagi powyżej, których mogę użyć, aby dowiedzieć się, czy ten proces działa w kontenerze?

[Zaktualizowano2]: Zauważyłem również, że ustalanie, czy proces działa w lxc / Docker , ale wydaje się nie działać w tym przypadku, zawartość /proc/1/cgroupmojego kontenera to:

8:perf_event:/
7:blkio:/
6:freezer:/
5:devices:/
4:memory:/
3:cpuacct:/
2:cpu:/docker/25ef774c390558ad8c4e9a8590b6a1956231aae404d6a7aba4dde320ff569b8b
1:cpuset:/

No / lxc / containerid


Niezbyt jasne pytanie. Dlaczego tego potrzebujesz?
Henk Langeveld


@fish no / lxc / <containerid> w moim przypadku, zobacz aktualizację
harryz

1
Parametry jądra @HenkLangeveld są tylko do odczytu w kontenerze Docker, więc muszę wiedzieć, czy moja powłoka działa w kontenerach i wyłączyć funkcje jądra w mojej powłoce. zobacz aktualizację.
harryz

Niektóre kroki w skrypcie próbują zmodyfikować parametry jądra i należy je pominąć podczas uruchamiania w Dockerze. Jasny.
Henk Langeveld

Odpowiedzi:


69

Aby sprawdzić wewnątrz kontenera Docker, czy jesteś w kontenerze Docker, czy nie, można to zrobić za pomocą /proc/1/cgroup. Jak sugeruje ten post , możesz wykonać następujące czynności:

Poza kontenerem docker wszystkie wpisy /proc/1/cgroupkończą się, /jak widać tutaj:

vagrant@ubuntu-13:~$ cat /proc/1/cgroup
11:name=systemd:/
10:hugetlb:/
9:perf_event:/
8:blkio:/
7:freezer:/
6:devices:/
5:memory:/
4:cpuacct:/
3:cpu:/
2:cpuset:/

Wewnątrz kontenera Docker niektóre grupy kontrolne będą należeć do Dockera (lub LXC):

vagrant@ubuntu-13:~$ docker run busybox cat /proc/1/cgroup
11:name=systemd:/
10:hugetlb:/
9:perf_event:/
8:blkio:/
7:freezer:/
6:devices:/docker/3601745b3bd54d9780436faa5f0e4f72bb46231663bb99a6bb892764917832c2
5:memory:/
4:cpuacct:/
3:cpu:/docker/3601745b3bd54d9780436faa5f0e4f72bb46231663bb99a6bb892764917832c2
2:cpuset:/

@Founder odpowiedź jest czystsza
Scott Stensland

5
nie jest do końca prawdą, że „Poza kontenerem dokera wszystkie wpisy w / proc / 1 / cgroup kończą się na /”. Na przykład na ubuntu 16.04 mam:12:perf_event:/ 11:blkio:/init.scope 10:cpuset:/ 9:devices:/init.scope 8:hugetlb:/ 7:cpu,cpuacct:/init.scope 6:net_cls,net_prio:/ 5:memory:/init.scope 4:pids:/init.scope 3:rdma:/ 2:freezer:/ 1:name=systemd:/init.scope
samfr

Działa to prawie tylko na Linuksie, a nie na Darwinie lub innych BSD, które nawet nie używają procfs.
Christian

@Christian Docker / LXC to tylko rzeczy dla Linuksa, więc w porządku, prawda :)?
Robert Lacroix

@RobertLacroix, więc mówisz, że jeśli nie znajdziesz procfs, nie jesteś w Dockerze? Cóż, to chyba wystarczy ...
Christian

109

Docker tworzy .dockerenvi .dockerinit( usunięte w wersji 1.11 ) pliki na górze drzewa katalogów kontenera, więc możesz chcieć sprawdzić, czy one istnieją.

Coś takiego powinno działać.

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

1
O ile, oczywiście, ty lub ktoś inny nie utworzył /.dockerinitna twoim hoście (być może przez przypadek), w takim przypadku będzie źle poza kontenerem.
sosiouxme

18
Jeśli ktoś inny zrobił to w /, to jest rootem i masz gorsze problemy niż wiedza, czy jesteś w dockerze, czy nie.
davey

15
Strzeż się polegania na /.dockerenvdłuższą metę. Nie jest przeznaczone do tego celu .
ReactiveRaven

fwiw, Podman nie tworzy /.dockerenv. Tworzy, /run/.containerenvale zgodnie z podobną logiką brzmi jak szczegół implementacji, na którym nie można polegać. Zobacz github.com/containers/libpod/issues/3586, aby zapoznać się z alternatywami specyficznymi dla podmana.
Beni Cherniavsky-Paskin

22

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 polecenia / 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. np. możesz zrobić:

if [[ ! $(cat /proc/1/sched | head -n 1 | grep init) ]]; then {
    echo in docker
} else {
    echo not in docker
} fi

jest to właściwie bardzo cenna informacja. dzięki
Fabian Lange

4
W zależności od systemu operacyjnego, „init” może wymagać zastąpienia przez „systemd”. Więcej informacji o systemd tutaj .
BrianV

2
Jak wspomniał @BrianV, to też nie działa dla mnie.
Shubham Chaudhary

5
W kontenerze Docker działającym w klastrze k8s head -n1 /proc/1/schedzwraca dumb-init (1, #threads: 1), więc sprawdzenie sugerowane w tej odpowiedzi kończy się niepowodzeniem. (Ponadto, wbrew temu, co sugeruje odpowiedź, PID jest wyświetlany jako „1” w tym wierszu, chociaż robię to w kontenerze.)
Stefan Majewsky

To zdecydowanie nie jest rozwiązanie uniwersalne. Możesz (w pewnym sensie) użyć cokolwiek chcesz dla PID 1 kontenera. Np. Jeśli to zrobisz docker run --init ..., będzie docker-init. Jeśli to zrobisz, docker run ... head -n 1 /proc/1/schedto będzie head.
jpkotta

21

Rozwiązanie Thomasa jako kod:

running_in_docker() {
  (awk -F/ '$2 == "docker"' /proc/self/cgroup | read non_empty_input)
}

Uwaga

readZe zmienną manekina jest proste idiom za to się wyświetli niczego? . Jest to kompaktowa metoda przekształcania być może rozwlekłego greplub awkw test wzoru.

Dodatkowa uwaga dotycząca czytania


10
Tyle że ... to się nie powiedzie w niektórych środowiskach, ponieważ np. 3:cpu,cpuacct:/system.slice/docker-1ce79a0dec4a2084d54acf187a1e177e0339dc90d0218b48b4456576ecaf291e.scopeNie będzie pasować. Prostsze grep -q docker /proc/1/cgroup; kod wynikowy z tego również powinien być wystarczający.
larsks

2
readmoże zadziałać bash, ale w najczęściej używanej dashpowłoce musisz użyć albo read dummy(lub podobnego) lub użyć konstrukcji takiej jak[ -n "$(command)" ]
Daniel Alder

@DanielAlder Dobry chwyt, Daniel. Zaktualizuję tekst.
Henk Langeveld

1
Wcześniej twierdzono, że każda powłoka kompatybilna z Bourne obsługuje zwykłą wersję readbez nazwy zmiennej. Dotyczy to tylko bash i ksh93. Grupa Opengroup określa tylko read vari nie wspomina o readzachowaniu bez co najmniej jednej zmiennej. W bash i ksh93 , jeśli nie var jest podana, czytać używa zmiennej powłoki REPLY.
Henk Langeveld

1
Dlaczego nie możemy po prostu użyć awk -F: '$3 ~ /docker/' /proc/self/cgroup | read? Pracuje dla mnie.
Shubham Chaudhary

7

W moim przypadku działa sprawdzanie numeru i-węzła „/”. Wewnątrz dockera jest bardzo dużo. Poza dokerem jest to bardzo niska liczba, np. „2”. Sądzę, że to podejście zależałoby również od używanego systemu plików.

Przykład

Wewnątrz dokera:

# ls -ali / | sed '2!d' |awk {'print $1'}
1565265

Poza dokerem

$ ls -ali / | sed '2!d' |awk {'print $1'}
2

W skrypcie:

#!/bin/bash
INODE_NUM=`ls -ali / | sed '2!d' |awk {'print $1'}`
if [ $INODE_NUM == '2' ];
then
        echo "Outside the docker"
else
        echo "Inside the docker"
fi

w MSYS2 ls -ali / | sed '2! d' | awk {'print $ 1'} 232779805740174872
bo0k

tak samo jak ls -di /? wydaje się, że numer i-węzła nie jest wiarygodny na innej platformie
yurenchen

to jedyna rzecz, która
pomogła

1

Musieliśmy wykluczyć procesy działające w kontenerach, ale zamiast sprawdzać tylko grupy cgroup Dockera, zdecydowaliśmy się porównać /proc/<pid>/ns/pidz systemem init pod adresem /proc/1/ns/pid. Przykład:

pid=$(ps ax | grep "[r]edis-server \*:6379" | awk '{print $1}')
if [ $(readlink "/proc/$pid/ns/pid") == $(readlink /proc/1/ns/pid) ]; then
   echo "pid $pid is the same namespace as init system"
else
   echo "pid $pid is in a different namespace as init system"
fi

Lub w naszym przypadku chcieliśmy mieć jedną wkładkę, która generuje błąd, jeśli proces NIE jest w pojemniku

bash -c "test -h /proc/4129/ns/pid && test $(readlink /proc/4129/ns/pid) != $(readlink /proc/1/ns/pid)"

który możemy wykonać z innego procesu i jeśli kod zakończenia ma wartość zero, to określony PID działa w innej przestrzeni nazw.


Nie działa dla mnie. Od wewnątrz K8S zaplanowane Docker pojemnika, readlink /proc/self/ns/pidi readlink /proc/1/ns/piddają ten sam wynik.
Stefan Majewsky,

1
@StefanMajewsky Może zechcesz spróbować użyć github.com/jessfraz/amicontained, aby zobaczyć, jakie funkcje są włączone w środowisku wykonawczym kontenera.
Greg Bray

0

Na podstawie komentarza Dana Walsha o używaniu SELinux ps -eZ | grep container_t, ale bez konieczności psinstalacji:

$ podman run --rm fedora:31 cat /proc/1/attr/current
system_u:system_r:container_t:s0:c56,c299
$ podman run --rm alpine cat /proc/1/attr/current
system_u:system_r:container_t:s0:c558,c813
$ docker run --rm fedora:31 cat /proc/1/attr/current
system_u:system_r:container_t:s0:c8,c583
$ cat /proc/1/attr/current
system_u:system_r:init_t:s0

To właśnie mówi ci używasz w w pojemniku, ale nie które Runtime.

Nie sprawdzono innych środowisk wykonawczych kontenera, ale https://opensource.com/article/18/2/understanding-selinux-labels-container-runtimes zawiera więcej informacji i sugeruje, że jest to powszechnie używane, może również działać w przypadku rkt i lxc?


-1

Stworzyłem mały skrypt w Pythonie. Mam nadzieję, że ktoś uzna to za przydatne. :-)

#!/usr/bin/env python3
#@author Jorge III Altamirano Astorga 2018
import re
import math

total = None
meminfo = open('/proc/meminfo', 'r')
for line in meminfo:
    line = line.strip()
    if "MemTotal:" in line:
        line = re.sub("[^0-9]*", "", line)
        total = int(line)
meminfo.close()
print("Total memory: %d kB"%total)

procinfo = open('/proc/self/cgroup', 'r')
for line in procinfo: 
    line = line.strip()
    if re.match('.{1,5}:name=systemd:', line):
        dockerd = "/sys/fs/cgroup/memory" + \
            re.sub("^.{1,5}:name=systemd:", "", line) + \
            "/memory.stat"
        #print(dockerd)
        memstat = open(dockerd, 'r')
        for memline in memstat:
            memline = memline.strip()
            if re.match("hierarchical_memory_limit", memline):
                memline = re.sub("[^0-9]*", \
                    "", memline)  
                total = math.floor(int(memline) / 2**10)
        memstat.close()
procinfo.close()
print("Total available memory to the container: %d kB"%total)

jest fajnie, ale jak pomaga określić, czy jesteś w pojemniku, czy nie?
user528025

FileNotFoundError: [Errno 2] No such file or directory: '/sys/fs/cgroup/memory/docker/<docker_id>/memory.stat'
Scrooge McDuck
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.