Comment déterminer si un processus s'exécute dans lxc / Docker?

172

Existe-t-il un moyen de déterminer si un processus (script) s'exécute dans un conteneur lxc (~ Docker runtime)? Je sais que certains programmes sont capables de détecter s'ils s'exécutent à l'intérieur d'une machine virtuelle, est-ce que quelque chose de similaire est disponible pour lxc / docker?

Mate Varga
la source
Cela peut sembler pédant, mais il serait préférable de reformuler votre question pour décrire un problème que vous rencontrez et demander comment le résoudre - sans cela, la question a plus de chances d'être fermée. Dans de nombreux cas, il est difficile de faire ce changement, mais dans le vôtre, il ne serait pas difficile de simplement reformuler si vous le souhaitez.
mah du
il y a une réponse intéressante lors de l'émission de cette commande à l'intérieur d'un conteneur: uptime
Scott Stensland

Réponses:

170

Le moyen le plus fiable est de vérifier /proc/1/cgroup. Il vous indiquera les groupes de contrôle du processus d'initialisation, et lorsque vous n'êtes pas dans un conteneur, ce sera /pour toutes les hiérarchies. Lorsque vous êtes à l' intérieur d' un conteneur, vous verrez le nom du point d'ancrage. Avec les conteneurs LXC / Docker, ce sera quelque chose comme /lxc/<containerid>ou /docker/<containerid>respectivement.

jpetazzo
la source
13
docker utilise maintenant dockerau lieu de lxcdans ces chemins
Andy
4
Ne fonctionne pas pour les conteneurs lxd / lxc, contrairement à stackoverflow.com/a/20010626/170230 .
Draco Ater
Avec les versions ultérieures de systemd, il semble que vous ne pouvez pas compter sur le processus 1 /pour tous les groupes de contrôle; sur mon système Debian 9 (systemd 232), seuls trois des dix groupes de contrôle ( 3:cpuset, 4:perf_eventet 7:freezer) sont à la racine; le reste est sous /init.scope. Cela dit, je pense que la recherche de ce fichier :/docker/est probablement l'heuristique la plus fiable pour le moment.
cjs
2
grep 'docker\|lxc' /proc/1/cgroupfonctionne pour moi sur Docker 18.09.
rypel
1
Ne travaille pas pour moi. Hôte Ubuntu 19.04, invité Ubuntu 18.04 utilisant le conteneur privilégié LXC. / proc / 1 / cgroup ne contient PAS la chaîne lxc.
Gab
158

Docker crée un .dockerenvfichier à la racine de l'arborescence de répertoires à l'intérieur du conteneur. Vous pouvez exécuter ce script pour vérifier

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


PLUS: Ubuntu a en fait un script bash: /bin/running-in-containeret il peut en fait renvoyer le type de conteneur dans lequel il a été appelé. Cela pourrait être utile. Je ne sais pas pour les autres distributions majeures cependant.

at0S
la source
13
Note importante: le .dockerinitfichier a été supprimé dans les versions récentes de Docker , donc cette méthode ne fonctionnera plus. Au moment d'écrire ces lignes, le .dockerenvfichier est toujours conservé, donc peut-être qu'il pourrait être utilisé à la place.
Jason R
Sur Debian /bin/running-in-containerest fourni par upstart. Avec la transition vers systemd, il pourrait disparaître. J'espère que non - cela semble utile!
Max Murphy
"au sommet de l'arborescence des répertoires", qu'est-ce que cela signifie? où est-ce?
Alexander Mills
3
D'autres ont souligné que la vérification .dockerenvn'est pas recommandée
Dave
1
Remarque: le test de .dockerenv ne fonctionne que si le runtime est un démon docker. Si vous utilisez podman ou autre chose, cela échoue.
Benjamin Kircher
22

Sur un nouveau système ubuntu 16.04, de nouveaux systemd et lxc 2.0

sudo grep -qa container=lxc /proc/1/environ
larss
la source
Cela fonctionne pour moi sur Ubuntu focal 20.04. Aucune des réponses ci-dessus ne l'a fait.
Jonathan Hartley le
16

Une manière concise de vérifier le docker dans un script bash est:

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

Fonction Python pratique pour vérifier si elle fonctionne dans 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
la source
2
Note importante! Cela ne semble pas fonctionner lorsque le conteneur est exécuté dans kubernetes. Au lieu de cela, remplacez la dernière ligne par «kubepod» à la place de «docker». (Ou, insérez une déclaration "ou" qui vérifie les deux;))
JJC
1
C'est kubepodsje suppose.
rookie099
9

Nous utilisons le sched de proc (/ proc / $ PID / sched) pour extraire le PID du processus. Le PID du processus à l'intérieur du conteneur sera différent de celui de l'hôte (un système sans conteneur).

Par exemple, la sortie de / proc / 1 / sched sur un conteneur retournera:

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

Sur un hôte non-conteneur:

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

Cela permet de différencier si vous êtes dans un conteneur ou non.

Fondateur
la source
Selon le système d'exploitation, "init" peut devoir être remplacé par "systemd". Plus d'informations sur systemd ici .
BrianV
Oui, mais le point n'était pas le nom du processus init, le point était le numéro du processus.
MillerGeek
Cela semble ne fonctionner que sur Docker. Dans un conteneur LXC il renvoie Systemd PID 1
MillerGeek
Il renvoie également 1 dans le docker. Il est généralement shet pas initlà, mais il peut être presque n'importe quoi dans l'un ou l'autre.
Jan Hudec
Sous docker, ce n'est plus le cas -bash-5.0# cat /proc/1/sched bash (1, #threads: 1)
shalomb
5

Le moyen le plus simple serait de vérifier l'environnement. Si vous avez la container=lxcvariable, vous êtes dans un conteneur.

Sinon, si vous êtes root, vous pouvez essayer d'exécuter mknodou d' mountopérer, si cela échoue, vous êtes probablement dans un conteneur avec des capacités supprimées.

craquer
la source
Celui-ci fonctionne non seulement pour docker (je ne l'ai pas vérifié), mais plus important encore pour les conteneurs lxd / lxc (coché), où /proc/1/cgroupne vous permet pas de le détecter.
Draco Ater
2
pouvez-vous modifier la réponse avec du code au lieu du pseudocode? "container = lxc"? n'est rien de correct. voulez-vous dire quelque chose comme si [["lxc" = "$ container"]]?
Alexander Mills
3
Je veux dire ... c'est bizarre, généralement les variables d'env sont en majuscules, alors cherchez un peu de précision ici
Alexander Mills
7
docker run alpine envne donne rien qui ressemble à cette variable
Archimedes Trajano
3

Ma réponse ne s'applique qu'aux processus Node.js, mais peut être pertinente pour certains visiteurs qui tombent sur cette question à la recherche d'une réponse spécifique à Node.js.

J'ai eu le même problème et en m'appuyant sur /proc/self/cgroupj'ai créé un package npm dans ce seul but - pour détecter si un processus Node.js s'exécute ou non dans un conteneur Docker.

Le module npm conteneurisé vous aidera dans Node.js. Il n'est actuellement pas testé dans Io.js mais peut tout aussi bien y fonctionner.

Martin Tajur
la source
Merci pour ce module, il semble y avoir quelques correctifs ouverts en attente - le maintenez-vous toujours?
stevokk
2

Recherchez toutes les solutions ci-dessus 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())

Preuve de concept:

$ docker run --rm -it --mount type=bind,source=${PWD}/incontainer.py,target=/tmp/script.py python:3 python /tmp/script.py
True
blakev
la source
Cela n'a pas fonctionné pour moi sur le conteneur Docker basé sur Mac. Renvoie vide. Docker version 2.1.0.1 (37199).
splintercell
Celui-ci a fait: def is_non_docker(): return os.path.exists('/proc/1/cgroup')selon la réponse acceptée ici stackoverflow.com/questions/20010199/…
splintercell
2
Vous obtenez un prix d'utilisation inutile de chat. Et l'utilisation inutile du sous-processus un.
Jan Hudec
Ouais, c'est un tout nouveau niveau d'inutile cat! Nice one :-D
Timmmm
Vous avez raison, je vais mettre à jour la réponse même si ce n'est toujours pas tout. @JanHudec
blakev
1

Docker évolue de jour en jour, nous ne pouvons donc pas dire avec certitude s'ils vont continuer .dockerenv .dockerinitdans le futur.

Dans la plupart des versions Linux, initc'est le premier processus à démarrer. Mais dans le cas des conteneurs, ce n'est pas vrai.

#!/bin/bash
if ps -p1|grep -q init;then  
  echo "non-docker" 
else 
  echo "docker" 
fi
Govind Kailas
la source
6
@RomanTrofimov LXC / Docker non plus. Quel drôle de commentaire.
environ
1
Cela ne fonctionne pas non plus dans les centos 7. Lorsque je lance sur ma machine hôte, il dit docker. On dirait que systemd est en cours d'exécution en tant que processus id 1
Venkateswara Rao
@VenkateswaraRao - Cela doit être exécuté à l'intérieur du conteneur. L'intention est de savoir si vous êtes à l'intérieur d'un conteneur Docker ou non.
Govind Kailas
1
@GovindKailas: Le problème est que cela suppose que le PID normal est init, ce qui n'est pas vrai sur systemdou launchdbasé sur des systèmes ...
Gert van den Berg
3
@SamThomas: launchd, upstart, Solaris SMF, systemd, init de style Sys V, init de style BSD (ces deux et quelques autres peuvent cependant appeler leur PID 1 init), OpenRC, initng, runit. Regardez ici . La plupart des systèmes modernes basés sur Linux utiliseraient systemd, certains plus anciens, parvenus ... Tous les systèmes OS X modernes utiliseraientlaunchd
Gert van den Berg
0

Ce Q&A SO: "Découvrez si le système d'exploitation fonctionne dans un environnement virtuel" ; bien que différent de la question du PO, il répond en effet aux cas courants de recherche dans quel conteneur vous vous trouvez (voire pas du tout).

En particulier, installez et lisez le code de ce script bash qui semble fonctionner plutôt bien:

virt-quoi :

sudo apt install virt-what
kaiwan
la source
Ne fonctionne pas avec la virt-whatversion 1.14-1 sur Ubuntu 16.04. Besoin d'un patch.
Lucas le
0

J'ai traduit la réponse de JJC en rubis

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
la source
-1

Dans un conteneur Docker, les entrées /proc/self/cgroupsont montées sur des groupes de contrôle sur l'hôte.

par exemple dans un conteneur

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

alors que, pareil sur l'hôte

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

Utiliser quelque chose dans la coque pour un test discret

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
la source
Renvoie 1 sur les deux.
sorin le
-4

Peut-être que cela fera l'affaire:

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

Est-ce que c'est ce que tu veux? J'espère que ça aide =)

Léonard de Vinci
la source
1
Aucun dockerbinaire n'est disponible à l'intérieur du conteneur, évidemment.
toriningen
3
Euh, cela échouerait dans des situations (par exemple, gitlab docker-in-docker) où le conteneur de contrôle a dockeret accède au socket docker des hôtes.
shalomb
1
ouais, tu as raison, bien sûr qu'il n'y en a pas ^^. J'ai eu une mauvaise interprétation de la question au moment où je l'ai lue. Merci, Shalomb.
Leonardo Da Vinci le