本記事は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+)
必要なパッケージ:
systemd-networkd(通常systemdパッケージに含まれるか、個別のパッケージとして提供)jq(JSONデータ処理ツール)curl(HTTPリクエストツール)
権限: ネットワーク設定の変更には
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
解説:
OnBootSec=1min: システム起動後1分で最初の実行をトリガーします。OnUnitActiveSec=5min: サービス (update-network-config.service) が最後にアクティブになってから5分後に次の実行をトリガーします。これにより、前回の実行が完了してから次の実行が開始されることが保証されます。
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の実践を促進することができます。設定のバージョン管理、適切な権限分離、そしてロギングと監視を組み合わせることで、堅牢な自動化基盤を構築することが可能です。

