LXCで学ぶコンテナ入門 -軽量仮想化環境を実現する技術

第5回 Linuxカーネルのコンテナ機能[4] ─cgroupとは?(その3)

この記事を読むのに必要な時間:およそ 6.5 分

サブシステム紹介(続き)

今回は前回紹介できなかったサブシステムを紹介したあと,cgroup開発の現状に少し触れたいと思います。

Memoryサブシステム

コンテナに対してメモリの制限を行いたい場合に使用するのがmemoryサブシステムです。cgroupに対して制限値を設定したり,cgroupのメモリ使用量の監視をしたりできます。

まずは制限を設定してみましょう。制限を設定するには以下の2つのファイルに値を書き込みます。

memory.limit_in_bytes
メモリ消費量の制限値の設定と表示(バイト)
memory.memsw.limit_in_bytes
メモリ+スワップメモリの消費量の制限値の設定と表示(バイト)

スワップの消費量も含めた制限を設定したい場合は後者を,スワップの消費量はカウントしない場合は前者を使用します。制限値の設定にはk,K,m,M,g,Gといった単位の文字が使えます。

たとえばtest1グループのメモリ使用量を100MBに設定したい場合は以下のように設定します。/sys/fs/cgroup/memoryにmemoryサブシステムをマウント済みとします。

$ sudo mkdir /sys/fs/cgroup/memory/test1
$ echo $$ | sudo tee /sys/fs/cgroup/memory/test1/tasks (現在のシェルをtasksに登録)
31784
$ echo 100M | sudo tee /sys/fs/cgroup/memory/test1/memory.limit_in_bytes (制限値を100MBに設定)
100M
$ cat /sys/fs/cgroup/memory/test1/memory.limit_in_bytes (設定された制限値の確認)
104857600

100Mという文字列を書き込むと,きちんと100MBに制限値が設定されているのがわかります。

では実際に制限値に達した時にどうなるかを見る前にmemoryサブシステムで使用するファイルをさらにいくつか見ておきましょう。

memory.usage_in_bytes
cgroup内のプロセスが現在消費しているメモリ
memory.max_usage_in_bytes
cgroup内のプロセスが今までに消費したメモリの最大値
memory.failcnt
cgroup内のプロセスのメモリ消費量が制限値にヒットした回数

memory.usage_in_bytesを継続して監視することで,グループ内のプロセスのメモリ消費が監視できますし,memory.max_usage_in_bytesmemory.failcntをチェックして,グループに設定する制限値を見積もったりすることができます。

さて,それでは実際にメモリの制限値を設定して動きを見てみましょう。例では,繰り返しmalloc()でメモリを確保して,memset()でメモリを消費するだけのmemoryというプログラムを作成し,実行しました。

$ ./memory 
Killed

実行して少し時間が経つと"Killed"と表示されてプロセスがkillされました。これだけではなんのことかわからないかと思います。これはLinuxでシステムのメモリが足りなくなった時に発動するOOM Killerによってcgroup内のプロセスが強制終了させられています。メモリの消費が上限に達したことをmemory.max_usage_in_bytesを見て確認してみましょう。

$ cat /sys/fs/cgroup/memory/test1/memory.max_usage_in_bytes 
104857600

先ほど設定した制限値が最大値になっており,上限に達してプロセスが強制終了されたことがわかります。OOM Killerでいきなり強制終了させるのでなく,OOM Killerを無効にして,eventfd(2)を通じて通知を受け取ることもできます。詳しくはカーネル付属文書のmemory.txtをご覧ください。

また,3.10 カーネルからはcgroup内のプロセスのメモリの圧迫度合いに応じて同様にeventfdで通知が行えるようになっています。この機能を使うと,OOMKillerが発動するような状況になる前に通知を受け取れます。

メモリ使用量の制限を行うだけであれば,ここまでで説明した通り簡単に設定できました。しかし,memoryサブシステムにはいろいろと設定する上で注意する必要のある点が存在します。特に注意すべき点をいくつか挙げておきましょう。

  • memoryサブシステムをマウントしたルート直下のファイルへの値の設定は行えません。
  • 前回説明した階層構造はデフォルトでは無効になっています。有効にするにはmemory.use_hierarchyというファイルに1を書き込みます。ただし,cgroupがすでに配下に子供のcgroupを持つときはこのファイルの値の変更はできません。
  • 先に紹介したスワップを含めたメモリ消費の制限を設定するmemory.memsw.limit_in_bytesへ値を設定したい場合は,あらかじめmemory.limit_in_bytesに値を設定しておかなければなりません。

ここで紹介した以外にもmemoryサブシステムには多数の機能があります。詳しくは先に紹介したmemory.txtをご覧ください。

ここで紹介したメモリ制限はユーザメモリの制限であり,カーネルが使うメモリの制限を行うにはmemory.kmemで始まるファイルを使用します。しかしカーネルメモリの管理機能はまだまだ実装や改良が続いており,落ち着くにはもう少し時間がかかるようです。

net_clsサブシステム

net_clsサブシステムはcgroupに属するプロセスが発信するパケットに識別用の識別子を付け,そのIDを使ってトラフィック制御ができるようにするための仕組みです。識別子をトラフィック制御を行うためのtcコマンドで指定して,cgroupのプロセスから発信されるパケットを制御します。

また3.14カーネルでこの識別子をnetfilterから使う機能が実装されています。パケットに識別子を付け,そのパケットをフィルタリングできます。ただし,この機能に対応したiptablesコマンドは,現時点ではリリースされていないようです。

net_clsサブシステムについてはカーネル付属文書のnet_clsをご参照ください。

著者プロフィール

加藤泰文(かとうやすふみ)

2009年頃にLinuxカーネルのcgroup機能に興味を持って以来,Linuxのコンテナ関連の最新情報を追っかけたり,コンテナの勉強会を開いたりして勉強しています。英語力のない自分用にLXCのmanページを日本語訳していたところ,あっさり本家にマージされてしまい,それ以来日本語訳のパッチを送り続けています。

Plamo Linuxメンテナ。ファーストサーバ株式会社所属。

Twitter:@ten_forward
技術系のブログ:http://tenforward.hatenablog.com/

コメント

コメントの記入