PXEとPreseed(Kickstart)でOSの自動インストールができるので、そのままそのサーバの設定とかも自動でできたら便利だなと思い。PreseedでOSのインストール、Chefでサーバの設定やらソフトのインストールをしようと思った。
1.まず、何も考えずにlate_commandでchef-clientを呼んでみた。
とすると Packageリソースの評価あたりでこんなエラーがでた
397 STDERR: Extracting templates from packages: 50%^MExtracting templates from packages: 100%
398 /usr/share/debconf/confmodule: line 44: 3: Bad file descriptor
これに関しては、インストール時の環境変数が邪魔をしていて下記をunsetするとうまくいきます
unset UDPKG_QUIET
unset DEBIAN_FRONTEND
unset DEBCONF_REDIR
unset DEBIAN_HAS_FRONTEND
unset DEBCONF_OLD_FD_BASE
2.邪魔する環境変数をunsetして、chef-clientを呼んでみた
とすると、またまた、Packageリソースの評価あたりでこんなのが出た。
421 initctl: Unable to connect to Upstart: Failed to connect to socket /com/ubuntu/upstart: Connection refused
422 invoke-rc.d: unknown initscript, /etc/init.d/hogehoge not found.
/com/ubuntu/upstart: Connection refused だと、そんなことあるのか?ちゃんとドメインソケットがあるのか試してみた。(late_command実行時を確認するので毎回OSインストールからやり直しつらい。。。)
Active UNIX domain sockets (only servers)
Proto RefCnt Flags Type State I-Node Path
unix 2 [ ACC ] STREAM LISTENING 7628 /var/run/dbus/system_bus_socket
あれ?それらしきものないじゃん。
インストールしてReboot後に確認してみる
root@installedMachine:/home/ukinau# netstat -lnx
Active UNIX domain sockets (only servers)
Proto RefCnt Flags Type State I-Node Path
unix 2 [ ACC ] STREAM LISTENING 7003 @/com/ubuntu/upstart
unix 2 [ ACC ] SEQPACKET LISTENING 7324 /run/udev/control
unix 2 [ ACC ] STREAM LISTENING 7628 /var/run/dbus/system_bus_socket
あっある、@/com/ubuntu/upstartの持ち主を調べてみる
root@ installedMachine:/home/ukinau# lsof | grep /com/ubuntu/upstart
init 1 root 7u unix 0xffff880036c02700 0t0 7003 @/com/ubuntu/upstart
init 1 root 10u unix 0xffff88003d08d500 0t0 7316 @/com/ubuntu/upstart
init 1 root 14u unix 0xffff88003c4e2e00 0t0 7985 @/com/ubuntu/upstart
init 1 root 16u unix 0xffff88003bc62000 0t0 8511 @/com/ubuntu/upstart
「init」がお世話してるドメインソケットだということが分かる
う〜ん、なんでPreseedのlate_command実行時は、作られてないんだろう。。。。
initが呼ばれていないなんてこと考えられないしなぁ。。。。
あっ!?
ここで重要なことに気づく(なぜもっと早く気がつかなかった)
Preseedのlate_commandは、インストール用のカーネルが動いているところで実行されるので、インストール後のカーネルとは別ものな環境で動く
今回の例でいうと、late_command実行時に動いているinitとインストール後に動いてるinitはまったく別物!!
どういうことかは、OSインストールのプロセスを考えると分かりやすい
インストールはだいたい下記のようなイメージで進む
- サーバは、OSインストール用のカーネル、カーネル初期イメージを読み込む
- diskをルートディスクとして、/targetにマウントする
- /targetにファイルシステムを構築
- 必要なパッケージなどを/target配下にぶっ込む
- /target/bootにカーネルとカーネル初期イメージを配置
- diskにgrubブートローダをインストール
- preseedのlate_commandを実行
- リブート
- 先ほどインストールしたgrubブートローダの呼び出し
- 先ほどインストールしたカーネル、カーネル初期イメージを呼び出し
- init実行
ここで注目してもらいたいのが、1~7はインストール用カーネルで動く、だからインストール後のOS(e.g Ubuntu14.04)で実行されることを想定されているスクリプトなどは動かないこともある(当然)
「2.邪魔する環境変数をunsetして、chef-clientを呼んでみた」で出たエラー
421 initctl: Unable to connect to Upstart: Failed to connect to socket /com/ubuntu/upstart: Connection refused
はupstartのdomainソケットがないことが原因だった。
これは、インストール用カーネルが最初に叩く、initがインストール後のinitとは別物で、Upstartに対応していないから起きている。
試しに、late_commandの中でps axを実行すると
1 PID TTY STAT TIME COMMAND
2 1 ? Ss 0:00 /bin/busybox init
3 2 ? S 0:00 [kthreadd]
4 3 ? S 0:00 [ksoftirqd/0]
5 4 ? S 0:00 [kworker/0:0]
なんか/bin/busybox initというのが呼ばれていることが分かる。
こいつがUpstartに対応していないせいで、chefでUpstartで動くデーモンをインストールしようとすると、エラーが起きてしまう。
しかも、apt-get install とやるとUbuntuはインストールしたdamonを即座にスタートしようとするのでUpstart/Sysvinitを呼びにいくのである。そこでエラーが出るとapt-get自体がエラーコード吐いて終了してしまう(やっかいだ)
こう考えると、Preseedのlate_commandでchefでいろいろするのは危険かも知れない。
Fileの配置、設定ファイルの編集程度なら大丈夫だとは思うが。
結論
Preseedのlate_commandで、Chef-clientを実行する際、
Upstartで動くserviceをインストールしようとすると失敗する(sysvinitで動くやつはイケました)
もし、Preseedからchef-clientを実行して全部自動化したいと思った場合は、上の制約だけ覚えといてほしい。Upstartで動くserviceがレシピ内になければうまくいくはずです。
もし、Upstartで動くServiceのレシピを適用したい場合は、やっぱりCronに仕込んだりして回避するしかなさそう。
PS.
busyboxのinitをupstartに対応させてほしい。。。。(切実)