Podman이 systemd로 시작될 때 conmon이 다른 cgroup에 있는 이유는 무엇입니까?

Podman이 systemd로 시작될 때 conmon이 다른 cgroup에 있는 이유는 무엇입니까?

주어진 Podman은 Linux 시스템과 baz.service라는 systemd 단위에 설치되어 있습니다.

# /etc/systemd/system/baz.service
[Service]
ExecStart=/usr/bin/podman run --rm --tty --name baz alpine sh -c 'while true; do date; sleep 1; done'
ExecStop=/usr/bin/podman stop baz

baz.service가 시작되었습니다:

# systemctl daemon-reload
# systemctl start baz.service

그런 다음 장치 상태를 확인할 때 /system.slice/baz.service cgroup에 sh또는 프로세스가 표시되지 않습니다.sleep

# systemctl status baz
● baz.service
   Loaded: loaded (/etc/systemd/system/baz.service; static; vendor preset: enabl
   Active: active (running) since Sat 2019-08-10 05:50:18 UTC; 14s ago
 Main PID: 16910 (podman)
    Tasks: 9
   Memory: 7.3M
      CPU: 68ms
   CGroup: /system.slice/baz.service
           └─16910 /usr/bin/podman run --rm --tty --name baz alpine sh -c while
# ...

Podman이 전통적인 포크 실행 모델을 사용한다는 Redhat 사람들로부터 들었기 때문에 baz.service 상태에서 sh및 하위 키를 보고 싶었습니다.sleep

Podman이 포크 및 실행을 수행하는 경우 내 shsleep프로세스는 Podman의 하위 프로세스가 아니며 원래 Podman 프로세스와 동일한 cgroup에 있습니까?

나는 아이들이 다른 부모에게 가서 내 baz.service ssystemd 유닛을 탈출하지 않고도 systemd와 podman을 사용하여 내 컨테이너를 관리할 수 있기를 원합니다.

출력을 보면 하위 프로세스가 실제로 이름이 다른 프로세스라는 것을 ps알 수 있습니다 . conmon이 어디서 왔는지, 어떻게 시작되었는지는 잘 모르겠지만 systemd에서는 이를 포착하지 못합니다.shsleepconmon

# ps -Heo user,pid,ppid,comm
# ...
root     17254     1   podman
root     17331     1   conmon
root     17345 17331     sh
root     17380 17345       sleep

내 baz.service 장치가 conmon -> sh -> sleep 체인을 관리하지 않는다는 것이 출력에서 ​​분명합니다.

  • Podman은 Docker 클라이언트 서버 모델과 어떻게 다릅니까?
  • Podman의 conmon과 docker의 컨테이너의 차이점은 무엇입니까?

어쩌면 둘 다 컨테이너 런타임이고 dockerd데몬은 사람들이 제거하고 싶어하는 것일 수도 있습니다.

아마도 도커는 다음과 같을 것입니다:

  • 도커드 데몬
  • 도커 명령줄
  • Containerd 컨테이너 런타임

포드맨은 다음과 같다:

  • Podman 명령줄 인터페이스
  • 공통 컨테이너 런타임

따라서 podman은 전통적인 포크 실행 모델을 사용하지만, podman cli가 포크와 실행을 수행하는 대신 일반적인 프로세스입니다.

혼란스러워요.

답변1

이에 대한 전체 아이디어는 중앙 집중식 데몬이 단일 실패 지점인 podman매우 강력한 감독자(예: )가 있는 중앙 집중식 아키텍처에서 벗어나는 것입니다 . dockerd이에 대한 태그도 있습니다. - "#nobigfatdaemons".

컨테이너의 중앙 집중식 관리를 피하는 방법은 무엇입니까? 단일 기본 데몬(다시 말하지만 dockerd)을 제거하고 컨테이너를 독립적으로 시작합니다(결국 컨테이너는 프로세스일 뿐이므로 컨테이너를 생성하는 데 데몬이 필요하지 않습니다).

그러나 여전히 방법이 필요합니다.

  • 컨테이너에서 로그를 수집합니다. 누군가가 stdout컨테이너를 보관해야 합니다 stderr.
  • 컨테이너의 종료 코드 수집 - 누군가 wait(2)컨테이너의 PID 1을 수집해야 합니다.

이를 위해 각 Podman 컨테이너는 conmon("컨테이너 모니터"에서) 호출되는 작은 데몬에 의해 계속해서 감독됩니다. Docker 데몬과의 차이점은 이 데몬이 가능한 한 작다는 것입니다(확인소스 코드 크기)이며 컨테이너별로 생성됩니다. 컨테이너 하나가 충돌 하더라도 conmon시스템의 나머지 부분은 영향을 받지 않습니다.

다음으로 컨테이너는 어떻게 생성되나요?

사용자가 Docker처럼 백그라운드에서 컨테이너를 실행하기를 원할 수 있다는 점을 고려하면 프로세스가 podman run분기됩니다.두 배그런 다음 다음을 실행하십시오 conmon.

$ strace -fe trace=fork,vfork,clone,execve -qq podman run alpine
execve("/usr/bin/podman", ["podman", "run", "alpine"], 0x7ffeceb01518 /* 30 vars */) = 0
...
[pid  8480] clone(child_stack=0x7fac6bffeef0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tid=[8484], tls=0x7fac6bfff700, child_tidptr=0x7fac6bfff9d0) = 8484
...
[pid  8484] clone(child_stack=NULL, flags=CLONE_VM|CLONE_VFORK|SIGCHLD <unfinished ...>
[pid  8491] execve("/usr/bin/conmon", ... <unfinished ...>
[pid  8484] <... clone resumed>)        = 8491

podman run사이에 있는 중간 프로세스 conmon(즉, 직접 상위 프로세스 conmon- 위의 예에서는 PID 8484)가 종료되고 conmon상위가 다시 지정되어 init자체 관리 데몬이 됩니다. 그런 다음 conmon런타임도 포크되고(예 runc: ) 마지막으로 런타임은 컨테이너의 진입점(예: /bin/sh)을 실행합니다.

컨테이너가 실행되는 동안에는 podman run더 이상 필요하지 않아 종료될 수 있지만 귀하의 경우에는 컨테이너에서 분리를 요청하지 않았기 때문에 온라인 상태로 유지됩니다.

다음으로 podmancgroup을 사용하여 컨테이너를 제한합니다. 이것은 그것을 의미한다새 컨테이너에 대한 새 cgroup을 생성하고 프로세스를 여기로 이동합니다.. cgroup의 규칙에 따르면 프로세스는 한 번에 하나의 cgroup에만 속할 수 있으며, cgroup에 프로세스를 추가하면 동일한 계층(이전에 위치했던)의 다른 cgroup에서 해당 프로세스가 제거됩니다. 따라서 컨테이너가 시작되면 cgroup의 최종 레이아웃은 다음과 같습니다. podman run생성된 cgroup에 남아 있고 프로세스는 자체 cgroup에 배치되며 컨테이너화된 프로세스는 자체 cgroup에 배치됩니다.baz.servicesystemdconmon

$ ps axf
<...>
 1660 ?        Ssl    0:01 /usr/bin/podman run --rm --tty --name baz alpine sh -c while true; do date; sleep 1; done
 1741 ?        Ssl    0:00 /usr/bin/conmon -s -c 2f56e37a0c5ca6f4282cc4c0f4c8e5c899e697303f15c5dc38b2f31d56967ed6 <...>
 1753 pts/0    Ss+    0:02  \_ sh -c while true; do date; sleep 1; done
13043 pts/0    S+     0:00      \_ sleep 1
<...>

$ cd /sys/fs/cgroup/memory/machine.slice
$ ls -d1 libpod*
libpod-2f56e37a0c5ca6f4282cc4c0f4c8e5c899e697303f15c5dc38b2f31d56967ed6.scope
libpod-conmon-2f56e37a0c5ca6f4282cc4c0f4c8e5c899e697303f15c5dc38b2f31d56967ed6.scope

$ cat libpod-2f56e37a0c5ca6f4282cc4c0f4c8e5c899e697303f15c5dc38b2f31d56967ed6.scope/cgroup.procs 
1753
13075

$ cat libpod-conmon-2f56e37a0c5ca6f4282cc4c0f4c8e5c899e697303f15c5dc38b2f31d56967ed6.scope/cgroup.procs 
1741

참고: 위의 PID 13075는 실제로 sleep 1PID 13043이 죽은 후에 생성된 프로세스입니다.

도움이 되었기를 바랍니다.

답변2

podman은 --cgroups splitsystemd에 더 적합한 방식으로 cgroup을 생성합니다. (systemd-nspawn이 수행하는 작업과 유사하며 감독자 및 컨테이너 프로세스에 "서비스" cgroup 및 하위 cgroup을 사용함)

예 - 내 rwhod 컨테이너:

 CGroup: /machine.slice/rwhod.service
         ├─container
         │ ├─ 998 /dev/init -- /container/tool/run
         │ ├─1040 /usr/bin/python3 -u /container/tool/run
         │ └─1706 /usr/sbin/rwhod -i mgmt0 -S -D
         └─supervisor
           └─995 /opt/podman/libexec/podman/conmon --api-version 1 -c ddf3e27960378fd57b2ebd15d7beb7474506f612e7329acb014c5f89cd652562 >

이 블로그 토론의 일부로 저는 특히 이 목적을 위해 해당 메서드를 podman에 추가했습니다.https://github.com/containers/podman/issues/6400

관련 정보