multitmuxで複数サーバに同一のコマンドを発行する

tmuxで複数サーバの同時オペレーション
これを見て思い出したが、自分も同じようなshell script作った: https://github.com/keisatou/multitmux

30台とか60台に対して同じコマンドを発行したいことが運用やってると割とあるので、そういった場面で便利。multitmuxで並列にコマンド発行して楽して、確認だけは慎重にやるみたいなオペレーションを想定している。

こんな感じで使う:

まず改行区切りのホストリストファイルを用意。(まとめて一行で書く記法には未対応。)

  • host.list
host1
host2
host3
  • openコマンドにホストリストを与えると、tmuxのwindowを開いてsshする:
$ multitmux open host.list

※ 0個目(一番左端のwindowはssh元のホストのままにしてある。)

  • コマンドを送りたいときはこう:
$ multitmux exec 'hostname'
  • パスワードを送りたいときはこう:
$ multitmux password
  • 全windowを閉じたいときはこう:
$ multitmux close

会社ではこれのscreen版があって、それをまるまるパクりました。 確か古いtmuxだと-tオプションが無くて動かなかった気がする。

dockerのtrusted buildsを試してみた

trusted buildsとは?

trusted buildはdocker indexにuploadされたdocker imageとgithubのソースコードを関連付けて、「このソースコード(Dockerfile)からdocker buildされたイメージですよ」ということを証明する。buildはgithubへのpushをトリガとして自動で実行され、ソースコード(Dockerfile)に悪意が無いことを証明する訳ではないことに注意。 発端はgoogle group(docker-dev)での提案ぽい(上記のリンク先を参照)。

今回自分で試してみたtrusted buildsへのリンクは以下: https://index.docker.io/u/keisatou/centos-solr/
※ 2013/12/17追記: リポジトリ名変えた(古いものを削除して、新規作成)。

ApacheのSolrという全文検索エンジンをインストールし(深い意味は無いです)、base imageはdocker社公式のcentos:6.4を利用した。

公式の例だと"Build Bundle"というリンクがあるが、自分のには何故か無いみたい。もう少し待てば作られるのかも。まだbeta版な機能なので、ビルドの進捗状況などは参照できない。
※ -2013/12/17追記: 少し待てば"Build Bundle"リンクが作成されることを確認した。-←勘違い。。。作成されてなかった。

"unsigned long long int"型の変数の値が負のとき

メモ。

test.cc

#include <iostream>
#include <iomanip>
#include <limits> 

int main()
{
    unsigned long long int a = 1;
    unsigned long long int b = 2;
    unsigned long long int c = -1;

    std::cout << std::setw(20) << std::right <<  "1 - 2 = " << a - b << std::endl;
    std::cout << std::setw(20) << std::right <<  "-1 = " << c << std::endl; 
    std::cout << std::setw(20) << std::right <<  "ULLONG_MAX = " << ULLONG_MAX << std::endl;
    return 0;
}

実行

$ g++ test.cc
$ ./a.out
            1 - 2 = 18446744073709551615
               -1 = 18446744073709551615
       ULLONG_MAX = 18446744073709551615

負数は2の補数で表現されるので、2進数だと-1は全ビットが1となる。
その値の型をunsignedにすると、当然ながら最上位ビットも通常の値と解釈されるので、その型のMAX値と同値となる。
上記のtest.ccでは、"unsigned long long int"型の「-1」と"unsigned long long int"型のMAX値を表すULLONG_MAXが同じ値であることを示した。

ULLONG_MAXの定義は /usr/include/i386/limits.h に書かれている

$ grep ULLONG_MAX /usr/include/i386/limits.h
#define ULLONG_MAX      0xffffffffffffffffULL   /* max unsigned long long */
#define UQUAD_MAX       ULLONG_MAX

UNIXネットワークプログラミング第2版 Vol.1 買った

いろいろ忘れそうなので、その都度メモしながら読む。
UNIX Network Programming, Volume 1, Second Editionが2011/12現在のサポートページ(本に書かれているリンクとは異なるので注意。)。

UNIXネットワークプログラミング〈Vol.1〉ネットワークAPI:ソケットとXTI

UNIXネットワークプログラミング〈Vol.1〉ネットワークAPI:ソケットとXTI

  • 作者: W.リチャードスティーヴンス,W.Richard Stevens,篠田陽一
  • 出版社/メーカー: ピアソンエデュケーション
  • 発売日: 1999/07
  • メディア: 単行本
  • 購入: 8人 クリック: 151回
  • この商品を含むブログ (35件) を見る

第2版と第3版の違い

第2版は大分内容が古くなっているようなので注意。
買ってから気付いたが、、日本語訳の最新版は原著の第2版。
原著の最新版は第3版。素直に英語版を買ったほうがよさげ。。。。
第3版のサーポートページ: UNIX Network Programming

第3版では、XTIは廃れたので丸ごと削られている

というこは、日本語訳版 第2版のp.735〜p.850の115ページ分は読まなくてよい。

第3版では、トランザクション用TCP(T/TCP)も削られている

日本語訳版 第2版だと、p.359で取り上げられている。

第3版では、SCTPという比較的新しいトランスポートプロトコルの説明に3章費している
第3版では、例題の検証に使用したOSが新しくなっている

これ重要。第2版のサンプルコードだとmakeが通らないことが多いみたい。(第3版でも修正が必要な箇所はあるようだが、新しいコードを使うに越したことはない。)
第3版も買えばいいんですね!!!!!!!!!!!!!!

Unix Network Programming, Volume 1: The Sockets Networking API (Addison-Wesley Professional Computing Series)

Unix Network Programming, Volume 1: The Sockets Networking API (Addison-Wesley Professional Computing Series)

  • 作者: W. Richard Fenner, Bill Rudoff, Andrew M. Stevens
  • 出版社/メーカー: Addison-Wesley Professional
  • 発売日: 2003/10/22
  • メディア: ハードカバー
  • 購入: 1人 クリック: 46回
  • この商品を含むブログ (4件) を見る

プログラムの実行環境

以下の環境でサンプルコードをビルドした。

OS

Mac OS X 10.5.8

メモ

サンプルプログラムの./configure時のエラー
  • npv13e/libfree
    • mcast_leave.c

問題: 「error: argument ‘size’ doesn’t match prototype」と言われてmakeが失敗する。

$ gmake 
gcc -I../lib -g -O2 -D_REENTRANT -Wall   -c -o inet_ntop.o inet_ntop.c
inet_ntop.c: In function ‘inet_ntop’:
inet_ntop.c:61: error: argument ‘size’ doesn’t match prototype
/usr/include/arpa/inet.h:99: error: prototype declaration
gmake: *** [inet_ntop.o] Error 1

解決策: あとで調べて追記する。
参考ページ: あとで調べて追記する。

カーネルの再構築

以下の作業中にカーネルの再構築が必要になったので、方法を調べて実施する。
jail内でのmount - 英語とプログラミング気まぐれ日記

現在のカーネルのバージョンを確認しておく

この作業は必須ではない。念の為。

$ sysctl kern.version
kern.version: FreeBSD 7.3-RELEASE-p2 #0: Mon Jul 12 19:04:04 UTC 2010
    root@i386-builder.daemonology.net:/usr/obj/usr/src/sys/GENERIC

使用されているカーネルモジュールを調べる。

$ kldstat 
Id Refs Address    Size     Name
 1    5 0xc0400000 a220cc   kernel
 2    1 0xc0e23000 6a500    acpi.ko
 3    1 0xc277a000 4000     nullfs.ko
 4    1 0xc27b6000 4000     fdescfs.ko

カーネルモジュールは /boot/kernel/ディレクトリ 以下に大量に存在するが、現在使用されているのは"acpi"、"nullfs"、"fdescfs"だけであることが分かった。

これらのモジュールだけコンパイルされるよう設定する

カーネルの設定ファイルを編集する。
ここでは、GENERICカーネルの設定ファイル "/usr/src/sys/i386/conf/GENERIC" をコピーして編集することにする。

GENERICカーネルの設定ファイル(GENERIC)(CUSTOM_NULLFS)にコピー
$ cd /usr/src/sys/i386/conf/
$ sudo cp GENERIC CUSTOM_NULLFS

コピーしたファイルを編集。
kldstatで調べたモジュール名を空白区切りで指定する。
$ sudo vim CUSTOM_NULLFS
makeoptions  MODULES_OVERRIDE="linux acpi/acpi nullfs fdescfs"
    ※ モジュール名は /usr/src/sys/modules 以下にあるディレクトリ名らしい

カーネルのコンパイル

configの実行
コンパイル用のディレクトリが作成される
$ cd /usr/src/sys/i386/conf/
$ sudo config CUSTOM_NULLFS

コンパイル用のディレクトリに移動
$ cd /usr/src/sys/compile/CUSTOM_NULLFS

コンパイルの実行
$ sudo make depend
$ sudo make

現在のカーネルと入れ替える

$ sudo make install

再起動して、カーネルが変更されていることを確認。

$ sysctl kern.version
kern.version: FreeBSD 7.3-RELEASE-p4 #0: Sun Apr  3 20:26:57 JST 2011
    root@test-freebsd.dip.jp:/usr/src/sys/i386/compile/CUSTOM_NULLFS

おお、うまくいったみたい。

Mojolicious を使ってみる

ものすごいドキュメントが充実してる。
Mojolicious - Perl real-time web framework

とりあえずインストール

$ cpanm Mojolicious
Fetching http://search.cpan.org/CPAN/authors/id/K/KR/KRAIH/Mojolicious-1.12.tar.gz ... OK
Configuring Mojolicious-1.12 ... OK
Building and testing Mojolicious-1.12 for Mojolicious ... OK
Successfully installed Mojolicious-1.12

とりあえず以下で感じをつかんだ

Mojolicious::Guides - Mojolicious guide to the galaxy

Mojolicious::Lite でプロトタイプを作成してから、Mojolicious アプリに仕上げていく過程を以下で学んだ

Mojolicious::Guides - Mojolicious guide to the galaxy
躓いたところを以下にメモしておく。

to()メソッドの引数が何を意味しているか分からなかった
  package MyApp;
  use Mojo::Base 'Mojolicious';
...
    $r->any('/')->to('login#index')->name('index');
は
    $r->any('/')->to(controller => 'login', action => 'index')->name('index');
と同じ。

上記の例だと、「/」にアクセスすると、lib/MyApp/Login.pm コントローラの indexアクションメソッドが呼ばれる。
to()メソッドについて詳しくはMojolicious::Guides - Mojolicious guide to the galaxyに載っている。
Mojoliciousのディレクトリ構成はMojolicious::Guides - Mojolicious guide to the galaxyを参照。

テストコードをよく理解していない

とりあえずコピペで動いた。
あとでいろいろ試す。

jail内でのmount

jail内でmount_nullfsができなくて嵌った。

mount_nullfs: Operation not permitted

とか言われる。


調べてみると、FreeBSD Handbookに「The root user is not allowed to mount or unmount file systems from within a jail(8). 」と書いてあった。。
15.5. Fine Tuning and Administration


jail(8)のmanに詳細があった:

   Jails and File Systems
     It is not possible to mount(8) or umount(8) any file system inside a jail
     unless the file system is marked jail-friendly.  See
     security.jail.mount_allowed in the Sysctl MIB Entries section.

jail-friendlyフラグが立っているファイルシステムでなければjail内でのマウントは不可能らしい。
更に"security.jail.mount_allowed" を見ろとある。

     security.jail.mount_allowed
          This MIB entry determines if a privileged user inside a jail will be
          able to mount and unmount file system types marked as jail-friendly.
          The lsvfs(1) command can be used to find file system types available
          for mount from within a jail.  This functionality is disabled by
          default, but can be enabled by setting this MIB entry to 1.

このフラグが立っていても、そのファイルシステムがjail-friendlyでなければjail内でマウントできないぽい。
ファイルシステムがjail-friendlyかどうか調べるには、「lsvfs(1)」が使えるとのこと。


lsvfs(1)をjailホストで実行してみる。

$ lsvfs 
Filesystem                        Refs Flags
-------------------------------- ----- ---------------
ufs                                  4 
procfs                               1 synthetic
nfs                                  0 network
devfs                                2 synthetic
msdosfs                              0 
cd9660                               0 read-only
nfs4                                 0 network
nullfs                               1 loopback
fdescfs                              1 synthetic

lsvfsのmanを見たが、「Flags」の意味が分からないのでソースを読む。

$ locate lsvfs
/usr/bin/lsvfs
/usr/jails/basejail/usr/bin/lsvfs
/usr/jails/tinderbox.dip.jp/basejail/usr/bin/lsvfs
/usr/share/man/man1/lsvfs.1.gz
/usr/src/usr.bin/lsvfs
/usr/src/usr.bin/lsvfs/Makefile
/usr/src/usr.bin/lsvfs/lsvfs.1
/usr/src/usr.bin/lsvfs/lsvfs.c


$ vim /usr/src/usr.bin/lsvfs/lsvfs.c
static const char *
fmt_flags(int flags)
{ 
  /*
   * NB: if you add new flags, don't forget to add them here vvvvvv too.
   */
  static char buf[sizeof
    "static, network, read-only, synthetic, loopback, unicode, jail"];
  int comma = 0;

  buf[0] = '\0';

  if(flags & VFCF_STATIC) {
    if(comma++) strcat(buf, ", ");
    strcat(buf, "static");
  }

  if(flags & VFCF_NETWORK) {
    if(comma++) strcat(buf, ", ");
    strcat(buf, "network");
  }

  if(flags & VFCF_READONLY) {
    if(comma++) strcat(buf, ", ");
    strcat(buf, "read-only");
  }

  if(flags & VFCF_SYNTHETIC) {
    if(comma++) strcat(buf, ", ");
    strcat(buf, "synthetic");
  }

  if(flags & VFCF_LOOPBACK) {
    if(comma++) strcat(buf, ", ");
    strcat(buf, "loopback");
  }

  if(flags & VFCF_UNICODE) {
    if(comma++) strcat(buf, ", ");
    strcat(buf, "unicode");
  }

  if(flags & VFCF_JAIL) {
    if(comma++) strcat(buf, ", ");
    strcat(buf, "jail");
  }

  return buf;
}

VFCF_*ヘッダの意味を調べる。

$ grep -nr VFCF_LOOPBACK /usr/include/
/usr/include/sys/mount.h:453:#define    VFCF_LOOPBACK   0x00100000      /* aliases some other mounted FS */

$ vi /usr/include/sys/mount.h
/*
 * NB: these flags refer to IMPLEMENTATION properties, not properties of
 * any actual mounts; i.e., it does not make sense to change the flags.
 */
#define VFCF_STATIC     0x00010000      /* statically compiled into kernel */
#define VFCF_NETWORK    0x00020000      /* may get data over the network */
#define VFCF_READONLY   0x00040000      /* writes are not implemented */
#define VFCF_SYNTHETIC  0x00080000      /* data does not represent real files */
#define VFCF_LOOPBACK   0x00100000      /* aliases some other mounted FS */
#define VFCF_UNICODE    0x00200000      /* stores file names as Unicode */
#define VFCF_JAIL       0x00400000      /* can be mounted from within a jail */

VFCF_JAILというフラグが立っているファイルシステムであれば、jail内からマウント可能らしい。改めてlsvfsの出力を見てみる。

$ lsvfs
Filesystem                        Refs Flags
-------------------------------- ----- ---------------
ufs                                  4 
procfs                               1 synthetic
nfs                                  0 network
devfs                                2 synthetic
msdosfs                              0 
cd9660                               0 read-only
nfs4                                 0 network
nullfs                               1 loopback
fdescfs                              1 synthetic

nullfsはjailフラグが立っていないのでjail内からのマウントはできない…。
他のファイルシステムを見てもjailフラグが立っているものは無いので、この中にはjail内からのマウントができるファイルシステムは無いということになる。。


以下のリンクでも同じことが議論されていた:
Re: mount_nullfs inside a jail
このリンク先の内容を信じると、以下のようにしたら、nullfsでもjail内でマウントできるようになったとのこと:

/usr/src/sys/fs/nullfs/null_vfsops.c の以下の行を編集

/* VFS_SET(null_vfsops, nullfs, VFCF_LOOPBACK); */
VFS_SET(null_vfsops, nullfs, VFCF_LOOPBACK | VFCF_JAIL);

たぶんカーネルの再構築が必要。
やったことないので調べる。
ttt: FreeBSD 6.3-RELEASEとiPod nano 8GB (第三世代) など参考にさせていただいて、あとでやってみる。

security.jail.enforce_statfs を 0 にセットする

これでjail内からでもnullfsマウントができるようになったらしい。

TODO

/usr/src/sys/fs/nullfs/null_vfsops.c を編集
FreeBSDのカーネル再構築方法を調べて実施。
yak shaving...