Cách kiểm tra xem một quá trình có đang chạy bên trong bộ chứa docker không


85

[Updated1] Tôi có một trình bao sẽ thay đổi các tham số hạt nhân TCP trong một số chức năng, nhưng bây giờ tôi cần làm cho trình bao này chạy trong vùng chứa Docker, điều đó có nghĩa là, trình bao cần biết nó đang chạy bên trong một vùng chứa và dừng cấu hình hạt nhân.

Bây giờ tôi không chắc làm thế nào để đạt được điều đó, đây là nội dung /proc/self/cgroupbên trong vùng chứa:

9:hugetlb:/
8:perf_event:/
7:blkio:/
6:freezer:/
5:devices:/
4:memory:/
3:cpuacct:/
2:cpu:/docker/25ef774c390558ad8c4e9a8590b6a1956231aae404d6a7aba4dde320ff569b8b
1:cpuset:/

Tôi có thể sử dụng bất kỳ cờ nào ở trên để tìm hiểu xem quá trình này có đang chạy bên trong vùng chứa không?

[Updated2]: Tôi cũng đã nhận thấy Xác định xem một quy trình có chạy bên trong lxc / Docker hay không , nhưng có vẻ như nó không hoạt động trong trường hợp này, nội dung trong /proc/1/cgroupvùng chứa của tôi là:

8:perf_event:/
7:blkio:/
6:freezer:/
5:devices:/
4:memory:/
3:cpuacct:/
2:cpu:/docker/25ef774c390558ad8c4e9a8590b6a1956231aae404d6a7aba4dde320ff569b8b
1:cpuset:/

Không / lxc / containernerid


Không phải là một câu hỏi rất rõ ràng. Tại sao bạn cần cái này?
Henk Langeveld


@fish no / lxc / <containerid> trong trường hợp của tôi, hãy xem cập nhật
harryz

1
Các tham số hạt nhân @HenkLangeveld là chỉ đọc trong vùng chứa Docker, vì vậy tôi cần biết liệu trình bao của mình có đang chạy bên trong các vùng chứa hay không và tắt các chức năng của hạt nhân trong trình bao của tôi. xem bản cập nhật.
harryz

Một số bước trong tập lệnh cố gắng sửa đổi các tham số hạt nhân và cần được bỏ qua khi chạy trong Docker. Thông thoáng.
Henk Langeveld

Câu trả lời:


68

Để kiểm tra bên trong vùng chứa Docker xem bạn có đang ở trong vùng chứa Docker hay không, bạn có thể thực hiện thông qua /proc/1/cgroup. Như bài đăng này gợi ý bạn có thể làm như sau:

Bên ngoài thùng chứa docker, tất cả các mục nhập /proc/1/cgroupcuối cùng /như bạn có thể thấy ở đây:

vagrant@ubuntu-13:~$ cat /proc/1/cgroup
11:name=systemd:/
10:hugetlb:/
9:perf_event:/
8:blkio:/
7:freezer:/
6:devices:/
5:memory:/
4:cpuacct:/
3:cpu:/
2:cpuset:/

Bên trong vùng chứa Docker, một số nhóm điều khiển sẽ thuộc về Docker (hoặc LXC):

vagrant@ubuntu-13:~$ docker run busybox cat /proc/1/cgroup
11:name=systemd:/
10:hugetlb:/
9:perf_event:/
8:blkio:/
7:freezer:/
6:devices:/docker/3601745b3bd54d9780436faa5f0e4f72bb46231663bb99a6bb892764917832c2
5:memory:/
4:cpuacct:/
3:cpu:/docker/3601745b3bd54d9780436faa5f0e4f72bb46231663bb99a6bb892764917832c2
2:cpuset:/

@ Người sáng lập câu trả lời rõ ràng hơn
Scott Stensland

5
không hoàn toàn đúng khi "Bên ngoài một vùng chứa docker, tất cả các mục nhập trong / proc / 1 / cgroup kết thúc bằng /". Trên ubuntu 16.04 chẳng hạn, tôi có:12:perf_event:/ 11:blkio:/init.scope 10:cpuset:/ 9:devices:/init.scope 8:hugetlb:/ 7:cpu,cpuacct:/init.scope 6:net_cls,net_prio:/ 5:memory:/init.scope 4:pids:/init.scope 3:rdma:/ 2:freezer:/ 1:name=systemd:/init.scope
samfr

Điều này hầu như chỉ hoạt động trên Linux, không hoạt động trên Darwin hoặc các BSD khác thậm chí không sử dụng procfs.
Christian

@Christian Docker / LXC là những thứ chỉ dành cho Linux, vì vậy điều đó tốt, phải không :)?
Robert Lacroix

@RobertLacroix vậy bạn đang nói nếu bạn không tìm thấy procfs thì bạn không ở trong Docker? Chà, tôi đoán vậy là đủ công bằng ...
Christian

107

Docker tạo .dockerenv.dockerinit( loại bỏ trong v1.11 ) các tệp ở đầu cây thư mục của vùng chứa, vì vậy bạn có thể muốn kiểm tra xem chúng có tồn tại hay không.

Một cái gì đó như thế này sẽ hoạt động.

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

1
Tất nhiên, trừ khi bạn hoặc ai đó đã tạo /.dockerinittrên máy chủ của bạn (có thể là do tình cờ), trong trường hợp đó nó sẽ bị sai bên ngoài vùng chứa.
sosiouxme

18
Nếu ai đó khác đã tạo / thì họ đã root và bạn gặp phải vấn đề tồi tệ hơn là biết liệu bạn có đang ở trong docker hay không.
davey

15
Hãy coi chừng dựa vào /.dockerenvtrong dài hạn. Nó không được sử dụng theo cách này .
ReactiveRaven

fwiw, Podman không tạo /.dockerenv. Nó tạo ra /run/.containerenvnhưng theo logic tương tự, nghe có vẻ như chi tiết triển khai không cần dựa vào. Xem github.com/containers/libpod/issues/3586 để biết một số lựa chọn thay thế dành riêng cho podman.
Beni Cherniavsky-Paskin

21

Thomas 'giải pháp dưới dạng mã:

running_in_docker() {
  (awk -F/ '$2 == "docker"' /proc/self/cgroup | read non_empty_input)
}

Ghi chú

Với readmột biến giả là một thành ngữ đơn giản cho Điều này có tạo ra bất kỳ đầu ra nào không? . Đó là một phương pháp nhỏ gọn để biến một câu có thể dài dòng grephoặc awkthành một bài kiểm tra của một mẫu.

Ghi chú bổ sung khi đọc


10
Ngoại trừ ... điều này sẽ không thành công trong một số môi trường, bởi vì, ví dụ, 3:cpu,cpuacct:/system.slice/docker-1ce79a0dec4a2084d54acf187a1e177e0339dc90d0218b48b4456576ecaf291e.scopesẽ không phù hợp. Đơn giản hơn để grep -q docker /proc/1/cgroup; mã kết quả từ đó cũng phải đủ.
larsks

2
readcông sức cho bash, nhưng trong sử dụng nhiều nhất dashvỏ bạn phải sử dụng một trong hai read dummy(hoặc tương tự) hoặc sử dụng một cấu trúc giống như[ -n "$(command)" ]
Daniel Alder

@DanielAlder Bắt tốt đấy, Daniel. Tôi sẽ cập nhật văn bản.
Henk Langeveld

1
Trước đây, điều này tuyên bố rằng bất kỳ trình bao nào tương thích với Bourne đều hỗ trợ đồng bằng readkhông có tên biến. Điều này chỉ đúng với bash và ksh93. Opengroup chỉ xác định read varvà không đề cập đến readhành vi mà không có ít nhất một biến. Trong bashksh93 , nếu không có var , thì read sử dụng biến shell REPLY.
Henk Langeveld

1
Tại sao chúng ta không thể sử dụng awk -F: '$3 ~ /docker/' /proc/self/cgroup | read? Làm việc cho tôi.
Shubham Chaudhary

21

Chúng tôi sử dụng lịch trình của proc (/ proc / $ PID / Schedule) để trích xuất PID của quá trình. PID của tiến trình bên trong vùng chứa 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 / Schedule trên vùng chứa sẽ trả về:

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

Khi ở trên 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 bạn có đang ở trong một thùng chứa hay không. ví dụ bạn có thể làm:

if [[ ! $(cat /proc/1/sched | head -n 1 | grep init) ]]; then {
    echo in docker
} else {
    echo not in docker
} fi

đây thực sự là một thông tin khá có giá trị. cảm ơn
Fabian Lange

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

2
Như đã đề cập bởi @BrianV, điều này cũng không hiệu quả với tôi.
Shubham Chaudhary

5
Trong một vùng chứa Docker chạy trên một cụm k8s, head -n1 /proc/1/schedtrả về dumb-init (1, #threads: 1), do đó, kiểm tra được đề xuất trong câu trả lời này không thành công. (Ngoài ra, trái ngược với những gì câu trả lời gợi ý, PID được hiển thị là "1" trong dòng đó mặc dù tôi đang làm điều này trong một thùng chứa.)
Stefan Majewsky 12/02/18

Đây chắc chắn không phải là một giải pháp phổ quát. Bạn có thể (đại loại) sử dụng bất cứ thứ gì bạn muốn cho PID của container 1. Ví dụ: nếu bạn làm như docker run --init ...vậy docker-init. Nếu bạn làm, ví dụ như docker run ... head -n 1 /proc/1/schednó sẽ được head.
jpkotta

6

Điều hiệu quả với tôi là kiểm tra số inode của '/.' Bên trong docker, một con số rất cao. Bên ngoài docker, nó là một con số rất thấp như '2'. Tôi nghĩ rằng cách tiếp cận này cũng sẽ phụ thuộc vào FileSystem đang được sử dụng.

Thí dụ

Bên trong docker:

# ls -ali / | sed '2!d' |awk {'print $1'}
1565265

Bên ngoài docker

$ ls -ali / | sed '2!d' |awk {'print $1'}
2

Trong một tập lệnh:

#!/bin/bash
INODE_NUM=`ls -ali / | sed '2!d' |awk {'print $1'}`
if [ $INODE_NUM == '2' ];
then
        echo "Outside the docker"
else
        echo "Inside the docker"
fi

trong MSYS2 ls -ali / | sed '2! d' | awk {'print $ 1'} 232779805740174872
bo0k Ngày

giống như ls -di /? Có vẻ như inode num không đáng tin cậy trên nền tảng khác
yurenchen

đây là điều duy nhất giúp tôi phân biệt giữa máy chủ Xen domU và vùng chứa
docker

1

Chúng tôi cần loại trừ các quy trình đang chạy trong vùng chứa, nhưng thay vì chỉ kiểm tra các nhóm docker, chúng tôi quyết định so sánh /proc/<pid>/ns/pidvới hệ thống init tại /proc/1/ns/pid. Thí dụ:

pid=$(ps ax | grep "[r]edis-server \*:6379" | awk '{print $1}')
if [ $(readlink "/proc/$pid/ns/pid") == $(readlink /proc/1/ns/pid) ]; then
   echo "pid $pid is the same namespace as init system"
else
   echo "pid $pid is in a different namespace as init system"
fi

Hoặc trong trường hợp của chúng tôi, chúng tôi muốn một lớp lót tạo ra lỗi nếu quy trình KHÔNG nằm trong vùng chứa

bash -c "test -h /proc/4129/ns/pid && test $(readlink /proc/4129/ns/pid) != $(readlink /proc/1/ns/pid)"

mà chúng tôi có thể thực thi từ một quy trình khác và nếu mã thoát bằng 0 thì PID được chỉ định đang chạy trong một không gian tên khác.


Không làm việc cho tôi. Từ bên trong vùng chứa Docker được lập lịch k8s readlink /proc/self/ns/pidreadlink /proc/1/ns/pidtạo ra cùng một đầu ra.
Stefan Majewsky

1
@StefanMajewsky Có thể muốn thử sử dụng github.com/jessfraz/amicontained để xem những tính năng nào được bật trong thời gian chạy vùng chứa.
Greg Bray

0

Dựa trên nhận xét của Dan Walsh về việc sử dụng SELinux ps -eZ | grep container_t, nhưng không yêu cầu pscài đặt:

$ podman run --rm fedora:31 cat /proc/1/attr/current
system_u:system_r:container_t:s0:c56,c299
$ podman run --rm alpine cat /proc/1/attr/current
system_u:system_r:container_t:s0:c558,c813
$ docker run --rm fedora:31 cat /proc/1/attr/current
system_u:system_r:container_t:s0:c8,c583
$ cat /proc/1/attr/current
system_u:system_r:init_t:s0

Điều này chỉ cho bạn biết bạn đang chạy trong một vùng chứa, nhưng không phải là thời gian chạy nào.

Không kiểm tra các thời gian chạy vùng chứa khác nhưng https://opensource.com/article/18/2/und hieu-selinux-labels- container-runtimes cung cấp thêm thông tin và cho thấy điều này được sử dụng rộng rãi, cũng có thể hoạt động cho rkt và lxc?


-1

Tôi đã tạo một tập lệnh python nhỏ. Hy vọng ai đó thấy nó hữu ích. :-)

#!/usr/bin/env python3
#@author Jorge III Altamirano Astorga 2018
import re
import math

total = None
meminfo = open('/proc/meminfo', 'r')
for line in meminfo:
    line = line.strip()
    if "MemTotal:" in line:
        line = re.sub("[^0-9]*", "", line)
        total = int(line)
meminfo.close()
print("Total memory: %d kB"%total)

procinfo = open('/proc/self/cgroup', 'r')
for line in procinfo: 
    line = line.strip()
    if re.match('.{1,5}:name=systemd:', line):
        dockerd = "/sys/fs/cgroup/memory" + \
            re.sub("^.{1,5}:name=systemd:", "", line) + \
            "/memory.stat"
        #print(dockerd)
        memstat = open(dockerd, 'r')
        for memline in memstat:
            memline = memline.strip()
            if re.match("hierarchical_memory_limit", memline):
                memline = re.sub("[^0-9]*", \
                    "", memline)  
                total = math.floor(int(memline) / 2**10)
        memstat.close()
procinfo.close()
print("Total available memory to the container: %d kB"%total)

thật tuyệt, nhưng làm thế nào để xác định xem bạn có đang ở bên trong một thùng chứa hay không?
user528025,

FileNotFoundError: [Errno 2] No such file or directory: '/sys/fs/cgroup/memory/docker/<docker_id>/memory.stat'
Scrooge McDuck
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.