Як визначити, чи працює процес всередині lxc / Docker?


172

Чи є спосіб визначити, чи працює процес (скрипт) всередині контейнера lxc (~ час виконання Docker)? Я знаю, що деякі програми здатні виявити, чи працюють вони у віртуальній машині, чи є щось подібне для lxc / docker?


Це може здатися педантичним, але найкраще перефразувати своє питання, щоб описати проблему, яка виникає, і запитати, як її вирішити - без цього питання більше шансів бути закритим. У багатьох випадках важко зробити цю зміну, але у ваших проблемах не важко буде просто перефразувати, якщо хочете.
ма

є цікава відповідь при видачі цієї команди, перебуваючи всередині контейнера: uptime
Scott Stensland,

Відповіді:


169

Найбільш надійний спосіб - перевірити /proc/1/cgroup. Він розповість вам про групи управління процесом init, і коли ви не знаходитесь в контейнері, це буде /для всіх ієрархій. Коли ви знаходитесь всередині контейнера, ви побачите назву точки прив’язки. З контейнерами LXC / Docker це буде щось подібне /lxc/<containerid>або /docker/<containerid>відповідно.


13
Докер тепер використовує dockerзамість lxcцих шляхів
Енді

4
Не працює для lxd / lxc контейнерів, але stackoverflow.com/a/20010626/170230 робить.
Драко Атер

З пізнішими версіями systemd схоже, що ви не можете розраховувати на процес 1, який використовується /для всіх груп; в моїй Debian 9 (Systemd 232) тільки три з десяти контрольних груп ( 3:cpuset, 4:perf_eventі 7:freezer) знаходяться в кореневому каталозі; решта - під /init.scope. З цього приводу я думаю, що пошук цього файлу :/docker/, мабуть, є найбільш надійним евристичним на даний момент.
cjs

2
grep 'docker\|lxc' /proc/1/cgroupпрацює для мене на Docker 18.09.
рипель

1
Не працює для мене. Хост Ubuntu 19.04, гостьовий Ubuntu 18.04, використовуючи привілейований контейнер LXC. / proc / 1 / cgroup НЕ містить рядок lxc.
Габ

157

Docker створює .dockerenvфайл у корені дерева каталогів всередині контейнера. Ви можете запустити цей сценарій для підтвердження

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


БІЛЬШЕ: Насправді Ubuntu має сценарій bash: /bin/running-in-containerі він фактично може повернути тип контейнера, в який він викликався. Можливо, це буде корисним. Не знаю, проте, про інші основні дистрибуції.


13
Важлива примітка: .dockerinitфайл видалено в останніх версіях Docker , тому цей спосіб більше не працюватиме. На момент написання цього .dockerenvфайлу все ще зберігається, тому, можливо, він може бути використаний замість цього.
Джейсон R

На Debian /bin/running-in-containerнадає компанія upstart. З переходом на systemd він може піти. Сподіваюсь, що ні - це звучить корисно!
Макс Мерфі

"на вершині дерева директорій", що це означає? де це?
Олександр Міллс

3
Інші зазначають, що перевірка .dockerenvє не рекомендується
Dave

1
Примітка: тестування на .dockerenv працює лише в тому випадку, якщо час виконання - докерський демон. Якщо ви використовуєте podman або щось інше, це не вдасться.
Бенджамін Кірхер

22

На новій системі ubuntu 16.04 новий systemd & lxc 2.0

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

Це працює для мене на Ubuntu фокусному 20.04. Ніхто з відповідей вище цього питання не зробив.
Джонатан Хартлі

16

Короткий спосіб перевірити наявність докера в bash-скрипті:

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

14

Зручна функція Python, щоб перевірити, чи працює в 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
Важлива примітка! Схоже, це не працює, коли контейнер працює в кубернетах. Замість цього замініть останній рядок на "kubepod" замість "docker". (Або
JJC

1
Це kubepodsя здогадуюсь.
rookie099

9

Для вилучення PID процесу ми використовуємо scha (/ proc / $ PID / sched). PID процесу всередині контейнера буде відрізнятися, тоді це PID на хості (без контейнерної системи).

Наприклад, вихід / proc / 1 / sched на контейнер поверне:

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

Перебуваючи на неконтейнерному хості:

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

Це допомагає розрізнити, знаходитесь ви в контейнері чи ні.


Залежно від ОС "init" може знадобитися замінити на "systemd". Більше інформації про systemd тут .
BrianV

Так, але точка не була іменем процесу init, крапка - це номер процесу.
MillerGeek

Здається, це працює лише на Докера. У контейнері LXC він повертає Systemd PID 1
MillerGeek

Зараз він також повертає 1 в докер. Це, як правило , shі не initіснує, але це може бути майже все , що ні в одному.
Ян Худек

Під докером це вже не так -bash-5.0# cat /proc/1/sched bash (1, #threads: 1)
shalomb

5

Найпростіше було б перевірити навколишнє середовище. Якщо у вас є container=lxcзмінна, ви знаходитесь в контейнері.

В іншому випадку, якщо ви root, ви можете спробувати виконати mknodабо виконати mountоперацію, якщо це не вдасться, ви, швидше за все, знаходитесь в контейнері зі скинутими можливостями.


Цей працює не лише для докера (я цього не перевіряв), але ще важливіше для контейнерів lxd / lxc (перевірено), де /proc/1/cgroupце не дозволяє виявити.
Драко Атер

2
ви можете редагувати відповідь кодом замість псевдокоду? "контейнер = lxc" - нічого не належне. ти маєш на увазі щось на зразок if [["lxc" = "$ container"]]?
Олександр Міллс

3
Я маю на увазі ... це дивно, як правило, змінні ENV є у всіх шапках, тому тут шукаємо деяку точність
Олександр Міллс

7
docker run alpine envне дає нічого, що схоже на цю змінну
Архімед

3

Моя відповідь стосується лише процесів Node.js, але може бути актуальною для деяких відвідувачів, які натрапляють на це питання, шукаючи конкретної відповіді Node.js.

У мене була така ж проблема, і покладаючись на те, що /proc/self/cgroupя створив пакет npm виключно для цієї мети - виявити, чи працює процес Node.js всередині контейнера Docker чи ні.

Контейнерний модуль НПМ допоможе вам в Node.js. В даний час він не тестується в Io.js, але може також так само добре працювати там.


Дякуємо за цей модуль, здається, ще є кілька відкритих виправлень у стані очікування - ви все ще підтримуєте це?
stevokk

2

Перевірте всі рішення вище в 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())

Доказ концепції:

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

Це не спрацювало для мене на док-контейнері на базі Mac. Повертається порожнім. Докер версія 2.1.0.1 (37199).
splintercell

Це зробив: def is_non_docker(): return os.path.exists('/proc/1/cgroup')відповідно до прийнятої відповіді тут stackoverflow.com/questions/20010199/…
splintercell

2
Ви отримуєте нагороду за марно використання котів. І марне використання підпроцесу.
Ян Худець

Так, це зовсім новий непотрібний рівень cat! Хороший :-D
Timmmm

Ви маєте рацію, я оновлю відповідь, хоча це все ще не всеохоплююче. @JanHudec
blakev

1

Докер розвивається з кожним днем, тому ми не можемо точно сказати, чи збираються вони .dockerenv .dockerinitв майбутньому.

У більшості Linux аромати init- це перший процес, який розпочато. Але у випадку з контейнерами це неправда.

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

6
@RomanTrofimov LXC / Docker теж не має. Який смішний коментар.
abourget

1
Він також не працює у центрі 7. Коли я бігаю в хост-машині, він каже, що докер. Схоже, systemd працює як ідентифікатор 1 процесу
Venkateswara Rao

@VenkateswaraRao - це потрібно запустити всередині контейнера. Намір полягає в тому, щоб дізнатися, чи знаходитесь ви в докерному контейнері чи ні.
Говінд Кайлас

1
@GovindKailas: Проблема полягає в тому, що це передбачає, що нормальний PID є init, що не відповідає дійсності systemdабо launchdна базі систем ...
Gert van den Berg

3
@SamThomas: запуск, запуску, Solaris SMF, systemd, стиль Sys V init, стиль BSD init (ці двоє та деякі інші можуть називати їх PID 1, initхоча), OpenRC, initng, runit. Дивіться тут . Використовували б більшість сучасних систем на базі Linux systemd, деякі старіші, на початку .... Всі сучасні системи OS X використовували бlaunchd
Герт ван ден Берг,

0

Це ТАК питання: "Дізнайтесь, чи працює ОС у віртуальному середовищі" ; Хоча це не те саме, що питання ОП, воно дійсно відповідає на поширені випадки пошуку того, в якому контейнері ви знаходитесь (якщо він є).

Зокрема, встановіть та прочитайте код цього скрипту bash, який, здається, працює досить добре:

virt-що :

sudo apt install virt-what

Не працює з virt-whatверсією 1.14-1 на Ubuntu 16.04. Потребує виправлення.
Лукас

0

Відповідь JJC я переклав на рубін

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

У контейнері docker записи /proc/self/cgroupмонтуються до груп на хості.

наприклад у контейнері

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

тоді як те саме на хості

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

Використання чого-небудь в оболонці для тесту на низький профіль

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

Повертає 1 для обох.
sorin

-4

Можливо, це зробити трюк:

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

Це те, чого ти хочеш? Сподіваюся, що це допомагає =)


1
Немає dockerдвоичная доступний з внутрішньої сторони контейнера, очевидно.
toriningen

3
Гм, це може бути невдалим у ситуаціях (наприклад, gitlab docker-in-docker), коли керуючий контейнер має dockerдоступ та доступ до гнізда докера хоста.
шалом

1
так, ти маєш рацію, звичайно, немає ^^. Я отримав неправильне тлумачення питання ще в той час, коли я його читав. Дякую, Шаломб.
Леонардо да Вінчі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.