本稿は「KLab Engineer Advent Calendar 2025」の25日目です。記事を書いてくださった皆さん、お疲れさまでした!
はじめに
私は過去に何度か「自宅のマシン管理にAnsibleを使うぞ」と挑戦しては敗れ去ってきました。定着しなかった一番の理由は「オーバーテクノロジーでコスパが悪いから」です。同じ経験をした人も多いのではないでしょうか。
しかし、試行錯誤の末、自宅のマシン管理に最適な「ホスト指向Ansible」に辿り着きました。本稿ではその概要を紹介します。
なぜ自宅環境だとAnsibleはコスパが悪いのか
Ansibleを知らない人向けに簡単に説明すると、Ansibleは複数マシンのセットアップ手順をコード化する有名OSSです。典型的な教科書通りのAnsibleでは、次のような概念で各ホストを管理します。
graph LR
%%{init: {'theme': 'base', 'themeVariables': { 'lineColor': '#888', 'edgeLabelBackground':'#bbb' }}}%%
Host((ホスト)) -->|N:N| Group[グループ]
Group -->|N:N| Role[Role]
Role -->|1:N| Task(Task)
ソフトウェア1個をセットアップする手順のかたまりをRoleと呼びます(例:「nginx」や「MySQL」)。グループは「Webサーバ」「DBサーバ」などホストの役割を定義します。
企業のインフラなら「同じ構成のWebサーバを10台作る」ためにグループは必須です。しかし、自宅では同じ役割のマシンが複数必要になることはまずありません。それぞれのマシンが異なる役割を持つ自宅環境で、グループをどう扱うかは悩みの種になります。
また、N:N関係を表現するために設定ファイルの階層が深くなり、冗長性が高くなる点も、個人環境での取っつきにくさの原因と言えるでしょう。
自宅で使うなら「ホスト指向Ansible」
私の出した結論は、自宅ではグループの概念は不要と割り切り、下記のスタイルで運用するというものです。
%%{init: {'theme': 'base', 'themeVariables': { 'lineColor': '#888', 'edgeLabelBackground':'#bbb' }}}%%
graph LR
Host((ホスト)) -->|1:N| Role[Role]
Role -->|1:N| Task(Task)
バッサリと中間層を削り、N:N関係も排除しました。 このアプローチにより、1ホストに対応する設定ファイルは1ファイルのみ(host_vars)となり、見通しが劇的に良くなります。
具体的には、以下のように各ホスト変数ファイル内で「適用したいRoleのリスト」を定義するような方針です。Ansibleに挫折した人でも、このファイルならメンテナンスできるイメージが湧くのではないでしょうか。
--- apply_roles: - system_bootstrap - rsyslog - prometheus.prometheus.node_exporter - name: geerlingguy.docker become: true - docker_apps docker_daemon_options: log-driver: "journald" log-opts: tag: "{{ '{{' }}.Name{{ '}}' }}" docker_apps: - dockge - alloy
site.yml を汎用の実行エンジンにする
この構成を実現する最大のポイントは、メインのPlaybookである site.yml に具体的な構成情報を一切持たせないことです。
通常のPlaybookではグループごとに対応するRoleを記述しますが、この構成では全てのホストに対して「変数 apply_roles に書かれたRoleを順番に実行する」という処理だけを行います。
--- - name: Apply dynamic roles to hosts hosts: all tasks: - name: Include roles based on host variable ansible.builtin.include_role: name: "{{ role_item.name | default(role_item) }}" apply: become: "{{ role_item.become | default(false) | bool }}" tags: "{{ role_item.tags | default([]) }}" loop: "{{ apply_roles }}" loop_control: loop_var: role_item tags: - always
これにより、新しいサーバーを追加する際も site.yml を編集する必要がなくなり、新しいホスト用の host_vars ファイルを一つ作るだけで作業が完了します。
汎用Roleで省コストなコンテナ配置
私が過去にAnsibleに挫折した頃は、個人のマシン管理にDockerは大げさすぎると思っていました。特に自分しか使わない自作デーモンをコンテナ化するのはコスパが合わないと感じていました。
その考え方を変え、今回はコンテナ化できるものは全てコンテナ化するようにしました。また、コンテナ管理のための汎用のコンテナデプロイRole(docker_app)を用意しました。
この Role は、docker_apps変数で渡されたアプリ名(例: alloy)に基づいて、以下の処理を自動で行います。
- 設定ファイルの探索:
host_varsまたは Role 内のテンプレートからdocker-compose.ymlやその他設定ファイルを探す。 - 配置: サーバー上の所定のディレクトリ(例:
/opt/stacks/alloy)にファイルを配置。 - 起動: docker compose up -d を実行。
ビルド済みコンテナさえあれば、docker-compose.yml を書いて host_vars に1行追加するだけでコンテナを増やせるので、試行錯誤が多い自宅環境に非常に向いています。
まとめ
自宅でのAnsible運用が現実的になったよ、という話を紹介しました。
今回の説明用Ansibleプロジェクトは以下のURLで公開しています。過去に自宅Ansibleに挫折した方は参考にしてみてください。
本稿の取り組みで感じたのが、AI時代になって「コスパ」の考え方が以前と変わっているんじゃないか?ということです。人は楽をしたい生き物なので、優れているけど複雑すぎるものを使い続けることはできません。しかし、AIの助けで入門が楽になったり、楽に運用する方法を一緒に考えたりできるようになり、以前ならコスパが合わなかった技術が今なら採用できる、ということが今後増えていくのではないでしょうか。