วิธีการตรวจสอบว่ากระบวนการทำงานภายใน lxc / Docker หรือไม่?


172

มีวิธีการตรวจสอบว่ากระบวนการ (สคริปต์) ทำงานในภาชนะ lxc (~ นักเทียบท่ารันไทม์)? ฉันรู้ว่าบางโปรแกรมสามารถตรวจพบว่าพวกเขาทำงานภายในเครื่องเสมือนจริงมีอะไรที่คล้ายกันสำหรับ lxc / docker หรือไม่?


มันอาจดูเชื่องช้า แต่เป็นการดีที่สุดที่จะใช้คำถามใหม่เพื่ออธิบายปัญหาที่คุณมีและถามว่าจะแก้ปัญหาอย่างไรโดยที่คำถามนั้นมีโอกาสสูงที่จะถูกปิด ในหลายกรณีเป็นการยากที่จะเปลี่ยนแปลง แต่ในตัวคุณมันไม่ยากที่จะเรียบเรียงใหม่หากคุณต้องการ
mah

มีการตอบสนองที่น่าสนใจเมื่อออกคำสั่งนี้ขณะอยู่ในที่เก็บ: uptime
Scott Stensland

คำตอบ:


169

/proc/1/cgroupวิธีที่เชื่อถือได้มากที่สุดคือการตรวจสอบ มันจะบอกคุณกลุ่มควบคุมของกระบวนการเริ่มต้นและเมื่อคุณไม่ได้อยู่ในคอนเทนเนอร์นั่นจะเป็น/ลำดับชั้นทั้งหมด เมื่อคุณอยู่ในภาชนะคุณจะเห็นชื่อของจุดยึด ด้วยตู้คอนเทนเนอร์ LXC / Docker มันจะเป็นอะไรที่ชอบ/lxc/<containerid>หรือ/docker/<containerid>ตามลำดับ


13
ตอนนี้นักเทียบท่าใช้dockerแทนlxcในเส้นทางเหล่านั้น
Andy

4
ไม่ทำงานสำหรับคอนเทนเนอร์ lxd / lxc แต่stackoverflow.com/a/20010626/170230ทำงาน
Draco Ater

ด้วย systemd เวอร์ชั่นที่ใหม่กว่าดูเหมือนว่าคุณไม่สามารถพึ่งพาโพรเซส 1 ที่ใช้/กับกลุ่ม cg ทั้งหมดได้ ในระบบ Debian 9 ของฉัน (systemd 232) เพียงสามของ cgroups สิบ ( 3:cpuset, 4:perf_eventและ7:freezer) อยู่ที่ราก /init.scopeส่วนที่เหลืออยู่ภายใต้ ที่กล่าวว่าฉันคิดว่าการค้นหาไฟล์:/docker/นั้นน่าจะเป็นฮิวริสติกที่เชื่อถือได้มากที่สุดในขณะนี้
cjs

2
grep 'docker\|lxc' /proc/1/cgroupทำงานได้สำหรับฉันที่ Docker 18.09
rypel

1
ไม่ทำงานสำหรับฉัน โฮสต์ Ubuntu 19.04, แขก Ubuntu 18.04 โดยใช้คอนเทนเนอร์ของ LXC / proc / 1 / cgroup ไม่มีสตริง lxc
Gab

157

นักเทียบท่าสร้าง.dockerenvไฟล์ที่รากของต้นไม้ไดเรกทอรีภายในภาชนะ คุณสามารถเรียกใช้สคริปต์นี้เพื่อตรวจสอบ

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


เพิ่มเติม: อูบุนตูมีสคริปต์ทุบตี/bin/running-in-containerจริง ๆ และจริง ๆ แล้วมันสามารถคืนชนิดของคอนเทนเนอร์ที่ถูกเรียกใช้งานได้อาจเป็นประโยชน์ ไม่ทราบเกี่ยวกับสิ่งรบกวนสำคัญอื่น ๆ


13
หมายเหตุสำคัญ: .dockerinitไฟล์ถูกลบใน Docker เวอร์ชันล่าสุดดังนั้นวิธีนี้จะไม่ทำงานอีกต่อไป จากการเขียนนี้.dockerenvไฟล์ยังคงอยู่รอบ ๆ ดังนั้นอาจใช้แทนได้
Jason R

ใน Debian ให้บริการโดย/bin/running-in-container upstartด้วยการเปลี่ยนเป็น systemd มันอาจหายไป ฉันหวังว่าจะไม่ - ฟังดูมีประโยชน์!
Max Murphy

"ที่ด้านบนสุดของแผนผังไดเรกทอรี" หมายความว่าอย่างไร อยู่ที่ไหน
Alexander Mills

3
อื่น ๆ ได้ชี้ให้เห็นว่าการตรวจสอบ.dockerenvจะไม่แนะนำ
เดฟ

1
หมายเหตุ: การทดสอบ. dockerenv ใช้ได้เฉพาะเมื่อรันไทม์คือ docker daemon หากคุณใช้พอดแมนหรืออย่างอื่นจะล้มเหลว
Benjamin Kircher

22

บนระบบใหม่ของ Ubuntu 16.04 ระบบใหม่ systemd & lxc 2.0

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

สิ่งนี้ใช้ได้กับฉันใน Ubuntu focal 20.04 ไม่มีคำตอบเหนือจุดนี้เลย
Jonathan Hartley

16

วิธีรัดกุมในการตรวจสอบนักเทียบท่าในสคริปต์ทุบตีคือ:

#!/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
โน๊ตสำคัญ! สิ่งนี้ไม่ปรากฏขึ้นเมื่อคอนเทนเนอร์กำลังทำงานใน kubernetes ให้แทนที่บรรทัดสุดท้ายด้วย 'kubepod' แทน 'docker' (หรือใส่คำสั่ง "หรือ" ที่ตรวจสอบทั้งคู่))
JJC

1
มันkubepodsฉันเดา
rookie099

9

เราใช้กำหนดการของ proc (/ proc / $ PID / sched) เพื่อแยก PID ของกระบวนการ 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

ใช่ แต่ประเด็นไม่ใช่ชื่อของกระบวนการเริ่มต้นประเด็นคือหมายเลขกระบวนการ
MillerGeek

ดูเหมือนว่าจะใช้ได้กับ Docker เท่านั้น ในคอนเทนเนอร์ LXC จะส่งคืน Systemd PID 1
MillerGeek

ตอนนี้มันกลับมาเป็น 1 ในนักเทียบท่าเช่นกัน มันมักจะเป็นshและไม่ได้initอยู่ที่นั่น แต่อาจเป็นอะไรก็ได้
Jan Hudec

ภายใต้นักเทียบท่านี่ไม่ใช่กรณีอีกต่อไปแล้ว -bash-5.0# cat /proc/1/sched bash (1, #threads: 1)
shalomb

5

วิธีที่ง่ายที่สุดคือการตรวจสอบสภาพแวดล้อม หากคุณมีcontainer=lxcตัวแปรแสดงว่าคุณอยู่ในคอนเทนเนอร์

มิฉะนั้นถ้าคุณเป็นรูทคุณสามารถลองดำเนินการmknodหรือmountล้มเหลวได้หากเป็นไปได้ว่าคุณมักจะอยู่ในภาชนะที่มีความสามารถในการตก


อันนี้ใช้ได้กับนักเทียบท่าเท่านั้น (ฉันไม่ได้ตรวจสอบว่า) แต่ที่สำคัญกว่าสำหรับคอนเทนเนอร์ lxd / lxc (ทำเครื่องหมายไว้) ซึ่ง/proc/1/cgroupไม่อนุญาตให้คุณตรวจจับได้
Draco Ater

2
คุณสามารถแก้ไขคำตอบด้วยรหัสแทนรหัสเทียมได้หรือไม่? "container = lxc"? ไม่เหมาะสมอะไร คุณหมายถึงอะไรเช่นถ้า [["lxc" = "$ container"]]?
Alexander Mills

3
ฉันหมายถึง ... มันแปลกประหลาดโดยปกติแล้วตัวแปร env จะอยู่ในตัวพิมพ์ใหญ่ทั้งหมดดังนั้นมองหาความแม่นยำที่นี่
Alexander Mills

7
docker run alpine envไม่ได้ให้อะไรที่ดูเหมือนตัวแปรนั้น
Archimedes Trajano

3

คำตอบของฉันใช้กับกระบวนการ Node.jsเท่านั้น แต่อาจเกี่ยวข้องกับผู้เข้าชมบางคนที่สะดุดกับคำถามนี้เพื่อค้นหาคำตอบเฉพาะของ Node.js

ฉันมีปัญหาเดียวกันและพึ่งพา/proc/self/cgroupฉันสร้างแพคเกจ npmสำหรับวัตถุประสงค์นี้เพียงอย่างเดียว - เพื่อตรวจสอบว่ากระบวนการ Node.js ทำงานในคอนเทนเนอร์ Docker หรือไม่

โมดูล NPM containerizedจะช่วยให้คุณออกมาใน 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
คุณได้รับประโยชน์จากการใช้แมวเป็นรางวัล และการใช้กระบวนการย่อยที่ไร้ประโยชน์อย่างใดอย่างหนึ่ง
Jan Hudec

ใช่นี่เป็นระดับใหม่โดยไม่จำเป็นcat! Nice one :-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
มันไม่ทำงานใน centos 7 เช่นกัน เมื่อฉันทำงานในเครื่องโฮสต์ของฉันมันบอกว่านักเทียบท่า ดูเหมือนว่า systemd กำลังทำงานตามกระบวนการ id 1
Venkateswara Rao

@VenkateswaraRao - จะต้องเรียกใช้ภายในคอนเทนเนอร์ ความตั้งใจคือการดูว่าคุณอยู่ในคอนเทนเนอร์นักเทียบท่าหรือไม่
Govind Kailas

1
@GovindKailas: ปัญหาคือว่านี้ถือว่าเป็นหนึ่ง PID ปกติinitซึ่งไม่เป็นความจริงในระบบที่ใช้systemdหรือlaunchd...
Gert van den Berg

3
@ SamThomas: launchd, พุ่งพรวด, Solaris SMF, systemd, init Sys V style, เริ่มต้นสไตล์ BSD (ทั้งสองนี้และคนอื่น ๆ อาจเรียก PID 1 ของพวกเขาได้init), OpenRC, initng, runit ดูที่นี่ ระบบที่ใช้ลีนุกซ์ที่ทันสมัยส่วนใหญ่จะใช้systemd, บางอันที่เก่ากว่า, พุ่งพรวด .... ระบบ OS X ที่ทันสมัยทั้งหมดจะใช้launchd
Gert van den Berg

0

คำถาม & คำตอบนี้: "ค้นหาว่าระบบปฏิบัติการทำงานในสภาพแวดล้อมเสมือนจริง"หรือไม่ แม้ว่าจะไม่เหมือนกับคำถามของ OP แต่แน่นอนว่ามันจะตอบกรณีทั่วไปในการค้นหาว่าคุณอยู่ในคอนเทนเนอร์ใด (ถ้าเลย)

โดยเฉพาะอย่างยิ่งติดตั้งและอ่านโค้ดของสคริปต์ทุบตีนี้ซึ่งทำงานได้ดี:

คุณธรรม - อะไร :

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

ในคอนเทนเนอร์นักเทียบท่ารายการ/proc/self/cgroupถูกเมาท์กับ cgroups บนโฮสต์

เช่นในภาชนะ

# 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 ทั้งคู่
โซริน

-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และเข้าถึงซ็อกเก็ตพอร์ตของโฮสต์
shalomb

1
ใช่ถูกต้องแน่นอนไม่มี ^^ ฉันได้รับการตีความผิด ๆ เกี่ยวกับคำถามย้อนกลับไปเมื่อฉันอ่าน ขอบคุณ Shalomb
Leonardo Da Vinci
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.