Bagaimana cara menentukan apakah suatu proses berjalan di dalam lxc / Docker?

172

Apakah ada cara untuk menentukan apakah suatu proses (skrip) berjalan di dalam wadah lxc (~ Docker runtime)? Saya tahu bahwa beberapa program dapat mendeteksi apakah mereka berjalan di dalam mesin virtual, apakah tersedia sesuatu yang serupa untuk lxc / docker?

Mate Varga
sumber
Ini mungkin terlihat sangat rumit, tetapi akan lebih baik untuk mengulangi pertanyaan Anda untuk menggambarkan masalah yang Anda hadapi dan bertanya bagaimana cara menyelesaikannya - tanpa itu, pertanyaan itu memiliki peluang lebih besar untuk ditutup. Dalam banyak kasus sulit untuk melakukan perubahan itu tetapi di dalam kamu tidak akan sulit untuk hanya mengulangi jika kamu mau.
mah
ada respons yang menarik ketika mengeluarkan perintah ini saat berada di dalam sebuah wadah: uptime
Scott Stensland

Jawaban:

170

Cara yang paling dapat diandalkan adalah memeriksa /proc/1/cgroup. Ini akan memberi tahu Anda kelompok kontrol dari proses init, dan ketika Anda tidak berada dalam sebuah wadah, itu akan berlaku /untuk semua hierarki. Ketika Anda berada di dalam wadah, Anda akan melihat nama titik jangkar. Dengan wadah LXC / Docker, itu akan menjadi sesuatu seperti /lxc/<containerid>atau /docker/<containerid>masing - masing.

jpetazzo
sumber
13
buruh pelabuhan sekarang menggunakan dockerbukannya lxcdi jalur itu
Andy
4
Tidak berfungsi untuk kontainer lxd / lxc, tetapi stackoverflow.com/a/20010626/170230 berfungsi .
Draco Ater
Dengan versi systemd yang lebih baru sepertinya Anda tidak bisa mengandalkan proses 1 menggunakan /untuk semua cgroups; pada sistem 9 Debian saya (systemd 232) hanya tiga dari sepuluh kelompok ( 3:cpuset, 4:perf_eventdan 7:freezer) yang di root; sisanya ada di bawah /init.scope. Yang mengatakan, saya pikir mencari file :/docker/itu mungkin adalah heuristik yang paling dapat diandalkan saat ini.
cjs
2
grep 'docker\|lxc' /proc/1/cgroupbekerja untuk saya di Docker 18.09.
rypel
1
Tidak bekerja untukku. Host Ubuntu 19.04, guest Ubuntu 18.04 menggunakan wadah istimewa LXC. / proc / 1 / cgroup TIDAK mengandung string lxc.
Gab
158

Docker membuat .dockerenvfile di akar pohon direktori di dalam wadah. Anda dapat menjalankan skrip ini untuk memverifikasi

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


LEBIH BANYAK: Ubuntu sebenarnya memiliki skrip bash: /bin/running-in-containerdan itu benar-benar dapat mengembalikan jenis wadah yang telah dipanggil. Mungkin bermanfaat. Tidak tahu tentang distro besar lainnya.

at0S
sumber
13
Catatan penting: .dockerinitfile telah dihapus di versi terbaru Docker , jadi metode ini tidak akan berfungsi lagi. Sampai tulisan ini dibuat, .dockerenvfile tersebut masih disimpan, jadi mungkin itu bisa digunakan sebagai gantinya.
Jason R
Di Debian /bin/running-in-containerdisediakan oleh upstart. Dengan transisi ke systemd mungkin hilang. Saya harap tidak - kedengarannya bermanfaat!
Max Murphy
"di atas pohon direktori", apa artinya itu? Dimanakah itu?
Alexander Mills
3
Lain telah menunjukkan pemeriksaan yang .dockerenvadalah tidak dianjurkan
Dave
1
Catatan: pengujian untuk .dockerenv hanya berfungsi jika runtime adalah docker daemon. Jika Anda menggunakan podman atau yang lain ini gagal.
Benjamin Kircher
22

Pada sistem ubuntu 16.04 baru, systemd baru & lxc 2.0

sudo grep -qa container=lxc /proc/1/environ
lars
sumber
Ini berfungsi untuk saya di Ubuntu focal 20.04. Tak satu pun dari jawaban di atas titik ini yang melakukannya.
Jonathan Hartley
16

Cara ringkas untuk memeriksa buruh pelabuhan dalam skrip bash adalah:

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

Fungsi Python yang berguna untuk memeriksa apakah berjalan di 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
sumber
2
Catatan penting! Tampaknya ini tidak berfungsi ketika wadah berjalan di kubernetes. Sebagai gantinya, ganti baris terakhir dengan 'kubepod' sebagai pengganti 'buruh pelabuhan'. (Atau, masukkan pernyataan "atau" yang memeriksa keduanya;))
JJC
1
Ini kubepodssaya kira.
rookie099
9

Kami menggunakan sch's proc (/ proc / $ PID / sched) untuk mengekstraksi PID dari proses tersebut. PID proses di dalam wadah akan berbeda dengan PID di host (sistem non-wadah).

Misalnya, output dari / proc / 1 / sched pada suatu wadah akan kembali:

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

Saat berada di host non-kontainer:

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

Ini membantu membedakan apakah Anda berada dalam wadah atau tidak.

Pendiri
sumber
Bergantung pada OS, "init" mungkin perlu diganti dengan "systemd". Informasi lebih lanjut tentang systemd di sini .
BrianV
Ya, tapi intinya bukan nama proses init, intinya adalah nomor proses.
MillerGeek
Ini sepertinya hanya bekerja pada Docker. Dalam wadah LXC Ini mengembalikan Systemd PID 1
MillerGeek
Sekarang kembali 1 di buruh pelabuhan juga. Biasanya shdan tidak initada di sana, tetapi mungkin hampir apa saja di keduanya.
Jan Hudec
Di bawah buruh pelabuhan, ini tidak lagi terjadi -bash-5.0# cat /proc/1/sched bash (1, #threads: 1)
shalomb
5

Cara termudah adalah dengan memeriksa lingkungan. Jika Anda memiliki container=lxcvariabel, Anda berada di dalam sebuah wadah.

Kalau tidak, jika Anda root, Anda dapat mencoba melakukan mknodatau mountoperasi, jika gagal, Anda kemungkinan besar berada dalam sebuah wadah dengan kemampuan yang menurun.

creack
sumber
Yang ini berfungsi tidak hanya untuk buruh pelabuhan (saya tidak memeriksanya), tetapi yang lebih penting untuk kontainer lxd / lxc (dicentang), di mana /proc/1/cgrouptidak memungkinkan Anda mendeteksi itu.
Draco Ater
2
dapatkah Anda mengedit jawabannya dengan kode alih-alih pseudocode? "container = lxc"? bukan sesuatu yang patut apakah maksud Anda seperti if [["lxc" = "$ container"]]?
Alexander Mills
3
Maksudku ... ini aneh, biasanya variabel env ada di semua batas, jadi mencari beberapa presisi di sini
Alexander Mills
7
docker run alpine envtidak memberikan apa pun yang tampak seperti variabel itu
Archimedes Trajano
3

Jawaban saya hanya berlaku untuk proses Node.js tetapi mungkin relevan bagi beberapa pengunjung yang tersandung ke pertanyaan ini mencari jawaban spesifik Node.js.

Saya memiliki masalah yang sama dan mengandalkan /proc/self/cgroupsaya membuat paket npm hanya untuk tujuan ini - untuk mendeteksi apakah proses Node.js berjalan di dalam wadah Docker atau tidak.

The Modul NPM kemas akan membantu Anda dalam Node.js. Saat ini tidak diuji di Io.js tetapi mungkin juga berfungsi di sana.

Martin Tajur
sumber
Terima kasih untuk modul ini, sepertinya ada beberapa perbaikan terbuka yang tertunda - apakah Anda masih mempertahankan ini?
stevokk
2

Periksa semua solusi di atas dalam 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())

Bukti dari konsep:

$ docker run --rm -it --mount type=bind,source=${PWD}/incontainer.py,target=/tmp/script.py python:3 python /tmp/script.py
True
blakev
sumber
Ini tidak berhasil untuk saya di wadah buruh pelabuhan berbasis Mac. Pengembalian kosong. Docker versi 2.1.0.1 (37199).
splintercell
Yang ini memang: def is_non_docker(): return os.path.exists('/proc/1/cgroup')sesuai dengan jawaban yang diterima di sini stackoverflow.com/questions/20010199/…
splintercell
2
Anda mendapatkan Penghargaan Penggunaan Kucing yang Tidak Berguna. Dan Penggunaan Subprocess yang Tidak Berguna.
Jan Hudec
Ya ini adalah level baru yang sama sekali tidak perlu cat! Nice one :-D
Timmmm
Anda benar, saya akan memperbarui jawabannya meskipun itu masih belum mencakup semuanya. @JanHudec
blakev
1

Docker berkembang dari hari ke hari, jadi kami tidak bisa mengatakan dengan pasti apakah mereka akan tetap .dockerenv .dockerinitdi masa depan.

Di sebagian besar rasa Linux initadalah proses pertama untuk memulai. Tetapi dalam kasus kontainer ini tidak benar.

#!/bin/bash
if ps -p1|grep -q init;then  
  echo "non-docker" 
else 
  echo "docker" 
fi
Govind Kailas
sumber
6
@RomanTrofimov LXC / Docker juga tidak. Komentar yang lucu.
abourget
1
Itu tidak bekerja di centos 7 juga. Ketika saya menjalankan di mesin host saya ia mengatakan buruh pelabuhan. Sepertinya systemd berjalan sebagai proses id 1
Venkateswara Rao
@VenkateswaraRao - Ini harus dijalankan di dalam wadah. Tujuannya adalah untuk mengetahui apakah Anda berada di dalam wadah buruh pelabuhan atau tidak.
Govind Kailas
1
@GovindKailas: Masalahnya adalah ini mengasumsikan bahwa PID normal adalah init, yang tidak benar pada sistem systemdatau launchdberbasis ...
Gert van den Berg
3
@ SamThomas: launchd, pemula, Solaris SMF, systemd, init gaya Sys V, init gaya BSD (keduanya dan beberapa yang lain mungkin memanggil PID 1 mereka init), OpenRC, initng, runit. Lihat di sini . Sebagian besar sistem berbasis Linux modern akan menggunakan systemd, beberapa yang lebih tua, pemula .... Semua sistem OS X modern akan menggunakanlaunchd
Gert van den Berg
0

T&J SO ini: "Cari tahu apakah OS berjalan di lingkungan virtual" ; meskipun tidak sama dengan pertanyaan OP, itu memang menjawab kasus umum menemukan wadah tempat Anda berada (jika sama sekali).

Khususnya, instal dan baca kode skrip bash ini yang sepertinya berfungsi cukup baik:

kebajikan-apa :

sudo apt install virt-what
kaiwan
sumber
Tidak bekerja dengan virt-whatversi 1.14-1 di Ubuntu 16.04. Butuh tambalan.
Lucas
0

Saya telah menerjemahkan jawaban JJC ke dalam 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
sumber
-1

Dalam wadah buruh pelabuhan, entri /proc/self/cgroupdipasang ke grup di host.

misalnya dalam sebuah wadah

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

padahal, sama pada host

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

Menggunakan sesuatu di shell untuk tes profil rendah

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
sumber
Mengembalikan 1 pada keduanya.
sorin
-4

Mungkin ini berhasil:

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

Itukah yang kamu inginkan? Semoga ini membantu =)

Leonardo Da Vinci
sumber
1
Tidak ada dockerbiner tersedia di dalam wadah, jelas.
toriningen
3
Hmm, ini akan gagal dalam situasi (mis. Gitlab docker-in-docker) di mana wadah pengontrol memiliki dockerdan akses ke soket docker host.
shalomb
1
ya, kamu benar, tentu saja tidak ada ^^. Saya mendapat interpretasi yang salah tentang pertanyaan kembali pada saat saya membacanya. Terima kasih, Shalomb.
Leonardo Da Vinci