Làm thế nào để xác định nếu một quá trình chạy bên trong lxc / Docker?


172

Có cách nào để xác định xem một tiến trình (tập lệnh) có chạy trong bộ chứa lxc (~ Docker runtime không) không? Tôi biết rằng một số chương trình có thể phát hiện xem chúng có chạy bên trong một máy ảo hay không, có phải cái gì đó tương tự có sẵn cho lxc / docker không?


Nó có vẻ mang tính mô phạm, nhưng tốt nhất là bạn nên viết lại câu hỏi của bạn để mô tả một vấn đề bạn đang gặp phải và hỏi cách giải quyết nó - nếu không có điều đó, câu hỏi có khả năng bị đóng cao hơn. Trong nhiều trường hợp, thật khó để thực hiện thay đổi đó, nhưng trong bạn, sẽ không khó để viết lại nếu bạn muốn.
mah

có một phản hồi thú vị khi ban hành lệnh này khi ở trong một container: thời gian hoạt động
Scott Stensland

Câu trả lời:


169

Cách đáng tin cậy nhất là kiểm tra /proc/1/cgroup. Nó sẽ cho bạn biết các nhóm điều khiển của quá trình init và khi bạn không ở trong một thùng chứa, điều đó sẽ /dành cho tất cả các hệ thống phân cấp. Khi bạn ở trong một container, bạn sẽ thấy tên của điểm neo. Với các container LXC / Docker, nó sẽ giống /lxc/<containerid>hoặc /docker/<containerid>tương ứng.


13
Docker hiện sử dụng dockerthay vì lxctrong các đường dẫn đó
Andy

4
Không hoạt động đối với các thùng chứa lxd / lxc, nhưng stackoverflow.com/a/20010626/170230 thì có.
Draco Ater

Với các phiên bản sau của systemd, có vẻ như bạn không thể dựa vào quy trình 1 bằng cách sử dụng /cho tất cả các nhóm; trên hệ thống Debian 9 của tôi (systemd 232) chỉ có ba của cgroups mười ( 3:cpuset, 4:perf_event7:freezer) đang ở gốc; phần còn lại là dưới /init.scope. Điều đó nói rằng, tôi nghĩ rằng tìm kiếm tập tin đó :/docker/có lẽ là heuristic đáng tin cậy nhất tại thời điểm này.
cjs

2
grep 'docker\|lxc' /proc/1/cgrouplàm việc cho tôi trên Docker 18,09.
rypel

1
Không làm việc cho tôi. Lưu trữ Ubuntu 19.04, khách Ubuntu 18.04 sử dụng bộ chứa đặc quyền LXC. / Proc / 1 / cgroup KHÔNG chứa chuỗi lxc.
Gab

157

Docker tạo một .dockerenvtập tin ở thư mục gốc của cây thư mục bên trong container. Bạn có thể chạy tập lệnh này để xác minh

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


XEM THÊM: Ubuntu thực sự có một tập lệnh bash: /bin/running-in-containervà nó thực sự có thể trả về loại container mà nó đã được gọi. Có thể hữu ích. Không biết về các distro lớn khác mặc dù.


13
Lưu ý quan trọng: .dockerinittệp đã bị xóa trong các phiên bản gần đây của Docker , vì vậy phương pháp này sẽ không hoạt động nữa. Khi viết bài này, .dockerenvtập tin vẫn được giữ xung quanh, vì vậy có lẽ điều đó có thể được sử dụng thay thế.
Jason R

Trên Debian /bin/running-in-containerđược cung cấp bởi upstart. Với việc chuyển sang systemd nó có thể biến mất. Tôi hy vọng không - nghe có vẻ hữu ích!
Max Murphy

"Trên đỉnh của thư mục", điều đó có nghĩa là gì? đó là ở đâu
Alexander Mills

3
Những người khác đã chỉ ra rằng việc kiểm tra .dockerenvđược không được khuyến khích
Dave

1
Lưu ý: kiểm tra cho .dockerenv chỉ hoạt động nếu thời gian chạy là daemon docker. Nếu bạn đang sử dụng podman hoặc cái gì khác thì điều này không thành công.
Benjamin Kircher

22

Trên hệ thống Ubuntu 16.04 mới, systemd & lxc 2.0 mới

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

Điều này làm việc cho tôi trên Ubuntu đầu mối 20.04. Không có câu trả lời trên điểm này đã làm.
Jonathan Hartley

16

Một cách ngắn gọn để kiểm tra docker trong tập lệnh bash là:

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

14

Chức năng Python tiện dụng để kiểm tra nếu chạy trong 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
Lưu ý quan trọng! Điều này dường như không hoạt động khi container đang chạy trong kubernetes. Thay vào đó, thay thế dòng cuối cùng bằng 'kubepod' thay cho 'docker'. (Hoặc, đưa vào câu lệnh "hoặc" kiểm tra cả hai;))
JJC

1
Đó là kubepodstôi đoán.
rookie099

9

Chúng tôi sử dụng lịch biểu của Proc (/ Proc / $ PID / calendar) để trích xuất PID của quy trình. Quá trình PID bên trong container sẽ khác với PID trên máy chủ (hệ thống không chứa).

Ví dụ: đầu ra của / Proc / 1 / calendar trên một container sẽ trả về:

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

Trong khi trên một máy chủ không chứa:

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

Điều này giúp phân biệt nếu bạn đang ở trong một container hoặc không.


Tùy thuộc vào HĐH, "init" có thể cần được thay thế bằng "systemd". Thêm thông tin về systemd tại đây .
BrianV

Đúng, nhưng điểm không phải là tên của quá trình init, điểm chính là số tiến trình.
MillerGeek

Điều này dường như chỉ hoạt động trên Docker. Trong một thùng chứa LXC, nó sẽ trả về Systemd PID 1
MillerGeek

Bây giờ nó cũng trở lại 1 trong docker. Nó thường shvà không initcó ở đó, nhưng nó có thể là hầu hết mọi thứ.
Jan Hudec

Theo docker, đây không còn là trường hợp nữa -bash-5.0# cat /proc/1/sched bash (1, #threads: 1)
shalomb

5

Cách dễ nhất sẽ là kiểm tra môi trường. Nếu bạn có container=lxcbiến, bạn đang ở trong một container.

Mặt khác, nếu bạn đã root, bạn có thể thử thực hiện mknodhoặc mountvận hành, nếu thất bại, rất có thể bạn đang ở trong một container có khả năng bị bỏ.


Công cụ này không chỉ hoạt động cho docker (tôi không kiểm tra điều đó), mà quan trọng hơn là các container lxd / lxc (đã chọn), nơi /proc/1/cgroupkhông cho phép bạn phát hiện ra điều đó.
Draco Ater

2
bạn có thể chỉnh sửa câu trả lời bằng mã thay vì mã giả không? "container = lxc"? không đúng gì cả. bạn có nghĩa là một cái gì đó như nếu [["lxc" = "$ container"]]?
Alexander Mills

3
Ý tôi là ... thật kỳ lạ, thông thường các biến env có trong tất cả các mũ, vì vậy hãy tìm kiếm một số độ chính xác ở đây
Alexander Mills

7
docker run alpine envkhông đưa ra bất cứ thứ gì trông giống như biến đó
Archimedes Trajano

3

Câu trả lời của tôi chỉ áp dụng cho các quy trình Node.js nhưng có thể phù hợp với một số khách truy cập vấp phải câu hỏi này để tìm câu trả lời cụ thể của Node.js.

Tôi gặp vấn đề tương tự và dựa vào /proc/self/cgrouptôi đã tạo ra gói npm chỉ cho mục đích này - để phát hiện xem quy trình Node.js có chạy bên trong bộ chứa Docker hay không.

Các mô-đun NPM container sẽ giúp bạn ra ngoài trong Node.js. Nó hiện chưa được thử nghiệm trong Io.js nhưng cũng có thể hoạt động tốt ở đó.


Cảm ơn mô-đun này, dường như có một vài bản sửa lỗi đang chờ xử lý - bạn vẫn đang duy trì điều này?
stevokk

2

Kiểm tra tất cả các giải pháp trên trong 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())

Bằng chứng của khái niệm:

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

Điều này không làm việc cho tôi trên container docker dựa trên Mac. Trả về sản phẩm nào. Docker phiên bản 2.1.0.1 (37199).
splintercell

Điều này đã làm: def is_non_docker(): return os.path.exists('/proc/1/cgroup')theo câu trả lời được chấp nhận ở đây stackoverflow.com/questions/20010199/ trên
splintercell

2
Bạn nhận được một giải thưởng sử dụng mèo vô dụng. Và sử dụng vô dụng của quy trình một.
Jan Hudec

Vâng, đây là một cấp độ hoàn toàn mới không cần thiết cat! Một người đẹp :-D
Timmmm

Bạn nói đúng, tôi sẽ cập nhật câu trả lời mặc dù nó vẫn chưa bao gồm tất cả. @JanHudec
blakev

1

Docker đang phát triển từng ngày, vì vậy chúng tôi không thể nói chắc chắn rằng họ sẽ giữ .dockerenv .dockerinittrong tương lai.

Trong hầu hết các hương vị Linux initlà quá trình đầu tiên để bắt đầu. Nhưng trong trường hợp container thì điều này không đúng.

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

6
@RomanTrofimov LXC / Docker cũng không. Thật là một bình luận hài hước.
abourget

1
Nó cũng không hoạt động trong centos 7. Khi tôi chạy trong máy chủ của tôi, nó báo docker. Có vẻ như systemd đang chạy như tiến trình id 1
Venkateswara Rao

@VenkateswaraRao - Cái này phải được chạy bên trong container. Mục đích là để tìm hiểu xem bạn có ở trong một container hay không.
Govind Kailas

1
@GovindKailas: Vấn đề là điều này giả định rằng một PID bình thường là init, đó là không đúng sự thật trên systemdhoặc launchdcác hệ thống dựa ...
Gert van den Berg

3
@SamThomas: launchd, upstart, Solaris SMF, systemd, Sys V style init, BSD style init (hai cái này và một số cái khác có thể gọi là PID 1 của họ init), OpenRC, initng, runit. Xem ở đây . Hầu hết các hệ thống dựa trên Linux hiện đại sẽ sử dụng systemd, một số hệ thống cũ hơn, mới bắt đầu .... Tất cả các hệ thống OS X hiện đại sẽ sử dụnglaunchd
Gert van den Berg

0

Câu hỏi và trả lời SO này: "Tìm hiểu xem HĐH có chạy trong môi trường ảo không" ; mặc dù không giống như câu hỏi của OP, nhưng nó thực sự trả lời các trường hợp phổ biến về việc tìm kiếm container nào (nếu có).

Cụ thể, cài đặt và đọc mã của tập lệnh bash này có vẻ hoạt động khá tốt:

đức-gì :

sudo apt install virt-what

Không hoạt động với virt-whatphiên bản 1.14-1 trên Ubuntu 16.04. Cần vá.
Lucas

0

Tôi đã dịch câu trả lời của JJC thành 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

-1

Trong một container /proc/self/cgroupdocker , các mục được gắn vào các nhóm trên máy chủ.

ví dụ trong một container

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

trong khi đó, tương tự trên máy chủ

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

Sử dụng một cái gì đó trong vỏ cho một bài kiểm tra cấu hình thấp

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

Trả về 1 trên cả hai.
sorin

-4

Có lẽ điều này làm nên mánh khóe:

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

Đó là điều bạn muốn? Hy vọng nó sẽ giúp =)


1
Không có dockernhị phân có sẵn từ bên trong của container, rõ ràng.
toriningen

3
Umm, điều này sẽ thất bại trong các tình huống (ví dụ: gitlab docker-in-docker) trong đó container điều khiển có dockervà truy cập vào ổ cắm docker của máy chủ.
shalomb

1
vâng, bạn nói đúng, tất nhiên là không ^^. Tôi đã hiểu sai về câu hỏi trở lại vào thời điểm tôi đọc nó. Cảm ơn bạn, Shalomb.
Leonardo Da Vinci
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.