Como determinar se um processo é executado no lxc / Docker?

172

Existe alguma maneira de determinar se um processo (script) é executado dentro de um contêiner lxc (~ Docker runtime)? Eu sei que alguns programas são capazes de detectar se são executados dentro de uma máquina virtual. Existe algo semelhante disponível para o lxc / docker?

Mate Varga
fonte
Pode parecer pedante, mas seria melhor reformular sua pergunta para descrever um problema que você está tendo e perguntar como resolvê-lo - sem isso, a pergunta tem uma chance maior de ser encerrada. Em muitos casos, é difícil fazer essa alteração, mas no seu não seria difícil simplesmente reformular, se desejar.
mah
há uma resposta interessante ao emitir este comando, enquanto no interior de um recipiente: o tempo de funcionamento
Scott Stensland

Respostas:

169

A maneira mais confiável é verificar /proc/1/cgroup. Ele informará os grupos de controle do processo init e, quando você não estiver em um contêiner, será /para todas as hierarquias. Quando você estiver dentro de um contêiner, verá o nome do ponto de ancoragem. Com os contêineres LXC / Docker, será algo parecido /lxc/<containerid>ou /docker/<containerid>respectivamente.

jpetazzo
fonte
13
docker agora usa em dockervez de lxcnesses caminhos
Andy
4
Não funciona para contêineres lxd / lxc, mas o stackoverflow.com/a/20010626/170230 funciona.
Draco Ater
Nas versões posteriores do systemd, parece que você não pode confiar no processo 1 usado /para todos os cgroups; no meu sistema Debian 9 (systemd 232), apenas três dos dez cgroups ( 3:cpuset, 4:perf_evente 7:freezer) estão na raiz; o resto está abaixo /init.scope. Dito isso, acho que pesquisar nesse arquivo :/docker/é provavelmente a heurística mais confiável no momento.
CJS
2
grep 'docker\|lxc' /proc/1/cgroupfunciona para mim no Docker 18.09.
Ripel
1
Não está trabalhando para mim. Hospede o Ubuntu 19.04, Ubuntu convidado 18.04 usando o contêiner privilegiado LXC. / proc / 1 / cgroup NÃO contém a string lxc.
Gab
157

O Docker cria um .dockerenvarquivo na raiz da árvore de diretórios dentro do contêiner. Você pode executar este script para verificar

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


MAIS: O Ubuntu realmente possui um script bash: /bin/running-in-containere na verdade pode retornar o tipo de contêiner em que foi chamado. Pode ser útil. Porém, não conheço outras distros importantes.

at0S
fonte
13
Nota importante: o .dockerinitarquivo foi removido nas versões recentes do Docker , portanto, esse método não funcionará mais. Até o momento em que este artigo foi escrito, o .dockerenvarquivo ainda é mantido, então talvez isso possa ser usado.
Jason R
No Debian /bin/running-in-containeré fornecido por upstart. Com a transição para o systemd, isso pode desaparecer. Espero que não - parece útil!
Max Murphy
"no topo da árvore de diretórios", o que isso significa? onde fica isso?
Alexander Mills
3
Outros têm apontado que a verificação .dockerenvé não recomendado
Dave
1
Nota: o teste para .dockerenv funcionará apenas se o tempo de execução for daemon do docker. Se você estiver usando o podman ou outra coisa, isso falhará.
Benjamin Kircher
22

Em um novo sistema ubuntu 16.04, o novo systemd & lxc 2.0

sudo grep -qa container=lxc /proc/1/environ
Larss
fonte
Isso funciona para mim no Ubuntu focal 20.04. Nenhuma das respostas acima deste ponto o fez.
Jonathan Hartley
16

Uma maneira concisa de verificar a janela de encaixe em um script bash é:

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

Função útil do Python para verificar se está sendo executado no 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
fonte
2
Nota importante! Isso não parece funcionar quando o contêiner está sendo executado nos kubernetes. Em vez disso, substitua a última linha por 'kubepod' no lugar de 'docker'. (Ou, coloque uma declaração "ou" que verifique os dois;))
JJC
1
É kubepods, eu acho.
precisa saber é o seguinte
9

Usamos a programação do proc (/ proc / $ PID / sched) para extrair o PID do processo. O PID do processo dentro do contêiner será diferente do PID no host (um sistema sem contêiner).

Por exemplo, a saída de / proc / 1 / sched em um contêiner retornará:

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

Enquanto estiver em um host sem contêiner:

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

Isso ajuda a diferenciar se você está em um contêiner ou não.

Fundador
fonte
Dependendo do sistema operacional, "init" pode precisar ser substituído por "systemd". Mais informações sobre o systemd aqui .
BrianV
Sim, mas o ponto não era o nome do processo init, o ponto era o número do processo.
MillerGeek
Isso parece funcionar apenas no Docker. Em um contêiner LXC Ele está retornando Systemd PID 1
MillerGeek
Agora também está retornando 1 na janela de encaixe. É geralmente she não initexiste, mas pode ser quase tudo em qualquer um.
Jan Hudec
Sob docker, este não é mais o caso -bash-5.0# cat /proc/1/sched bash (1, #threads: 1)
shalomb
5

A maneira mais fácil seria verificar o ambiente. Se você tiver a container=lxcvariável, você está dentro de um contêiner.

Caso contrário, se você for root, poderá tentar executar mknodou mountoperar, se falhar, provavelmente estará em um contêiner com recursos descartados.

creack
fonte
Este funciona não apenas para o docker (eu não verifiquei isso), mas mais importante para os contêineres lxd / lxc (marcados), onde /proc/1/cgroupnão permite detectar isso.
Draco Ater
2
você pode editar a resposta com código em vez de pseudocódigo? "container = lxc"? não é nada apropriado. você quer dizer algo como se [["lxc" = "$ container"]]?
Alexander Mills
3
Quero dizer ... é estranho, normalmente variáveis env estão em todas as tampas, assim procurando alguma precisão aqui
Alexander Mills
7
docker run alpine envnão dá qualquer coisa que se parece com essa variável
Archimedes Trajano
3

Minha resposta se aplica apenas aos processos do Node.js., mas pode ser relevante para alguns visitantes que se deparam com essa pergunta à procura de uma resposta específica ao Node.js.

Eu tive o mesmo problema e, contando com a /proc/self/cgroupcriação, criei um pacote npm apenas para esse fim - para detectar se um processo Node.js é executado dentro de um contêiner do Docker ou não.

o módulo npm em contêiner ajudará você no Node.js. No momento, ele não está testado no Io.js, mas também pode funcionar lá.

Martin Tajur
fonte
Obrigado por este módulo, parece haver algumas correções pendentes - você ainda está mantendo isso?
Stevokk
2

Verifique todas as soluções acima em 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())

Prova de conceito:

$ docker run --rm -it --mount type=bind,source=${PWD}/incontainer.py,target=/tmp/script.py python:3 python /tmp/script.py
True
blakev
fonte
Isso não funcionou para mim no container docker baseado em Mac. Retorna vazio. Docker versão 2.1.0.1 (37199).
SplinterCell
Este foi o seguinte: de def is_non_docker(): return os.path.exists('/proc/1/cgroup')acordo com a resposta aceita aqui stackoverflow.com/questions/20010199/…
splintercell:
2
Você recebe um prêmio de uso inútil de gato. E uso inútil do subprocesso um.
Jan Hudec
Sim, este é um nível totalmente novo de desnecessário cat! Nice one :-D
Timmmm
Você está certo, eu atualizarei a resposta, mesmo que ainda não seja abrangente. @JanHudec
blakev
1

O Docker está evoluindo dia a dia, então não podemos dizer com certeza se eles continuarão .dockerenv .dockerinitno futuro.

Na maioria dos sabores do Linux, inité o primeiro processo a ser iniciado. Mas no caso de contêineres isso não é verdade.

#!/bin/bash
if ps -p1|grep -q init;then  
  echo "non-docker" 
else 
  echo "docker" 
fi
Govind Kailas
fonte
6
@RomanTrofimov LXC / Docker também não. Que comentário engraçado.
abourget
1
Também não funciona no centos 7. Quando corro na minha máquina host, diz docker. Looks como systemd está sendo executado como ID do processo 1
Venkateswara Rao
@VenkateswaraRao - Isso deve ser executado dentro do contêiner. A intenção é descobrir se você está dentro de um contêiner de docker ou não.
Govind Kailas
1
@GovindKailas: O problema é que isso pressupõe que o normal PID é init, o que não é verdade em systemdou launchdsistemas baseados ...
Gert van den Berg
3
@ SamThomas: launchd, upstart, Solaris SMF, systemd, init no estilo Sys V, init no estilo BSD (esses dois e alguns outros podem chamar seu PID 1 init), OpenRC, initng, runit. Veja aqui . A maioria dos sistemas baseados em Linux modernas usaria systemd, alguns mais, arrivista .... Todos os modernos sistemas OS X mais velhos usarialaunchd
Gert van den Berg
0

Este SO Q&A: "Descubra se o sistema operacional está sendo executado em um ambiente virtual" ; embora não seja o mesmo que a pergunta do OP, ele realmente responde a casos comuns de encontrar em qual container você está (se é que está).

Em particular, instale e leia o código desse script bash, que parece funcionar muito bem:

virt-what :

sudo apt install virt-what
kaiwan
fonte
Não funciona com a virt-whatversão 1.14-1 no Ubuntu 16.04. Precisa de correção.
Lucas
0

Traduzi a resposta de JJC para ruby

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
fonte
-1

Em um contêiner de janela de encaixe, as entradas /proc/self/cgroupsão montadas em cgroups no host.

por exemplo, em um recipiente

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

enquanto o mesmo no host

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

Usando algo no shell para um teste de baixo perfil

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
fonte
Retorna 1 em ambos.
sorin
-4

Talvez isso faça o truque:

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

É isso que você quer? Espero que ajude =)

Leonardo da Vinci
fonte
1
Nenhum dockerbinário está disponível dentro do contêiner, obviamente.
toriningen
3
Umm, isso falharia em situações (por exemplo, docker-in-docker do gitlab) em que o contêiner de controle tem dockere acesso ao soquete do docker dos hosts.
21418 shalomb
1
Sim, você está certo, é claro que não há ^^. Recebi a interpretação errada sobre a pergunta na época em que a li. Obrigado, Shalomb.
Leonardo Da Vinci