Ansible × Jinja2:泥臭いコンフィグ管理を「芸術」へと昇華させる極限術
現場で「AnsibleでNginxのコンフィグを書いてます」というエンジニアに出会うと、よくあるのが「`template` モジュールで巨大な静的ファイルを管理し、変数を埋め込んでいるだけ」という状況だ。
それは自動化ではない。単なる「置き換え作業」だ。
真のSREは、「状態の抽象化」を愛する。Jinja2を単なるテンプレートエンジンとしてではなく、宣言的インフラを構築するための「コンパイラ」として使い倒す。本稿では、現場の複雑怪奇なミドルウェア設定を、シンプルかつ堅牢に管理するための「深淵のテクニック」を伝授する。
—
1. 「if地獄」からの脱却:スマートな条件分岐とデータ構造の最適化
コンフィグファイル内に `{% if … %}` が乱立しているテンプレートは、メンテナンス不能なレガシーコードへの第一歩だ。
アンチパターン:ベタ書きのif
悪夢の始まり
{% if ssl_enabled %}
ssl_certificate /etc/nginx/ssl/{{ domain }}.crt;
{% endif %}
推奨:ロジックをYAML(データ側)に寄せる
テンプレートは「表示」に徹するべきだ。複雑な判断は `vars` や `defaults` で完結させる。
vars/main.yml
nginx_ssl_config:
enabled: true
cert_path: “/etc/nginx/ssl/{{ domain }}.crt”
template.j2
{% if nginx_ssl_config.enabled -%}
ssl_certificate {{ nginx_ssl_config.cert_path }};
{%- endif %}
このように、「データ構造がテンプレートを決定する」という設計思想を貫くことで、テンプレート自体は数行のループで済むようになる。
—
2. ジニアスなループ処理:`selectattr` と `map` の活用
NginxのupstreamやHAProxyのbackend設定で、リストを回す際に「特定の条件を満たすものだけ」をフィルタリングしたい場面があるだろう。
稼働中のバックエンドだけを抽出して設定生成
upstream backend_servers {
{% for server in servers | selectattr(‘state’, ‘equalto’, ‘active’) %}
server {{ server.ip }}:{{ server.port }};
{% endfor %}
}
`selectattr` を使うだけで、ロジックが劇的にスッキリする。さらに `map` を併用すれば、データ加工も一行で完結する。
—
3. 禁断の秘術:カスタムJinja2フィルターの自作
標準フィルターで足りないなら、自分で書けばいい。Ansibleのプラグインディレクトリに配置するだけで、テンプレート内で独自のビジネスロジックを実行できる。
配置場所: `role_name/filter_plugins/custom_filters.py`
filter_plugins/custom_filters.py
class FilterModule(object):
def filters(self):
return {
‘to_nginx_listen’: self.to_nginx_listen
}
def to_nginx_listen(self, port_list):
# ポートリストをNginxのlistenディレクティブ形式に変換する魔法
return ” “.join([f”listen {p};” for p in port_list])
テンプレートでの利用:
{{ my_ports | to_nginx_listen }}
これで、テンプレートがどれほど複雑になっても、可読性を損なうことなく高度な処理を実装できる。
—
4. チーム開発を加速させる「神」環境設定
VS Code 拡張機能の鉄板
- Ansible (Red Hat公式): これが入っていないなら今すぐ入れること。YAMLのバリデーションと補完が劇的に変わる。
- Jinja2 (wholroyd): Jinja2の構文ハイライトは必須。これがないと視認性が死ぬ。
チーム開発の絶対ルール:`ansible-lint` をCIに組み込め
個人の勘に頼るな。「Ansible Lint」は、冪等性が担保されていないコードや、非推奨なモジュールの使用を即座に検知する。GitHub Actionsで `ansible-lint` が通らないコードはマージさせない。これがプロのチームだ。
設定ファイルのベストプラクティス:構造化データ
設定ファイルは必ず `group_vars/all.yml` を起点に階層化せよ。
推奨ディレクトリ構成
group_vars/
all.yml # 全体共通設定
webservers.yml # ロール単位の特殊設定
templates/
nginx.conf.j2
`include_vars` を使って環境ごとに設定を読み分けるのが、大規模環境での定石だ。
—
結論:IaCの真髄は「読みやすさ」にある
複雑なインフラを動的に生成する時、最も重要なのは「未来の自分が読んだときに、どれだけ早く理解できるか」だ。テンプレートの中にロジックを詰め込むな。フィルターで隠蔽し、YAMLでデータを定義せよ。
コードは、常に「読み手」のためにある。
この設計思想を取り入れた瞬間、君のAnsibleは単なる自動化スクリプトから、チームの生産性を底上げする「プラットフォーム」へと進化するはずだ。
次は、これをどうテストするか――それはまた別の機会に話そう。健闘を祈る。