手間がかからずおいしい朝ごはんを目指して
この記事はぴょこりんクラスタ:Re Advent Calendar 2016 - Adventarのために書いたものです。
サマリ
- おいしい朝ごはんを楽して食べたい
- 冷凍チャーハンのコスパがよいのでおすすめ
- 栄養面で改善の余地が大いにあるのでなんとかしたい
はじめに
ひとり暮らしの僕にとって、朝ごはんは頭の痛い問題である。具体的には以下の3つ。
- 問題点1:できるだけ長い時間うとうとしていたいのに朝ちょっと早起きしなきゃいけない
- 問題点2:自分ひとりのために作るのが面倒*1
- 問題点3:コンビニなりパン屋なりで買うと結構高くつく(コンビニで買うものは味が濃いので毎日食べられない問題もある)
いろいろ問題はあるにせよ、朝ごはんを食べたいことには変わりないので、 何とかしてこの辺を解決する方法を見つけたい。
朝ごはんの要件
問題点から、朝ごはんの満たす要件は以下の2つになる。以降、以下の要件を満たす朝ごはん案について、実際に試したことがあるものについて述べる。
- 要件1:手早く、簡単に、おいしいものが用意できる(問題点1、2に対応)
- 要件2:コンビニなりパン屋で買うよりもお金がかからない(問題点3に対応)
案1:シリアル
シリアルのよいところ
今回言うところのシリアルは、フルーツグラノーラもしくはオールブランとする*2。 牛乳をかければ即食べられるという、手軽さの面で他の追随を許さないところがよい。 甘みがあり食べやすいのもポイント。 栄養強化もされてるっぽいので栄養面でも死角はないのではないかと思うけども、実際はよくわからない。
価格の面でも有利であり、1食換算すると30円くらいになるんじゃなかろうか(1袋500円で、2週間くらい持ったような気がする)。
シリアルの悪いところ
いつかフルーツグラノーラの甘みに耐えられなくなる。何度かフルーツグラノーラ生活をしているが、 僕はだいたい3か月〜半年くらいで耐えられなくなってくる。 オールブランとか甘くないでしょというのは確かにそうだが、それでも多少は甘みがある。 甘みがないと食べられないが、甘いだけだと辛くなるジレンマは解決の見通しが立たない。
案2:手作りおにぎり
手作りおにぎりのよいところ
米を炊いたものを冷凍しておけば、翌朝解凍して、具を混ぜるなりふりかけをかければ立派なおにぎりのできあがりである。 解凍までは3分ほどだし、具を混ぜたりふりかけをかけるだけだが作る喜びも多少は味わえるし、 何より米を食べられるのがよい*3。水気もあるので単体でもいける。
手作りおにぎりを試行するにあたり、試しに鯖フレークを買ってみたが、これが大変おいしく、 単体でむしゃむしゃ食べてしまったことは大いに反省している。
価格の面では、まあそこそこいいんじゃないですかね。コンビニでおにぎりを買うよりは相当安いよ多分。
手作りおにぎりの悪いところ
米を炊くときに増える洗い物がダメ。 1回炊くと7個おにぎりが作れるので、1回作るとしばらく洗わなくてもいいんだけど、 洗い物が増えるという心理的負担に耐え切れずに挫折。 おにぎりが悪いわけではなくて、何か洗い物があんまり好きじゃない僕のせい。 もちろんやるときはやるし、洗い物を無限にためたりも絶対しないけど、 炊飯釜とか炊飯器蓋とか、大きめのものはできれば洗いたくないなという気持ちでいっぱいになるので ダメだった。
あと、あえて言うならもっとおかずを追加して栄養バランスを取ったほうがよい。あえて言うなら。
案3:お茶漬け
お茶漬けのよいところ
ごはんを解凍して、お湯をかけるだけなので楽ちんだし、お茶漬けの素もそんなに高くないのでコスパもよい。
お茶漬けの悪いところ
手作りおにぎりの問題に加えて、飽きてしまうのが問題。 味を変えながら2週間くらい食べ続けたところで、お茶漬けに飽きてしまった。はて、何でだろう。
案4:冷凍焼きおにぎり
冷凍焼きおにぎりのよいところ
手作りおにぎりはかなりいい線まで行ったが、洗い物をしたくないという心理的ハードルに破れた。 今回は大きな洗い物をしなくてよいというところで死角がなくなった。
価格は8個入り500円なので、手作りおにぎりよりも多少高いと思うが、 コンビニおにぎりほどではないので特に問題なし。
冷凍焼きおにぎりの悪いところ
これも手作りおにぎりと同じで、栄養バランスがよくないのがいまいち。 あとは、味が単調になるのでいつか飽きそうな点だけど、 同じ味の焼きおにぎりを2週間くらい食べ続けてみたところ、2週間くらいなら大丈夫だった。 お茶漬けとの違いは全くわからないが、何となく歯ごたえに原因がありそうな気がする。
案5:冷凍チャーハン
冷凍チャーハンのよいところ
焼きおにぎりのよいところとほぼ同じ。400gで250円で、だいたい1週間ちょいくらい持つので、冷凍焼きおにぎりよりもコスパはよい。 冷凍のくせに味もよいので、今は冷凍チャーハン生活をしている。
冷凍チャーハンの悪いところ
焼きおにぎりに同じ。栄養バランス取りたい。
まとめ
冷凍チャーハンは安くて味もよく、飽きにくいのでおすすめ。 しかし、栄養バランスが明らかにわるいので、何か野菜とたんぱく質が取れるおかずを追加したほうがよい。
[参考]突撃となりの朝ごはん
同期やら先輩やらに、朝ごはんに何を食べているかを聞いた結果を以下にまとめる。 やはりごはん食よりも手軽そうなパン食が多いっぽい。 冷奴というのは結構独創性があってよいと思ったが、まだ試せていない。
- カロリーメイトとかそれに類するもの
- コンビニで買ったパン
- コンビニで買ったおにぎり
- ホームベーカリーで手作りしたパン
- パン屋で買ったパン
- 冷奴
- 栄養ドリンクとウィダーインゼリー
- 焼いた食パンとベーコンエッグ
- ベーコントースト(食パンの上にベーコンを載せてトースターで焼く)
[参考]僕の理想の朝ごはん
参考までに、僕の理想の朝ごはんメニューはこんな感じ*4。 そこそこ以上のホテルの朝ごはんはおおよそ条件を満たしてくれる上に、片付けをしなくていいので幸せにひたれる。
- ふっくら炊きあがり、水気をやや多めに含んだ白米
- だしのきいた具だくさんの味噌汁
- 焼き魚
- 塩鮭、鯖、アジの開き、さんまの塩焼き(蒲焼きでもいい)などなど、脂が乗ってて骨ごと食べられる魚がベスト。
- うるめいわしやししゃもも渋くてよいが、あまり見かけない
- 漬物
- 例えば、ふっくらした明太子、ごりっと歯ごたえのあるごぼうの味噌漬け、山形名産のだし、ぱりっとしたたくあん、酒粕で漬けた瓜などが挙げられる
- ふわっとしただし巻き卵(半熟の目玉焼きでもいい)
- ベーコンと野菜の炒めもの(野菜を取るのが趣旨なのでサラダで代替してもよい)
パンも好きだが、ごはん派です。
"pyokkorin feat. Kagamine Rin!" is so classic
この記事はぴょこりんクラスタ:Re Advent Calendar 2016のために書いたものです。
サマリ
pyokkorin feat. Kagamine Rin!に動画をつけました。この動画が全てで、あとの文章は全ておまけ。
背景
まずはこれをみてほしい。お風呂に入りながら携帯ではてブを眺めるという あれなアクティビティに勤しんでいたときに見つけた動画だ。
僕はこれを見て、「すごい!生きてる!!!」と 今思えばよくわからない理由で感動しすぎて文字通りぐずぐずに泣いた。 感動のあとは、自分も同じくMMDで何か作ってみたいという衝動が湧いてきたわけだけど、 MMDをダウンロードして使い方をざっと調べたところで何をしたらいいかよくわからなかった。 よくあるダウンロードしてチュートリアルしたら満足してしまう病気だ。
そんなところで今年もピョッコリンさん主催でアドベントカレンダーをやることになった。 まがりなりにも2年間続いたので、せっかくなら去年のアドベントカレンダーとの間に連続性を持たせたい。 去年のピョッコリンアドベントカレンダーのおさらいをしたところ、 ちょうどいい感じに12/24の回にピョッコリンさんが曲をリリースしていたので、その曲にMMDでダンスをつけた。
練習作ということで、リンちゃん*1にはジャージで踊ってもらった。 MVにジャージはどうなのよということも考えたけれど、踊っているときに手が衣装にめり込みにくく、 ひらひらしてない分長い手足の動きが目立つ(ような気がする)という利点があり、 さらには表情の動きがとてもいい感じにつけられる初心者にやさしいモデルなので、 衣装云々に関してはあまり気にしていない。これはこれでかわいらしいと思う。
振り付けは冒頭の初月 is so Classicを作った@Somubu_choさんの作ったものから 何となくリズムがあっているLove Shakeを選んだ。 本当は初月 is so Classicのダンスを当てたかったけど、 リズムが全然合わない上に、それを強引に合わせこむ技量がなかったのでリリース優先でがんばることにした。
せっかくなので苦労した点
音楽とダンスを合わせるのが一番大変だった*2。 合わないのはわかる、でも何がずれているから合わないように見えるのかがわからなくて苦労した。 結局のところ、ダンスはステップが全てで、音楽のリズムとステップが合ってれば だいたいうまくいってるように見えるけど、ステップが合わなければ何をしてもダメ。 その辺は偉大な先人が踊っているのをひたすら眺めてたら気づいた。 Michael Jackson - Thriller - YouTubeと、 Pulp Fiction - Dance Scene (HQ) - YouTubeはどれだけ見ても飽きないですね。
あとはニコニコ動画にアップロードするときのffmpegオプション。 なかなか覚えられないし今後はHandbrakeみたいにかんたんなやつでやろう*3。
kill_fasyncの引数のまぎらわしさ
tl;dr
- kill_fasyncの第2引数は飛ばしたいシグナル番号を指定するわけではない
- つまみ食いで勉強すると落とし穴にはまる危険があるので気をつける
詳細
kill_fasyncという関数をご存知だろうか。kill_fasyncとは、Linuxカーネルが提供する関数の1つで、 カーネルモジュールからユーザプロセスへシグナルを飛ばすものだ。
Kernel 4.8での実装はこんな感じ。至ってシンプルで、 正直これで何がわかるか、というところであるが、少なくとも何をいくつ引数に取るかわかる。
Linux/fs/fcntl.c - Linux Cross Reference - Free Electrons
724 void kill_fasync(struct fasync_struct **fp, int sig, int band) 725 { 726 /* First a quick test without locking: usually 727 * the list is empty. 728 */ 729 if (*fp) { 730 rcu_read_lock(); 731 kill_fasync_rcu(rcu_dereference(*fp), sig, band); 732 rcu_read_unlock(); 733 } 734 } 735 EXPORT_SYMBOL(kill_fasync);
さて、これを見て何を思うか。素直な心と有り余る読解力で読むと、第2引数のsigは飛ばすシグナルの番号だと思うのではないだろうか。 ところがこれは飛ばすシグナルの番号とは全く関係がない。
さて、kill_fasync_rcuを見てみよう。
699 static void kill_fasync_rcu(struct fasync_struct *fa, int sig, int band) 700 { 701 while (fa) { 702 struct fown_struct *fown; 703 unsigned long flags; 704 705 if (fa->magic != FASYNC_MAGIC) { 706 printk(KERN_ERR "kill_fasync: bad magic number in " 707 "fasync_struct!\n"); 708 return; 709 } 710 spin_lock_irqsave(&fa->fa_lock, flags); 711 if (fa->fa_file) { 712 fown = &fa->fa_file->f_owner; 713 /* Don't send SIGURG to processes which have not set a 714 queued signum: SIGURG has its own default signalling 715 mechanism. */ 716 if (!(sig == SIGURG && fown->signum == 0)) 717 send_sigio(fown, fa->fa_fd, band); 718 } 719 spin_unlock_irqrestore(&fa->fa_lock, flags); 720 fa = rcu_dereference(fa->fa_next); 721 } 722 }
意外にもsigはSIGURGじゃなければOKで、実際にシグナルを飛ばしていると思しき send_sigioにはsigが全く入っていない。じゃあ一体sigって何なのか。 それに飛ばしたいシグナル番号ってどこに入ってるんだ。
順番が前後するが、飛ばしたいシグナル番号はsend_sigio関数を見ればわかるよね。 send_sigioはさらにsend_sigio_to_taskという関数を呼んでる。
491 void send_sigio(struct fown_struct *fown, int fd, int band) 492 { 493 struct task_struct *p; 494 enum pid_type type; 495 struct pid *pid; 496 int group = 1; 497 498 read_lock(&fown->lock); 499 500 type = fown->pid_type; 501 if (type == PIDTYPE_MAX) { 502 group = 0; 503 type = PIDTYPE_PID; 504 } 505 506 pid = fown->pid; 507 if (!pid) 508 goto out_unlock_fown; 509 510 read_lock(&tasklist_lock); 511 do_each_pid_task(pid, type, p) { 512 send_sigio_to_task(p, fown, fd, band, group); 513 } while_each_pid_task(pid, type, p); 514 read_unlock(&tasklist_lock); 515 out_unlock_fown: 516 read_unlock(&fown->lock); 517 }
あった。シグナル番号signumはfownに入ってる。
449 static void send_sigio_to_task(struct task_struct *p, 450 struct fown_struct *fown, 451 int fd, int reason, int group) 452 { 453 /* 454 * F_SETSIG can change ->signum lockless in parallel, make 455 * sure we read it once and use the same value throughout. 456 */ 457 int signum = ACCESS_ONCE(fown->signum); 458 459 if (!sigio_perm(p, fown, signum)) 460 return; 461 462 switch (signum) { 463 siginfo_t si; 464 default: 465 /* Queue a rt signal with the appropriate fd as its 466 value. We use SI_SIGIO as the source, not 467 SI_KERNEL, since kernel signals always get 468 delivered even if we can't queue. Failure to 469 queue in this case _should_ be reported; we fall 470 back to SIGIO in that case. --sct */ 471 si.si_signo = signum; 472 si.si_errno = 0; 473 si.si_code = reason; 474 /* Make sure we are called with one of the POLL_* 475 reasons, otherwise we could leak kernel stack into 476 userspace. */ 477 BUG_ON((reason & __SI_MASK) != __SI_POLL); 478 if (reason - POLL_IN >= NSIGPOLL) 479 si.si_band = ~0L; 480 else 481 si.si_band = band_table[reason - POLL_IN]; 482 si.si_fd = fd; 483 if (!do_send_sig_info(signum, &si, p, group)) 484 break; 485 /* fall-through: fall back on the old plain SIGIO signal */ 486 case 0: 487 do_send_sig_info(SIGIO, SEND_SIG_PRIV, p, group); 488 } 489 }
でもfown_structなんてどこで設定するんだ?と思ったあなたは鋭い。 実はkill_fasyncを使うには(当たり前だが)準備がいる。 具体的にはfcntlを使えばよい。以下のスライドを見てくれれば何となくわかると思う。 F_SETSIGとシグナル番号を与えてfcntlを撃ってやればOKだ。先に見るべきだった。
http://www.cs.usfca.edu/~cruse/cs635s05/lesson22.ppt
では、SIGIOは一体何なのか。 このへんを読むと、非同期のI/Oイベントを伝えるときにはSIGIOを使うらしいというのがわかる。 要はある種のお約束的なものですね。 まあ確かにカーネルモジュールというかドライバだから、ユーザプロセスに何か通知するのって、 外部デバイスの入出力イベント以外にないよなあ。
- 6.4. Asynchronous Notification
- Asynchronous I/O on linux
- The GNU C Library: Asynchronous I/O Signals
- Man page of SIGNAL
ところでSIGURGって何で特別扱いされてるの?と気になるけど、こちらもある種のお約束的なものらしい。 SIGIOよりも用途が限定されてるようなので特別扱いなのかも。
SIGURG は、OOB データをサポートしているソケットでアウト・オブ・バンド (OOB) データを受信するときに送信される信号です。たとえば、AF_INET アドレス・ファミリーで SOCK_STREAM タイプのソケットは、 SIGURG 信号を送信するように条件付けることができます。
SIGIO は、あらゆるタイプのソケットで通常のデータ、OOB データ、エラー条件、その他が発生したときに送信される信号です。
まとめ
kill_fasyncの第2引数はある種のおまじない的にSIGIOを指定すればよいっぽい。 使い方をちゃんと勉強しないと余計なことを調べなきゃいけなくなるので、 ショートカットせずに地道に調べた方がよい。
Crowiでもプラグインを使いたかったんです
サマリ
Crowiでオレオレjavascriptを実行できるようにした。
背景
CrowiはMarkdownでかけるwikiで、見た目もおしゃれで大変いい感じなんだけど、 pluginが使えないのがちょっと残念だったので作った。
予防線
- 自分のJavascript的知能指数は2くらいしかないので、ゴリラが文字を書くようなコードになっていてつらい
- あんまりテストしていないのでバグってる可能性が多々ある
- 本家crowiとは全く関係ない
使い方
- public/js以下にpluginフォルダを作って、pluginのjsファイルを放り込む
- 以下のようにmarkdownを書くと、plugin_name.jsをロードして、同名の関数にデータを入れたjsonを引数にしてコールしてくれる。
- pluginはmarked(https://github.com/chjj/marked)をちょこっといじって実装しているので、返り値は必ずHTMLにすること。
- 1ページにつき1つのプラグインしかサポートしていない
- 複数使いたい欲張りはもっとちゃんとしたやつを作って僕にも使わせてください
```#plugin_name {json形式(改行なし)でデータを入れる} ```
どんなことができるの?
こんな感じで、markdownだけどフォームを入れ込んだりできる。要は調整さんとかdoodleとかの 出欠確認フォームみたいなのを作れるというわけですね。
プラグインサンプルよこせ
くらえ!これがJavascript的知能指数2のコードだ!!!
どういう仕組みで実現しているの?
プラグインコール
markedのRenderer(markdownからhtmlに変換するところ)をoverrideして使っています。
```#
を見つけたらpluginだと判断して、#
に続く文字列をevalして
プラグインをコール。
参考URL
Tumbling Dice — [JavaScript]marked.jsを無理矢理拡張してオレオレパーサーを作る
プラグインロード
lib/route/page.jsで、記事の中から```#<plugin_name>
を抜き出します。
renderVarsに、pluginというプロパティを定義し、<plugin_name>.js
を覚えさせておきます。
そして、lib/views/layout/layout.htmlで、pluginプロパティが定義されているときにscriptタグを追加するようにします。
なんでplugin1個だけサポートなのかというと、 Promise内にループを仕掛けるのが結構大変そうだったから。
今更ながらdockerメモ
目次
- 目次
- サマリ
- 参考文献
- dockerのインストール
- dockerでhello world
- Docker Hubからdocker imageを取得して動かす
- オレオレdocker imageを作る
- Dockerのネットワーク機能
- Dockerにおけるデータ管理
サマリ
dockerをさわってみたのでメモ。
参考文献
ていねいなユーザマニュアルが標準装備なのはたいへんありがたいですね。
dockerのインストール
Ubuntuだとaptで入れられるのでらくちんですね。 なお、以下のバージョンしか公式にサポートしていない模様。 さらに、カーネルは3.10以上じゃないとダメ。
以下、手順。僕の環境はUbuntu 14.04。 ログアウトは、端末を開き直すだけじゃダメ。
sudo apt-get install linux-image-extra-$(uname -r)
は、
aufsを使うためだけっぽいのでいらないと思う。
# aptがhttpsを使えるように $ sudo aptitude update $ sudo aptitude install apt-transport-https ca-certificates # aptのGPG keyを追加 $ sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D # /etc/apt/sources.list.d/docker.listをまっさらにして作りなおす $ echo "deb https://apt.dockerproject.org/repo ubuntu-trusty main" > /etc/apt/sources.list.d/docker.list # aptのパッケージをアップデート $ sudo aptitude update # lxc-dockerをすでに入れていたらpurgeしておこう $ sudo aptitude purge lxc-docker # aptが正しくリポジトリを認識ているか確認しよう $ sudo apt-cache policy docker-engine # インストール! $ sudo apt-get install docker-engine # Dockerグループに自分をいれておくと、sudoしなくてもdockerコマンドをたたけるようになるので # いれておく $ sudo gpasswd -a $USER Docker # 一旦ログアウトしよう $ logout
dockerでhello world
docker run hello-world
して、以下のメッセージが出てきたら成功。
最初にDocker Hubからhello-worldイメージを取ってきて、
そこから起動するみたい。
$ docker run hello-world Unable to find image 'hello-world:latest' locally latest: Pulling from library/hello-world 03f4658f8b78: Pull complete a3ed95caeb02: Pull complete Digest: sha256:8be990ef2aeb16dbcb9271ddfe2610fa6658d13f6dfb8bc72074cc1ca36966a7 Status: Downloaded newer image for hello-world:latest Hello from Docker. This message shows that your installation appears to be working correctly. To generate this message, Docker took the following steps: 1. The Docker client contacted the Docker daemon. 2. The Docker daemon pulled the "hello-world" image from the Docker Hub. 3. The Docker daemon created a new container from that image which runs the executable that produces the output you are currently reading. 4. The Docker daemon streamed that output to the Docker client, which sent it to your terminal. To try something more ambitious, you can run an Ubuntu container with: $ docker run -it ubuntu bash Share images, automate workflows, and more with a free Docker Hub account: https://hub.docker.com For more examples and ideas, visit: https://docs.docker.com/userguide/
Docker Hubからdocker imageを取得して動かす
GitHubみたいに、docker imageを置いておくことができる
Docker Hubというものがある。
公式リポジトリがいくつかあるようなので、そこから試しにubuntuを取得してみる。
docker pull <リポジトリ>:<タグ>
でdocker imageを取得できる。
<タグ>
を省略すると、最新版を取得する。
例えば、以下の例では、ubuntuリポジトリのタグ"14.04"を取得する。
$ docker pull ubuntu:14.04
取得したイメージはdocker images
で見られる。
$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE ubuntu 14.04 07c86167cdc4 2 days ago 188 MB hello-world latest 690ed74de00f 4 months ago 960 B
取得したものは、docker run
で動かすことができる。
取得しなくとも、docker run
を打つと、
勝手にDocker Hubに探しに行って取得してくれるので便利。
プログラムを動かしたままコンテナから脱出するにはCtrl-p
Ctrl-q
。
logoutしてしまうと、コンテナが停止してしまう。
# 単に動かす $ docker run ubuntu echo "hello world" ### ubuntuイメージがない場合はDocker Hubから勝手に取ってきてくれる hello world # backgroundで動かす $ docker run -d ubuntu echo "hello world" ### ubuntuイメージがない場合はDocker Hubから勝手に取ってきてくれる hello world # -itをつけると、対話型のプログラムも動かせる。 $ docker run -it ubuntu /bin/bash root@44d395e6298d:/# # コンテナに名前をつける $ docker run -it --name bash_test ubuntu /bin/bash
コンテナのリストを取得するのは、docker ps
docker ps -a
で、止まっているコンテナも見ることができる。
NAMES(コンテナの名前。以後コンテナ名とする)はDocker Engineが勝手につけてくれる(もちろん自分でつけてもよい)。 動かしたり止めたりするときに、コンテナIDを指定してもよいし、コンテナ名を指定してもよい。
$ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 44d395e6298d ubuntu:14.04 "/bin/bash" 13 seconds ago Exited (0) 3 seconds ago sharp_panini b4a331a7280d ubuntu:14.04 "echo 'hello world'" 26 seconds ago Exited (0) 25 seconds ago mad_hugle a627000187a6 hello-world "/hello" 8 minutes ago Exited (0) 8 minutes ago nostalgic_bhabha
お作法としては、コンテナは使い終わったら破棄。
停止しているコンテナの破棄は、docker rm
でできる。
# sharp_paniniを破棄 $ docker rm sharp_panini sharp_panini # いちいち指定するのが面倒なので全部破棄 $ docker rm $(docker ps -a -q) # --rmをつけてrunすると、終了後にdocker rm してくれる $ docker run --rm -it ubuntu /bin/bash
オレオレdocker imageを作る
直感的なやり方
いちばん直感的なのは、コンテナ起動して、必要なプログラムをインストールした後、コミットするやり方。 例えば、sysstatをインストール済みのコンテナを作るとすると、こんな感じになる。
$ docker run -it ubuntu:14.04 /bin/bash root@cd9379115537:/# sudo aptitude install sysstat root@cd9379115537:/# exit # -m はコミットログ。 -a は変更作成者。 # nbisco/sysstatというイメージを、testタグをつけて作成。 $ docker commit -m "Added sysstat" -a "nbisco" \ cd9379115537 nbisco/sysstat:test
Dockerfileを使うやり方
Dockerfileを使うと、いちいちコンテナ起動しなくても docker imageを作ることができる。
何はともあれ、まずはDockerfileを作る。
$ mkdir test $ cd test $ touch Dockerfile
Dockerfileを作ったら、以下を書き込む。 何のことはない、単にやってほしいことを書くだけだ。
# コメント行 FROM ubuntu:14.04 # どのイメージをベースにするか MAINTAINER nbisco <XXXX@XXXX.XXX> # イメージのメンテナはだれか RUN aptitude update && aptitude install -y sysstat # コンテナ起動後に実行するコマンド
Dockerfileを作ったら、以下のコマンドでイメージ作成。
# 最後の引数はDockerfileへのパスを指定すること。dotなので見落としがち。 $ docker build -t nbisco/sysstat:dev .
作ったimageは同じようにdocker run nbisco/sysstat:dev
で起動できる。
らくちん。
Dockerのネットワーク機能
コンテナにおけるネットワークは、(1)何とも繋がないnone、(2)ホストオンリーのhost、 (3)他コンテナやホストと繋げられるbridgeの3種類に大別できる。 デフォルトはbridge。
ネットワークは、以下のコマンドで確認できる。
$ docker network ls
NETWORK ID NAME DRIVER
18a2866682b8 none null
c288470c46f6 host host
7b369448dccb bridge bridge
ネットワークの状況は、docker network inspect <network名>
で調べられる。
※特に何も繋がっていない状況なので、"Containers"が空になっている。
$docker network inspect bridge [ { "Name": "bridge", "Id": "157fb4893818ff6e8fa7512b142b9e97df007f042d61f5bbc7bbdfbe9c9da2cb", "Scope": "local", "Driver": "bridge", "IPAM": { "Driver": "default", "Options": null, "Config": [ { "Subnet": "172.17.0.0/16" } ] }, "Containers": {}, "Options": { "com.docker.network.bridge.default_bridge": "true", "com.docker.network.bridge.enable_icc": "true", "com.docker.network.bridge.enable_ip_masquerade": "true", "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0", "com.docker.network.bridge.name": "docker0", "com.docker.network.driver.mtu": "1500" } } ]
動かしているコンテナのネットワークを切り離すこともできる。
$ docker run -d --name networktest training/webapp python app.py $ docker network disconnect bridge networktest
専用のbridgeネットワークを作って、コンテナ同士をつなげたりもできる。
# コンテナスタート時にネットワークを指定する場合 $ docker network create -d bridge my-bridge-network $ docker run -d --net=my-bridge-network --name network_test1 ubuntu $ docker run -it --net=my-bridge-network --name network_test2 ubuntu /bin/bash root@047745a86ac1:/# ping network_test1 PING db (172.18.0.3) 56(84) bytes of data. 64 bytes from db.my-bridge-network (172.18.0.3): icmp_seq=1 ttl=64 time=0.101 ms 64 bytes from db.my-bridge-network (172.18.0.3): icmp_seq=2 ttl=64 time=0.063 ms # 一旦止めれば、ネットワークに接続させることもできる $ docker run -it --name network_test3 ubuntu /bin/bash ★IPが172.18.0.0と別セグメントになっているので、届かない。 root@51057043d3ff:/# ifconfig eth0 Link encap:Ethernet HWaddr 02:42:ac:11:00:02 inet addr:172.17.0.2 Bcast:0.0.0.0 Mask:255.255.0.0 inet6 addr: fe80::42:acff:fe11:2/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:25 errors:0 dropped:0 overruns:0 frame:0 TX packets:8 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:4814 (4.8 KB) TX bytes:648 (648.0 B) lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:65536 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B) $ docker stop network_test3 $ docker network connect my-bridge-network network_test3 $ docker start network_test3 $ docker exec -it network_test3 /bin/bash root@51057043d3ff:/# ifconfig eth0 Link encap:Ethernet HWaddr 02:42:ac:11:00:02 inet addr:172.17.0.2 Bcast:0.0.0.0 Mask:255.255.0.0 inet6 addr: fe80::42:acff:fe11:2/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:26 errors:0 dropped:0 overruns:0 frame:0 TX packets:8 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:4825 (4.8 KB) TX bytes:648 (648.0 B) # ★もう1個できて、network_test1/2とつながるようになった eth1 Link encap:Ethernet HWaddr 02:42:ac:12:00:04 inet addr:172.18.0.4 Bcast:0.0.0.0 Mask:255.255.0.0 inet6 addr: fe80::42:acff:fe12:4/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:26 errors:0 dropped:0 overruns:0 frame:0 TX packets:8 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:4825 (4.8 KB) TX bytes:648 (648.0 B) lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:65536 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:0 (0.0 B) TX bytes:0 (0.0 B)
Dockerにおけるデータ管理
コンテナ起動時に-v
オプションをつけると、コンテナイメージに含まれない
ボリュームを作ることができる。例えばこんな感じ。
$ docker run -d -P -v /testweb --name web training/webapp python app.py $ docker exec -it web /bin/bash root@fc0beb95b345:/opt/webapp# ls / bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys testweb tmp usr var root@fc0beb95b345:/opt/webapp#
ボリュームの場所は、docker inspect
で調べられる。
ボリュームと言っても、単なるディレクトリに見えるので、作ったデータを取り出すのは簡単。
$ docker inspect web | less (略) "Mounts": [ { "Name": "08375e69b62c71792953d2dc83ac735c1c5cb8de63ac655557098f9446b95936", "Source": "/var/lib/docker/volumes/08375e69b62c71792953d2dc83ac735c1c5cb8de63ac655557098f9446b95936/_data", "Destination": "/testweb", "Driver": "local", "Mode": "", "RW": true, "Propagation": "" } ], (略) $ docker exec -it web /bin/bash docker exec -it web /bin/bash root@fc0beb95b345:/opt/webapp# touch /testweb/test.txt $ ls /var/lib/docker/volumes/08375e69b62c71792953d2dc83ac735c1c5cb8de63ac655557098f9446b95936/_data test.txt
既存のホストディレクトリをマウントすることもできる。 lsするとサブディレクトリ以下まで普通に見えてしまう。
$ mkdir /home/nbisco/test_docker $ touch /home/nbisco/test_docker/test.txt $ mkdir /home/nbisco/test_docker/test_docker_sub $ docker run -d -P -v /home/nbisco/test_docker:/test_docker --name web training/webapp python app.py $ docker exec -it web /bin/bash root@fce1df482e8d:/opt/webapp# ls /test_docker test_docker_sub test.txt
ディレクトリだけでなく、ファイルもマウントできちゃう。 わざわざdotfileをcloneしたりしなくて済むね。
$ docker run --rm -it -v ~/.bash_history:/root/.bash_history ubuntu /bin/bash
もちろん、他のコンテナとディレクトリを共有することもできる。
Docker Userguideには、/dbdata
を共有する例が載ってる。
コンテナ間でディレクトリを共有すると、バックアップも手軽にできちゃう。
$ docker create -v /dbdata --name dbstore training/postgres /bin/true $ docker run -d --volumes-from dbstore --name db1 training/postgres $ docker run -d --volumes-from dbstore --name db2 training/postgres # バックアップの例 $ docker run --rm --volumes-from dbstore -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata # バックアップから復元したデータでコンテナを動かす $ docker run --rm --volumes-from dbstore2 -v $(pwd):/backup ubuntu bash -c "cd /dbdata && tar xvf /backup/backup.tar --strip 1"
以上、ざっくり基本動作のメモでした。
Node.js + Express + MongoDBでログイン機構を作る
ユーザプログラムの関数トレーサを作りなおした
サマリ
ここやらここや ここで解説されている ユーザプログラムの関数トレーサftraceを手直しして、少し機能追加しました。 もとのftraceだと名前がまぎらわしいのと、2011年で開発が止まっているっぽかったので、 uftrace(Userspaceのu)と名前を変えて公開しました。 github.com
ちなみに、ftraceの開発者hamanoさんのレポジトリはこれ。 github.com
ビルド方法
テンプレ的な方法でいけます。autotoolsはまだ勉強途上でよくわからない・・・
$ git clone https://github.com/bisco/uftrace.git $ cd uftrace $ ./configure $ make $ sudo make install
使い方
gccのオプション-g -finstrument-functions
をつけてビルドしなおしたあと、
こんな感じで使えます。
$ uftrace <your_program> <your_program_args>
追加した機能たち
細々追加しましたが、いちばんの目玉はフィルタ機能。 大きなプログラムだといろいろ出すぎて困るので作りました。
- ファイル名と行数を表示(ftrace-0.90から手直しして復活)
- 関数から出た時に情報を出力(ftrace-0.90から手直しして復活)
- フィルター機能:正規表現でパターンを指定。マッチしたパターンを出力"しない"。