Dockerコンテナ内でプロセスが実行されているかどうかを確認する方法


89

[Updated1]一部の関数でTCPカーネルパラメーターを変更するシェルがありますが、このシェルをDockerコンテナーで実行する必要があります。つまり、シェルはコンテナー内で実行されていることを認識し、カーネルの構成を停止する必要があります。

これを実現する方法がわかりません。/proc/self/cgroupコンテナ内の内容は次のとおりです。

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

上記のフラグを使用して、このプロセスがコンテナー内で実行されているかどうかを確認できますか?

[Updated2]:プロセスがlxc / Docker内で実行されているかどうかの判断にも気づきましたが、この場合は機能していないよう/proc/1/cgroupです。コンテナーのコンテンツは次のとおりです。

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

/ lxc / containeridはありません


あまり明確な質問ではありません。なぜこれが必要なのですか?
Henk Langeveld 2014年


@fish no / lxc / <containerid>私の場合、更新を参照
harryz 2014年

1
@HenkLangeveldカーネルパラメーターはDockerコンテナーでは読み取り専用であるため、シェルがコンテナー内で実行されているかどうかを確認し、シェルのカーネル関数を無効にする必要があります。更新を参照してください。
harryz 2014年

スクリプトの一部の手順はカーネルパラメーターを変更しようとするため、Dockerで実行する場合はスキップする必要があります。晴れ。
Henk Langeveld 2014年

回答:


70

Dockerコンテナー内にいるかどうかを確認するには、を介して実行できます/proc/1/cgroupこのポストは示唆して次のことをするためにすることができます:

Dockerコンテナの外では、 /proc/1/cgroup/ここに表示されているように終了します。

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

Dockerコンテナー内では、いくつかのコントロールグループがDocker(または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:/

@Founderの回答はよりクリーンです
Scott Stensland

5
「Dockerコンテナの外部では、/ proc / 1 / cgroup内のすべてのエントリが/で終了する」というのは厳密には真実ではありません。:Ubuntuの私は例えば16.04オン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

これはほとんどLinuxでのみ機能し、ダーウィンやprocfsを使用しない他のBSDでは機能しません。
クリスチャン

@Christian Docker / LXCはLinuxのみのものなので、それで問題ありません:)?
RobertLacroix20年

@RobertLacroixだから、procfsが見つからない場合は、Dockerを使用していないということですか?まあ、それは私が推測するのに十分公平です...
クリスチャン

112

Dockerが作成し.dockerenv.dockerinitv1.11で削除)、コンテナーのディレクトリー・ツリーの最上位にファイルを)、それらが存在するかどうかを確認することをお勧めします。

このようなものが機能するはずです。

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

1
もちろん、あなたまたは他の誰かが/.dockerinitあなたのホスト上で(おそらく偶然に)作成した場合を除いて、その場合、それはコンテナの外で間違っているでしょう。
sosiouxme 2015年

18
他の誰かが/でそれを作った場合、それらはルートであり、Dockerにいるかどうかを知るよりも悪い問題があります。
davey 2015年

15
/.dockerenv長期的に依存することに注意してください。このように使用することを意図したものではありません
ReactiveRaven 2016

fwiw、Podmanは作成しません/.dockerenv。それは作成します/run/.containerenvが、同様のロジックにより、実装の詳細は信頼できないように聞こえます。ポッドマン固有の代替手段については、github.com / container / libpod / issues / 3586を参照してください。
BeniCherniavsky-Paskin20年

24

procのsched(/ 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)

これは、コンテナ内にいるかどうかを区別するのに役立ちます。たとえば、次のことができます。

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

これは実際には非常に貴重な情報です。ありがとう
ファビアンランゲ2016年

4
OSによっては、「init」を「systemd」に置き換える必要がある場合があります。systemdの詳細については、こちらをご覧ください
BrianV 2017年

2
@BrianVが述べたように、これは私にとってもうまくいきません。
Shubham Chaudhary 2017

5
k8sクラスターで実行されているDockerコンテナーでhead -n1 /proc/1/scheddumb-init (1, #threads: 1)、が返されるため、この回答で提案されているチェックは失敗します。(また、答えが示唆していることに反して、私はこれをコンテナで行っていますが、PIDはその行に「1」として表示されます。)
Stefan Majewsky 2018

これは間違いなく普遍的な解決策ではありません。コンテナのPID1には、(ある種の)好きなものを使用できます。たとえば、使用するとdocker run --init ...、になりますdocker-init。あなたがそうするならば、例えばdocker run ... head -n 1 /proc/1/schedそれはそうなるでしょうhead
jpkotta

21

コードとしてのThomasのソリューション:

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

注意

readダミー変数とするための単純なイディオムである任意の出力このプロデュースしていますか?。これは、おそらく冗長grepまたはパターンのテストawk変換するためのコンパクトな方法です。

読むことに関する追加の注記


10
を除いて...これは、たとえば3:cpu,cpuacct:/system.slice/docker-1ce79a0dec4a2084d54acf187a1e177e0339dc90d0218b48b4456576ecaf291e.scope一致しないため、一部の環境では失敗します。簡単にgrep -q docker /proc/1/cgroup; その結果のコードも十分なはずです。
larsks 2015年

2
readで機能する可能性がありますがbash、最もよく使用されるdashシェルでは、いずれかread dummy(または同様の)を使用するか、次のような構成を使用する必要があります[ -n "$(command)" ]
Daniel Alder

@DanielAlderグッドキャッチ、ダニエル。テキストを更新します。
Henk Langeveld 2015年

1
以前、これは、Bourne互換シェルがread変数名のないプレーンをサポートすると主張していました。これはbashとksh93にのみ当てはまります。Opengroupは、少なくとも1つの変数read varがない場合のread動作を指定するだけで、言及しません。bashは、ksh93一切場合、VARが与えられていない、読み取りは、シェル変数を使用していますREPLY
Henk Langeveld 2015年

1
なぜ私たちはただ使うことができないのawk -F: '$3 ~ /docker/' /proc/self/cgroup | readですか?私のために働きます。
Shubham Chaudhary 2017

7

私にとってうまくいくのは、「/」のiノード番号を確認することです。Dockerの内部では、非常に多くなっています。Dockerの外では、「2」のような非常に少ない数です。このアプローチは、使用されているファイルシステムにも依存すると思います。

Dockerの内部:

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

Dockerの外

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

スクリプト内:

#!/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でls-ali / | sedの'!2 D' | awkが232779805740174872 { '$ 1印刷する'}
bo0k

と同じ ls -di /?異なるプラットフォーム上のinode numが信頼性がないと思われる
yurenchen

これは、
XendomU

1

コンテナで実行されているプロセスを除外する必要がありましたが、docker cgroupだけをチェックする代わり/proc/<pid>/ns/pidに、のinitシステムと比較することにしました/proc/1/ns/pid。例:

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

または、私たちの場合、プロセスがコンテナ内にない場合にエラーを生成する1つのライナーが必要でした

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

これは別のプロセスから実行でき、終了コードがゼロの場合、指定されたPIDは別の名前空間で実行されています。


私には効きません。k8sでスケジュールされたDockerコンテナ内から、同じ出力readlink /proc/self/ns/pidreadlink /proc/1/ns/pid生成します。
Stefan Majewsky 2018

1
@StefanMajewsky github.com/jessfraz/amicontainedを使用して、コンテナーランタイムで有効になっている機能を確認することをお勧めします。
グレッグブレイ

0

SELinuxの使用に関するDanWalshのコメントに基づいていますが、インストールps -eZ | grep container_tする必要psはありません。

$ 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

これはちょうどあなたが実行しているかを示しますAコンテナでどのランタイムを実行しているのかはわかりません。

他のコンテナランタイムをチェックしませんでしたが、https: //opensource.com/article/18/2/understanding-selinux-labels-container-runtimesはより多くの情報を提供し、これが広く使用されていることを示唆しています。rktとlxcでも機能する可能性がありますか?


0

golangコード

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

小さなPythonスクリプトを作成しました。誰かがそれが役に立つと思うことを願っています。:-)

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

かっこいいですが、コンテナの中にいるかどうかを判断するのにどのように役立ちますか?
user5280 2519

FileNotFoundError: [Errno 2] No such file or directory: '/sys/fs/cgroup/memory/docker/<docker_id>/memory.stat'
スクルージマクダック
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.