cgroups

提供: ArchWiki
ナビゲーションに移動 検索に移動

関連記事

コントロールグループ (一般的には cgroup と知られています) とは、プロセスのグループを管理、制限、監査するための、Linux カーネルによって提供されている機能です。cgroup はプロセスの集合 (およびその部分集合) に対して操作することができる (また、異なるシステムユーザを用いることもできる) ので 、nice(1) コマンドや /etc/security/limits.conf のような他のアプローチと比べて、cgroup はより柔軟です。

コントロールグループは様々なツールによってアクセスできます:

  • systemd ユニットファイルでディレクティブを使ってサービスやスライスに対する制限を指定する。
  • cgroup ファイルシステムに直接アクセスする。
  • cgcreatecgexeccgclassify (libcgroupAURlibcgroup-gitAUR の一部です) のようなツールを使う。
  • "Rules Engine Daemon" を使って、特定のユーザ/グループ/コマンドをグループに自動的に移動する (/etc/cgrules.confcgconfig.service) (libcgroupAURlibcgroup-gitAUR の一部です)。
  • Linux Containers (LXC) 仮想化などのような他のソフトウェアを使う。

Arch Linux の場合は、systemd がデフォルトのインストールの一部なので、cgroup を起動・管理する方法として systemd が最も簡単で推奨されます。

インストール

cgroup を自動的に管理するために、以下のパッケージのうち1つをインストールしていることを確認してください:

  • systemd - systemd サービスのリソースを管理するために必要です。
  • libcgroupAURlibcgroup-gitAUR - スタンドアロンツールのセット (cgcreatecgclassify、永続的な設定は cgconfig.conf)。

systemd を使う

階層

現在の cgroup 階層は systemctl status コマンドか systemd-cgls コマンドを使って見ることができます。

$ systemctl status
● myarchlinux
    State: running
     Jobs: 0 queued
   Failed: 0 units
    Since: Wed 2019-12-04 22:16:28 UTC; 1 day 4h ago
   CGroup: /
           ├─user.slice 
           │ └─user-1000.slice 
           │   ├─user@1000.service 
           │   │ ├─gnome-shell-wayland.service 
           │   │ │ ├─ 1129 /usr/bin/gnome-shell
           │   │ ├─gnome-terminal-server.service 
           │   │ │ ├─33519 /usr/lib/gnome-terminal-server
           │   │ │ ├─37298 fish
           │   │ │ └─39239 systemctl status
           │   │ ├─init.scope 
           │   │ │ ├─1066 /usr/lib/systemd/systemd --user
           │   │ │ └─1067 (sd-pam)
           │   └─session-2.scope 
           │     ├─1053 gdm-session-worker [pam/gdm-password]
           │     ├─1078 /usr/bin/gnome-keyring-daemon --daemonize --login
           │     ├─1082 /usr/lib/gdm-wayland-session /usr/bin/gnome-session
           │     ├─1086 /usr/lib/gnome-session-binary
           │     └─3514 /usr/bin/ssh-agent -D -a /run/user/1000/keyring/.ssh
           ├─init.scope 
           │ └─1 /sbin/init
           └─system.slice 
             ├─systemd-udevd.service 
             │ └─285 /usr/lib/systemd/systemd-udevd
             ├─systemd-journald.service 
             │ └─272 /usr/lib/systemd/systemd-journald
             ├─NetworkManager.service 
             │ └─656 /usr/bin/NetworkManager --no-daemon
             ├─gdm.service 
             │ └─668 /usr/bin/gdm
             └─systemd-logind.service 
               └─654 /usr/lib/systemd/systemd-logind

プロセスの cgroup を見つける

あるプロセスの cgroup 名は、/proc/PID/cgroup で見ることができます。

例えば、現在のシェルの cgroup は:

$ cat /proc/self/cgroup
0::/user.slice/user-1000.slice/session-3.scope

cgroup のリソース使用量

systemd-cgtop コマンドを使用して、cgroup のリソース使用量を見ることができます:

$ systemd-cgtop
Control Group                            Tasks   %CPU   Memory  Input/s Output/s
user.slice                                 540  152,8     3.3G        -        -
user.slice/user-1000.slice                 540  152,8     3.3G        -        -
user.slice/u…000.slice/session-1.scope     425  149,5     3.1G        -        -
system.slice                                37      -   215.6M        -        -

カスタムの cgroup

systemd.slice(5) systemd ユニットファイルを使うことで、カスタムの cgroup 設定を定義できます。このユニットファイルは、systemd のディレクトリ内 (/etc/systemd/system/ など) に配置しなければなりません。リソースの割り当て可能な管理オプションは、systemd.resource-control(5) にてドキュメント化されています。

以下は、1つの CPU の 30% のみの使用を許可する slice ユニットの例です:

/etc/systemd/system/my.slice
[Slice]
CPUQuota=30%

サービスとして

サービスユニットファイル

リソースは、サービスの定義で、あるいはドロップインファイル として指定可能です:

[Service]
MemoryMax=1G 

この例では、サービスのメモリ使用量を 1 GB に制限します。

スライスでユニットをグループ化

サービスは、どのスライス内で実行するかを指定できます:

[Service]
Slice=my.slice

root として

systemd-run を使うことで、指定されたスライス内でコマンドを実行することができます。

# systemd-run --slice=my.slice command

--uid=username オプションを使うことで、指定されたユーザとしてコマンドをスポーンできます。

# systemd-run --uid=username --slice=my.slice command

--shell オプションを使うことで、スライスの中でコマンドシェルをスポーンできます。

非特権ユーザとして

非特権ユーザは、いくつかの条件を満たせば、そのユーザに与えられたリソースを新しい cgroup に配分することができます。

非 root ユーザが cgroup リソースを管理できるようにするには、cgroup v2 を使用しなければなりません。

コントローラのタイプ

すべてのリソースがユーザによって制御できるわけではありません。

コントローラ ユーザによって制御可能か オプション
cpu 委譲する必要あり CPUAccounting, CPUWeight, CPUQuota, AllowedCPUs, AllowedMemoryNodes
io 委譲する必要あり IOWeight, IOReadBandwidthMax, IOWriteBandwidthMax, IODeviceLatencyTargetSec
memory Yes MemoryLow, MemoryHigh, MemoryMax, MemorySwapMax
pids Yes TasksMax
rdma No ?
eBPF No IPAddressDeny, DeviceAllow, DevicePolicy
ノート: 技術的には eBPF はコントローラではありませんが、上記の systemd オプションは eBPF を使って実装されており、root のみがそれらのオプションの設定を許可されています。

ユーザ委譲

ユーザが cpu や io リソースを制御するには、リソースを委譲する必要があります。これはドロップインファイルを使うことで可能です。

例えば、あなたのユーザ ID が 1000 の場合:

/etc/systemd/system/user@1000.service.d/delegate.conf
[Service]
Delegate=cpu cpuset io

再起動し、あなたのセッションのスライスが cpu と io コントローラを所有していることを確認してください:

$ cat /sys/fs/cgroup/user.slice/user-1000.slice/cgroup.controllers
cpuset cpu io memory pids

ユーザ定義のスライス

ユーザのスライスファイルは ~/.config/systemd/user/ に配置できます。

特定のスライス下でコマンドを実行するには:

$ systemd-run --user --slice=my.slice command

また、ログインシェルをスライス内で実行することも可能です:

$ systemd-run --user --slice=my.slice --shell

実行時の調整

cgroup のリソースは、systemctl set-property コマンドを使うことで実行時に調整可能です。オプションについては systemd.resource-control(5) と同じです。

警告: --runtime オプションを渡さなかった場合、加えた調整は 永続化 されます。加えた調整は、システム全体のオプションは /etc/systemd/system.control/ に保存され、ユーザのオプションは .config/systemd/user.control/ に保存されますs。
ノート: すべてのリソースの変更が即座に反映されるわけではありません。例えば、TaskMax を変更した場合、新しいプロセスを作成したときに変更が適用されます。

例えば、すべてのユーザセッションに対してインターネットアクセスを切断するには:

$ systemctl set-property user.slice IPAddressDeny=any

libcgroup を使う

systemd を使って cgconfig有効化できます。これにより、cgconfig.conf 内のエラーをより簡単に追跡できます。

一時的なグループ

「一時的な」なグループをその場で作成できます。一般ユーザにカスタムのグループを作成する権限を与えることもできます。以下の groupname は cgroup 名です:

# cgcreate -a user -t user -g memory,cpu:groupname

これで、groupname グループで調整可能なものはすべて、あなたのユーザによって書き込み可能です:

$ ls -l /sys/fs/cgroup/memory/groupname
total 0
-rwxrwxr-x 1 user root 0 Sep 25 00:39 cgroup.event_control
-rwxrwxr-x 1 user root 0 Sep 25 00:39 cgroup.procs
-rwxrwxr-x 1 user root 0 Sep 25 00:39 cpu.rt_period_us
-rwxrwxr-x 1 user root 0 Sep 25 00:39 cpu.rt_runtime_us
-rwxrwxr-x 1 user root 0 Sep 25 00:39 cpu.shares
-rwxrwxr-x 1 user root 0 Sep 25 00:39 notify_on_release
-rwxrwxr-x 1 user root 0 Sep 25 00:39 tasks

cgroup は階層的なので、好きなだけサブグループを作成できます。通常のユーザが bash シェルを新しいサブグループ foo 下で実行したい場合:

$ cgcreate -g memory,cpu:groupname/foo
$ cgexec    -g memory,cpu:groupname/foo bash

確認するには (レガシーな (v1) cgroup でのみ意味があります):

$ cat /proc/self/cgroup
11:memory:/groupname/foo
6:cpu:/groupname/foo

新しいサブディレクトリがこのグループ用に作成されました。このグループ内のすべてのプロセスのメモリ使用量を 10 MBに制限するには、以下を実行してください:

$ echo 10000000 > /sys/fs/cgroup/memory/groupname/foo/memory.limit_in_bytes

メモリ制限は RAM の使用に対してのみ適用されることに注意してください。一度タスクがこの制限に到達すると、タスクはスワップし始めます。しかし、他のプロセスのパフォーマンスに大きな影響を及ぼすことはありません。

同じように、このグループの CPU の優先度 ("shares") も変更できます。デフォルトでは、すべてのグループは 1024 shares となっています。100 shares のグループは CPU 時間の約 10 % を獲得します:

$ echo 100 > /sys/fs/cgroup/cpu/groupname/foo/cpu.shares

cgroup のディレクトリを一覧表示することで、より多くのパラメータや統計を見ることができます。

また、すでに実行中のプロセスの cgroup を変更することもできます。すべての 'bash' コマンドをこのグループに移動するには:

$ pidof bash
13244 13266
$ cgclassify -g memory,cpu:groupname/foo `pidof bash`
$ cat /proc/13244/cgroup
11:memory:/groupname/foo
6:cpu:/groupname/foo

グループの設定を永続化する

ノート: systemd ≥ 205 を使って cgroups を管理する場合、このファイルは完全に無視することができます。

起動時に cgroup が作成されるようにしたい場合、代わりに /etc/cgconfig.conf でグループを定義することができます。例えば、"groupname" に制限を管理しタスクを追加する $USER のパーミッションとグループ $GROUPusers を定義します。サブグループの "groupname/foo" グループの定義は以下のようになります:

/etc/cgconfig.conf 
group groupname {
  perm {
# who can manage limits
    admin {
      uid = $USER;
      gid = $GROUP;
    }
# who can add tasks to this group
    task {
      uid = $USER;
      gid = $GROUP;
    }
  }
# create this group in cpu and memory controllers
  cpu { }
  memory { }
}

group groupname/foo {
  cpu {
    cpu.shares = 100;
  }
  memory {
    memory.limit_in_bytes = 10000000;
  }
}
ノート:
  • コメントは行の先頭から始めてください! コメントを表す # 文字は行の始めの文字として現れなければなりません。そうしないと、cgconfigparser が解析するときに問題が発生しますが、cgconfigSystemd で起動しない限り、エラーとしては cgroup change of group failed しか報告されません。
  • permissions セクションは任意です。
  • /sys/fs/cgroup/ ディレクトリ階層には controllers サブディレクトリが全て含まれ、起動時に仮想ファイルシステムとして作成・マウントされます。$CONTROLLER-NAME { } コマンドを使って新しいグループエントリを作成することが可能です。何らかの理由で他の場所に階層を作成・マウントしたいときは、/etc/cgconfig.conf に以下のようにふたつ目のエントリを書く必要があります:
 mount {    
   cpuset = /your/path/groupname;
 }

これは以下のシェルコマンドと同等です:

 # mkdir /your/path/groupname
 # mount -t /your/path -o cpuset groupname /your/path/groupname

cgroup の仮想ファイルシステムを使う

systemd 232 以降では、次のセクションで説明する cgm メソッドについて説明しますが、このセクションでは代わりにメモリ使用量を制限する手動のメソッドについて説明します。

新しい cgroup を作成してください (ここでは名前は groupname とします):

# mkdir /sys/fs/cgroup/memory/groupname

例: 最大のメモリ制限を 100MB に設定するには:

# echo 100000000 > /sys/fs/cgroup/memory/groupname/memory.limit_in_bytes

プロセスを cgroup に移動してください (注: 1度に1つの PID のみを書き込むことができます。移動させたいプロセスそれぞれに対してこれを繰り返してください):

# echo pid > /sys/fs/cgroup/memory/groupname/cgroup.procs
ノート: この最後のコマンドでは、一度に 1 つの PID のみを書き込むことができるため、移動する必要があるプロセスごとにこれを繰り返します。

コマンドのメモリ使用を制限する

次の例は、特定のコマンドを 2 GB のメモリに制限する cgroup を示しています。

$ systemd-run --scope -p MemoryMax=2G --user command

Matlab

MATLAB にはマシンのメモリや CPU を食い尽くす事態に対する保護が存在しないため、高負荷な計算を行うとシステムがクラッシュする危険があります。以下の例は、始めの CPU コア 6 つとメモリ 5 GB に制限する cgroup です。

systemd で

~/.config/systemd/user/matlab.slice
[Slice]
AllowedCPUs=0-5
MemoryHigh=6G

Matlab を以下のように実行してください (正しいパスを使ってください):

$ systemd-run --user --slice=matlab.slice /opt/MATLAB/2012b/bin/matlab -desktop

libcgroup で

/etc/cgconfig.conf
group matlab {
    perm {
        admin {
            uid = username;
        }
        task {
            uid = username;
        }
    }

    cpuset {
        cpuset.mems="0";
        cpuset.cpus="0-5";
    }
    memory {
        memory.limit_in_bytes = 5000000000;
    }
}

username を変更することで、そのユーザとして Matlab を実行できます。

また、cpu 制限によって CPU share を制限することもできます。

以下のように Matlab を実行してください (正しいパスを使ってください):

$ cgexec -g memory,cpuset:matlab /opt/MATLAB/2012b/bin/matlab -desktop

ドキュメント

  • コントローラーや特定のスイッチ・オプションに関する情報はカーネルのドキュメント (v1v2) を参照してください (または linux-docs をインストールして /usr/src/linux/Documentation/cgroup を見て下さい)。
  • 詳細かつ完全なリソース管理ガイドが fedora プロジェクトのドキュメント にあります。

コマンドや設定ファイルについては、man cgcreateman cgrules.conf などの該当する man ページを見て下さい。

ヒントとテクニック

cgroup v1 を有効化する

現在、cgroup v2 がデフォルトで有効化されています。cgroup v1 に切り替えたいなら、次のカーネルパラメータを設定する必要があります:

systemd.unified_cgroup_hierarchy=0

参照

翻訳ステータス: このページは en:cgroups の翻訳バージョンです。最後の翻訳日は 2022-09-22 です。もし英語版に 変更 があれば、翻訳の同期を手伝うことができます。