systemdを使用したcgroups v2の管理

cgroups v2を使用してリソース割当てを管理するための優先される方法は、systemdによって提供される制御グループ機能を使用することです。

ノート:

システムでcgroups v2機能を有効にする方法の詳細は、『Oracle Linux 8: カーネルおよびシステム・ブートの管理』を参照してください

デフォルトでは、systemdは、ホストに設定されたsystemdサービスごとにcgroupフォルダを作成します。systemdは、servicename.serviceという形式を使用してこれらのフォルダに名前を付けます。servicenameは、フォルダに関連付けられたサービスの名前です。

systemdがサービスに対して作成するcgroupフォルダのリストを表示するには、次のサンプル・コード・ブロックに示すように、cgroupファイル・システムのsystem.sliceブランチでlsコマンドを実行します:

ls /sys/fs/cgroup/system.slice/
...                     ...                           ...
app_service1.service    cgroup.subtree_control        httpd.service
app_service2.service    chronyd.service               ...  
...                     crond.service                 ...
cgroup.controllers      dbus-broker.service           ...
cgroup.events           dtprobed.service              ...
cgroup.freeze           firewalld.service             ...
...                     gssproxy.service              ...
...                     ...                           ...
前述のコマンド・ブロックの内容は次のとおりです:
  • フォルダapp_service1.serviceおよびapp_service2.serviceは、システム上に存在する可能性のあるカスタム・アプリケーション・サービスを表します。

systemdでは、サービス制御グループに加えて、ホスト上のユーザーごとにcgroupフォルダも作成されます。各ユーザーに対して作成されたcgroupを確認するには、次のサンプル・コード・ブロックに示すように、cgroupファイル・システムのuser.sliceブランチでlsコマンドを実行します:

ls /sys/fs/cgroup/user.slice/
cgroup.controllers      cgroup.subtree_control        user-1001.slice
cgroup.events           cgroup.threads                user-982.slice
cgroup.freeze           cgroup.type                   ...
...                     ...                           ...
...                     ...                           ...
...                     ...                           ...

前述のコード・ブロックの内容は次のとおりです:

  • 各ユーザーのcgroupフォルダには、user-UID.sliceという形式を使用して名前が付けられます。したがって、制御グループuser-1001.sliceは、たとえばUIDが1001のユーザー用です。

systemdは、cgroupおよびカーネル・リソース・コントローラ機能への高レベルのアクセスを提供するため、ファイル・システムに直接アクセスする必要はありません。たとえば、app_service1.serviceというサービスのCPUの重みを設定するには、次のようにsystemctl set-propertyコマンドを実行します:

sudo systemctl set-property app_service1.service CPUWeight=150

したがって、systemdを使用すると、systemd機能を使用せずにcgroupを構成するときに使用されるプロセスのPIDレベルではなく、アプリケーション・レベルでリソース配分を管理できます。

systemdでのスライスとリソース割当てについて

この項では、次の円グラフの例に示すように、systemdがデフォルトの各カーネル・コントローラ(たとえば、CPUmemoryおよびblkio)をスライスと呼ばれる部分に分割する方法を確認します:

ノート:

「リソース・コントローラ・オプションの設定およびカスタム・スライスの作成」の項に示すように、リソース配分用に独自のカスタム・スライスを作成することもできます。

図7-1 CPUやメモリーなどのリソース・コントローラの配分を示す円グラフ


等しいサイズの3つのスライスを含む、System、MachineおよびUserのラベルが付いた円グラフ。UserとSystemはさらにサブスライスに分割されます。

前述の円グラフが示すように、デフォルトでは、各リソース・コントローラは次の3つのスライス間で均等に分割されます:

  • System (system.slice)。

  • User (user.slice)。

  • Machine (machine.slice)。

次のリストは、各スライスをさらに詳しく示します。説明のために、リストの例ではCPUコントローラに焦点を当てています。

System (system.slice)

このリソース・スライスは、デーモンおよびサービス・ユニット間のリソース割当てを管理するために使用されます。

前述の円グラフの例に示すように、システム・スライスはさらにサブスライスに分割されます。たとえば、CPUリソースの場合、次のようにサブスライスの割当てがシステム・スライス内に存在する可能性があります:
  • httpd.service (CPUWeight=100)

  • sshd.service (CPUWeight =100)

  • crond.service (CPUWeight =100)

  • app1.service (CPUWeight =100)

  • app2.service (CPUWeight =100)

前述のリストで、app1.serviceおよびapp2.serviceは、システムで実行している可能性のあるカスタム・アプリケーション・サービスを表します。
User (user.slice)
このリソース・スライスは、ユーザー・セッション間のリソース割当てを管理するために使用されます。関連付けられたユーザーがサーバーでアクティブになっているログインの数に関係なく、UIDごとに1つのスライスが作成されます。円グラフの例に続いて、サブスライスは次のようになります:
  • user1 (CPUWeight=100, UID=982)

  • user2 (CPUWeight=100, UID=1001)

Machine (machine.slice)
このリソース・スライスは、KVMゲストやLinuxコンテナなどのホストされた仮想マシン間のリソース割当ての管理に使用されます。マシン・スライスは、サーバーが仮想マシンまたはLinuxコンテナをホストしている場合にのみサーバーに存在します。

ノート:

共有割当てでは、リソースの最大制限は設定されません。

たとえば、前述の例では、スライスuser.sliceには、user1およびuser2の2人のユーザーがあります。各ユーザーには、親user.sliceで使用可能なCPUリソースの等しい共有が割り当てられます。ただし、user1に関連付けられたプロセスがアイドル状態であり、CPUリソースを必要としない場合、そのCPU共有は必要に応じてuser2への割当てに使用できます。このような状況では、他のユーザーが必要とする場合、親user.sliceに割り当てられているCPUリソース全体がuser2に割り当てられることもあります。

CPUリソースを制限するには、CPUQuotaプロパティを必要な割合に設定する必要があります。

cgroup階層内のスライス、サービスおよびスコープ

前述の項で使用されている円グラフから類推すると、リソースの区分をスライスに概念化できます。ただし、構造的な組織では、制御グループは階層に配置されます。systemd-cglsコマンドを次のように実行すると、システム上のsystemd制御グループ階層を表示できます:

ヒント:

次の例のように、ルート・スライス-.sliceから始まるcgroup階層全体を表示するには、制御グループ・マウント・ポイント/sys/fs/cgroup/の外部からsystemd-cglsを実行してください。それ以外の場合、/sys/fs/cgroup/内からコマンドを実行すると、コマンドの実行元のcgroupの場所から出力が開始されます。詳細は、systemd-cgls(1)を参照してください。

systemd-cgls
Control group /:
-.slice
...
├─user.slice (#1429)
│ → user.invocation_id: 604cf5ef07fa4bb4bb86993bb5ec15e0
│ ├─user-982.slice (#4131)
│ │ → user.invocation_id: 9d0d94d7b8a54bcea2498048911136c8
│ │ ├─session-c1.scope (#4437)
│ │ │ ├─2416 /usr/bin/sudo -u ocarun /usr/libexec/oracle-cloud-agent/plugins/runcommand/runcommand
│ │ │ └─2494 /usr/libexec/oracle-cloud-agent/plugins/runcommand/runcommand
│ │ └─user@982.service … (#4199)
│ │   → user.delegate: 1
│ │   → user.invocation_id: 37c7aed7aa6e4874980b79616acf0c82
│ │   └─init.scope (#4233)
│ │     ├─2437 /usr/lib/systemd/systemd --user
│ │     └─2445 (sd-pam)
│ └─user-1001.slice (#7225)
│   → user.invocation_id: ce93ad5f5299407e9477964494df63b7
│   ├─session-2.scope (#7463)
│   │ ├─20304 sshd: oracle [priv]
│   │ ├─20404 sshd: oracle@pts/0
│   │ ├─20405 -bash
│   │ ├─20441 systemd-cgls
│   │ └─20442 less
│   └─user@1001.service … (#7293)
│     → user.delegate: 1
│     → user.invocation_id: 70284db060c1476db5f3633e5fda7fba
│     └─init.scope (#7327)
│       ├─20395 /usr/lib/systemd/systemd --user
│       └─20397 (sd-pam)
├─init.scope (#19)
│ └─1 /usr/lib/systemd/systemd --switched-root --system --deserialize 28
└─system.slice (#53)
 ...
  ├─dbus-broker.service (#2737)
  │ → user.invocation_id: 2bbe054a2c4d49809b16cb9c6552d5a6
  │ ├─1450 /usr/bin/dbus-broker-launch --scope system --audit
  │ └─1457 dbus-broker --log 4 --controller 9 --machine-id 852951209c274cfea35a953ad2964622 --max-bytes 536870912 --max-fds 4096 --max-matches 131072 --audit
 ...
  ├─chronyd.service (#2805)
  │ → user.invocation_id: e264f67ad6114ad5afbe7929142faa4b
  │ └─1482 /usr/sbin/chronyd -F 2
  ├─auditd.service (#2601)
  │ → user.invocation_id: f7a8286921734949b73849b4642e3277
  │ ├─1421 /sbin/auditd
  │ └─1423 /usr/sbin/sedispatch
  ├─tuned.service (#3349)
  │ → user.invocation_id: fec7f73678754ed687e3910017886c5e
  │ └─1564 /usr/bin/python3 -Es /usr/sbin/tuned -l -P
  ├─systemd-journald.service (#1837)
  │ → user.invocation_id: bf7fb22ba12f44afab3054aab661aedb
  │ └─1068 /usr/lib/systemd/systemd-journald
  ├─atd.service (#3961)
  │ → user.invocation_id: 1c59679265ab492482bfdc9c02f5eec5
  │ └─2146 /usr/sbin/atd -f
  ├─sshd.service (#3757)
  │ → user.invocation_id: 57e195491341431298db233e998fb180
  │ └─2097 sshd: /usr/sbin/sshd -D [listener] 0 of 10-100 startups
  ├─crond.service (#3995)
  │ → user.invocation_id: 4f5b380a53db4de5adcf23f35d638ff5
  │ └─2150 /usr/sbin/crond -n
  ...

前述のサンプル出力は、すべての*.slice制御グループがルート・スライス-.sliceの下にどのように存在しているかを示しています。ルート・スライスの下には、 user.sliceおよびsystem.slice制御グループがあり、それぞれに子cgroupサブスライスがあります。

systemd-cgls コマンドの出力を確認すると、ルート-.sliceを除いて、すべてのプロセスがリーフ・ノード上にあることがわかります。この配置は、cgroups v2によって"内部プロセスなし"ルールと呼ばれるルールで強制されます。"内部プロセスなし"ルールの詳細は、cgroups (7)を参照してください。

前述のsystemd-cgls コマンド例の出力では、スライスにsystemdスコープの子制御グループを含める方法も示しています。systemdスコープについては、次の項で説明します。

systemdスコープ

systemdスコープは、systemdとは無関係に起動されたシステム・サービス・ワーカー・プロセスをグループ化するsystemdユニット・タイプです。スコープ・ユニットは、systemdのバス・インタフェースを使用してプログラムで作成される一時cgroupです。

たとえば、次のサンプル・コードでは、UID 1001のユーザーがsystemd-cglsコマンドを実行しており、出力には、systemdとは関係なくユーザーが生成したプロセス(コマンド自体のプロセス21380 sudo systemd-cglsを含む)に対してsession-2.scopeが作成されていることが示されています:

ノート:

次の例では、制御グループのマウント・ポイント/sys/fs/cgroup/内からコマンドが実行されています。したがって、ルート・スライスのかわりに、コマンドの実行元のcgroupの場所から出力が開始されます。
sudo systemd-cgls
Working directory /sys/fs/cgroup:
...
├─user.slice (#1429)
│ → user.invocation_id: 604cf5ef07fa4bb4bb86993bb5ec15e0
│ → trusted.invocation_id: 604cf5ef07fa4bb4bb86993bb5ec15e0
...
│ └─user-1001.slice (#7225)
│   → user.invocation_id: ce93ad5f5299407e9477964494df63b7
│   → trusted.invocation_id: ce93ad5f5299407e9477964494df63b7
│   ├─session-2.scope (#7463)
│   │ ├─20304 sshd: oracle [priv]
│   │ ├─20404 sshd: oracle@pts/0
│   │ ├─20405 -bash
│   │ ├─21380 sudo systemd-cgls
│   │ ├─21382 systemd-cgls
│   │ └─21383 less
│   └─user@1001.service … (#7293)
│     → user.delegate: 1
│     → trusted.delegate: 1
│     → user.invocation_id: 70284db060c1476db5f3633e5fda7fba
│     → trusted.invocation_id: 70284db060c1476db5f3633e5fda7fba
│     └─init.scope (#7327)
│       ├─20395 /usr/lib/systemd/systemd --user
│       └─20397 (sd-pam)

リソース・コントローラ・オプションの設定およびカスタム・スライスの作成

systemdには、システムでのリソース割当てをカスタマイズするために、CPUWeightCPUQuotaなどのリソース・コントローラ・オプションを設定するための次の方法が用意されています:

  • サービス・ユニット・ファイルの使用。

  • ドロップイン・ファイルの使用。

  • systemctl set-propertyコマンドの使用。

次の項では、これらの各方法を使用してシステム内のリソースとスライスを構成する手順の例を示します。

サービス・ユニット・ファイルの使用

サービス・ユニット・ファイルでオプションを設定するには、次のステップを実行します:

  1. 次の内容でファイル/etc/systemd/system/myservice1.serviceを作成します:
    [Service]
    Type=oneshot
    ExecStart=/usr/lib/systemd/generate_load.sh
    TimeoutSec=0
    StandardOutput=tty
    RemainAfterExit=yes
    
    [Install]
    WantedBy=multi-user.target
  2. 前述のステップで作成したサービスには、bashスクリプト/usr/lib/systemd/generate_load.shが必要です。次の内容でファイルを作成します:
    #!/bin/bash
    for i in {1..4};do while : ; do : ; done & done
  3. スクリプトを実行可能にします:
    sudo chmod +x /usr/lib/systemd/generate_load.sh
  4. サービスを有効化して起動します:
    sudo systemctl enable myservice1 --now
  5. systemd-cglsコマンドを実行し、サービスmyservice1system.sliceで実行されていることを確認します:
    systemd-cgls
    Control group /:
    -.slice
    ...
    ├─user.slice (#1429)
    ...
    └─system.slice (#53)
      ...
      ├─myservice1.service (#7939)
      │ → user.invocation_id: e227f8f288444fed92a976d391e6a897
      │ ├─22325 /bin/bash /usr/lib/systemd/generate_load.sh
      │ ├─22326 /bin/bash /usr/lib/systemd/generate_load.sh
      │ ├─22327 /bin/bash /usr/lib/systemd/generate_load.sh
      │ └─22328 /bin/bash /usr/lib/systemd/generate_load.sh
      ├─pmie.service (#4369)
      │ → user.invocation_id: 68fcd40071594481936edf0f1d7a8e12
       ...
  6. サービスのカスタム・スライスを作成します。

    次のコード・ブロックに示すように、前述のステップで作成したmyservice1.serviceファイルの[Service]セクションにSlice=my_custom_slice.slice行を追加します:

    [Service]
    Slice=my_custom_slice.slice
    Type=oneshot
    ExecStart=/usr/lib/systemd/generate_load.sh
    TimeoutSec=0
    StandardOutput=tty
    RemainAfterExit=yes
    
    [Install]
    WantedBy=multi-user.target
    

    注意:

    スライス名で用語を区切るには、ダッシュのかわりにアンダースコアを使用します。

    systemdでは、スライス名のダッシュは特殊文字です。systemdでは、スライス名のダッシュを使用して、スライスへの完全なcgroupパス(ルート・スライスから開始)を記述します。たとえば、スライス名をmy-custom-slice.sliceとして指定すると、その名前のスライスを作成するかわりに、systemdによってルート・スライスの下にcgroupパスmy.slice/my-custom.slice/my-custom-slice.sliceが作成されます。

  7. ファイルを編集すると、systemdがその構成ファイルをリロードし、サービスを再起動します:
    sudo systemctl daemon-reload
    sudo systemctl restart myservice1
  8. systemd-cglsコマンドを実行し、サービスmyservice1がカスタム・スライスmy_custom_sliceで実行されていることを確認します:
    systemd-cgls
    Control group /:
    -.slice
    ...
    ├─user.slice (#1429)
    ...
    ├─my_custom_slice.slice (#7973)
    │ → user.invocation_id: a8a493a8db1342be85e2cdf1e80255f8
    │ └─myservice1.service (#8007)
    │   → user.invocation_id: 9a4a6171f2844e479d4a0f347aac38ce
    │   ├─22385 /bin/bash /usr/lib/systemd/generate_load.sh
    │   ├─22386 /bin/bash /usr/lib/systemd/generate_load.sh
    │   ├─22387 /bin/bash /usr/lib/systemd/generate_load.sh
    │   └─22388 /bin/bash /usr/lib/systemd/generate_load.sh
    ├─init.scope (#19)
    │ └─1 /usr/lib/systemd/systemd --switched-root --system --deserialize 28
    └─system.slice (#53)
      ├─irqbalance.service (#2907)
      │ → user.invocation_id: 00d64c9b9d224f179496a83536dd60bb
      │ └─1464 /usr/sbin/irqbalance --foreground
     ...
    

ドロップイン・ファイルの使用

ドロップイン・ファイルを使用してリソースを構成するには、次のステップを実行します:

  1. サービス・ドロップイン・ファイルのディレクトリを作成します。

    ヒント:

    サービスのドロップイン・ファイルのドロップイン・ディレクトリは、/etc/systemd/system/service_name.service.dにあります。service_nameは、サービスの名前です。

    サービスmyservice1を使用してこの例を続けると、次のコマンドが実行されます:

    sudo mkdir -p /etc/systemd/system/myservice1.service.d/
    
  2. 前述のステップで作成したmyservice1.service.dディレクトリに、00-slice.confおよび10-CPUSettings.confという2つのドロップイン・ファイルを作成します。

    ノート:

    • 名前が異なる複数のドロップイン・ファイルは、辞書式順序で適用されます。

    • これらのドロップイン・ファイルは、サービス・ユニット・ファイルよりも優先されます。

  3. 次の内容を00-slice.confに追加します
    [Service]
    Slice=my_custom_slice2.slice
    MemoryAccounting=yes
    CPUAccounting=yes
    
  4. 次の内容を10-CPUSettings.confに追加します
    [Service]
    CPUWeight=200
    
  5. 2つ目のサービス(myservice2)を作成し、myservice1に割り当てられた別のCPUWeightをこれに割り当てます:
    1. 次の内容でファイル/etc/systemd/system/myservice2.serviceを作成します:
      [Service]
      Slice=my_custom_slice2.slice
      Type=oneshot
      ExecStart=/usr/lib/systemd/generate_load2.sh
      TimeoutSec=0
      StandardOutput=tty
      RemainAfterExit=yes
      
      [Install]
      WantedBy=multi-user.target
    2. 前述のステップで作成したサービスには、bashスクリプト/usr/lib/systemd/generate_load2.shが必要です。次の内容でファイルを作成します:
      #!/bin/bash
      for i in {1..4};do while : ; do : ; done & done
    3. スクリプトを実行可能にします:
      sudo chmod +x /usr/lib/systemd/generate_load2.sh
    4. 次の内容で、myservice2のドロップイン・ファイル/etc/systemd/system/myservice2.service.d/10-CPUSettings.confを作成します:
      [Service]
      CPUWeight=400
      
  6. systemdが構成ファイルをリロードし、myservice1を再起動し、myservices2を有効にして起動します:
    sudo systemctl daemon-reload
    sudo systemctl restart myservice1
    sudo systemctl enable myservice2 --now
  7. systemd-cgtopコマンドを実行して、リソース使用量順に並べられた制御グループを表示します。次のサンプル出力から、各スライスのリソース使用量に加えて、systemd-cgtopコマンドで各スライス内のリソース使用量の内訳が表示されるため、これを使用して、CPUの重みが予想どおりに分割されていることを確認できます。
    systemd-cgtop
    Control Group                                     Tasks   %CPU   Memory  Input/s Output/s
    /                                                   228  198.8   712.5M        -        -
    my_custom_slice2.slice                                8  198.5     1.8M        -        -
    my_custom_slice2.slice/myservice2.service             4  132.8   944.0K        -        -
    my_custom_slice2.slice/myservice1.service             4   65.6   976.0K        -        -
    user.slice                                           18    0.9    43.9M        -        -
    user.slice/user-1001.slice                            6    0.9    13.7M        -        -
    user.slice/user-1001.slice/session-2.scope            4    0.9     9.4M        -        -
    system.slice                                         60    0.0   690.8M        -        -
    

systemctl set-propertyの使用

systemctl set-propertyコマンドは、構成ファイルを次の場所に配置します:

/etc/systemd/system.control

注意:

systemctl set-propertyコマンドで作成されるファイルを手動で編集しないでください。

ノート:

systemctl set-propertyコマンドでは、このトピックで前述したシステム・ユニット・ファイルおよびドロップイン・ファイルで使用されるすべてのリソース制御プロパティが認識されるわけではありません。

次の手順では、systemctl set-propertyコマンドを使用してリソース割当てを構成する方法を示します:

  1. この例を続けて次の内容を使用し、/etc/systemd/system/myservice3.serviceの場所に別のサービス・ファイルを作成します:
    [Service]
    Type=oneshot
    ExecStart=/usr/lib/systemd/generate_load3.sh
    TimeoutSec=0
    StandardOutput=tty
    RemainAfterExit=yes
    [Install]
    WantedBy=multi-user.target
  2. myservice3.serviceファイルの[Service]セクションに次の行を追加して、サービスのスライスをmy_custom_slice2 (前述のステップで作成したサービスによって使用されたものと同じスライス)に設定します:
    Slice=my_custom_slice2.slice

    ノート:

    systemctl set-propertyコマンドでSliceプロパティが認識されないため、スライスはサービス・ユニット・ファイルで設定する必要があります。

  3. 前述のステップで作成したサービスには、bashスクリプト/usr/lib/systemd/generate_load3.shが必要です。次の内容でファイルを作成します:
    #!/bin/bash
    for i in {1..4};do while : ; do : ; done & done
  4. スクリプトを実行可能にします:
    sudo chmod +x /usr/lib/systemd/generate_load3.sh
  5. systemdが構成ファイルをリロードしてから、サービスを有効化して起動します:
    sudo systemctl daemon-reload
    sudo systemctl enable myservice3 --now
  6. systemd-cgtopを実行して、3つのサービスmyservice1myservice2およびmyservice3がすべて同じスライスで実行されていることを確認します。
  7. systemctl set-propertyコマンドを使用して、myservice3CPUWeightを800に設定します:
    sudo systemctl set-property myservice3.service CPUWeight=800
  8. /etc/systemd/system.control/myservice3.service.dの下にドロップイン・ファイルが作成されていることを確認します。ただし、ファイルを編集することはできません:
    cat /etc/systemd/system.control/myservice3.service.d/50-CPUWeight.conf
    # This is a drop-in unit file extension, created via "systemctl set-property"
    # or an equivalent operation. Do not edit.
    [Service]
    CPUWeight=800
    
  9. systemdが構成ファイルをリロードし、すべてのサービスを再起動します:
    sudo systemctl daemon-reload
    sudo systemctl restart myservice1
    sudo systemctl restart myservice2
    sudo systemctl restart myservice3
  10. systemd-cgtopコマンドを実行して、CPUの重みが予想どおりに分割されていることを確認します:
    systemd-cgtop
    Control Group                                         Tasks   %CPU   Memory  Input/s Output/s
    /                                                       235  200.0   706.1M        -        -
    my_custom_slice2.slice                                   12  198.4     2.9M        -        -
    my_custom_slice2.slice/myservice3.service                 4  112.7   976.0K        -        -
    my_custom_slice2.slice/myservice2.service                 4   56.9   996.0K        -        -
    my_custom_slice2.slice/myservice1.service                 4   28.8   988.0K        -        -
    user.slice                                               18    0.9    44.1M        -        -
    user.slice/user-1001.slice                                6    0.9    13.9M        -        -
    user.slice/user-1001.slice/session-2.scope                4    0.9     9.5M        -        -