pyinfra — エージェントレスなインフラ自動化を純粋なPythonで
(pyinfra.com)- サーバー自動化作業をPythonコードで記述し、SSHで並列実行して、エージェントなしでコマンドを冪等に実行する
- pyinfraは同一ワークロードでAnsibleより6倍高速を掲げており、geventとSSHベースの同時実行を使用する
--dryオプションで適用前にホストごとの変更diffを確認でき、実際の実行時には結果が並列ストリーミングで返ってくる- 対象ホストにはshellとSSHだけが必要で、デーモン・状態ファイル・コントロールプレーンがない
- YAMLに制御フローをエンコードせず、Pythonのループや条件文をそのまま使うコード中心の構成を強調している
主要機能と実行フロー
-
数千台のサーバー自動化
- pyinfraはPythonネイティブのagentless自動化ツールで、SSHでコマンドを実行する
- コマンド実行は並行性、冪等性、速度を重視し、同一ワークロードでAnsibleより6倍高速を掲げている
- インストールコマンドは
$ uv tool install pyinfraである - 記載されている基本条件はMIT license、Python 3.10以上、no agents、zero configである
-
デプロイコード例
apt、files、systemd操作をPythonコードで読み込み、パッケージのインストール、テンプレートの配置、サービスのリロードを行う- 例のコードは
nginxとcertbotパッケージをインストールし、templates/nginx.conf.j2を/etc/nginx/sites-enabled/apiに配置する - 最後の段階で
systemd.service("nginx", reloaded=True)によりnginxサービスをリロードする
from pyinfra.operations import apt, files, systemd apt.packages( packages=["nginx", "certbot"], update=True, ) files.template( src="templates/nginx.conf.j2", dest="/etc/nginx/sites-enabled/api", ) systemd.service("nginx", reloaded=True) -
インベントリと実行結果
- インベントリの例では
web-01.prodからweb-23.prodまでのWebホストと、db-01.prod、db-02.prodのデータベースホストを構成する $ pyinfra inventory.py deploy.py --limit webコマンドはweb対象のみに絞って実行する- 実行出力はインベントリの読み込み、並行fact収集、
deploy.py実行、サマリーの順で進む - 例のサマリーでは23ホスト成功、18変更、失敗0、合計2.1秒を記録している
- インベントリの例では
-
変更前確認
--dryはpyinfraが実行するすべての作業についてホストごとのdiffを先に確認できるようにする- 実際の実行では結果が並列にストリーミングされ、各ホストの変更数と実行時間が表示される
- 例の実行では24ホスト中18変更、6変更なし、失敗0、合計2.1秒を記録している
特徴、Ansible比較、原則
-
pyinfraを選ぶ6つの理由
- Just Python: YAMLやJinja-in-YAMLなしで、実際の制御フローをPythonで記述する
- Concurrent SSH: geventとSSHベースで同時実行し、同一ワークロードでAnsibleより6倍高速
- Diff before apply:
--dryですべての変更を事前に確認でき、冪等な作業は再実行時にno-opになる - 0 agents: ホストにはshellとSSHだけが必要で、デーモン・状態ファイル・コントロールプレーンがない
- Scale-ready: 1ホストから10,000ホストまで動作し、並列実行とリアルタイムのストリーミング出力をサポートする
- Hackable: 10行でカスタム操作を作成でき、shellと通信するdocker、lxc、k8sに接続できる
-
Ansibleとpyinfraのコード比較
- Ansibleの例は
playbook.yml16行でnginxのインストール、テンプレートのレンダリング、ハンドラーベースのサービスリロードを構成する - pyinfraの例は
deploy.py8行で同じ流れをPythonコードで記述する - pyinfraの例では
files.templateの結果のcfg.will_changeが真のときだけsystemd.service("nginx", reloaded=True)を実行する
from pyinfra.operations import apt, files, systemd apt.packages(["nginx"], update=True) cfg = files.template( src="nginx.conf.j2", dest="/etc/nginx/sites-enabled/api", ) if cfg.will_change: systemd.service("nginx", reloaded=True) - Ansibleの例は
-
宣言
- Code > config: ループはループのままであり、制御フローをYAMLにエンコードしない
- Show, then do: まずdiffを見て、その後に適用することで予期しない変更を避ける
- Stay out of the way: エージェント、状態ファイル、コントロールプレーンなしでSSHから直接実行する
- Read like english: 操作は
apt.packages、files.template、systemd.serviceのように名詞と動詞の形で読める
-
開始コマンド
- インストールコマンドは
$ uv tool install pyinfraである - 5分のquickstartを読み、最初のホストをデプロイするよう案内している
- インストールコマンドは
1件のコメント
Lobste.rsの意見
pyinfraは、Ansibleが本来こうあるべきだったと思わせる。テンプレート混じりのYAMLに制御フローを付け足す代わりに、自動化をPythonで直接書ける
Ansibleを長く扱ってきた後だと新鮮で、別にAnsibleが嫌いだったわけでもない
対象サーバー側でもPythonを使うハイブリッドのほうがよさそうだ。ファイル更新時の引用符地獄が減り、
sedの正規表現の限界のような問題も避けられるからだpyinfraは好きだし、もっと広く使われてほしい
これまで働いた会社はどこも、Terraformを併用しているかどうかに関係なくAnsibleを使っていて、経験のないツールのために既存の自動化を全部書き直す準備ができているところはなかった
pyinfraはSysOpsがPythonを知っている必要があるが、個人的にはSysOpsはスクリプト言語をひとつくらい知っているべきだと思う。特にAnsibleでもPythonでモジュールを書けばYAMLの混沌は減らせるが、少なくともフランスでは一般的な考えではないようだ
そこまで激しい論争の種ではないかもしれない
ホームラボでAnsibleを使っていたが、だんだん窮屈に感じるようになった。YAML設定はひどく、すべてがハックのように感じられ、速度も悲しいほど遅かった。シェルコマンドをいくつか実行するためだけにサーバーに
python3が必要なのも納得できなかったGoogle AI Modeのおかげで
pyinfraを知り、ほぼ1か月使った範囲ではずっと快適だった。利点はAnsibleよりはるかに速く、繰り返しや条件をPythonで書けて、ロールやネストしたディレクトリなしでサーバー側にはシェルさえあればいいことだ。実行前に現在の状態に基づいたプランを作り、-yを付けなければ確認も求める欠点は、標準のタスク群がAnsibleのモジュールに比べてかなり小さい部分集合であること、コードがすぐにスパゲッティ化し得ること、そして
if 'web_server' in hosts.groupsのようなやり方もあまり良くないことだ。operation(..., filter_group='web_server')のほうがよいのかもしれない最悪なのは、カスタムコネクタの作成があまりにもつらいことだ。
pyinfra専用のentry pointが入ったpyproject.tomlが必要に見え、uvを使っても社内コネクタ開発は悪夢のようだ。プロジェクト内の普通のPythonファイルとして作れるべきだ数日間、pyinfraをホームラボのデプロイツールとして試しているが、Ansibleと比べて今のところ一番気に入っているのはPython構文より速度だ
Ansibleはいつも耐えられないほど遅く感じていた
たいていの場所でAnsibleやSaltの利用を置き換えたい
コードとしてのインフラが一周したのは面白い。スクリプトからYAMLへ行き、またより洗練されたスクリプトへ戻ってきた
それぞれのアプローチにはちょうどよい地点があり、Ansibleユーザーの観点から見るとpyinfraはかなり良さそうだ
Ansibleを採用する決め手になったのは、ドライランと差分表示モードだった。想定外の作業をしないと確信できたからだ
でも、pyinfra CLIにはそのようなオプションがないように見える。すべてのオプションをアルファベット順に並べたリファレンス文書を見つけられていないので、見落としているのかもしれない
—dryフラグがあり、pyinfraの最初の画面にすぐ出ている興味のある人向けに、これに似た14年前の自分のプロジェクトもある: https://github.com/sebastien/cuisine/tree/main
エージェントレスでSSHだけを使い、コア管理機能の上にPythonらしいAPIを載せているが、ドライモードはサポートしていない
私たちはOpenStackでリソースをプロビジョニングするときはAnsibleを使い、それ以外はpyinfraで処理しているが、この数年かなりうまく動いている
最大の欠点はコミュニティが小さいので、自分で解決策を書くことになる点だ。たとえば、デプロイに必要な共有シークレットはkeyring + privyでディスクに保存し、OpenStackのコンピュートインベントリをhostsデータに変換する数行のコードも自分で書いている