programing

도커 컨테이너 내부에서 프로세스가 실행되고 있는지 확인하는 방법은 무엇입니까?

javamemo 2023. 8. 13. 09:03
반응형

도커 컨테이너 내부에서 프로세스가 실행되고 있는지 확인하는 방법은 무엇입니까?

[Update1] 일부 기능에서 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:/

위의 플래그를 사용하여 이 프로세스가 컨테이너 내부에서 실행되고 있는지 확인할 수 있습니까?

[업데이트2]: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 없음

도커가 작성하는 항목.dockerenv그리고. .dockerinit (v1.11에 나와 있음) 파일이 컨테이너의 디렉터리 트리 맨 위에 있으므로 해당 파일이 있는지 확인할 수 있습니다.

이런 것도 효과가 있을 겁니다.

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

하는 것은 도커 안에 있는지 확인하는 것은 도커 컨테이너 안에서 할 수 ./proc/1/cgroup 게시물에서 알 수 있듯이 다음을 수행할 수 있습니다.

에 있는 모든 /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:/

도커 컨테이너 내부의 일부 제어 그룹은 도커(또는 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:/

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

환경 변수 사용

저는 도커 이미지 내부에 환경 변수를 설정하여 애플리케이션에서 감지하는 것을 선호합니다.

를 들어,입니다.Dockerfile구성:

FROM node:12.20.1 as base
ENV DOCKER_RUNNING=true
RUN yarn install --production
RUN yarn build

은 두번째줄다같음설환정다니합경을은과은ar▁다▁env▁the▁sets▁called설▁second니정합▁line라는 환경을 설정합니다.DOCKER_RUNNING그러면 쉽게 감지할 수 있습니다.이 문제는 다단계 빌드에서 다음을 반복해야 한다는 것입니다.ENV을 설 FROM외부 이미지에서 분리합니다.를 들면, I , ▁i내.FROM이닌에서 node:12.20.1여기에는 많은 여분의 것(예: 깃)이 포함됩니다.에 나의 에서.Dockerfile 저는 ㅠㅠCOPY기반을 둔 새로운 이미지로 사물을 넘깁니다.node:12.20.1-slim훨씬 더 작은 것:

FROM node:12.20.1-slim as server
ENV DOCKER_RUNNING=true
EXPOSE 3000
COPY --from=base /build /build
CMD ["node", "server.js"]

가 대상이 되는 server 같은안있에 .Dockerfile기본 이미지가 다르기 때문에 ENV 변수를 다시 정의해야 합니다.

Docker-Compose를 사용하면 대신 환경을 쉽게 정의할 수 있습니다.를 들어, 여러분의 를들어, 당의신이 있습니다.docker-compose.yml파일의 모양은 다음과 같습니다.

version: "3.8"
services:
  nodeserver:
    image: michaeloryl/stackdemo
    environment:
      - NODE_ENV=production
      - DOCKER_RUNNING=true

코드로서의 Thomas의 솔루션:

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

메모

read더미 변수를 사용하는 것은 "이것이 어떤 출력을 생성합니까?"의 간단한 관용구입니다.장황하게 설명할 수 있는 간결한 방법입니다.grep또는awk패턴의 테스트로.

읽기 시 추가 참고 사항

제가 할 수 있는 일은 '/'의 아이노드 번호를 확인하는 것입니다. 도커 안에는 매우 높은 숫자가 있습니다.도커 밖에서는 '2'와 같이 매우 낮은 숫자입니다.이 접근 방식은 사용 중인 파일 시스템에 따라 달라질 것이라고 생각합니다.

도커 내부:

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

도커 외부

$ 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

cgroup을 비교하기로 ./proc/<pid>/ns/pid의 초기 /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

또는 우리의 경우 공정이 컨테이너에 없을 경우 오류가 발생하는 하나의 라이너를 원했습니다.

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

다른 프로세스에서 실행할 수 있으며 종료 코드가 0이면 지정된 PID가 다른 네임스페이스에서 실행되고 있습니다.

docker에서 프로세스를 확인하기 위해 /golang/%s/cgroup을 통해 k8s 클러스터를 검색하는 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
}

SELinux 사용에 대한 Dan Walsh의 의견을 기반으로 합니다.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

이것은 컨테이너에서 실행 중이라는 것을 알려주는 것일 뿐, 어떤 런타임인지는 알려주지 않습니다.

다른 컨테이너 런타임을 확인하지 않았지만 https://opensource.com/article/18/2/understanding-selinux-labels-container-runtimes 은 더 많은 정보를 제공하고 이것이 널리 사용되고 있다고 제안합니다. 또한 rkt와 lxc에도 작동할 수 있습니까?

시스템 프로그램/스크립트가 실행될 것으로 알고 있는 한 PID 1로 실행되는 것이 다음과 같은지 확인하는 것이 좋습니다.systemd(또는 동등).그렇지 않다면, 그것은 용기입니다.도커뿐만 아니라 모든 리눅스 컨테이너에 대해서도 마찬가지입니다.

/.dockerenvGitPod를 사용할 때 파일이 존재하지 않는 것 같아 @at0S의 답변에 다음 체크를 추가로 사용했습니다.

if [ -f /.dockerenv ] | [ -n "$(env | grep "^GITPOD")" ]; then
  echo "In Docker"
else
  echo "Outside Docker"
fi

2022년에 macOS에서 이 기능이 필요했으며 @at0S의 답변만 다른 모든 옵션에서 여전히 작동합니다.

  • /proc/1/cgroup달리 구성되지 않은 한 컨테이너에 루트 디렉터리만 있음
  • /proc/1/sched에서는 동일한 내부 프로세스 번호를 보여주었습니다.이름이 달랐습니다(bash휴대성이 떨어집니다.
  • 사용자가 직접 컨테이너를 구성하면 환경 변수가 작동하지만 기본 환경 변수 중 어떤 것도 도움이 되지 않습니다.

다른 답변에 나열되지 않은 옵션을 찾았습니다./proc/1/mounts포함된overlay경로에 "파일 시스템"이 있습니다.

언급URL : https://stackoverflow.com/questions/23513045/how-to-check-if-a-process-is-running-inside-docker-container

반응형