hkoba blog

プログラマーです。プログラミング言語ミーハーです。ツッコミ歓迎です。よろしくどうぞ(能代口調)

シングルサーバーの管理自動化に、Make に代わるものが欲しい

シングルサーバーの管理自動化に ansible や chef は良い道具か?

ansible によるサーバー運用管理の自動化が流行っているようですね。管理対象サーバーが沢山有り、なおかつ既存のレシピ(ansible だと module?)が自分の業務に活用できるなら、強力なのでしょう。

ですが世の中には、サーバー一台でも全ての業務を余裕で処理できてしまい、かつ自社の独自アプリ群の運用が主なテーマであるようなお仕事もありまして…

そういうお仕事で、 ansible (に限らず、流行の運用自動化ツール… chef? puppet?) は果たして便利なんだろうか?という疑問が有ったりします。例えば:

  • ansible は yaml で簡潔に書けるように頑張ってるけど、ツイッターを見ていると、変数展開?の挙動に関する苦情をチラホラ見かけるような? (何となく、グリーンスパンの第10法則が思い出されます…)
    • chef の設定ファイルは ruby だから、そういうピジン言語の悩みは無さそうですが…
  • chef も、設定ファイルが ruby だとファイル名を沢山書く時に疲れませんか? doublequote の嵐で…
    • サーバーの設定はファイル名やらホスト名やら…大量の文字列を扱うので、それを汎用言語の構文に収まるように変換しながら書くことは、単純に労力が大きい、という面があるかと思います。
  • そしてしばしば、最後は shell (bash) スクリプトの呼び出しになってませんか?

みたいなことを思うのです。

生の shell(bash) スクリプトも色々辛い

かと言って生の shellスクリプトだと(確かにファイル名とかは雑に書けて楽なのですが)、 そもそも shell(bash)スクリプトの弱点として

  • 変数展開一つとっても罠が多い(初心者殺し)
  • エラー処理を堅く書くのが大変(難度が高い)
  • Unit Test を書くのも大変

という問題があります。

その上、管理自動化用の機能を全部自分で書く必要があるでしょう。例えば:

  1. べき等性の実現方法
  2. dry-run の仕組み
  3. タスクの依存関係の処理

このうち 1, 2 は shellスクリプトの書き方に慣れればある程度は対応できます。 ただ、shell(bash)スクリプトでは複雑なデータ構造のサポートが足りないため、タスクの依存関係の処理までは 手が回らないことが多いのではないでしょうか?

Makefile はファイルの mtime ベースでしか依存関係を扱えない

この 3つを一挙に解決する道具として Makefile を使う手もあります。 特に最終的な目標がファイルの作成である場合は、とても有効です。

しかし、Makefile はファイルのタイムスタンプのみに基づいて依存関係を処理します。 ですから例えば /etc/ のあるファイルの中に〇〇が記述されていなければ記述を足す、みたいな処理を書くことは困難です。 つまり、サーバーの設定ファイルの自動書き換えには向かない面があります。

bash が嫌なら Tcl はどうか

ところで皆さんお忘れですが Tcl という言語が存在します。 Tcl は文字列の扱いに関して shell よりも更に緩くかつ構文を最小限に絞っています。 にも関わらず例外処理や名前空間があり、ある程度複雑なものも書ける、本格的なプログラミング言語です。

ということは、 Tcl に Make に似た依存関係探索ライブラリーが有ったら、サーバー管理の自動化に 使えるのではないかしら?

という思いつきで実験を重ねてきたコードがこちらです。その名の通り wip ですが、やりたいことは伝わるのではと> GitHub - hkoba/wip-TclTaskRunner0: WIP: Small task runner library in Tcl. Makefile alternative.

この現在の実験版では、例えば、 webmaster というユーザーと devel というグループのべき等な追加処理を下記のように書けます。 check が検査のコードで、check が false を返した時のみ、 action ブロックが実行されます。 ** は dry-run のマーカーです。タスク定義ファイルの中には普通の Tcl の手続きや変数を定義して使うことも可能です:

#!/usr/bin/env TclTaskRunner.tcl

import {file-has} from utils.tcl

default target all dependsTasks {
    webmaster
    devel
}

target webmaster check {
    check-user $target
} action {
    ** exec useradd -s /sbin/nologin $target
}

target devel check {
    check-group $target
} action {
    ** exec groupadd $target
}

proc check-user {user} {
    # id コマンドの呼び出しても良いですが、ファイルの中身の確認の例ということで…
    file-has ^${user}: /etc/passwd
}

proc check-group {group} {
    file-has ^${group}: /etc/group
}

こういう構想にご興味ございましたら是非お話しましょう〜

いまは例えばこういう所を悩んでいます:

  • タスクを宣言するコマンドの名前は target よりも task の方が良い? (タスクランナーって名乗っているのだから…けど依存関係は target って言ったほうが自然な気がする)
  • 再帰 Make 的なものの実例が欲しい気がする。
  • リモートなタスクへの依存関係も記述したい。 (リモート実行は sshcomm の出番)
  • make -j みたいな並列実行もしたいのでは? thread か?
  • Make の重要な機能である、変数をコマンド行からオーバライドする機能が欲しい気がするが、どんな実例を書こうか

ここまで読んで下さり、有難うございました。