web-dev-qa-db-ja.com

systemd、ユーザーごとのCPUおよび/またはメモリの制限

同様の質問があります: Cgroups、ユーザーごとのメモリ制限 ですが、このソリューションはcgroup階層がsystemdによって管理されている「最新の」システムでは機能しません。

簡単な解決策— user-UID.sliceのテンプレート化—機能しません。サポートされていないためです https://github.com/systemd/systemd/issues/2556 を参照してください。

望ましい効果を達成する方法はありますか?ユーザーごとにCPUおよび/またはメモリリソースを管理しますか?

[〜#〜] upd [〜#〜]:履歴のためにソリューションを保持しますが、_systemctl set-property_はログイン時に_pam_exec_を使用して呼び出されます https://github.com/hashbang/Shell-etc/pull/18 を参照してください。このアプローチでは、ユーザーのログインと制限の設定の間に時間枠はありません。

私の解決策インターフェイス_org.freedesktop.login1.Manage_ of _/org/freedesktop/login1_オブジェクトUserNew(u uid, o object_path)シグナルを発行します。シグナルをリッスンする単純なデーモンを作成し、それが発行されるたびに、ログインしたユーザーのスライスに_CPUAccounting=true_を設定しました。

8
intelfx

[〜#〜] upd [〜#〜]:履歴のためにソリューションを保持しますが、systemctl set-propertyはログイン時にpam_execを使用して呼び出されます。 https://github.com/hashbang/Shell-etc/pull/18 を参照してください。このアプローチでは、ユーザーのログインと制限の設定の間に時間枠はありません。

古いソリューション

これは仕事をする非常に単純なスクリプトです

#!/bin/bash

STATE=1 # 1 -- waiting for signal; 2 -- reading UID

dbus-monitor --system "interface=org.freedesktop.login1.Manager,member=UserNew" |
while read line
do
    case $STATE in
    1) [[ $line =~ member=UserNew ]] && STATE=2 ;;
    2) read dbus_type ID <<< $line
       systemctl set-property user-$ID.slice CPUAccounting=true
       STATE=1
    ;;
    esac
done

ユーザーごとのメモリ制限をサポートするように簡単に拡張できます。

VM 2 CPUと2ユーザーでテストしました。最初のユーザーはdd if=/dev/zero of=/dev/null | dd if=/dev/zero of=/dev/nullコマンドを実行し、2番目のユーザーはddのインスタンスを1つだけ実行します。このスクリプトなしでは実行中、ddの各インスタンスはCPUの約70%を使用しました。

次に、スクリプトを開始し、ユーザーを再度ログインさせ、ddコマンドに再びスターを付けました。今回は、最初のユーザーの2つのddプロセスがそれぞれ50%のCPUしか使用せず、2番目のユーザーのプロセスが100%のCPUを使用しました。また、systemd-cgtopは、/user.slice/user-UID1.slice/user.slice/user-UID2.sliceがそれぞれCPU時間の100%を消費することを示しましたが、最初のスライスには6つのタスクがあり、2番目のスライスには5つのタスクしかありません。

2番目のユーザーのddタスクをkillすると、最初のユーザーがCPU時間の200%を消費し始めます。したがって、「各ユーザーが使用できるコアは1つだけ」などの人為的な制限なしに、公平なリソース割り当てが可能です。

4
intelfx

Systemd v239以降では、ドロップインを使用できます https://github.com/systemd/systemd/commit/5396624506e155c4bc10c0ee65b939600860ab67

# mkdir -p /etc/systemd/system/user-.slice.d
# cat > /etc/systemd/system/user-.slice.d/50-memory.conf << EOF
[Slice]
MemoryMax=1G
EOF
# systemctl daemon-reload
3
ValdikSS

あなたが言及した問題はまだオープンですが、これは私にとってはうまくいきます。

Sudo systemctl edit --force user-1234.slice

次に、これを入力して保存します。

[Slice]
CPUQuota=10%

なぜ機能するのかわかりません。

Cgroupsを介してCPUまたはメモリの制限を達成する別の可能性は、libpam-cgroupを使用することです。これにより、ログイン時に/etc/cgconfig.confからプロファイルを選択できます。一般的に見られる例は次のとおりです。

group limited {
   cpu {
     cpu.cfs_period_us = "1000000";
     cpu.cfs_quota_us = "500000";
   }
   memory {
      memory.limit_in_bytes = "1G";
      memory.memsw.limit_in_bytes = "1G";
   }
}

これにより、リソースを1 GBのメモリとCPUコアの50%に制限するinteractiveグループが作成されます(合計CPU時間の1秒あたり500ミリ秒)。次に、/etc/cgrules.confファイルを設定して、特定のグループまたはユーザーをこのグループの下に置くことができます。

root       cpu,memory      /
@nolimits  cpu,memory      /
*          cpu,memory      /limited

この場合、rootnolimitsグループに属する全員がデフォルトの(無制限の)cgroupを取得しますが、他のすべてのユーザーは上記のポリシーセットによって制限されます。

最初に一致する行が使用されるため、次のように特定のユーザーまたはグループを制限しながら、デフォルトの無制限ポリシーを設定できます。

spam       cpu,memory      /limited
*          cpu,memory      /

この場合、spamユーザーを制限し、他のユーザーは制限しません。

これが機能するためには、たとえばpam_cgroup.so PAMプロファイルで/etc/pam.d/sshdを有効にする必要があります。

session    optional     pam_cgroup.so

最後に、cgrules.confファイルを起動時に解析する必要があります。これは、シンプルなsystemdサービスで実現できます。

[Unit]
Description=Load cgroup profiles

[Service]
Type=oneshot
ExecStart=/usr/sbin/cgconfigparser -l /etc/cgconfig.conf

[Install]
WantedBy=multi-user.target

これは、たとえば/etc/systemd/system/loadcg.serviceに保存して、systemctl enable loadcgで有効にすることができます。

0
Ale