Java SwingでGUIを手書きする話

岩手県立大学 Advent Calendar 2020 第9日目の記事です。
今日はソフトウェア演習ではJavaGUIを手書きするという話をしようと思います。
(ただし我々の世界とは時間軸が完全に一致していない可能性があります...)

Java SwingでGUIを手書きする

ソフトウェア演習ではJavaを用いたプログラミングの授業が行われます。
CLIで動作するアプリだけでなく、SwingというJavaGUI用クラスライブラリを用いたアプリケーション作成の課題が出されたりします。

Hello,World的なGUIアプリケーション

GUIアプリは以下のような感じで手書きします。JBuilderのお試し版をインストールして動かしている人もいますが、メモリが128MBの環境ではJBuilderのようなIDEはだいぶ重たい動作になってしまいます...。

import javax.swing.JFrame;
import javax.swing.JButton;

public class Hello extends JFrame {
    Hello() {
        super("hello");
        getContentPane().add(new JButton("Hello,World."));
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        pack();
        setVisible(true);
    }
    public static void main(String... args) {
        new Hello();
    }
}

そのためソフトウェア演習ではMuleというemacsへの多言語対応版エディタを使ってソースコードを書いています。人によってはよりコンパクトなエディタであるviを使ったりもするようです。
デスクトップ環境のCDEに付属しているdtpadというメモ帳風のエディタも試してみたのですが、さすがにこれでソースコードを書くのは少々骨が折れます...。

エディタの話を始めると大論争がおこるという都市伝説がありますが、個人的にはviの基本的な使い方を抑えておくと後々つぶしが効く(?)感じです。

Swing GUIを手書きする場合のコツ

そしてSwing GUIを手書きするという点についても、それほど難しい感じではありません、以下のような感じでBorderLayoutにボタンやラベル、テキストエリアを追加してゆくことでUI部品の配置やウインドウリサイズ時の再配置が動的に行われるようになります。

f:id:furandon_pig:20201210213640p:plain

私もSwingを使いこなせているワケではありませんが、ちょっとしたGUIアプリケーションを作成するだけであれば、以下のクラスの使い方を把握しているだけで充分対応できるという印象です。

GUI部品はどのアプリケーションでも似たような使い方になるので、イディオム的な使い方のサンプルを用意しておくと、テンプレート的な感じでソースコードを利用できるのでおススメです。

ソフトウェア情報学部の計算機環境

遅くなってしまいましたが岩手県立大学 Advent Calendar 2020 第4日目の記事です。
今日は学内でのソフトウェア演習で用いられている環境の紹介をしようと思います。
(ただし我々の世界とは時間軸が完全に一致していない可能性があります...)

学内の計算機環境

ソフトウェア情報学部では、Sun MicrosystemsSolarisというOSが利用できるようになっています。このSolaris環境でC言語シェルスクリプトPerlJavaを用いたプログラミングの授業が行われています。また、LaTeXという組版システムもインストールされており、これを用いてレポートを作成したりします。

f:id:furandon_pig:20201209025004p:plain

ちなみに、UNIXの系譜で見るとSolarisは当初BSDをベースにしており、のちにSystemVベースになったという経緯があります。BSD系のOSでは、デフォルトシェルがtcsh(Cシェルの機能拡張版)なのですが、学内のSolaris環境ではbash(Bourne Shellの機能拡張版)がデフォルトシェルに設定されています。Linux等でもbashがデフォルトシェルになっていたりするので、それぞれの環境を行き来する場合でも挙動の差異にあまり悩まされなくて済みそうです。

学生一人に1台のSolarisマシンが割り当てられるようになっており、各マシンの /usr/local 以下にソースコードからビルドしたアプリケーションをインストールして利用することも可能です。とはいえ、ソースコードからビルドしようとすると、まず最初に関連ライブラリをインストールするところから始める必要もあったりするのでちょっと大変です...(逆に考えると、ビルド力の向上に役立つと言えるかもしれません)。 学内のSolaris環境を利用してどんなことができるかは、以降のアドベントカレンダーで紹介させてもらえればと思います。

JustTechTalk#06 参加メモ(1/3)「スマイルゼミの裏側:データベース編」

JustTechTalk#06 スマイルゼミの裏側(DB編)とRDBMS最新動向に参加してきました。 タイトルにもある通り、今回はDB関連の話がメインで以下の3つの発表がありました。

  • スマイルゼミの裏側:データベース編
  • OSS DBの最新情報
  • Amazon独自のDBマネージメントシステム

全部まとめると長々とした内容になってしまうので、今回は発表内容ごとにブログの記事を分けてみます。 (一つにまとめると後から自分で見返す時も大変ということに今更ながら気がついたのです...)

スマイルゼミの裏側:データベース編

ジャストシステムが運営する「スマイルゼミ」のサービスの裏側に関する内容でした。 スマイルゼミのサービスはTomcat+PostgreSQL 9.3で構築されており、今回はDB的な意味でやらかしてしまった話を聞くことができました。

スマイルゼミについて

  • スマイルゼミは小学生と中学生でニーズが異なる
    • サーバとクライアントの構成も小、中学生向けで別物というくらい異なっている
  • アクセスのピーク時間にも違いがあり、基本的に朝と夜にピークの山がある
  • 小学生向けのサーバでは朝の6:00〜8:00前くらい、中学生だと夜にピークがある

DBでやらかしてしまった話

DBでやらかしてしまった話として、unionにまつわる2つのケースが解説されていました。

viewの中のunionが悪さをしていた話

  • ある日のこと、平日のピークではない時間帯に負荷が急上昇した
  • 前日にhotfixを当てており、これが問題の引き金になった模様
  • 内部のバッチ処理で1300万行のシーケンシャルスキャンが発生していた
  • 調べてみると怪しいviewがあった。
    • (4000行のviewとのことで、業務だとそれくらい大きなviewを使うものなのですね...)
    • viewを使うようにプログラムを変更しており、viewを使うとオプティマイザが絞り込みをしなくなってしまう
    • さらに、viewの中でunionを使っており、これが性能劣化の原因であった
      • (ちょっと記憶と手元のメモが曖昧。viewの中でunionしたことで、オプティマイザが働かなくなった、という話かも)
  • 対策として、前日の学習結果の集計をview定義の段階で学習日で絞った

(今度は逆に)unionで問題解消できた話

  • スマイルゼミのサービスとして、「みまもるトーク」というLINE的(?)なサービスがあるとのこと
  • これを中学生向けにも展開するため、ユーザ認証関連のSQLを修正した
    • WHERE句に小学生、中学生、親の条件を追加する形での修正
  • すると実行計画が狂ってしまい、インデックスが使用されなくなりシーケンシャルスキャンが発生
  • 対策として、小学生、中学生、親のそれぞれで行を絞り込んでからunionする方法で問題解消

得られた教訓

  • unionしている箇所の変更は慎重に行う必要がある
    • また、unionしてもよいのは中間結果が小さい場合のみ
  • viewの中でのunionは危険

まとめ

JustTechTalk#06 参加メモを書いてみました。他の2つの発表についても順次メモをまとめてみます。 DB関連のやらかしはケーススタディとして聞いた瞬間は「なるほど、自分も気をつけよう」と思うのですが、やはり実際にハマってみないと身につかないため、view+unionで実際に性能劣化が発生する様を手元の環境で試してみようと思います。

Linuxカーネルもくもく会#21に参加してきました

Linuxカーネルもくもく会 #21に参加してきました。iij/ipgenというパケットジェネレータで使用されている、高速パケットI/Oフレームワークの"netmap"に興味が湧きつつあり、少しずつソースコードを読み進めています。 今回と前回のもくもく会でnetmapのLinux実装部分のコードを読んでみたので、把握できた内容を簡単にまとめてみました。

netmapのコードはGitHubから取得できます。現時点ではLinux,FreeBSD,Windows環境向けにnetmapが実装されています。ちなみにnetmapは当初FreeBSDで開発されていたこともあり、netmapのコードはFreeBSDカーネルにマージされています。

Linuxにおけるopen("/dev/netmap",...)処理

さっそくLinuxにおけるnetmapの実装を見てみます。netmapのソースコードには内部構造の詳しい解説コメントが記載されており、実装の理解の助けになります。例えばnetmap.cには以下のコメントがあり、Linuxではlinux_netmap_open()から見て行くと良さそうです。

sys/dev/netmap/netmap.c
/* --- internals ----
 *
 * Roadmap to the code that implements the above.
 *
 * > 1. a process/thread issues one or more open() on /dev/netmap, to create
 * >    select()able file descriptor on which events are reported.
 *
 *      Internally, we allocate a netmap_priv_d structure, that will be
 *      initialized on ioctl(NIOCREGIF). There is one netmap_priv_d
 *      structure for each open().
 *
 *      os-specific:
 *          FreeBSD: see netmap_open() (netmap_freebsd.c)
 *          linux:   see linux_netmap_open() (netmap_linux.c) 

処理の流れを把握するため、linux_netmap_open()の関数呼び出し階層を示します。

LINUX/netmap_linux.c:
1057 static struct file_operations netmap_fops = {
1058     .owner = THIS_MODULE,
1059     .open = linux_netmap_open,
1060     .mmap = linux_netmap_mmap,
1061     LIN_IOCTL_NAME = linux_netmap_ioctl,
1062     .poll = linux_netmap_poll,
1063     .release = linux_netmap_release,
1064 };

関数の呼び出し階層は以下のようになっています。

-> LINUX/netmap_linux.c:linux_netmap_open()
  -> sys/dev/netmap/netmap.c:netmap_priv_new()
    -> LINUX/netmap_linux.c:nm_os_get_module()

linux_netmap_open()は帰り値として常に0を返すようです。変数errorは握りつぶされている気がする...。

1036 static int
1037 linux_netmap_open(struct inode *inode, struct file *file)
1038 {
1039         struct netmap_priv_d *priv;
1040         int error;
1041         (void)inode;    /* UNUSED */
1042
1043         NMG_LOCK();
1044         priv = netmap_priv_new();
1045         if (priv == NULL) {
1046                 error = -ENOMEM;
1047                 goto out;
1048         }
1049         file->private_data = priv;
1050 out:
1051         NMG_UNLOCK();
1052
1053         return (0);
1054 }

netmap_priv_new()はnetmap用の構造体(struct netmap_priv_d)用のカーネルメモリを確保し、linux_netmap_open()に返します。 先ほどの変数errorの値はlinux_netmap_open()から参照できなさそうですが、file->private_data == NULLの判定をエラーが発生しているかどうかは判定できそうです。

 959 struct netmap_priv_d*
 960 netmap_priv_new(void)
 961 {
 962         struct netmap_priv_d *priv;
 963
 964         priv = malloc(sizeof(struct netmap_priv_d), M_DEVBUF,
 965                               M_NOWAIT | M_ZERO);
 966         if (priv == NULL)
 967                 return NULL;
 968         priv->np_refs = 1;
 969         nm_os_get_module();
 970         return priv;
 971 }

nm_os_get_module()は自身のモジュールを取得するだけの処理です。

LINUX/netmap_linux.c:
  63 void
  64 nm_os_get_module(void)
  65 {
  66         __module_get(THIS_MODULE);
  67 }

処理がlinux_netmap_open()に戻ってきたのち、確保したstruct netmap_priv_dへの参照をfile->private_dataに設定します。

1036 static int
1037 linux_netmap_open(struct inode *inode, struct file *file)
1038 {
1039         struct netmap_priv_d *priv;
...
1049         file->private_data = priv;
1050 out:
1051         NMG_UNLOCK();
1052
1053         return (0);
1054 }

linux_netmap_open()の変数errorについて

linux_netmap_open()内の変数errorは握りつぶされている(呼び出し元に変数errorの値が渡らない)ように見える件、例えばLinuxのwrite()に対応する関数ではエラー値を負値にしてreturnしています。これに倣うとlinux_netmap_open()でもreturn (-ENOMEM);とするのが良いのかもしれません。

linux-4.5/fs/read_write.c:
 617 SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf,
 618                 size_t, count)
 619 {
 620         struct fd f = fdget_pos(fd);
 621         ssize_t ret = -EBADF;
 622
 623         if (f.file) {
 624                 loff_t pos = file_pos_read(f.file);
 625                 ret = vfs_write(f.file, buf, count, &pos);
 626                 if (ret >= 0)
 627                         file_pos_write(f.file, pos);
 628                 fdput_pos(f);
 629         }
 630
 631         return ret;
 632 }

Linuxカーネルmalloc()に対するグルーコード

netmap_priv_new()でmalloc()を呼んでいます。このmalloc()はLinuxでもBSD系と同じ引数で呼び出せるよう、ラッパーコードを挟んでいます。netmapはFreeBSDで実装されたこともあり、グルーコードの形で既存の処理を変更することなく別プラットフォームへの移植を行っている、ということですね。

sys/dev/netmap/netmap.c:
 959 struct netmap_priv_d*
 960 netmap_priv_new(void)
 961 {
 ...
 964         priv = malloc(sizeof(struct netmap_priv_d), M_DEVBUF,
 965                               M_NOWAIT | M_ZERO);
 966         if (priv == NULL)
 967                 return NULL;
 ...
 971 }

*_glue.hで各プラットフォーム向けのmalloc()ラッパーコードが実装されています。

$ global malloc
LINUX/bsd_glue.h
WINDOWS/win_glue.h

Linux/bsd_glue.hではkmalloc()へのラッパーになっています。

LINUX/bsd_glue.h:
304 /*
305  * in the malloc/free code we ignore the type
306  */
307 /* use volatile to fix a probable compiler error on 2.6.25 */
308 #define malloc(_size, type, flags)                      \
309         ({ volatile int _v = _size; kmalloc(_v, GFP_ATOMIC | __GFP_ZERO); })

WINDOWS/win_glue.hではwin_kernel_malloc()を挟んでExAllocatePoolWithTag APIを読んでいます。

WINDOWS/win_glue.h:
315 /*-------------------------------------------
316  *      KERNEL MEMORY ALLOCATION and management
317  */
...
321 #define malloc(size, _ty, flags)                win_kernel_malloc(size, _ty, flags)
...
325 /*
326  * we default to always allocating and zeroing
327  */
328 static void *
329 win_kernel_malloc(size_t size, int32_t ty, int flags)
330 {
331         void* mem = ExAllocatePoolWithTag(NonPagedPool, size, ty);
332
333         (void)flags;
334
335         if (mem != NULL) { // && flags & M_ZERO XXX todo
336                 RtlZeroMemory(mem, size);
337         }
338         return mem;
339 }

まとめ

Linuxにおけるnetmapのopen()に関する処理を追いかけてみました。linux_netmap_open()は比較的シンプルな実装になっています。netmapのソースコードには処理の流れやデータ構造の詳しい説明がコメントの形で記載されており理解の助けになります。

第35回「ネットワーク パケットを読む会(仮)」参加メモ

第35回「ネットワーク パケットを読む会(仮)」に参加してきました。

今回は「パケットジェネレータipgenから見るnetmap」という内容で、ipgennetmapに関するネタで発表してきました。

スライドで解説しているテスト用環境の構築手順はQiitaの記事にまとめてあります。ipgenが使用しているnetmapは面白そうな機能なので、いろいろと調べてみたいと思います。

勉強会メモ

以下は簡単ではありますが、勉強会のメモです。

この勉強会では、『ネットワークパケットを読む』と銘打ってあるように、毎回パケットキャプチャツールの更新情報についての解説があります。今回は以下のツールについてアップデート情報の解説がありました。

  • Wireshark 2.0.3が4/22にリリースされている
  • NetworkMiner
    • NetworkMiner 2.0がリリースされている
    • 2.0での変更点として、MIME Typeがバイナリなファイル(x-msdos-program等)の扱いが挙げられる。
      • これまでは.exeや.jar等のファイルは、拡張子を書き換えることで直接実行させないようになっていた
      • しかし、2.0からはこの機能がなくなっているため、安易にファイルリストのファイルを開くと悪意のあるファイルを実行してしまう恐れがあるので注意が必要
        • 機能が無効化された理由は、"Defang Executables"という有償版の機能に格上げ(?)されたため
  • Microsoft Message Analyzer
    • 公式のblogがあり、ツールの使い方や機能が紹介されているので定期的にチェックするとよさげ
  • Ostinatoというパケットジェネレータが存在するとのこと

他にも、とある通信機材を試してみたという話や、特定分野で現在も稼働し続けているWindowsXPマシンに関するセキュリティ上の懸念に関する話がありました。この勉強会はセキュリティ関連の発表も多く、自分のセキュリティに関する知識・認識のアップデートに役立ちます。

次回は6月の開催予定とのことで、興味を持たれた方はぜひ参加してみてください。

「第4回 エンジニアのためのプレゼン技術研究会」の参加メモ

第4回 エンジニアのためのプレゼン技術研究会「みんなの自由研究発表」と「前佛さんのスライドの作り方」に参加してきました。

プレゼン用の図を自動生成する話

今回のテーマは「みんなの自由研究発表」で、各人の自由研究の成果を持ち時間5分で発表するというものでした。自分も「プレゼン用の図を自動生成する話」というタイトルで発表を行いました。

Webブラウザ上で動作するmermaidAPI.jsというJavaScriptライブラリがあり、これを利用して簡単なテキストから動的に図を生成する、というネタでの発表内容でした。

サンプルプログラムは以下のURLから試してみることができます。

mermaidAPI.jsのサンプルプログラム使用手順

発表時間が5分ということもあり、当日の発表ではデモを行えなかったので、上記のサンプルプログラムを使用した簡単な作業フローを紹介します。

まずはサンプルプログラムでmermaidの記法に沿ったテキストを入力し、図を作成します。図は自動で生成(レンダリング)されます。

例として、アニメ「プリパラ」の人物相関図を作成してみます。以下のような感じですね。

f:id:furandon_pig:20151012174646p:plain

mermaidAPI.jsはSVGを生成するので、Inkscape等のSVGが編集可能なツールで図の修正や微調整が行えます。ただし、mermaidAPI.jsが生成するSVGは、テキスト表示用に独自のSVGタグを使っていたりするので、そのままではInkscapeで表示できないものがあります。上記サンプルプログラムではInkscapeで表示できるよう、生成されたSVGを一部修正しています。

f:id:furandon_pig:20151012174715p:plain

Inkscapeで表示すると以下のような感じになります。図中の矢印は直線で構成されていますが、パスの中間点を削除すると滑らかな曲線になるので、ここは手動で中間点を削除します。他にもパスの端点を矢印の形に変更したりしています。

f:id:furandon_pig:20151012234535p:plain

あとはEPS形式で保存するだけなのですが、その前に画像サイズを調整します。[ファイル]-[ドキュメントのプロパティ(D)...]を選択し、「ページ」タブの中にある「ページサイズを描画全体または選択オブジェクトに合わせる(R)」ボタンをクリックします。

f:id:furandon_pig:20151012235420p:plain

ESPで保存した画像は、KeynotePowerPointなどに挿入して利用します。Keynoteの場合は、メニューから[挿入]-[選択...]でEPSファイルを挿入できます。

f:id:furandon_pig:20151012174725p:plain

まとめ

第4回 エンジニアのためのプレゼン技術研究会で発表した内容の補足説明をまとめてみました。プレゼン技術に関するノウハウはスライドの作り方・構成方法、発表時のハマり所等、以外と範囲が広いです。今後もプレゼン技術研究会でノウハウを集めてゆければと思います。

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

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