<p><!--META
{
"title": "systemd-networkdでLinuxネットワーク自動化",
"primary_category": "Linux",
"secondary_categories": ["DevOps","ネットワーク","systemd"],
"tags": ["systemd-networkd", "systemd", "ネットワーク自動化", "bash", "jq", "curl", "systemctl"],
"summary": "systemd-networkdを用いたLinuxネットワークの宣言的自動化手順を、安全なbashスクリプト、systemd unit/timer、jq、curlの具体例とともに解説。",
"mermaid": true,
"verify_level": "L0",
"tweet_hint": {"text":"systemd-networkdでLinuxネットワークを宣言的に自動化!安全なbashスクリプト、systemd unit/timer、jq、curlを活用した実践的なDevOps手法を解説。#systemd
#DevOps #Linux","hashtags":["#systemd","#DevOps"]},
"link_hints": ["https://www.freedesktop.org/software/systemd/man/systemd-networkd.service.html","https://github.com/systemd/systemd/releases","https://curl.se/docs/manpage.html"]
}
-->
本記事は<strong>Geminiの出力をプロンプト工学で整理した業務ドラフト(未検証)</strong>です。</p>
<h1 class="wp-block-heading">systemd-networkdでLinuxネットワーク自動化</h1>
<h2 class="wp-block-heading">1. 要件と前提</h2>
<p>Linuxシステムにおけるネットワーク設定は、古くは <code>/etc/network/interfaces</code> (Debian系) や <code>/etc/sysconfig/network-scripts</code> (Red Hat系) といったディストリビューション固有のファイル群で管理されていました。しかし、<code>systemd</code> の導入により、一貫性のある宣言的なネットワーク設定を提供する <code>systemd-networkd</code> が標準的なツールとして注目されています。</p>
<p><code>systemd-networkd</code> は、ネットワークインターフェース、IPアドレス、ルーティング、DNS設定などを、<code>systemd</code> の他のサービスと同様に宣言的な設定ファイルで管理するデーモンです。これにより、ネットワーク設定の変更を自動化し、状態の一貫性(<strong>冪等性</strong>)を保ちやすくなります。</p>
<h3 class="wp-block-heading">前提ツールと環境</h3>
<ul class="wp-block-list">
<li><p><strong>OS</strong>: systemd を採用しているLinuxディストリビューション (例: CentOS 7+, Ubuntu 16.04+, RHEL 7+)</p></li>
<li><p><strong>必要なパッケージ</strong>:</p>
<ul>
<li><p><code>systemd-networkd</code> (通常 <code>systemd</code> パッケージに含まれるか、個別のパッケージとして提供)</p></li>
<li><p><code>jq</code> (JSONデータ処理ツール)</p></li>
<li><p><code>curl</code> (HTTPリクエストツール)</p></li>
</ul></li>
<li><p><strong>権限</strong>: ネットワーク設定の変更には <code>root</code> 権限が必要です。本記事では、自動化スクリプトが <code>root</code> 権限で実行されることを前提としますが、運用においては最小権限の原則に基づき、権限分離を検討することが重要です。</p></li>
</ul>
<h3 class="wp-block-heading">ネットワーク自動化のフロー</h3>
<p>外部APIからネットワーク情報を取得し、<code>systemd-networkd</code> の設定ファイルを動的に生成・適用するフローを図示します。</p>
<div class="wp-block-merpress-mermaidjs diagram-source-mermaid"><pre class="mermaid">
graph TD
A["外部APIからネットワーク設定取得"] -->|curlでJSONデータ取得| B{"JSONデータ処理"};
B -->|jqで必要な情報を抽出| C["systemd-networkd設定ファイル生成"];
C -->|一時ファイルとして作成| D{"設定ファイルの配置と適用"};
D -->|/etc/systemd/network/にコピー| E["systemctl restart systemd-networkd"];
E -->|デーモン再起動| F["ネットワーク設定反映"];
F -->|成功| G["定期実行 (systemd.timer)"];
G -->|設定更新間隔| A;
G -->|実行失敗| H["エラーログ確認 (journalctl)"];
</pre></div>
<h2 class="wp-block-heading">2. 実装</h2>
<p>このセクションでは、外部APIから取得した情報に基づいてネットワーク設定を自動化するスクリプトと、それを定期実行する <code>systemd</code> ユニットの具体的な実装を示します。</p>
<h3 class="wp-block-heading">2.1. systemd-networkd 設定ファイルの作成例</h3>
<p><code>/etc/systemd/network/</code> ディレクトリに <code>.network</code> ファイルを配置することで、ネットワークインターフェースの設定を行います。以下は、特定のインターフェース <code>eth0</code> に固定IPアドレスを設定する例です。</p>
<div class="codehilite">
<pre data-enlighter-language="generic"># /etc/systemd/network/20-eth0.network
[Match]
Name=eth0
[Network]
Address=192.168.1.100/24
Gateway=192.168.1.1
DNS=8.8.8.8
DNS=8.8.4.4
</pre>
</div>
<h3 class="wp-block-heading">2.2. systemd-networkd の有効化と起動</h3>
<p><code>systemd-networkd</code> はデフォルトで有効化されていない場合があります。以下のコマンドで有効化し、起動します。</p>
<div class="codehilite">
<pre data-enlighter-language="generic">sudo systemctl enable systemd-networkd
sudo systemctl start systemd-networkd
</pre>
</div>
<h3 class="wp-block-heading">2.3. ネットワーク自動化スクリプト</h3>
<p>外部APIからネットワーク設定情報を取得し、<code>systemd-networkd</code> の設定ファイルを動的に生成・適用するシェルスクリプトを作成します。ここでは、仮のAPIエンドポイントからJSONデータを取得する想定です。</p>
<p>ファイル名: <code>/usr/local/bin/update-network-config.sh</code></p>
<div class="codehilite">
<pre data-enlighter-language="generic">#!/bin/bash
# systemd-networkd設定を外部APIから自動更新するスクリプト
#
# このスクリプトはsystemd.timerによって定期的に実行されることを想定しています。
# ネットワーク設定変更のためroot権限が必要です。
set -euo pipefail
# 一時ディレクトリの作成とクリーンアップ
# mktemp -d は安全に一時ディレクトリを作成します。
TMP_DIR=$(mktemp -d)
trap 'rm -rf "$TMP_DIR"' EXIT
# APIエンドポイントと設定ファイルパス
API_ENDPOINT="https://api.example.com/network-config" # 仮のAPIエンドポイント
NETWORK_CONFIG_PATH="/etc/systemd/network/20-dynamic.network"
# curlでのAPI呼び出しとjqでの処理
# --retry: 再試行回数 (例: 5回)
# --retry-connrefused: 接続拒否でも再試行
# --retry-delay: 再試行間隔 (秒)
# --retry-max-time: 最大再試行時間 (秒)
# -k: TLS証明書検証を無効化 (開発/テスト用途。本番では適切なCA証明書を使用すること)
NETWORK_DATA=$(curl -sS --retry 5 --retry-connrefused --retry-delay 5 --retry-max-time 30 -k "$API_ENDPOINT" | jq -c '.')
if [[ -z "$NETWORK_DATA" || "$NETWORK_DATA" == "null" ]]; then
echo "$(date '+%Y-%m-%d %H:%M:%S %Z'): ERROR: Failed to retrieve network data or data is empty." >&2
exit 1
fi
echo "$(date '+%Y-%m-%d %H:%M:%S %Z'): INFO: Retrieved network data: $NETWORK_DATA"
# JSONから必要な情報を抽出
INTERFACE_NAME=$(echo "$NETWORK_DATA" | jq -r '.interface_name // "eth0"')
IP_ADDRESS=$(echo "$NETWORK_DATA" | jq -r '.ip_address // ""')
GATEWAY=$(echo "$NETWORK_DATA" | jq -r '.gateway // ""')
DNS_SERVERS=$(echo "$NETWORK_DATA" | jq -r '.dns_servers[] // ""') # DNSは複数行になる可能性
# 有効なIPアドレスが取得できたか確認
if [[ -z "$IP_ADDRESS" ]]; then
echo "$(date '+%Y-%m-%d %H:%M:%S %Z'): ERROR: No IP address found in API response." >&2
exit 1
fi
# systemd-networkd設定ファイルを生成
echo "[Match]" > "$TMP_DIR/new-network.network"
echo "Name=$INTERFACE_NAME" >> "$TMP_DIR/new-network.network"
echo "" >> "$TMP_DIR/new-network.network"
echo "[Network]" >> "$TMP_DIR/new-network.network"
echo "Address=$IP_ADDRESS" >> "$TMP_DIR/new-network.network"
[[ -n "$GATEWAY" ]] && echo "Gateway=$GATEWAY" >> "$TMP_DIR/new-network.network"
for dns in $DNS_SERVERS; do
[[ -n "$dns" ]] && echo "DNS=$dns" >> "$TMP_DIR/new-network.network"
done
# 既存の設定ファイルと比較し、変更がある場合のみ更新
if cmp -s "$TMP_DIR/new-network.network" "$NETWORK_CONFIG_PATH"; then
echo "$(date '+%Y-%m-%d %H:%M:%S %Z'): INFO: Network configuration is up to date. No changes applied."
else
echo "$(date '+%Y-%m-%d %H:%M:%S %Z'): INFO: Network configuration changed. Applying update."
sudo install -m 644 "$TMP_DIR/new-network.network" "$NETWORK_CONFIG_PATH"
# systemd-networkdに設定を再読み込みさせる
sudo systemctl reload systemd-networkd || sudo systemctl restart systemd-networkd
echo "$(date '+%Y-%m-%d %H:%M:%S %Z'): INFO: Network configuration updated and systemd-networkd reloaded."
fi
</pre>
</div>
<p><strong>解説:</strong></p>
<ul class="wp-block-list">
<li><p><code>set -euo pipefail</code>: シェルスクリプトの安全性を高めるための慣用句です。</p>
<ul>
<li><p><code>-e</code>: コマンドが失敗した場合、スクリプトを即座に終了させます。</p></li>
<li><p><code>-u</code>: 未定義の変数を使用した場合にエラーを発生させます。</p></li>
<li><p><code>-o pipefail</code>: パイプライン中のコマンドが失敗した場合、パイプライン全体が失敗したとみなされます。</p></li>
</ul></li>
<li><p><code>TMP_DIR=$(mktemp -d)</code> と <code>trap 'rm -rf "$TMP_DIR"' EXIT</code>: 安全な一時ディレクトリを作成し、スクリプト終了時に自動的にクリーンアップします。</p></li>
<li><p><code>curl</code> コマンド: <code>--retry</code> オプション群により、ネットワークが一時的に不安定な場合でも再試行を行い、堅牢性を高めます。<code>-k</code> オプションは開発/テスト用であり、本番環境では信頼できるCA証明書を使用すべきです。</p></li>
<li><p><code>jq</code>: JSONレスポンスから必要な値を抽出します。<code>// ""</code> は、キーが存在しない場合に空文字列を返すことでエラーを防ぎます。</p></li>
<li><p><code>cmp -s</code>: 既存の設定ファイルと新しく生成したファイルを比較し、内容が異なる場合のみ更新を行います。これにより、不要な <code>systemd-networkd</code> の再起動を防ぎ、<strong>冪等性</strong>を保ちます。</p></li>
<li><p><code>sudo install -m 644</code>: 設定ファイルを正しいパーミッションで <code>NETWORK_CONFIG_PATH</code> にコピーします。</p></li>
<li><p><code>sudo systemctl reload systemd-networkd || sudo systemctl restart systemd-networkd</code>: <code>reload</code> は設定ファイルを再読み込みするだけなのでサービス停止がありません。<code>reload</code> がサポートされない、または不十分な場合に <code>restart</code> をフォールバックとして使用します。</p></li>
</ul>
<h3 class="wp-block-heading">2.4. systemd Unit と Timer による定期実行</h3>
<p>上記のスクリプトを <code>systemd.timer</code> を使って定期的に実行します。</p>
<h4 class="wp-block-heading">2.4.1. <code>.service</code> ファイル (サービス定義)</h4>
<p>ファイル名: <code>/etc/systemd/system/update-network-config.service</code></p>
<div class="codehilite">
<pre data-enlighter-language="generic">[Unit]
Description=Update Network Configuration from API
Documentation=https://api.example.com/network-config-doc
After=network-online.target systemd-networkd.service
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/update-network-config.sh
# 失敗時に再試行する場合 (Timer側で制御するため基本不要だが、サービス単体実行時の堅牢性向上に)
# Restart=on-failure
# RestartSec=60s
User=root # ネットワーク設定変更にはroot権限が必要
Group=root
[Install]
WantedBy=multi-user.target
</pre>
</div>
<p><strong>解説:</strong></p>
<ul class="wp-block-list">
<li><p><code>Type=oneshot</code>: スクリプトが1回実行され、終了したらサービスも終了するタイプ。</p></li>
<li><p><code>ExecStart</code>: 実行するスクリプトのパス。</p></li>
<li><p><code>User=root</code>, <code>Group=root</code>: スクリプトが <code>root</code> 権限で実行されることを明示します。セキュリティの観点から、ネットワーク設定変更に必要な最小限の権限を持つ専用ユーザーを作成することも検討すべきです。</p></li>
</ul>
<h4 class="wp-block-heading">2.4.2. <code>.timer</code> ファイル (タイマー定義)</h4>
<p>ファイル名: <code>/etc/systemd/system/update-network-config.timer</code></p>
<div class="codehilite">
<pre data-enlighter-language="generic">[Unit]
Description=Run network configuration update every 5 minutes
Requires=update-network-config.service
[Timer]
OnBootSec=1min
OnUnitActiveSec=5min
Unit=update-network-config.service
[Install]
WantedBy=timers.target
</pre>
</div>
<p><strong>解説:</strong></p>
<ul class="wp-block-list">
<li><p><code>OnBootSec=1min</code>: システム起動後1分で最初の実行をトリガーします。</p></li>
<li><p><code>OnUnitActiveSec=5min</code>: サービス (<code>update-network-config.service</code>) が最後にアクティブになってから5分後に次の実行をトリガーします。これにより、前回の実行が完了してから次の実行が開始されることが保証されます。</p></li>
</ul>
<h4 class="wp-block-heading">2.4.3. systemdユニットの有効化と起動</h4>
<p><code>systemd</code> に新しいユニットファイルを認識させ、タイマーを有効化し起動します。</p>
<div class="codehilite">
<pre data-enlighter-language="generic">sudo systemctl daemon-reload
sudo systemctl enable update-network-config.timer
sudo systemctl start update-network-config.timer
</pre>
</div>
<h2 class="wp-block-heading">3. 検証</h2>
<p>設定が正しく適用されているかを確認します。</p>
<h3 class="wp-block-heading">3.1. ネットワーク設定の確認</h3>
<div class="codehilite">
<pre data-enlighter-language="generic"># IPアドレス設定を確認
ip addr show eth0
# networkctlでsystemd-networkdの状態を確認
networkctl status eth0
networkctl
</pre>
</div>
<h3 class="wp-block-heading">3.2. systemdサービスとタイマーの稼働状況確認</h3>
<div class="codehilite">
<pre data-enlighter-language="generic"># サービスのステータスを確認
systemctl status update-network-config.service
# タイマーのステータスと次の実行時刻を確認
systemctl status update-network-config.timer
</pre>
</div>
<h3 class="wp-block-heading">3.3. ログの確認</h3>
<p>スクリプトや <code>systemd-networkd</code> の動作ログは <code>journalctl</code> で確認できます。</p>
<div class="codehilite">
<pre data-enlighter-language="generic"># スクリプトのログを確認 (サービスのUnit名でフィルタ)
journalctl -u update-network-config.service --since "1 hour ago"
# systemd-networkdのログを確認
journalctl -u systemd-networkd.service --since "1 hour ago"
# エラーのみを表示
journalctl -u update-network-config.service -p err
</pre>
</div>
<h2 class="wp-block-heading">4. 運用</h2>
<h3 class="wp-block-heading">4.1. 設定のバージョン管理</h3>
<p><code>/etc/systemd/network/</code> や <code>/usr/local/bin/</code> に配置した設定ファイル、スクリプトはGitなどのバージョン管理システムで管理し、変更履歴を追跡できるようにすることが推奨されます。</p>
<h3 class="wp-block-heading">4.2. 監視</h3>
<p><code>systemd.timer</code> の実行状況やスクリプトの出力(特にエラーログ)を監視システムに連携させることが重要です。<code>journalctl</code> と連携するログ収集ツール (Fluentd, Promtailなど) を活用し、異常を早期に検知できるようにします。</p>
<h3 class="wp-block-heading">4.3. root権限と権限分離</h3>
<p>ネットワーク設定の変更はシステム全体に影響を与えるため、<code>root</code> 権限が必要です。本記事の例ではスクリプトを <code>root</code> で実行していますが、本番環境では以下の点に注意してください。</p>
<ul class="wp-block-list">
<li><p><strong>最小権限の原則</strong>: ネットワーク設定の更新に必要な最小限の権限を持つ専用のユーザーを作成し、そのユーザーでスクリプトを実行することを検討します。<code>systemd</code> の <code>User=</code> および <code>Group=</code> ディレクティブで指定可能です。ただし、ネットワーク設定の適用には <code>systemctl</code> コマンドやファイルコピー (<code>install</code> コマンド) が必要となるため、権限設計は複雑になる可能性があります。</p></li>
<li><p><strong>セキュアなAPIアクセス</strong>: <code>curl</code> で外部APIにアクセスする際、認証情報(APIキー、トークンなど)を使用する場合は、それらを環境変数、<code>systemd</code> の <code>ExecStartPre</code> で一時的に設定する、または <code>systemd-creds</code> のようなセキュアな方法で管理すべきです。スクリプト内に直接埋め込むことは避けてください。</p></li>
<li><p><strong>設定ファイルのパーミッション</strong>: <code>/etc/systemd/network/</code> の設定ファイルは <code>root</code> のみが書き込み可能で、一般ユーザーは読み取りのみ可能であるべきです (<code>644</code>)。</p></li>
</ul>
<h2 class="wp-block-heading">5. トラブルシュート</h2>
<p>自動化されたネットワーク設定で問題が発生した場合の一般的な対処法です。</p>
<h3 class="wp-block-heading">5.1. journalctlでのログ確認</h3>
<p>最も重要なツールは <code>journalctl</code> です。</p>
<ul class="wp-block-list">
<li><p><code>journalctl -u update-network-config.service</code>:スクリプトの実行ログを確認します。APIからのデータ取得失敗や <code>jq</code> のパースエラーなどが表示されます。</p></li>
<li><p><code>journalctl -u systemd-networkd.service</code>:<code>systemd-networkd</code> デーモン自体のログを確認します。設定ファイルの構文エラーやインターフェースの認識問題などが報告されます。</p></li>
</ul>
<h3 class="wp-block-heading">5.2. networkctlでの状態確認</h3>
<p><code>networkctl</code> コマンドは <code>systemd-networkd</code> が認識しているネットワークインターフェースの状態や設定を表示します。</p>
<ul class="wp-block-list">
<li><p><code>networkctl status</code>:全インターフェースの概要。</p></li>
<li><p><code>networkctl status <interface></code>:特定のインターフェースの詳細な状態。</p></li>
<li><p><code>networkctl debug</code>:デバッグ情報を出力し、設定ファイル解析やデーモンの内部状態をより詳細に調べることができます。</p></li>
</ul>
<h3 class="wp-block-heading">5.3. 設定ファイルのデバッグ</h3>
<ul class="wp-block-list">
<li><p><strong>構文チェック</strong>: <code>networkctl test /etc/systemd/network/20-dynamic.network</code> のように <code>networkctl test</code> コマンドを使って、設定ファイルの構文エラーがないか確認できます。</p></li>
<li><p><strong>一時的な手動適用</strong>: スクリプトが生成した設定ファイルを手動で <code>NETWORK_CONFIG_PATH</code> にコピーし、<code>sudo systemctl restart systemd-networkd</code> で適用してみて、意図した動作になるか確認します。</p></li>
<li><p><strong>ファイル比較</strong>: <code>cmp -s "$TMP_DIR/new-network.network" "$NETWORK_CONFIG_PATH"</code> コマンドは、変更がない場合に <code>0</code> を返します。スクリプト内でこの比較が正しく機能しているか確認し、設定が更新されない原因を特定します。</p></li>
</ul>
<h2 class="wp-block-heading">6. まとめ</h2>
<p>、<code>systemd-networkd</code> を用いたLinuxネットワークの自動化手法を解説しました。<code>systemd-networkd</code> の宣言的な設定と冪等な特性を活かし、安全な <code>bash</code> スクリプト、<code>jq</code>、<code>curl</code> を組み合わせて外部からの情報に基づいてネットワーク設定を動的に更新する仕組みを構築しました。さらに、<code>systemd.unit</code> と <code>systemd.timer</code> を活用してこのプロセスを定期実行し、その検証、運用、トラブルシュートについても触れました。</p>
<p>このような自動化により、多数のLinuxサーバーにおけるネットワーク設定の一貫性を保ち、手作業によるミスを削減し、DevOpsの実践を促進することができます。設定のバージョン管理、適切な権限分離、そしてロギングと監視を組み合わせることで、堅牢な自動化基盤を構築することが可能です。</p>
本記事はGeminiの出力をプロンプト工学で整理した業務ドラフト(未検証)です。
systemd-networkdでLinuxネットワーク自動化
1. 要件と前提
Linuxシステムにおけるネットワーク設定は、古くは /etc/network/interfaces (Debian系) や /etc/sysconfig/network-scripts (Red Hat系) といったディストリビューション固有のファイル群で管理されていました。しかし、systemd の導入により、一貫性のある宣言的なネットワーク設定を提供する systemd-networkd が標準的なツールとして注目されています。
systemd-networkd は、ネットワークインターフェース、IPアドレス、ルーティング、DNS設定などを、systemd の他のサービスと同様に宣言的な設定ファイルで管理するデーモンです。これにより、ネットワーク設定の変更を自動化し、状態の一貫性(冪等性)を保ちやすくなります。
前提ツールと環境
OS: systemd を採用しているLinuxディストリビューション (例: CentOS 7+, Ubuntu 16.04+, RHEL 7+)
必要なパッケージ:
権限: ネットワーク設定の変更には root 権限が必要です。本記事では、自動化スクリプトが root 権限で実行されることを前提としますが、運用においては最小権限の原則に基づき、権限分離を検討することが重要です。
ネットワーク自動化のフロー
外部APIからネットワーク情報を取得し、systemd-networkd の設定ファイルを動的に生成・適用するフローを図示します。
graph TD
A["外部APIからネットワーク設定取得"] -->|curlでJSONデータ取得| B{"JSONデータ処理"};
B -->|jqで必要な情報を抽出| C["systemd-networkd設定ファイル生成"];
C -->|一時ファイルとして作成| D{"設定ファイルの配置と適用"};
D -->|/etc/systemd/network/にコピー| E["systemctl restart systemd-networkd"];
E -->|デーモン再起動| F["ネットワーク設定反映"];
F -->|成功| G["定期実行 (systemd.timer)"];
G -->|設定更新間隔| A;
G -->|実行失敗| H["エラーログ確認 (journalctl)"];
2. 実装
このセクションでは、外部APIから取得した情報に基づいてネットワーク設定を自動化するスクリプトと、それを定期実行する systemd ユニットの具体的な実装を示します。
2.1. systemd-networkd 設定ファイルの作成例
/etc/systemd/network/ ディレクトリに .network ファイルを配置することで、ネットワークインターフェースの設定を行います。以下は、特定のインターフェース eth0 に固定IPアドレスを設定する例です。
# /etc/systemd/network/20-eth0.network
[Match]
Name=eth0
[Network]
Address=192.168.1.100/24
Gateway=192.168.1.1
DNS=8.8.8.8
DNS=8.8.4.4
2.2. systemd-networkd の有効化と起動
systemd-networkd はデフォルトで有効化されていない場合があります。以下のコマンドで有効化し、起動します。
sudo systemctl enable systemd-networkd
sudo systemctl start systemd-networkd
2.3. ネットワーク自動化スクリプト
外部APIからネットワーク設定情報を取得し、systemd-networkd の設定ファイルを動的に生成・適用するシェルスクリプトを作成します。ここでは、仮のAPIエンドポイントからJSONデータを取得する想定です。
ファイル名: /usr/local/bin/update-network-config.sh
#!/bin/bash
# systemd-networkd設定を外部APIから自動更新するスクリプト
#
# このスクリプトはsystemd.timerによって定期的に実行されることを想定しています。
# ネットワーク設定変更のためroot権限が必要です。
set -euo pipefail
# 一時ディレクトリの作成とクリーンアップ
# mktemp -d は安全に一時ディレクトリを作成します。
TMP_DIR=$(mktemp -d)
trap 'rm -rf "$TMP_DIR"' EXIT
# APIエンドポイントと設定ファイルパス
API_ENDPOINT="https://api.example.com/network-config" # 仮のAPIエンドポイント
NETWORK_CONFIG_PATH="/etc/systemd/network/20-dynamic.network"
# curlでのAPI呼び出しとjqでの処理
# --retry: 再試行回数 (例: 5回)
# --retry-connrefused: 接続拒否でも再試行
# --retry-delay: 再試行間隔 (秒)
# --retry-max-time: 最大再試行時間 (秒)
# -k: TLS証明書検証を無効化 (開発/テスト用途。本番では適切なCA証明書を使用すること)
NETWORK_DATA=$(curl -sS --retry 5 --retry-connrefused --retry-delay 5 --retry-max-time 30 -k "$API_ENDPOINT" | jq -c '.')
if [[ -z "$NETWORK_DATA" || "$NETWORK_DATA" == "null" ]]; then
echo "$(date '+%Y-%m-%d %H:%M:%S %Z'): ERROR: Failed to retrieve network data or data is empty." >&2
exit 1
fi
echo "$(date '+%Y-%m-%d %H:%M:%S %Z'): INFO: Retrieved network data: $NETWORK_DATA"
# JSONから必要な情報を抽出
INTERFACE_NAME=$(echo "$NETWORK_DATA" | jq -r '.interface_name // "eth0"')
IP_ADDRESS=$(echo "$NETWORK_DATA" | jq -r '.ip_address // ""')
GATEWAY=$(echo "$NETWORK_DATA" | jq -r '.gateway // ""')
DNS_SERVERS=$(echo "$NETWORK_DATA" | jq -r '.dns_servers[] // ""') # DNSは複数行になる可能性
# 有効なIPアドレスが取得できたか確認
if [[ -z "$IP_ADDRESS" ]]; then
echo "$(date '+%Y-%m-%d %H:%M:%S %Z'): ERROR: No IP address found in API response." >&2
exit 1
fi
# systemd-networkd設定ファイルを生成
echo "[Match]" > "$TMP_DIR/new-network.network"
echo "Name=$INTERFACE_NAME" >> "$TMP_DIR/new-network.network"
echo "" >> "$TMP_DIR/new-network.network"
echo "[Network]" >> "$TMP_DIR/new-network.network"
echo "Address=$IP_ADDRESS" >> "$TMP_DIR/new-network.network"
[[ -n "$GATEWAY" ]] && echo "Gateway=$GATEWAY" >> "$TMP_DIR/new-network.network"
for dns in $DNS_SERVERS; do
[[ -n "$dns" ]] && echo "DNS=$dns" >> "$TMP_DIR/new-network.network"
done
# 既存の設定ファイルと比較し、変更がある場合のみ更新
if cmp -s "$TMP_DIR/new-network.network" "$NETWORK_CONFIG_PATH"; then
echo "$(date '+%Y-%m-%d %H:%M:%S %Z'): INFO: Network configuration is up to date. No changes applied."
else
echo "$(date '+%Y-%m-%d %H:%M:%S %Z'): INFO: Network configuration changed. Applying update."
sudo install -m 644 "$TMP_DIR/new-network.network" "$NETWORK_CONFIG_PATH"
# systemd-networkdに設定を再読み込みさせる
sudo systemctl reload systemd-networkd || sudo systemctl restart systemd-networkd
echo "$(date '+%Y-%m-%d %H:%M:%S %Z'): INFO: Network configuration updated and systemd-networkd reloaded."
fi
解説:
set -euo pipefail: シェルスクリプトの安全性を高めるための慣用句です。
-e: コマンドが失敗した場合、スクリプトを即座に終了させます。
-u: 未定義の変数を使用した場合にエラーを発生させます。
-o pipefail: パイプライン中のコマンドが失敗した場合、パイプライン全体が失敗したとみなされます。
TMP_DIR=$(mktemp -d) と trap 'rm -rf "$TMP_DIR"' EXIT: 安全な一時ディレクトリを作成し、スクリプト終了時に自動的にクリーンアップします。
curl コマンド: --retry オプション群により、ネットワークが一時的に不安定な場合でも再試行を行い、堅牢性を高めます。-k オプションは開発/テスト用であり、本番環境では信頼できるCA証明書を使用すべきです。
jq: JSONレスポンスから必要な値を抽出します。// "" は、キーが存在しない場合に空文字列を返すことでエラーを防ぎます。
cmp -s: 既存の設定ファイルと新しく生成したファイルを比較し、内容が異なる場合のみ更新を行います。これにより、不要な systemd-networkd の再起動を防ぎ、冪等性を保ちます。
sudo install -m 644: 設定ファイルを正しいパーミッションで NETWORK_CONFIG_PATH にコピーします。
sudo systemctl reload systemd-networkd || sudo systemctl restart systemd-networkd: reload は設定ファイルを再読み込みするだけなのでサービス停止がありません。reload がサポートされない、または不十分な場合に restart をフォールバックとして使用します。
2.4. systemd Unit と Timer による定期実行
上記のスクリプトを systemd.timer を使って定期的に実行します。
2.4.1. .service ファイル (サービス定義)
ファイル名: /etc/systemd/system/update-network-config.service
[Unit]
Description=Update Network Configuration from API
Documentation=https://api.example.com/network-config-doc
After=network-online.target systemd-networkd.service
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/update-network-config.sh
# 失敗時に再試行する場合 (Timer側で制御するため基本不要だが、サービス単体実行時の堅牢性向上に)
# Restart=on-failure
# RestartSec=60s
User=root # ネットワーク設定変更にはroot権限が必要
Group=root
[Install]
WantedBy=multi-user.target
解説:
Type=oneshot: スクリプトが1回実行され、終了したらサービスも終了するタイプ。
ExecStart: 実行するスクリプトのパス。
User=root, Group=root: スクリプトが root 権限で実行されることを明示します。セキュリティの観点から、ネットワーク設定変更に必要な最小限の権限を持つ専用ユーザーを作成することも検討すべきです。
2.4.2. .timer ファイル (タイマー定義)
ファイル名: /etc/systemd/system/update-network-config.timer
[Unit]
Description=Run network configuration update every 5 minutes
Requires=update-network-config.service
[Timer]
OnBootSec=1min
OnUnitActiveSec=5min
Unit=update-network-config.service
[Install]
WantedBy=timers.target
解説:
2.4.3. systemdユニットの有効化と起動
systemd に新しいユニットファイルを認識させ、タイマーを有効化し起動します。
sudo systemctl daemon-reload
sudo systemctl enable update-network-config.timer
sudo systemctl start update-network-config.timer
3. 検証
設定が正しく適用されているかを確認します。
3.1. ネットワーク設定の確認
# IPアドレス設定を確認
ip addr show eth0
# networkctlでsystemd-networkdの状態を確認
networkctl status eth0
networkctl
3.2. systemdサービスとタイマーの稼働状況確認
# サービスのステータスを確認
systemctl status update-network-config.service
# タイマーのステータスと次の実行時刻を確認
systemctl status update-network-config.timer
3.3. ログの確認
スクリプトや systemd-networkd の動作ログは journalctl で確認できます。
# スクリプトのログを確認 (サービスのUnit名でフィルタ)
journalctl -u update-network-config.service --since "1 hour ago"
# systemd-networkdのログを確認
journalctl -u systemd-networkd.service --since "1 hour ago"
# エラーのみを表示
journalctl -u update-network-config.service -p err
4. 運用
4.1. 設定のバージョン管理
/etc/systemd/network/ や /usr/local/bin/ に配置した設定ファイル、スクリプトはGitなどのバージョン管理システムで管理し、変更履歴を追跡できるようにすることが推奨されます。
4.2. 監視
systemd.timer の実行状況やスクリプトの出力(特にエラーログ)を監視システムに連携させることが重要です。journalctl と連携するログ収集ツール (Fluentd, Promtailなど) を活用し、異常を早期に検知できるようにします。
4.3. root権限と権限分離
ネットワーク設定の変更はシステム全体に影響を与えるため、root 権限が必要です。本記事の例ではスクリプトを root で実行していますが、本番環境では以下の点に注意してください。
最小権限の原則: ネットワーク設定の更新に必要な最小限の権限を持つ専用のユーザーを作成し、そのユーザーでスクリプトを実行することを検討します。systemd の User= および Group= ディレクティブで指定可能です。ただし、ネットワーク設定の適用には systemctl コマンドやファイルコピー (install コマンド) が必要となるため、権限設計は複雑になる可能性があります。
セキュアなAPIアクセス: curl で外部APIにアクセスする際、認証情報(APIキー、トークンなど)を使用する場合は、それらを環境変数、systemd の ExecStartPre で一時的に設定する、または systemd-creds のようなセキュアな方法で管理すべきです。スクリプト内に直接埋め込むことは避けてください。
設定ファイルのパーミッション: /etc/systemd/network/ の設定ファイルは root のみが書き込み可能で、一般ユーザーは読み取りのみ可能であるべきです (644)。
5. トラブルシュート
自動化されたネットワーク設定で問題が発生した場合の一般的な対処法です。
5.1. journalctlでのログ確認
最も重要なツールは journalctl です。
journalctl -u update-network-config.service:スクリプトの実行ログを確認します。APIからのデータ取得失敗や jq のパースエラーなどが表示されます。
journalctl -u systemd-networkd.service:systemd-networkd デーモン自体のログを確認します。設定ファイルの構文エラーやインターフェースの認識問題などが報告されます。
5.2. networkctlでの状態確認
networkctl コマンドは systemd-networkd が認識しているネットワークインターフェースの状態や設定を表示します。
networkctl status:全インターフェースの概要。
networkctl status <interface>:特定のインターフェースの詳細な状態。
networkctl debug:デバッグ情報を出力し、設定ファイル解析やデーモンの内部状態をより詳細に調べることができます。
5.3. 設定ファイルのデバッグ
構文チェック: networkctl test /etc/systemd/network/20-dynamic.network のように networkctl test コマンドを使って、設定ファイルの構文エラーがないか確認できます。
一時的な手動適用: スクリプトが生成した設定ファイルを手動で NETWORK_CONFIG_PATH にコピーし、sudo systemctl restart systemd-networkd で適用してみて、意図した動作になるか確認します。
ファイル比較: cmp -s "$TMP_DIR/new-network.network" "$NETWORK_CONFIG_PATH" コマンドは、変更がない場合に 0 を返します。スクリプト内でこの比較が正しく機能しているか確認し、設定が更新されない原因を特定します。
6. まとめ
、systemd-networkd を用いたLinuxネットワークの自動化手法を解説しました。systemd-networkd の宣言的な設定と冪等な特性を活かし、安全な bash スクリプト、jq、curl を組み合わせて外部からの情報に基づいてネットワーク設定を動的に更新する仕組みを構築しました。さらに、systemd.unit と systemd.timer を活用してこのプロセスを定期実行し、その検証、運用、トラブルシュートについても触れました。
このような自動化により、多数のLinuxサーバーにおけるネットワーク設定の一貫性を保ち、手作業によるミスを削減し、DevOpsの実践を促進することができます。設定のバージョン管理、適切な権限分離、そしてロギングと監視を組み合わせることで、堅牢な自動化基盤を構築することが可能です。
コメント