「第8回 コンテナ型仮想化の情報交換会@東京」の参加メモ

先日開催された第8回 コンテナ型仮想化の情報交換会@東京に参加してきました。 FreeBSD VPSに関するLT発表をさせていただいたのですが、他の方とLTの内容がかぶっているという事態が発生してしまいました...。とはいえ、同じくFreeBSD VPSについてLT発表された方からFreeBSD-10.1向けのVPSパッチを作成したよ!という有益な情報をいただけたので内心満足しています。

勉強会で聞いた内容を忘れないうちにメモしておこうと思います。公開されている発表スライドを参照しつつメモをまとめていますが、私の理解が間違っている可能性もありますのでご注意ください。

Linux Namespaces

発表者は@masami256さん。

LinuxのNamespacesに関する話で、調査対象のバージョンはkernel 4.1、glibc 2.21とのこと。

Namespaces概要

Linuxのコンテナで使われる技術はNamespaces,cgroup等の「プロセス・リソース管理」とbtrfs,overlayfs,aufs等の「ストレージバックエンド」の二つに大別される。Linux名前空間については@TenForwardさんの資料を読むのが確実。

Linux4.1でサポートしている名前空間として、System Vのプロセス間通信とPOSIXメッセージキューを扱う「IPC」、ネットワークデバイスやIPv4,6プロトコルスタック、ルーティングテーブルを扱う「Net」、マウントポイントを扱う「Mount」、プロセスIDを扱う「PID」、UID,GIDを扱う「User」、ホスト名を扱う「UTS」がある。これらの名前空間は昔からあまり変わっていない。

名前空間の機能として「リソースの管理」が挙げられる。ここでのリソースはメモリやCPU等のリソースとは異なる類のもので、IPCやネットワーク、ホスト名等を管理する仕組みのこと。この仕組みを入れ替えることで名前空間の分離が実現できる。名前空間を分離する時の挙動は、元の名前空間の複製(例:Mount名前空間)と、完全に新規の名前空間の作成(例:Net名前空間)という二種類がある。 ユーザランド上での名前空間は/proc//ns/[namespace name]のような形でファイルとして見える。

Napespacesの登場人物

Namespacesの登場人物として、UTS,Net等の「名前空間」、カーネル内で名前空間を管理する構造体である「NSProxy」、個々の名前空間の「参照カウンタ」(実装上はNSProxy構造体のメンバ変数)がある。

基本的に子プロセスは親プロセスと同じ名前空間に所属するが、プロセスの親子関係と名前空間の関係は別。これは単に名前空間のデフォルト値をどうするかという話。また、親プロセスの名前空間からの独立は(例外はあるものの)いつでも可能。

システムコールによる名前空間の操作

システムコールを通じて名前空間に対する「親プロセスの名前空間の共有」、「親プロセスの名前空間から分離」、「別プロセスへの名前空間移動」の操作が行える。

システムコールはclone(2),setns(2),unshare(2)がある。setns(2)は純粋に名前空間を操作するだけ。他の二つは名前空間「も」操作できる。

clone(2)はfork(2)の仲間で、子プロセスを作成する。fork(2)との違いは、フラグを色々設定して細かい制御が可能な点。スレッドを作る場合にも利用される(カーネル内の実装では、do_fork()がfork/cloneの共通処理になっている)。clone(2),unshare(2)で使用するフラグは、CLONE_NEWXXXというマクロ定数。

プロセス起動時から新しい名前空間で動かしたい場合はclone(2)を使う。CLONE_NEWXXXフラグで指定しなかった名前空間は親プロセスと共有される。

unshare(2)を使う場合は、PID名前空間は分離できないという制限がある。名前空間を完全に新しくしたい場合はclone(2)を使う必要がある。

setns(2)は所属したい名前空間のfdを使って、その名前空間に移動する。別のPID名前空間に所属させることはできるが、そのプロセス自身のPID名前空間は変わらないという制限がある。名前空間をまっさらにしたい場合は、unshare(2)の場合と同じくclone(2)する必要がある。

基本的に各名前空間はデータ的に独立しているが、User Namespaceは例外。User名前空間以外の構造体は、User Namespaceへのポインタを持っている。これは名前空間を使用する際にケーパビリティの有無をチェックするために使用される。というわけで、User名前空間だけは他の名前空間と独立ではない。

Hadoopのコンテナのはなし

発表者は@oza_x86さん。

データの処理基盤におけるコンテナのスケジューリングに関する話。

有象無象の生データをDBに入れる際の前処理をETL(Extract/Transform/Load)と呼ぶ。大量の生データを処理する際のプログラミングモデルとしてMapreduceがある(実装としてHadoopがある)。これはMap関数、Reduce関数を記述することで、対故障性を持った処理が行えるというもので、これらの関数はMapスロット、Reduceスロットという形でスケジューラが割り当てを決める。

Hadoopの計算プラットフォームとしてYARN(Yet Another Resource Negotiator)がある。読み方は「ヤーン」。

YARNのスケジューラには、入ってきたジョブから順にスケジューリングする「FIFO Scheduler」(一番簡単なスケジューラ)、ユーザ数で割った分でスケジューリングする「Fair Scheduler」、各人に割り当てられたキャパシティの中でスケジューリングする「Capacity Scheduler」がある。

コンテナのスケジューリングを考える際、異なるサイズのメモリや異なるプロセッサ数のCPUリソースが混在する場合に何をもって"Fairness"とするべきか。

cgroupsの場合はCPU上限を決定してしまうため、計算機資源を使い切れない。その代わり他のタスクを邪魔しない利点がある。これはSLA(Service Level Agreement)が必要な場合に有用かもしれない。 Unixプロセスベースの場合はCPU上限がないので計算機資源は使い切りやすいが、CPUを使いまくる場合は他のジョブの進行を阻害する危険がある。

"Fairness"を実現するため、Apache Mesosに出てくる概念である、Dominant Resource Fairness(DRF)を利用する。

DataCenter OSレベルのisolationになってくると、コンテナ技術単体だけでなくクラスタ単位のスケジューリング技術が必要であり、これにはFacebookによるBistroというスケジューラが提案されている。

SmartOS入門

発表者は@nslopeさん。

コンテナ用OSであるSmartOSに関する話。

SmartOSはJoyentが開発しているillumosベースのクラウド用OS。コンテナ、仮想マシンに特化している。SmartOSで使用できる仮想環境は、Naticve Zone(通常のコンテナ)、LX Baranded Zone(Linuxコンテナ)、KVMの3種類。SmartOSではデフォルトでdtrace機能が利用できる、ただし、カーネルの中の情報を取得するのには制限がある。

【個人的な感想】メモをとり忘れていたので発表の動画が公開されたら改めてメモにまとめてみます...。

Docker Swarm入門

発表者は@zembutsuさん。

Dockerはクライアント・サーバ型で、dockerデーモンとコマンドラインツールから構成される。Docker EngineはDockerの中核となるプログラムでコンテナの制御を行い、他のツールと連携してオーケストレーション機能を実現している。

Dockerとコンテナのオーケストレーションはなぜ必要か?これはクラウドやType1仮想化で複数のホストを管理するのと同じことをコンテナでも実現したいため。Type1仮想化における、VM+ゲストOS相当の箇所がDocker Clusterの管理レイヤにあたる。加えて、クラウド・Type1仮想化の両方をシームレスに管理するのはもう少し先の話かもしれない。

【個人的な感想】クラウド・Type1仮想化の両方をシームレスに管理するユースケースがうまく思いつかない。素人考えで思いつくのはType1仮想化の上でゲストOSを動かしたけど、IOまわりのオーバーヘッドが予想よりも大きかったのでコンテナで動かしたい、というような場合なのかなと思います。

(Dockerだけに限る話ではないが)「インフラの抽象化」は開発者の視点では開発・テスト・リリースの各プロセスにおいて一貫したインフラ環境を利用できる、という開発効率とアプリケーションのポータビリティが良いという利点がある。 ただし、Docker自体が何かするのではなく、あくまでも利用者の利便性向上のツール(またはプラットホーム)という点がポイント。

Docker動作ホスト環境を自動作成するツールにDocker Machineがある。自動でTLSを有効にしたDocker動作環境を構築し、仮想サーバの起動とDockerデーモンのプロビジョニングを行う。ツールの位置付けとしては、boot2dockerの置き換え。また、ソースコードでDockerの環境を管理できるDocker Composeがある。複数のコンテナを定義可能でイメージとしてはDockerfileを複数のコンテナ向けに拡張したもの。構成情報はYAML形式のファイルで指定する。

Docker Swarm(ドッカースウォーム)はDockerクラスタの管理ツール複数OS上のDocker環境を一つのリソースプールとして扱える。コマンドラインからdocker-machineでDockerホスト環境を作成後、docker run swarm createでコンテナクラスタを作成する。Docker Machineとの合わせ技でDockerクラスタを管理する。

Docker Swarmの概念として、Dockerデーモンの代わりにコマンドを受け付ける「マネージャ」(というプログラム)、ノード等のリソース情報をマネージャへの登録を行う「ディスカバリ」、コンテナの自動配置方針を決定する「ストラテジ」、コンテナ配置条件を指定する「フィルタ」がある。

スケジューリングのストラテジには、コンテナ稼働数でランク付けした値を用いる「Spred」(デフォルトのストラテジ)、コンテナをノードに集約する「Binpack」、ランダムに配置する「Random」がある。

Docker SwarmはDockerのAPIと互換性があり、docker ps,run等のコマンドをDocker Swarmで作成したクラスタ全体に対して適用可能。クラスタ群へのAPI実行はマネージャが行う。

フィルタはどのDockerホスト上でコンテナを起動するかを指定する機能。指定したフィルタ条件はストラテジよりも優先される。フィルタの種類として、Constraint,Affinity,Port,Dependency,Healthがある。

MINCS - Container in the shell script

発表者は@mhiramatさん。

コンテナの実装にはDocker以外にもLXC,Runc,OpenVZ等の様々な実装がある。Dockerは多くの機能を提供しているが、すこし規模が大きく、個々の機能を試しにくい。そこでUnix哲学の"Keep It Simple, Stupid"という思想に倣い、MINCS(Minimum Container Shell-scripts)というコマンド群をシェルスクリプトで実装されたとのこと。MINCSはPOSIX shell script(bashスクリプトではない)で作成されているためポータビリティがあり、busybox shell,dash等でも動作可能。

最小限の実行環境分離を実現するため、名前空間の利用、デバイスファイルのバインド、Chroot/pivot_rootによるrootfsの変更、CapabilitiesとCPUSETを利用する。ファイルシステムのレイヤリングにおいては、Linux-3.18以降でOverlayfsが利用可能であり、これを利用してコンテナイメージの管理も試してみたとのこと。

MINCSはフロントエンドとバックエンドの構成でコマンドが用意されている。フロントエンドコマンドは基本的にパラメタのパースのみを行い、パラメタを環境変数に変換してバックエンドを呼び出す役割になっている。

フロントエンドのコマンドにはminc,marten,plecatがある。mincは指定したコマンドをコンテナ内部で動かすもので、chrootやdocker runコマンドのようなもの。デフォルトでは名前空間分離とoverleyfsによる作業空間分離を行い、ネットワークはそのまま見える。martenはマルチレイヤのコンテナイメージの管理する。polecatは自己実行形式のシングルバイナリコンテナアプリを生成する。バックエンドのコマンドにはminc-exec,minc-coat,minc-farm,minc-trapperがある。

mincコマンドはパラメタのパース後、バックエンドコマンドのminc-execを実行する。minc-execの中では以下の処理が行われる。

  • netnsとcpumaskの設定
    • MINC_NETNSで指定された名前のnetnsをip netnsで作る。これは終了時にtrapコマンドで削除される。併せてtasksetコマンドで実行するCPUを指定する
  • 新しい名前空間への移行
  • PIDの保存とutsの設定
    • 後でコンテナ外からPIDを知るために保存しておく
  • コンテナ用rootfsのセットアップ
  • デバイスファイルのバインド
  • 不要なマウントポイントの削除
    • 不要なマウントポイントを残しておくとchroot後にも見えてしまう。umountできないものがあるのでpivot_rootdで処理を行う
  • 新しいrootfsへの移行とcapabilitiesの設定
    • capshコマンドでLinuxケーパビリティを変更する。単にchrootだけを実行した場合、ケーバビリティは変更されない

FreeBSD Jail/VIMAGEの始め方

発表者は@BsdHackerさん。

jailとはchroot(8)の発展系でroot directoryを変更する機能。プロセスの実行環境を分離できる。 Linux emulator機能を利用することでjailでlinux環境を作成できる(ただし現状32bit環境のみ)。

VIMAGEとはFreeBSD-9.0-RELEASEから利用可能なjail毎に異なるネットワークスタックを作成可能にする拡張。ただし、カーネルの再構築が必要。まだ対応できていないネットワークドライバ/スタックもあるが、Jail内にネットワークインタフェースを自由に配置できる。

LXD入門

発表者は@ten_forwardさん。

lxdはGo言語で書かれた、REST APIを提供するコンテナ管理デーモン。lxdと通信し、コンテナを操作するコマンドラインクライアントがlxc。また、nova-compute-lxdというOpenStack Novaプラグインもある。

lxdの特徴として、セキュアであること(デフォルトでは非特権コンテナ)、イメージベースであることとシンプルなAPIコマンドラインの提供、ライブマイグレーションがある。

Ubuntu 15.04ならlxdのインストールは簡単(パッケージが用意されている)。しかし、lxdは頻繁に更新されるため、ubuntu-lxc/lxd-stableリポジトリをadd-apt-repositoryしておいてupdateするとよい。もちろんソースからビルドするのもあり。

コンテナイメージのインポートは、lxc image importコマンドで行う。イメージサーバを登録するとリモートイメージからコンテナを直接起動できる。リモートサーバのコンテナはデフォルトだとUnix domain socket経由での接続のみであるため、必要に応じてリモート接続設定を行う必要がある。

ライブマイグレーションはlxc moveコマンドをリモート間で実行する(ただし残念なことに現時点のバージョン0.18(2015年9月現在)ではライブマイグレーションは行えない)。ローカルで実行すると単にコンテナのリネームになる。ライブマイグレーション機能は内部的にCRIUを利用している。lxdはデフォルトで非特権コンテナであり、CRIUは非特権コンテナに対応していないため、ライブマイグレーションを行う際には特権コンテナにする必要がある。

LT

メインセッションのメモをまとめた段階で力尽きてしまいました。今はこれが精一杯...。

まとめ

第8回 コンテナ型仮想化の情報交換会@東京の参加メモをまとめてみました。後から自分で見返しやすいようにメモを小さくまとめたつもりなのですが、思っていたよりも長いメモになってしまいました...。

それでもコンテナ型仮想化に関する現状とノウハウについて把握できてきたので、次回のコンテナ型仮想化の情報交換会を楽しみにしつつ、メモを見返すようにしようと思います。