APC 技術ブログ

株式会社エーピーコミュニケーションズの技術ブログです。

株式会社 エーピーコミュニケーションズの技術ブログです。

【Linux】systemd/cgroupを利用してサービスのリソース制限を試してみる

はじめに

こんにちは。クラウド事業部の佐藤です。

利用可能なリソースが限られているマシン、特にクラウド環境ですとAWS EC2やAzure VMなどでサイズが小さいインスタンスを使用している際に「あれもこれもプログラム(サービス)を動かしたいけれどリソースが少ないから難しい。。。スペック(インスタンスサイズ)を上げずにできるだけ頑張りたい。。。」という場面に遭遇する方は少なからずいらっしゃるかと思います。

そんなときのアイデアの1つとして、この記事ではsystemdとcgroupを利用したサービスに対するリソース制限を試してみたいと思います。

仕組み

Linuxにはcgroupというシステムリソースの管理・制限を行う機能があるので、これを利用します。 (この機能はDockerなどのコンテナ技術でも利用されているようです)

docs.redhat.com

cgroup を使用することにより、システム管理者は、システムリソースの割り当て、優先順位付け、拒否、管理、および監視をきめ細かく制御できます。ハードウェアリソースをアプリケーションとユーザー間でスマートに分割できるため、全体的な効率が向上します。

実際にcgroupを利用する際にはcgroupを直接操作するのではなく、systemdにより管理されているサービスの設定ファイルを編集することで実現します。

整理すると、あるプログラムに対してリソース制限を行うには以下のような手順となります。

  1. プログラムをsystemdのサービスとして登録する
  2. サービスの定義ファイルを編集しリソース制限を適用する
  3. systemdはサービスの定義ファイルを読み込み、そのプログラムが実行されるプロセスに対してcgroupによる制限をかける

この手順により、プログラムはsystemdサービスとして利用可能( systemctlコマンドによる開始/終了などの操作が可能)となり、cgroupによるリソース制限を行うこともできるようになります。

検証環境

  • OS: Ubuntu 24.04.3
  • CPU: Intel Core-i5 6300U (2コア/4スレッド)
  • RAM: 4GB

検証の準備

ここでは「CPUの制限」「メモリ使用量の制限」「ディスクの書き込み量の制限」の3つの観点に着目して、それぞれ検証用のスクリプトとサービスを作成してみます。

下準備

/opt/resource-control-test/のディレクトリを作成し、ここを今回の検証用スクリプトの置き場とします

sudo mkdir -p /opt/resource-control-test

CPU

下記のシェルスクリプトを用意しました。 これを実行することでCPU100%(1コア分)を使用させることができます。

#!/bin/bash
while :; do :; done
EOF

/opt/resource/control-test/cpu-test.shとして保存し、実行権限を渡しておきます。

sudo chmod +x /opt/resource/control-test/cpu-test.sh

メモリ

下記のPythonのスクリプトを用意しました。 これを実行することで10MBずつメモリが確保されていきます。 制限をかけていないとそのままメモリを使い切ってしまいますのでご注意ください。

import time
import sys

data = []
print("Starting memory allocation...")
try:
    for i in range(1, 10000):
        data.append(' ' * 10 * 1024 * 1024)
        print(f"Allocated: {i * 10} MB")
except Exception as e:
    print(f"Error: {e}")

/opt/resource/control-test/memory-test.pyとして保存しておきます。

ディスク

下記のシェルスクリプトを用意しました。 これを実行することで1GBのファイルの作成・削除を繰り返し行いディスクへの書き込み負荷をかけることができます。

oflag=directオプションをつけないとメモリ上のキャッシュが利用されリソース制限がうまく機能しないのでつけておきます。

#!/bin/bash
while : ;do
  /usr/bin/dd if=/dev/zero of=/tmp/testfile bs=1M count=1000 oflag=direct
  rm /tmp/testfile
done

/opt/resource/control-test/disk-test.shとして保存し、実行権限を渡しておきます。

sudo chmod +x /opt/resource/control-test/disk-test.sh

systemdサービスの作成

/etc/systemd/system/内にサービスの定義ファイルを作成します。

CPU

ファイル名: resource-control-test-cpu.service

[Unit]
Description=Resource Control Test for CPU

[Service]
ExecStart=/opt/resource-control-test/cpu-test.sh

[Install]
WantedBy=multi-user.target

メモリ

ファイル名: resource-control-test-memory.service

[Unit]
Description=Resource Control Test for Memory

[Service]
ExecStart=/usr/bin/python3 opt/resource-control-test/memory-test.py

[Install]
WantedBy=multi-user.target

ディスク

ファイル名: resource-control-test-disk.service

[Unit]
Description=Resource Control Test for Disk

[Service]
ExecStart=/opt/resource-control-test/disk-test.sh

[Install]
WantedBy=multi-user.target

作成したファイルの確認

最終的に以下のようにファイルが作成できていることを確認します

$ ls -l /opt/resource-control-test/
total 12
-rwxrwxr-x 1 user user  36 Nov 29 03:48 cpu-test.sh
-rwxrwxr-x 1 user user 123 Nov 29 04:00 disk-test.sh
-rw-rw-r-- 1 user user 248 Nov 29 03:40 memory-test.py
$ ls -l /etc/systemd/system | grep resource-control-test-
-rw-r--r-- 1 root root  147 Nov 29 04:11 resource-control-test-cpu.service
-rw-r--r-- 1 root root  149 Nov 29 04:15 resource-control-test-disk.service
-rw-r--r-- 1 root root  169 Nov 29 04:14 resource-control-test-memory.service

サービスの読み込み

すべてのファイルを作成したら、systemdのサービスとして読み込ませるためのコマンドを実行します

sudo systemctl daemon-reload

上記のコマンドを実行したら、実際にsystemdのサービスとして読み込めているか確認します。

CPUの場合

systemctl cat resource-control-test-cpu.service

下記のように作成したサービス定義のファイルが表示されればOKです。他のファイルも同様に確認できればOKです。

$ systemctl cat resource-control-test-cpu.service
# /etc/systemd/system/resource-control-test-cpu.service
[Unit]
Description=Resource Control Test for CPU

[Service]
ExecStart=/opt/resource-control-test/cpu-test.sh

[Install]
WantedBy=multi-user.target

リソース制限なしで実行してみる

CPU

起動

sudo systemctl start resource-control-test-cpu.service 

確認

systemd-cgtop

%CPUの列を確認します。検証用のサービスがCPUを100%使用していることが確認できます。

CGroup                                                                                                                  Tasks   %CPU   Memory  Input/s Output/s
/                                                                                                                         234  100.6   550.1M        -        -
system.slice                                                                                                              124  100.1   298.9M        -        -
system.slice/resource-control-test-cpu.service                                                                              1  100.0   580.0K        -        -

終了

sudo systemctl stop resource-control-test-cpu.service 

メモリ

注意:このコマンドは一時的に使用可能なメモリをすべて使用してしまうのでOSの動作に影響が出る可能性が高いです。もし実行される際は注意してください。

起動

sudo systemctl start resource-control-test-memory.service 

syslogを見てログの確認

sudo less /var/log/syslog

使用可能なメモリを使い切ってしまい、OSのOOM killerにより強制終了されてしまいました。

anon-rss:3429504kBが物理メモリの使用量を示しており、約3.2GBとなっています。

025-11-29T05:09:56.070002+00:00 hostname1 kernel: Out of memory: Killed process 3328 (python3) total-vm:3449716kB, anon-rss:3429504kB, file-rss:2432kB, shmem-rss:0kB, UID:0 pgtables:6788kB oom_score_adj:0

終了

sudo systemctl stop resource-control-test-memory.service

ディスク

起動

sudo systemctl start resource-control-test-disk.service 

確認

sudo less /var/log/syslog

syslogに残っているddコマンドのログを確認します。約130MB/sから140MB/sの速度でddコマンドが実行されたことが確認できました

2025-11-29T05:21:56.356744+00:00 hostname1 disk-test.sh[3650]: 1000+0 records in
2025-11-29T05:21:56.357355+00:00 hostname1 disk-test.sh[3650]: 1000+0 records out
2025-11-29T05:21:56.357626+00:00 hostname1 disk-test.sh[3650]: 1048576000 bytes (1.0 GB, 1000 MiB) copied, 7.68633 s, 136 MB/s
2025-11-29T05:22:03.974375+00:00 hostname1 disk-test.sh[3653]: 1000+0 records in
2025-11-29T05:22:03.974822+00:00 hostname1 disk-test.sh[3653]: 1000+0 records out
2025-11-29T05:22:03.975077+00:00 hostname1 disk-test.sh[3653]: 1048576000 bytes (1.0 GB, 1000 MiB) copied, 7.60413 s, 138 MB/s
2025-11-29T05:22:11.463149+00:00 hostname1 disk-test.sh[3658]: 1000+0 records in
2025-11-29T05:22:11.463627+00:00 hostname1 disk-test.sh[3658]: 1000+0 records out
2025-11-29T05:22:11.463908+00:00 hostname1 disk-test.sh[3658]: 1048576000 bytes (1.0 GB, 1000 MiB) copied, 7.47594 s, 140 MB/s

終了

sudo systemctl stop resource-control-test-disk.service

リソース制限をかけてみる

systemdのバージョンにより利用可能な制限は異なるようなのですが、実際にそのマシンで利用可能な制限の項目はmanコマンドでドキュメントを見ることで確認できます。

man systemd.resource-control

私の検証環境のバージョンは255でした。

$ systemd --version
systemd 255 (255.4-1ubuntu8.11)

CPU

CPU使用率の制限のために CPUQuotaを利用してみます。

sudo mkdir /etc/systemd/system/resource-control-test-cpu.service.d/

/etc/systemd/system/resource-control-test-cpu.service.d/ディレクトリの中で制限をかけるための設定ファイルを作成します。

ここではファイル名を limit.confとします。下記の内容でCPU使用率が10%に制限されることを期待しています。

[Service]
CPUQuota=10%

作業の結果以下のような状態でディレクトリとファイルが作成されます。

$ ls -l /etc/systemd/system/resource-control-test-cpu.service.d/
total 4
-rw-r--r-- 1 root root 23 Nov 29 04:49 limit.conf
$ cat limit.conf 
[Service]
CPUQuota=10%

systemdサービスの再読み込みを実行します。

sudo systemctl daemon-reload

設定が読み込めたか確認します。

systemctl cat resource-control-test-cpu.service

下記の末尾3行を見てみると、追加した設定が正しく読み込めたことを確認できます。

$ systemctl cat resource-control-test-cpu.service
# /etc/systemd/system/resource-control-test-cpu.service
[Unit]
Description=Resource Control Test for CPU

[Service]
ExecStart=/opt/resource-control-test/cpu-test.sh

[Install]
WantedBy=multi-user.target

# /etc/systemd/system/resource-control-test-cpu.service.d/limit.conf
[Service]
CPUQuota=10%

この状態でサービスを起動し、CPU使用率を確認します。

sudo systemctl start resource-control-test-cpu.service
systemd-cgtop
CGroup                                                                                                                  Tasks   %CPU   Memory  Input/s Output/s
/                                                                                                                         234   10.9   560.5M        -        -
system.slice                                                                                                              124   10.2   280.0M        -        -
system.slice/resource-control-test-cpu.service                                                                              1    9.8   344.0K        -        -

CPU使用率が10%程度で収まっていることが確認できました。

メモリ

メモリ使用率の制限のために MemoryMaxを利用してみます。

基本的にはCPUと同じなので確認作業など一部省略しました。

sudo mkdir /etc/systemd/system/resource-control-test-memory.service.d/

/etc/systemd/system/resource-control-test-memory.service.d/ディレクトリの中で制限をかけるための設定ファイルを作成します。

ここではファイル名を limit.confとします。下記の内容でメモリの使用量が100MBに制限されることを期待しています。

[Service]
MemoryMax=100M

systemdサービスの再読み込みを実行します。

sudo systemctl daemon-reload

設定が読み込めたか確認します。

systemctl cat resource-control-test-memory.service

この状態でサービスを起動します

sudo systemctl start resource-control-test-memory.service

syslogでログの確認をします

sudo less /var/log/syslog
2025-11-29T05:11:11.433558+00:00 hostname1 kernel: Memory cgroup out of memory: Killed process 3411 (python3) total-vm:120416kB, anon-rss:101760kB, file-rss:2944kB, shmem-rss:0kB, UID:0 pgtables:276kB oom_score_adj:0

anon-rss:101760kBとなっており物理メモリの使用量が約100MBで終了したことがわかります。

また、OSのOOM Killerではなく、cgroupの制限によりプロセスがKillされたことがメッセージから読み取れます。設定した制限がうまく機能したようです。

ディスク

ディスクも同様に確認します。

ディスクの書き込み量の制限のために IOWriteBandwidthMaxを利用してみます。

sudo mkdir /etc/systemd/system/resource-control-test-disk.service.d/

/etc/systemd/system/resource-control-test-disk.service.d/ディレクトリの中で制限をかけるための設定ファイルを作成します。

ここではファイル名を limit.confとします。下記の内容で/dev/sda3に対する書き込みが10MB/secに制限されることを期待しています。

[Service]
IOWriteBandwidthMax=/dev/sda3 10M

systemdサービスの再読み込みを実行します。

sudo systemctl daemon-reload

設定が読み込めたか確認します。

systemctl cat resource-control-test-disk.service

この状態でサービスを起動し、syslogを確認します。

sudo systemctl start resource-control-test-disk.service
sudo less /var/log/syslog
2025-11-29T05:23:59.916796+00:00 hostname1 disk-test.sh[3722]: 1000+0 records in
2025-11-29T05:23:59.982810+00:00 hostname1 disk-test.sh[3722]: 1000+0 records out
2025-11-29T05:23:59.982971+00:00 hostname1 disk-test.sh[3722]: 1048576000 bytes (1.0 GB, 1000 MiB) copied, 104.866 s, 10.0 MB/s

制限が正しくかかり、10.0MB/sぴったりの速度でddコマンドが実行されたことを確認できました。

余談

cgroupの実体に適用されている設定は/sys/fs/cgroup/system.slice/以下のファイルを確認することで分かります

(以下のコマンドはディスクの制限を確認する場合)

cat /sys/fs/cgroup/system.slice/resource-control-test-disk.service/io.max
$ cat /sys/fs/cgroup/system.slice/resource-control-test-disk.service/io.max
8:0 rbps=max wbps=10000000 riops=max wiops=max

10000000 -> 10M

まとめ

systemd/cgroupによるリソース制限の手順を示し、簡単ではありますが効果を確認することができました。

リソースが少ないマシン/インスタンス上では、優先度の低いプログラムはsystemdのサービスとしてリソース制限をかけることで、システム全体の動作の改善が期待できるかもしれません。

各サービス間の調整を細かくすると管理の難易度が上がってしまうのかな?という気もしていますが、何かの役に立てばと思います。

おわりに

私達クラウド事業部はクラウド技術を活用したSI/SESのご支援をしております。

www.ap-com.co.jp

また、一緒に働いていただける仲間も募集中です! ご興味持っていただけましたらぜひお声がけください。

www.ap-com.co.jp