本セッションの登壇者
セッション動画
それでは「cgroupの歩き方」ということで、実際にコードを読むときのお話をしたいと思います。
まずは自己紹介です。加藤と申します。SNSは@ten_forwardという名前でやっていることが多いです(Twitter)。gihyo.jpでコンテナの連載を2014年からずっとやっております。コンテナは完全に趣味でやっていて、仕事の方はIDCフロンティアという会社でセキュリティの仕事をしています。
本日の内容はこんな感じです。ざっとcgroupのコードを読みたい方がどれぐらいいるかわかりませんが、読むときのヒントみたいなものを紹介できればと思います。
cgroupとは
まずcgroupについてですが、プロセスやスレッドなどのタスクをグループ化して、そのグループに対して専用のファイルシステムをマウントして使う、といった管理のための仕組みです。最近は、systemdがLinuxの上のプロセス管理に使っていますので、コンテナ専用の機能ではありません。v1、v2というのがあり、それぞれの機能や特徴は私の連載を読んでいただくといいかなと思います。
cgroupの構造ですが、便宜上言葉を割り当てると、cgroupコアというcgroupそのものの操作をする部分と、メモリの制限などリソースの制限を行うコントローラ部分の2つに分かれています。
cgroupのコードがどこにあるのかというと、ソースコードを展開するとkernel/cgroupの下にコアが存在しています。ファイル数も少なくてさらっと読めます。最初のsatさんのお話にもありましたけども、行数も少ないので手っ取り早く読めると思います。それ以外のコントローラは機能ごとにいろいろなところに存在していて、satさんも「探すにはgrepで探しましょう」とお話されていました。struct cgroup_subsys
というのを探すと実装されている場所がわかると思います。
cgroupの初期化
まず1つ目ですが、cgroupの初期化を追ってみましょう。
カーネル起動時には、cgroupの初期化はv1では実はほとんど走りません。一部のグローバル変数は初期化しますが、ほとんどの初期化はマウント時に行われます。v2になると、cgroupがあたりまえの世の中になったので、カーネル起動時にcgroupのさまざまな初期化が走ります。こういうことを覚えておくと、v1だけ読みたいときはカーネル起動時の処理は読まなくてもいいことがわかります。
cgroupコアの処理を追う
次はcgroupコアの処理を追います。
cgroup自体はファイルシステムを使って実装されているので、ファイルシステムのいろいろな処理を行う関数のインタフェースが定義されています。たとえばcgroupを作るときはmkdir
しますのでcgroup_mkdir
を読めばよくて、cgroupを削除するときはcgroup_rmdir
を読めばいいことがわかります。その前のマウント時の処理については、struct file_system_type
をgrepすれば、どこでやってるかがわかります。だいたいはこのcgroup.cという1つのコードの中に入っているので、grepもさほど難しくないと思います。
cgroupの内容の追いかけ方 ‐ 3つの構造体をチェックする
実際の中身を追っていきたいところなんですけれど、今日はそんな時間はありませんので、どういう順番でやっていけばいいかをお話しします。まず、cgroupそのものがどう動いてるかがわからなければコードを追ってもわからないので、cgroupの操作方法を学ぶのが第1です。2番目は、関連するいろいろな構造体を見て、それぞれの関係性を理解します。理解しながら3番目に実際の処理を追います。構造を頭に入れたり参照したりしながら処理を追うとよいでしょう。
cgroupの動きについては資料で紹介しています。また、一部内部構造についても発表したことがありますので、「cgroup v1概要」「cgroup v1の内部構造」などをご覧いただければと思います。
また、コアを読むときには中心となる構造体が3つあります。cgroup構造体は文字通りです。次にcgroupでリソースコントロールをするときに関係するcss_set構造体というものがあります。cgroup構造体とcss_set構造体はm:nの関係で、最後のcgrp_cset_link構造体を介してそれぞれが結びついていることになります。このあたりを覚えておくと読むときのヒントになるかと思います。
cgroupのコントローラを読むには
実際のコントローラの処理を追いたい人もいるかなと思います。しかし当然ながら、メモリのコントローラを追うにはメモリ管理の知識がいりますし、スケジューラのコントローラを読むにはスケジューラの知識がいるので、まずは各リソースの専門知識をつけることをおすすめします。
ただ、「とにかく何でもいいからcgroupのコントローラの実装を見てみたい」という人には、おすすめが2つあります。ひとつはpidsコントローラというcgroup内で生成できるタスクの数を制限するコントローラで、パッチ2つで実装されています。1つ目のパッチで、コントローラそのものをカーネルに追加するにはどういう定義を行ったらいいか、2つ目のパッチではどのように制限をかけているかがわかります。この2つだけを読めばいいので非常にシンプルです。
もうひとつ、net_prioコントローラもシンプルな構造になっていて、パッチ2つのうち1つはドキュメントなので、パッチが実質1つだけでコントローラが追加されています。これを読むとnet_prioコントローラが何をやってるかがわかります。ドキュメントを読んでもそのコントローラが何をやってるかはよくわからないことが多いんですが、構造を読むとわかります。
まとめ
まとめです。これだけでcgroupが読めるかというと、あとはもうひたすらがんばるしかないのですが、とりあえずヒントになりそうな情報をお話ししました。satさんのお話にもあった「目的を絞って取り組む」という点については、パッチがおすすめです。機能が追加されたときには必ずパッチが流れて、非常に限られた行数だけを読めばいいので、先ほど2つ挙げたようなとくにシンプルなコントローラでは行数もきわめて少ないので、そういったパッチを手掛かりに歩いていくのもよいと思います。
以上です。ありがとうございました。
cgroupのカーネルコードの世界に飛び込むほんの入口のお話をしました!!