Docker container içinde bir işlemin çalışıp çalışmadığını kontrol etme


89

[Güncelleme1] Bazı işlevlerde TCP çekirdek parametrelerini değiştirecek bir kabuğum var, ancak şimdi bu kabuğu Docker konteynerinde çalıştırmam gerekiyor, yani kabuğun bir konteyner içinde çalıştığını bilmesi ve çekirdeği yapılandırmayı bırakması gerekiyor.

Şimdi bunu nasıl başaracağımdan emin değilim, işte /proc/self/cgroupkabın içindeki içerik :

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

Bu işlemin bir konteyner içinde çalışıp çalışmadığını anlamak için yukarıdaki herhangi bir bayrak kullanabilir miyim?

[Güncellenmiş2]: Bir işlemin lxc / Docker içinde çalışıp çalışmadığını belirlerken de fark ettim , ancak bu durumda çalışmıyor, /proc/1/cgroupkapsayıcımın içeriği :

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

/ Lxc / containerid yok


Çok net bir soru değil. Niçin buna ihtiyacın var?
Henk Langeveld


@fish no / lxc / <containerid> benim durumumda, güncellemeye bakın
harryz

1
@HenkLangeveld çekirdek parametreleri Docker konteynerinde salt okunur, bu yüzden kabuğumun konteynerler içinde çalışıp çalışmadığını bilmem ve kabuğumdaki çekirdek işlevlerini devre dışı bırakmam gerekiyor. güncellemeye bakın.
harryz

Komut dosyasındaki bazı adımlar çekirdek parametrelerini değiştirmeye çalışır ve Docker'da çalıştırılırken atlanması gerekir. Açık.
Henk Langeveld

Yanıtlar:


70

Bir Docker konteynerinin içinde olup olmadığınızı kontrol etmek için Docker konteynerinin içinde olup olmadığınızı kontrol etmek için /proc/1/cgroup. Bu gönderinin önerdiği gibi , aşağıdakileri yapabilirsiniz:

Bir docker konteynerinin dışında, burada görebileceğiniz gibi tüm girişler /proc/1/cgroupsonunda /:

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:/

Bir Docker konteynerinin içinde bazı kontrol grupları Docker'a (veya LXC) ait olacaktır:

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:/

@ Kurucu cevap daha temiz
Scott Stensland

5
"Bir docker konteynerinin dışında, / proc / 1 / cgroup içindeki tüm girişlerin / üzerinde bittiği" kesinlikle doğru değildir. Örneğin ubuntu 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
16.04'te

Bu, Darwin'de veya procfs bile kullanmayan diğer BSD'lerde değil, sadece Linux'ta çalışır.
Christian

@Christian Docker / LXC yalnızca Linux şeylerdir, bu yüzden sorun değil, değil mi :)?
Robert Lacroix

@RobertLacroix yani bir procfs bulamazsanız Docker'da değilsiniz mi diyorsunuz? Pekala, bu yeterince adil sanırım ...
Christian

112

Docker , kapsayıcının dizin ağacının en üstünde dosyalar oluşturur .dockerenvve .dockerinit( v1.11'de kaldırılmıştır ), böylece bunların var olup olmadığını kontrol etmek isteyebilirsiniz.

Bunun gibi bir şey çalışmalı.

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

1
Elbette siz veya başka biri /.dockerinitev sahibinizde yaratmadıysa (belki kazara), bu durumda bir konteynerin dışında yanlış olacaktır.
sosiouxme

18
Eğer başka biri bunu yaptıysa / o zaman onlar köktür ve sizin docker'da olup olmadığınızı bilmekten daha kötü sorunlarınız var demektir.
davey

15
/.dockerenvUzun vadede güvenmeye dikkat edin . Bu şekilde kullanılması amaçlanmamıştır .
ReactiveRaven

fwiw, Podman yaratmaz /.dockerenv. Yaratır, /run/.containerenvancak benzer bir mantıkla, güvenilmeyecek uygulama detayı gibi ses çıkarır. Podman'a özgü bazı alternatifler için github.com/containers/libpod/issues/3586 adresine bakın .
Beni Cherniavsky-Paskin

24

İşlemin PID'sini çıkarmak için proc'un çizelgesini (/ proc / $ PID / sched) kullanıyoruz. Sürecin kapsayıcı içindeki PID'si farklı olacaktır, sonra ana bilgisayardaki PID'dir (kapsayıcı olmayan bir sistem).

Örneğin, bir kapsayıcıdaki / proc / 1 / sched çıktısı şunu döndürür:

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

Kapsayıcı olmayan bir ana bilgisayardayken:

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

Bu, bir kapta olup olmadığınızı ayırt etmeye yardımcı olur. örneğin şunları yapabilirsiniz:

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

bu aslında oldukça değerli bir bilgidir. teşekkürler
Fabian Lange

4
İşletim sistemine bağlı olarak, "init" in "systemd" ile değiştirilmesi gerekebilir. Systemd hakkında daha fazla bilgiyi burada bulabilirsiniz .
BrianV

2
@ BrianV tarafından belirtildiği gibi, bu benim için de çalışmıyor.
Shubham Chaudhary

5
Bir k8s kümesinde çalışan bir Docker konteynerinde head -n1 /proc/1/schedgeri döner dumb-init (1, #threads: 1), bu nedenle bu yanıtta önerilen kontrol başarısız olur. (Ayrıca, cevabın önerdiğinin aksine, bunu bir konteynırda yapmama rağmen PID bu satırda "1" olarak gösteriliyor.)
Stefan Majewsky

Bu kesinlikle evrensel bir çözüm değil. Bir kabın PID 1'i için istediğinizi (bir şekilde) kullanabilirsiniz. Örneğin, eğer yaparsanız docker run --init ..., olacaktır docker-init. Eğer yaparsan, örneğin docker run ... head -n 1 /proc/1/schedolacak head.
jpkotta

21

Thomas'ın kod olarak çözümü:

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

Not

readBir kukla değişken ile basit bir deyim olan Does bu herhangi bir çıktı üretmek? . Muhtemelen ayrıntılı grepveya bir model testineawk dönüştürmek için kompakt bir yöntemdir .

Okumayla ilgili ek not


10
Ancak ... bu bazı ortamlarda başarısız olacaktır, çünkü örneğin 3:cpu,cpuacct:/system.slice/docker-1ce79a0dec4a2084d54acf187a1e177e0339dc90d0218b48b4456576ecaf291e.scopeeşleşmeyecektir. Daha basit grep -q docker /proc/1/cgroup; bundan çıkan sonuç kodu da yeterli olmalıdır.
larsks

2
readişe yarayabilir bash, ancak en çok kullanılan dashkabukta birini read dummy(veya benzerini) veya benzeri bir yapı kullanmanız gerekir[ -n "$(command)" ]
Daniel Alder

@DanielAlder İyi yakaladın, Daniel. Metni güncelleyeceğim.
Henk Langeveld

1
Daha önce bu, herhangi bir Bourne uyumlu kabuğun readdeğişken adı olmayan düzlüğü desteklediğini iddia ediyordu . Bu yalnızca bash ve ksh93 için geçerlidir. Opengroup yalnızca en az bir değişkeni olmayan davranışı belirtir read varve bunlardan bahsetmez read. Gelen Bash ve ksh93 , herhangi bir halinde var verilir, metotlar bir kabuk değişkeni oku REPLY.
Henk Langeveld

1
Neden kullanamıyoruz awk -F: '$3 ~ /docker/' /proc/self/cgroup | read? Benim için çalışıyor.
Shubham Chaudhary

7

Benim için işe yarayan, '/' inode numarasını kontrol etmektir. Liman işçisinin içinde çok yüksek bir sayı. Docker dışında, '2' gibi çok düşük bir sayı. Bu yaklaşımın kullanılan Dosya Sistemine de bağlı olacağını düşünüyorum.

Misal

Liman işçisinin içinde:

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

Liman işçisinin dışında

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

Bir komut dosyasında:

#!/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

MSYS2'de ls -ali / | sed '2! d' | awk {'baskı 1 $'} 232779805740174872
bo0k

aynı ls -di /? inode num farklı platformda güvenilir değil gibi görünüyor
yurenchen

bu, bir Xen domU ana bilgisayarı ile docker kapsayıcısı arasında ayrım yapmam için işe yarayan tek şeydi
Michael Altfield

1

Kapsayıcılarda çalışan süreçleri dışlamamız gerekiyordu, ancak yalnızca docker cgroup'larını kontrol etmek yerine /proc/<pid>/ns/pidadresindeki init sistemiyle karşılaştırmaya karar verdik /proc/1/ns/pid. Misal:

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

Veya bizim durumumuzda, işlem bir konteynerde DEĞİLSE hata oluşturan tek bir astar istedik

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

bunu başka bir işlemden yürütebiliriz ve çıkış kodu sıfırsa, belirtilen PID farklı bir ad alanında çalışıyor demektir.


Benim için çalışmıyor. K8s-zamanlanmış bir Docker kapsayıcısından readlink /proc/self/ns/pidve readlink /proc/1/ns/pidaynı çıktıyı üretin.
Stefan Majewsky

1
@StefanMajewsky Kapsayıcı çalışma zamanında hangi özelliklerin etkinleştirildiğini görmek için github.com/jessfraz/amicontained kullanmayı denemek isteyebilirsiniz .
Greg Bray

0

Dan Walsh'ın SELinux kullanımı hakkındaki yorumuna dayanarak ps -eZ | grep container_t, ancak pskurulum gerektirmeden :

$ 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

Bu sadece bir kapta çalıştığınızı söyler , ancak hangi çalışma zamanında çalıştığınızı söylemez.

Diğer kapsayıcı çalışma zamanlarını kontrol etmedim, ancak https://opensource.com/article/18/2/understanding-selinux-labels-container-runtimes daha fazla bilgi sağlıyor ve bunun yaygın olarak kullanıldığını gösteriyor, olabilir RKT ve LXC için de çalışır?


0

golang kodu

func GetContainerID(pid int32) string {
    cgroupPath := fmt.Sprintf("/proc/%s/cgroup", strconv.Itoa(int(pid)))
    return getContainerID(cgroupPath)
}

func GetImage(containerId string) string {
    if containerId == "" {
        return ""
    }
    image, ok := containerImage[containerId]
    if ok {
        return image
    } else {
        return ""
    }
}
func getContainerID(cgroupPath string) string {
    containerID := ""
    content, err := ioutil.ReadFile(cgroupPath)
    if err != nil {
        return containerID
    }
    lines := strings.Split(string(content), "\n")
    for _, line := range lines {
        field := strings.Split(line, ":")
        if len(field) < 3 {
            continue
        }
        cgroup_path := field[2]
        if len(cgroup_path) < 64 {
            continue
        }
        // Non-systemd Docker
        //5:net_prio,net_cls:/docker/de630f22746b9c06c412858f26ca286c6cdfed086d3b302998aa403d9dcedc42
        //3:net_cls:/kubepods/burstable/pod5f399c1a-f9fc-11e8-bf65-246e9659ebfc/9170559b8aadd07d99978d9460cf8d1c71552f3c64fefc7e9906ab3fb7e18f69
        pos := strings.LastIndex(cgroup_path, "/")
        if pos > 0 {
            id_len := len(cgroup_path) - pos - 1
            if id_len == 64 {
                //p.InDocker = true
                // docker id
                containerID = cgroup_path[pos+1 : pos+1+64]
                // logs.Debug("pid:%v in docker id:%v", pid, id)
                return containerID
            }
        }
        // systemd Docker
        //5:net_cls:/system.slice/docker-afd862d2ed48ef5dc0ce8f1863e4475894e331098c9a512789233ca9ca06fc62.scope
        docker_str := "docker-"
        pos = strings.Index(cgroup_path, docker_str)
        if pos > 0 {
            pos_scope := strings.Index(cgroup_path, ".scope")
            id_len := pos_scope - pos - len(docker_str)
            if pos_scope > 0 && id_len == 64 {
                containerID = cgroup_path[pos+len(docker_str) : pos+len(docker_str)+64]
                return containerID
            }
        }
    }
    return containerID
}

-1

Küçük bir python betiği oluşturdum. Umarım birisi onu yararlı bulur. :-)

#!/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)

havalı, ama bir kabın içinde olup olmadığınızı belirlemeye nasıl yardımcı olur?
user528025

FileNotFoundError: [Errno 2] No such file or directory: '/sys/fs/cgroup/memory/docker/<docker_id>/memory.stat'
Scrooge McDuck
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.