작업 중.

NAME

cgroups - 리눅스 제어 그룹

DESCRIPTION

보통 cgroups라고 부르는 제어 그룹(control group)은 프로세스들을 계층적 그룹들로 조직해서 다양한 종류의 자원 사용을 제한하거나 감시할 수 있는 리눅스 커널의 기능이다. cgroupfs라는 유사 파일 시스템을 통해 커널의 cgroup 인터페이스가 제공된다. 그룹 관리는 커널의 cgroup 핵심 코드에 구현돼 있으며 자원 추적 및 제한은 자원 종류별 서브시스템(메모리, CPU 등등)에 구현돼 있다.

용어

cgroup이란 cgroup 파일 시스템을 통해 규정한 제한이나 매개변수들의 구속을 받는 프로세스들의 집합이다.

서브시스템(subsystem)이란 cgroup 내 프로세스들의 행동을 변경하는 커널 구성 요소다. 다양한 서브시스템이 구현돼 있어서 어떤 cgroup에서 이용 가능한 CPU 시간이나 메모리의 양을 제한하거나, cgroup에서 사용한 CPU 시간을 기록하거나, cgroup 내 프로세스들의 실행을 동결하고 재개하는 게 가능하다. 서브시스템을 자원 컨트롤러(resource controller)라고도 (그냥 컨트롤러라고도) 부른다.

어떤 컨트롤러의 cgroup들은 계층적으로 배치돼 있다. cgroup 파일 시스템 내에서 하위 디렉터리를 만들고, 지우고, 이름을 바꾸는 방식으로 그 계층 구조를 정의한다. 그리고 계층 구조의 각 단계에서 속성(가령 제한값)을 지정할 수 있다. cgroup에서 제공하는 제한, 제어, 기록 기능은 일반적으로 그 속성이 정의된 cgroup 이하의 하위 계층 구조 전체에 영향을 준다. 예를 들어 계층 구조 상위 단계의 cgroup에서 어떤 제한을 주면 자손 cgroup에서 그걸 초과할 수 없다.

cgroups 버전 1과 버전 2

cgroups 구현이 처음 출시된 건 리눅스 2.6.24에서였다. 시간이 흐르며 다양한 cgroup 컨트롤러들이 추가돼서 다양한 종류의 자원들을 관리할 수 있게 됐다. 하지만 그 컨트롤러들의 개발은 전반적으로 조정이 안 돼 있었고, 그래서 컨트롤러들 간에 비일관성이 발생하고 cgroup 계층 구조 관리가 꽤 복잡해지는 결과를 낳았다. 그 문제들에 대한 더 긴 설명은 커널 소스 파일 Documentation/admin-guide/cgroup-v2.rst(리눅스 4.17 이전은 Documentation/cgroup-v2.txt)에서 볼 수 있다.

cgroups 최초 구현(cgroups 버전 1)의 문제들 때문에 리눅스 3.10부터 그 문제들을 해결하기 위한 새롭고 독립적인 구현체를 만드는 작업이 시작됐다. 처음에는 실험적으로 표시되어 마운트 옵션 -o __DEVEL__sane_behavior 뒤에 숨어 있다가 리눅스 4.5가 출시될 때 마침내 새 버전(cgroups 버전 2)이 정식 버전이 됐다. 두 버전의 차이를 아래에서 설명한다. cgroups v1에 있는 cgroup.sane_behavior 파일은 이 마운트 옵션의 유물이다. 항상 "0"을 내놓으며 하위 호환성을 위해 유지되고 있을 뿐이다.

cgroups v2가 cgroups v1을 대체하기 위한 것이긴 하지만 이전 시스템은 계속 존재한다. (그리고 호환성 문제가 있기 때문에 쉽게 제거되지 않을 것 같다.) 현재 cgroups v2는 cgroups v1에서 쓸 수 있는 컨트롤러들 중 일부만 구현하고 있다. 같은 시스템에서 v1 컨트롤러와 v2 컨트롤러를 모두 마운트할 수 있도록 두 시스템이 구현돼 있다. 그래서 예를 들어 버전 2에서 지원하는 컨트롤러들을 사용하면서도 버전 2에서 아직 컨트롤러를 지원하지 않는 버전 1의 컨트롤러까지 사용하는 게 가능하다. 유일한 제약은 한 컨트롤러를 cgroups v1 계층 구조와 cgroups v2 계층 구조 모두에서 동시에 사용할 수는 없다는 점이다.

cgroups 버전 1

cgroups v1 하에서는 시스템 프로세스들에 대한 계층 구조를 각기 제공하는 별개의 cgroup 파일 시스템에 각 컨트롤러를 마운트할 수 있다. 또한 같은 cgroup 파일 시스템에 여러 (또는 모든) cgroups v1 컨트롤러들을 함께 마운트하는 것도 가능한데, 함께 마운트된 컨트롤러들이 같은 프로세스 계층 구조를 관리하는 것이다.

마운트된 각 계층 구조별로 디렉터리 트리가 제어 그룹 계층 구조를 반영한다. 각 디렉터리가 제어 그룹을 나타내고 자식 디렉터리는 자식 제어 그룹을 나타낸다. 예를 들어 /user/joe/1.session은 제어 그룹 /user의 자식인 cgroup joe의 자식인 1.session을 나타낸다. 각 cgroup 디렉터리에는 읽거나 쓸 수 있는 파일들이 있어서 자원 제한치와 몇몇 일반적인 cgroup 속성들을 나타낸다.

태스크(스레드) 대 프로세스

cgroup v1에서는 프로세스태스크를 구별한다. 그 관점에서는 한 프로세스가 여러 태스크(사용자 공간 쪽에선 주로 스레드라고 하며 이 맨 페이지 나머지에서도 그렇게 부름)로 이뤄져 있을 수 있다. cgroups v1에서는 프로세스 내 스레드들의 cgroup 소속을 독립적으로 조작하는 게 가능하다.

cgroups v1에서 스레드들을 여러 cgroup들로 쪼갤 수 있다는 점이 몇몇 경우에 문제를 일으켰다. 예를 들어 memory 컨트롤러에서는 말이 안 되는데, 프로세스의 모든 스레드가 한 주소 공간을 공유하기 때문이다. 이러한 문제들 때문에 프로세스 내 스레드들의 cgroup 소속을 독립적으로 조작할 수 있게 하는 것을 cgroups v2 최초 구현에서는 제거했으며, 그 뒤에 제한된 형태로 되살렸다. (아래의 "스레드 모드" 설명 참고.)

v1 컨트롤러 마운트

cgroups 사용을 위해선 커널이 CONFIG_CGROUP 옵션으로 빌드돼 있어야 한다. 또한 v1 컨트롤러 각각에 연관된 설정 옵션이 있어서 그걸 설정해 줘야 컨트롤러를 이용할 수 있다.

v1 컨트롤러를 사용하려면 cgroup 파일 시스템으로 마운트를 해야 한다. 보통은 /sys/fs/cgroup에 마운트된 tmpfs(5) 파일 시스템 아래에 마운트한다. 즉 cpu 컨트롤러를 다음처럼 마운트할 수 있을 것이다.

mount -t cgroup -o cpu none /sys/fs/cgroup/cpu

같은 계층 구조에 여러 컨트롤러를 함께 마운트하는 게 가능하다. 예를 들어 다음은 한 계층 구조에 cpu 컨트롤러와 cpuacct 컨트롤러를 함께 마운트한다.

mount -t cgroup -o cpu,cpuacct none /sys/fs/cgroup/cpu,cpuacct

컨트롤러들을 함께 마운트하면 그렇게 마운트한 모든 컨트롤러에 대해 프로세스가 같은 cgroup에 있게 되는 효과가 있다. 반면 컨트롤러들을 따로 마운트하면 프로세스가 한 컨트롤러에 대해선 cgroup /foo1에 있으면서 다른 컨트롤러에 대해선 /foo2/foo3에 있는 게 가능하다.

모든 v1 컨트롤러들을 같은 계층 구조로 함께 마운트하는 것도 가능하다.

mount -t cgroup -o all cgroup /sys/fs/cgroup

(컨트롤러를 따로 지정하지 않은 경우의 기본값이기도 하므로 -o all를 생략해도 같은 결과를 얻을 수 있다.)

동일 컨트롤러를 여러 cgroup 계층 구조에 마운트하는 건 불가능하다. 예를 들어 cpu 컨트롤러와 cpuacct 컨트롤러를 한 계층 구조에 같이 마운트하고서 cpu 컨트롤러만 따로 다른 계층 구조에 마운트하는 게 불가능하다. 정확히 동일한 컨트롤러 집합으로 여러 마운트 지점을 만드는 건 가능하다. 하지만 이렇게 하는 결과는 여러 마운트 지점에서 동일 계층 구조를 보여 주는 것일 뿐이다.

참고로 많은 시스템에서는 /sys/fs/cgroup 아래에 v1 컨트롤러들을 자동으로 마운트한다. 특히 systemd(1)에서 그런 마운트 지점들을 자동으로 생성한다.

v1 컨트롤러 언마운트

마운트된 cgroup 파일 시스템을 다음 예처럼 umount(8) 명령으로 언마운트할 수 있다.

umount /sys/fs/cgroup/pids

주의: cgroup 파일 시스템이 사용 중이 아니어야만, 즉 자식 cgroup이 없어야 언마운트된다. 안 그러면 umount(8)의 효과는 마운트를 보이지 않게 하는 것뿐이다. 즉 마운트 지점이 실제로 제거되게 하려면 모든 자식 cgroup을 먼저 제거해 둬야 하며, 그러려면 모든 소속 프로세스들을 그 cgroup에서 루트 cgroup으로 옮겨야 한다.

cgroups 버전 1 컨트롤러

cgroups 버전 1 컨트롤러 각각은 (아래 적힌) 커널 구성 옵션에 좌우된다. 추가로 cgroups 기능 사용 여부가 커널 구성 옵션 CONFIG_CGROUPS에 의해 좌우된다.

cpu (리눅스 2.6.24부터. CONFIG_CGROUP_SCHED)

.... 자세한 내용은 Documentation/scheduler/sched-design-CFS.rst(리눅스 5.2 이전은 Documentation/scheduler/sched-design-CFS.txt)를 보라.

....

커널 소스 파일 Documentation/scheduler/sched-bwc.rst(리눅스 5.2 이전은 Documentation/scheduler/sched-bwc.txt)에서 자세한 내용을 볼 수 있다.

cpuacct (리눅스 2.6.24부터. CONFIG_CGROUP_CPUACCT)

....

커널 소스 파일 Documentation/admin-guide/cgroup-v1/cpuacct.rst(리눅스 5.2 이전은 Documentation/cgroup-v1/cpuacct.txt)에서 자세한 내용을 볼 수 있다.

cpuset (리눅스 2.6.24부터. CONFIG_CPUSETS)

....

커널 소스 파일 Documentation/admin-guide/cgroup-v1/cpusets.rst(리눅스 5.2 이전은 Documentation/cgroup-v1/cpusets.txt)에서 자세한 내용을 볼 수 있다.

memory (리눅스 2.6.25부터. CONFIG_MEMCG)

....

커널 소스 파일 Documentation/admin-guide/cgroup-v1/memory.rst(리눅스 5.2 이전은 Documentation/cgroup-v1/memory.txt)에서 자세한 내용을 볼 수 있다.

devices (리눅스 2.6.26부터. CONFIG_CGROUP_DEVICE)

....

커널 소스 파일 Documentation/admin-guide/cgroup-v1/devices.rst(리눅스 5.2 이전은 Documentation/cgroup-v1/devices.txt)에서 자세한 내용을 볼 수 있다.

freezer (리눅스 2.6.28부터. CONFIG_CGROUP_FREEZER)

....

커널 소스 파일 Documentation/admin-guide/cgroup-v1/freezer-subsystem.rst(리눅스 5.2 이전은 Documentation/cgroup-v1/freezer-subsystem.txt)에서 자세한 내용을 볼 수 있다.

net_cls (리눅스 2.6.29부터. CONFIG_CGROUP_NET_CLASSID)

....

커널 소스 파일 Documentation/admin-guide/cgroup-v1/net_cls.rst(리눅스 5.2 이전은 Documentation/cgroup-v1/net_cls.txt)에서 자세한 내용을 볼 수 있다.

blkio (리눅스 2.6.33부터. CONFIG_BLK_CGROUP)

....

....

커널 소스 파일 Documentation/admin-guide/cgroup-v1/blkio-controller.rst(리눅스 5.2 이전은 Documentation/cgroup-v1/blkio-controller.txt)에서 자세한 내용을 볼 수 있다.

perf_event (리눅스 2.6.39부터. CONFIG_CGROUP_PERF)

....

커널 소스 파일들에서 자세한 내용을 볼 수 있다.

net_prio (리눅스 3.3부터. CONFIG_CGROUP_NET_PRIO)

....

커널 소스 파일 Documentation/admin-guide/cgroup-v1/net_prio.rst(리눅스 5.2 이전은 Documentation/cgroup-v1/net_prio.txt)에서 자세한 내용을 볼 수 있다.

hugetlb (리눅스 3.5부터. CONFIG_CGROUP_HUGETLB)

....

커널 소스 파일 Documentation/admin-guide/cgroup-v1/hugetlb.rst(리눅스 5.2 이전은 Documentation/cgroup-v1/hugetlb.txt)에서 자세한 내용을 볼 수 있다.

pids (리눅스 4.3부터. CONFIG_CGROUP_PIDS)

....

커널 소스 파일 Documentation/admin-guide/cgroup-v1/pids.rst(리눅스 5.2 이전은 Documentation/cgroup-v1/pids.txt)에서 자세한 내용을 볼 수 있다.

rdma (리눅스 4.11부터. CONFIG_CGROUP_RDMA)

....

커널 소스 파일 Documentation/admin-guide/cgroup-v1/rdma.rst(리눅스 5.2 이전은 Documentation/cgroup-v1/rdma.txt)에서 자세한 내용을 볼 수 있다.

cgroup 생성과 프로세스 이동

...

mkdir /sys/fs/cgroup/cpu/cg1

...

...

echo $$ > /sys/fs/cgroup/cpu/cg1/cgroup.procs

...

...

...

...

...

...

cgroup 제거

...

cgroups v1 해제 알림

...

...

...

...

mount -o release_agent=pathname ...

....

cgroups v1 이름 있는 계층 구조

....

mount -t cgroup -o none,name=somename none /some/mount/point

....

....

cgroups 버전 2

....

....

  1. ...

  2. ....

  3. ...

  4. ....

  5. ...

....

....

cgroups v2 통합 구조

....

mount -t cgroup2 none /mnt/cgroup2

....

....

cgroups v2 마운트 옵션

....

nsdelegate (리눅스 4.15부터)
....
memory_localevents (리눅스 5.2부터)
....

cgroups v2 컨트롤러

....

cpu (리눅스 4.15부터)
....
cpuset (리눅스 5.0부터)
....
freezer (리눅스 5.2부터)
....
hugetlb (리눅스 5.6부터)
....
io (리눅스 4.5부터)
....
memory (리눅스 4.5부터)
....
perf_event (리눅스 4.11부터)
....
pids (리눅스 4.5부터)
....
rdma (리눅스 4.11부터)
....

....

....

cgroups v2 서브트리 제어

....

cgroup.controllers
....
cgroup.subtree_control

....

echo '+pids -memory' > x/y/cgroup.subtree_control

....

....

....

cgroups v2 "내부 프로세스 없음" 규칙

....

....

....

....

cgroups v2 cgroup.events 파일

....

$ cat mygrp/cgroup.events
populated 1
frozen 0

....

populated
....
frozen (리눅스 5.2부터)
....

....

cgroups v2 해제 알림

....

....

cgroups v2 cgroup.stat 파일

....

nr_descendants
....
nr_dying_descendants

....

....

자손 cgroup 수 제한

....

cgroup.max.depth (리눅스 4.14부터)

....

....

cgroup.max.descendants (리눅스 4.14부터)

....

....

cgroups 위임: 작은 특권의 사용자에게 계층 구조 위임하기

....

....

....

/dlgt_grp
....
/dlgt_grp/cgroup.procs
....
/dlgt_grp/cgroup.subtree_control (cgroups v2 전용)
....
/dlgt_grp/cgroup.threads (cgroups v2 전용)

....

....

....

....

....

cgroups v2 위임: nsdelegate와 cgroup 네임스페이스

....

mount -t cgroup2 -o remount,nsdelegate \
                 none /sys/fs/cgroup/unified

....

....

....

....

주의: ....

cgroup_no_v1=all systemd.legacy_systemd_cgroup_controller

....

cgroups 위임 격납 규칙

....

주의: ....

cgroups 버전 2 스레드 모드

....

....

....

....

....

domain
....
threaded
....
domain threaded
....
domain invalid

....

....

스레드 대 도메인 컨트롤러

....

스레드 서브트리 생성

....

  1. ....

    • ....

    • ....

    • ....

  2. ....

....

  1. ....

    • ....

    • ....

  2. ....

....

스레드 서브트리 사용

....

....

....

....

....

....

....

cgroup.type 기록 및 스레드 서브트리 생성 규칙

....

....

....

"domain threaded" cgroup 유형

....

....

....

루트 cgroup의 예외 사항

....

....

....

cgroups v2 "cpu" 컨트롤러와 실시간 스레드

....

....

ERRORS

...

EBUSY
....

NOTES

....

....

/proc 파일

/proc/cgroups (리눅스 2.6.24부터)

....

#subsys_name    hierarchy      num_cgroups    enabled
cpuset          4              1              1
cpu             8              1              1
cpuacct         8              1              1
blkio           6              1              1
memory          3              1              1
devices         10             84             1
freezer         7              1              1
net_cls         9              1              1
perf_event      5              1              1
net_prio        9              1              1
hugetlb         0              1              0
pids            2              1              1

....

  1. ....

  2. ....

    a) ....

    b) ....

    c) ....

  3. ....

  4. ....

/proc/[pid]/cgroup (리눅스 2.6.24부터)

....

....

hierarchy-ID:controller-list:cgroup-path

....

5:cpuacct,cpu,cpuset:/daemons

....

  1. ....

  2. ....

  3. ....

/sys/kernel/cgroup 파일

/sys/kernel/cgroup/delegate (리눅스 4.15부터)
....
$ cat /sys/kernel/cgroup/delegate
cgroup.procs
cgroup.subtree_control
cgroup.threads
/sys/kernel/cgroup/features (리눅스 4.15부터)

....

$ cat /sys/kernel/cgroup/features
nsdelegate
memory_localevents

....

memory_localevents (리눅스 5.2부터)
....
nsdelegate (리눅스 4.15부터)
....

SEE ALSO

prlimit(1), systemd(1), systemd-cgls(1), systemd-cgtop(1), clone(2), ioprio_set(2), perf_event_open(2), setrlimit(2), cgroup_namespaces(7), cpuset(7), namespaces(7), sched(7), user_namespaces(7)

커널 소스 파일 Documentation/admin-guide/cgroup-v2.rst.


2021-03-22