Systemd と ControlGroup
これ 読んだり色々試してみたりしての、自分なりのまとめ。
Systemd のバージョンは 208 。
リソース制御の単位
Systemd のリソース制御で登場する unit たち。
Service :: 設定を元に systemd により起動・停止されるプロセス群をまとめたもの
Scopes :: 任意のプロセスから
fork()
され、 PID 1 に登録されたプロセス群をまとめたものSlices :: 上記 services や scopes をまとめるためのもの
3つ共に cgroup の tree を割り当てられているようなので、 どれに対してもリソース制御を設定できる。
systemd-cgls
で現在の tree の状態が表示されるので、とりあえず見てみるとよい。
Services, slices は設定ファイルからもしくは runtime に動的に生成でき、 scopes は runtime でのみ生成できる。 Runtime に生成された units を transient units と呼ぶ。
リソース制御の方法
設定ファイルから生成された units はそのファイル内でリソース制限を行える。 以下のコマンドにより、再設定することも出来る:
# systemctl set-property httpd.service CPUShares=500 MemoryLimit=500M
この場合、設定は恒久的に残り、リブート後も自動で設定が適用される。それが嫌なら --runtime
つける。
何が設定できるかは man systemd.resource-control
で。
Transient な unit を生成する
systemd-run
コマンドがその辺やってくれる君のようなので、色々やってみる。
$ sudo systemd-run sh -c 'ls /; sleep 3'
Running as unit run-26504.service.
$ journalctl -u run-26504.service
-- Logs begin at Mon 2013-08-12 00:11:06 JST, end at Sun 2013-10-06 17:42:55 JST. --
Oct 06 17:42:55 localhost systemd[1]: Starting /bin/sh -c ls /; sleep 3...
Oct 06 17:42:55 localhost systemd[1]: Started /bin/sh -c ls /; sleep 3.
Oct 06 17:42:55 localhost sh[26515]: bin
Oct 06 17:42:55 localhost sh[26515]: boot
Oct 06 17:42:55 localhost sh[26515]: dev
Oct 06 17:42:55 localhost sh[26515]: etc
Oct 06 17:42:55 localhost sh[26515]: home
Oct 06 17:42:55 localhost sh[26515]: lib
Oct 06 17:42:55 localhost sh[26515]: lib32
Oct 06 17:42:55 localhost sh[26515]: lib64
Oct 06 17:42:55 localhost sh[26515]: lost+found
Oct 06 17:42:55 localhost sh[26515]: media
Oct 06 17:42:55 localhost sh[26515]: mnt
Oct 06 17:42:55 localhost sh[26515]: opt
Oct 06 17:42:55 localhost sh[26515]: proc
Oct 06 17:42:55 localhost sh[26515]: root
Oct 06 17:42:55 localhost sh[26515]: run
Oct 06 17:42:55 localhost sh[26515]: sbin
Oct 06 17:42:55 localhost sh[26515]: sys
Oct 06 17:42:55 localhost sh[26515]: tmp
Oct 06 17:42:55 localhost sh[26515]: usr
Oct 06 17:42:55 localhost sh[26515]: var
$ sudo systemd-run --scope bash
Running as unit run-25802.scope.
# cat /proc/$$/cgroup
10:hugetlb:/
9:net_prio:/
8:blkio:/
7:freezer:/
6:devices:/
5:memory:/
4:cpuacct,cpu:/
3:cpuset:/
2:name=systemd:/system.slice/run-25802.scope
# systemctl set-property --runtime run-25802.scope CPUShares=500 MemoryLimit=500M
# cat /proc/$$/cgroup
# cat /proc/$$/cgroup
10:hugetlb:/
9:net_prio:/
8:blkio:/
7:freezer:/
6:devices:/
5:memory:/system.slice/run-25802.scope
4:cpuacct,cpu:/system.slice/run-25802.scope
3:cpuset:/
2:name=systemd:/system.slice/run-25802.scope
# cat /sys/fs/cgroup/cpu/system.slice/run-25802.scope/cpu.shares
500
systemd-run
で新しく transient な service が作られ、その下で指定されたコマンドが起動する。 コマンドは現在のプロセスとは独立して動作するので、出力を見たいなら journal で確認する。sleep
してるのは、そうしないと出力が journal に渡る前に service が終了 & 削除されちゃって、journalctl -u
で取れなくなるから。systemd-run --scope
で新しく scope unit が作られ、その下で指定されたコマンドが起動する。 コマンドは foreground で動く。systemctl set-property
には--runtime
付けないと効果がない模様systemd-run
には cgroup な property 設定する機能無い?sudo なしで scope 作ろうと
systemd-run --user
を試してみたら、Failed start transient unit: Process /bin/false exited with status 1
とかいって失敗する。 --user な systemd とうまく通信できてない?
おまけ
現在の scope/service を得るには sd_pid_get_unit()
を使え、とのことらしいが、 C とかよく分からんし、 python で ctypes 使ってもうまくいかなかったので、 go
でやってみたらなんか動いた。でも何やってるかよく分かってない。
sd_pid_get_unit.go
:
package main
/*
#cgo LDFLAGS: -lsystemd-login
#include <systemd/sd-login.h>
*/
import "C"
import (
"fmt"
"os"
)
func main() {
result := C.CString("")
ret, err := C.sd_pid_get_unit(C.pid_t(os.Getpid()), &result)
if err != nil {
panic(err)
}
if ret != 0 {
panic(ret)
}
fmt.Println(C.GoString(result))
}
$ go run sd_pid_get_unit.go
session-1.scope
$ sudo systemd-run --scope go run sd_pid_get_unit.go
Running as unit run-1539.scope.
run-1539.scope