【ネットワーク自動化】第2回:Ansibleはじめの一歩

導入

ネットワーク自動化シリーズの第2回です。

第1回では、ネットワーク運用における課題を解決する鍵として「ネットワーク自動化」がなぜ重要なのか、そして自動化のレベルや主要な技術要素(Ansible, Python, APIなど)の概要について解説しました。

第2回となる今回は、ネットワーク自動化ツールとして人気の高い「Ansible」に焦点を当てます。 Ansibleがなぜ多くのネットワークエンジニアに選ばれているのか、その基本的な仕組みから、実際にネットワーク機器を操作するための「Playbook」の書き方、そして具体的な実行例までを、ステップバイステップで述べていきます。

本文

1. なぜネットワーク自動化にAnsibleなのか?

数ある自動化ツールの中で、特にネットワーク分野でAnsibleが広く採用されているのには、いくつかの理由があります。

  • エージェントレス: Ansibleは、管理対象のネットワーク機器に専用のエージェントソフトウェアをインストールする必要がありません。SSH(またはNETCONFなど)で接続できれば管理できるため、既存のネットワーク環境への導入ハードルが低いのが大きなメリットです。
  • YAMLによるシンプルな記述: 自動化の手順を記述する「Playbook」は、人間が読み書きしやすいYAML形式で記述します。プログラミング経験が浅いエンジニアでも比較的理解しやすく、学習コストが低いとされています。
  • 豊富なネットワークモジュール: Cisco IOS/NX-OS/IOS-XR, Juniper Junos, Arista EOS, FortiOS, Palo Alto PAN-OSなど、主要なネットワークOSに対応した多数のモジュールが公式またはコミュニティによって提供されています。これにより、ベンダー固有のコマンドやAPIを意識することなく、統一的な方法で様々な機器を操作できます。
  • 冪等性 (Idempotency) の担保: 多くのAnsibleモジュールは「冪等性」を持つように設計されています。これは、Playbookを何度実行しても、結果が同じになる(=意図しない変更が繰り返されない)という重要な性質です。例えば、「NTPサーバーを設定する」というタスクは、既に設定されていれば何もせず、設定されていなければ設定するという動作になります。これにより、安心して自動化処理を実行できます。
  • 大規模なコミュニティ: 利用者が多く、情報交換が活発なため、学習リソースやサンプルコードを見つけやすいのも利点です。

2. Ansibleの基本コンセプト

Ansibleを使いこなす上で、まずは基本的な構成要素と用語を理解しましょう。

  • コントロールノード (Control Node): Ansibleをインストールし、Playbookを実行するマシンです。通常、LinuxやmacOSが使われます。(Windowsの場合はWSLなどが必要)
  • 管理対象ノード (Managed Node / Host): Ansibleによって管理されるサーバーやネットワーク機器のことです。
  • インベントリ (Inventory): 管理対象ノードのリスト(ホスト名やIPアドレス)と、それらのノードへの接続情報(ユーザー名、パスワード/SSHキー、OSタイプなど)を定義するファイルです。静的なファイル(INI形式やYAML形式)で記述するほか、外部のCMDBなどから動的に生成することも可能です。
  • Playbook: 自動化したい一連のタスク(処理)をYAML形式で記述したファイルです。どのホストに対して(hosts)、どのようなタスクを(tasks)、どのような順序で実行するかを定義します。
  • モジュール (Module): 特定の機能を持つ部品です。例えば、コマンドを実行するモジュール (command, ios_command)、設定を変更するモジュール (ios_config, junos_config)、ファイルをコピーするモジュール (copy) など、様々なモジュールが用意されています。Playbookの tasks の中でこれらのモジュールを呼び出して使います。
  • タスク (Task): Playbook内で定義される個々の操作単位です。通常、一つのタスクで一つのモジュールを実行します。
  • Play: Playbook内で特定のホストグループに対して実行される、一連のタスクのまとまりです。一つのPlaybookに複数のPlayを含めることもできます。
  • (オプション) Role: 複数のタスク、変数、ファイル、テンプレートなどを再利用可能な単位としてまとめたものです。複雑なPlaybookを整理したり、共通の処理を部品化したりするのに役立ちます。

3. 環境構築のポイント

Ansibleでネットワーク機器を操作するための環境を準備します。

  • コントロールノードの準備:
    • Linux(Ubuntu, CentOSなど)またはmacOSを用意します。
    • Python 3がインストールされていることを確認します。
    • pip (Pythonのパッケージ管理ツール) を使ってAnsibleをインストールします:

pip install ansible ansible-core
# ansible-coreにネットワーク関連モジュールが多く含まれる
# 必要に応じて特定のコレクションもインストール
# ansible-galaxy collection install cisco.ios junipernetworks.junos …

  • 管理対象ノード (ネットワーク機器) の準備:
    • SSH接続の有効化: コントロールノードから管理対象のネットワーク機器へSSHで接続できるように設定します。ユーザー名、パスワード認証、またはSSH鍵認証が必要です。セキュリティのため、SSH鍵認証を強く推奨します。
    • 権限: コマンド実行や設定変更に必要な権限を持つユーザーアカウントを用意します。
    • (オプション) APIの有効化: NETCONFやRESTCONFを使用する場合は、機器側でそれぞれの機能を有効にする設定が必要です。
  • 接続確認: コントロールノードから ssh user@device_ip コマンドでネットワーク機器にログインできることを確認しておきましょう。

4. インベントリファイルの作成

どの機器に対してPlaybookを実行するかを定義するインベントリファイルを作成します。ここではYAML形式の例を示します。

---
all: # 全てのホストを含む暗黙のグループ
  children: # グループを階層化できる
    cisco_routers: # 'cisco_routers' という名前のグループ
      hosts: # このグループに属するホストを定義
        r1: # ホスト名 (任意)
          ansible_host: 192.168.10.1 # 接続先IPアドレス or FQDN
        r2:
          ansible_host: 192.168.10.2
      vars: # このグループのホストに共通の変数を定義
        ansible_network_os: cisco.ios.ios # OSタイプを指定 (必須)
        ansible_user: network_admin # SSHユーザー名
        # パスワードや鍵はPlaybook実行時に指定するか、Vaultで暗号化推奨
        # ansible_password: "{{ vault_network_password }}"
        # ansible_ssh_private_key_file: ~/.ssh/id_rsa_ansible

    juniper_switches: # 'juniper_switches' という名前のグループ
      hosts:
        sw1:
          ansible_host: 172.16.0.1
        sw2:
          ansible_host: 172.16.0.2
      vars:
        ansible_network_os: junipernetworks.junos.junos
        ansible_user: juniper_admin
        ansible_connection: netconf # Junosの場合、NETCONF接続が良い場合も (デフォルトはnetwork_cli)

# グループに属さないホストも定義可能
# ungrouped_host:
#   ansible_host: 10.0.0.1
#   ansible_network_os: arista.eos.eos
#   ansible_user: arista_user

  • children: でホストをグループ化できます。グループ名は任意です (cisco_routers, juniper_switches など)。
  • hosts: で各ホストの論理名 (r1, sw1 など) と接続先IP/ホスト名 (ansible_host) を定義します。
  • vars: で接続に必要な情報を定義します。
    • ansible_network_os: どのベンダー/OS向けのモジュールを使うかを指定する重要な変数です。 (例: cisco.ios.ios, junipernetworks.junos.junos)
    • ansible_user: SSH接続ユーザー名。
    • ansible_password / ansible_ssh_private_key_file: 認証情報。ここに平文で書くのは避け、ansible-vault で暗号化するか、実行時に -k (パスワード) や --private-key (鍵) オプションで指定するのが安全です。 [アフィリエイト候補: Ansible Vault ドキュメント]
    • ansible_connection: 接続方法を指定します。ネットワーク機器の場合は network_cli (SSH経由でCLI操作) や netconf がよく使われます。省略時は network_cli になることが多いです。

5. Playbookの作成と実行

いよいよ、自動化の処理内容を Playbook に記述していきます。

例1: 複数デバイスからの情報収集 (get_info.yml)

---
- name: ネットワーク機器から情報を収集するPlay # Playの名前 (任意)
  hosts: cisco_routers:juniper_switches # 対象ホスト (インベントリのグループ名やホスト名を指定)
  gather_facts: no # OSのファクト収集はネットワーク機器では通常不要
  connection: network_cli # CLI経由で接続 (インベントリで指定があればそちらが優先)

  tasks: # 実行するタスクのリスト
    - name: Cisco IOS - show version を実行 # タスクの名前 (任意、分かりやすく)
      cisco.ios.ios_command: # 使用するモジュール名 (OSコレクション.モジュール名)
        commands: # 実行するコマンドのリスト
          - show version | include Version # パイプなども使える
      when: ansible_network_os == 'cisco.ios.ios' # このタスクを実行する条件 (IOSの場合のみ)
      register: ios_version_result # モジュールの実行結果を変数に格納

    - name: Juniper Junos - show version を実行
      junipernetworks.junos.junos_command: # Junos用モジュール
        commands:
          - show version | match "Junos:|Model:"
      when: ansible_network_os == 'junipernetworks.junos.junos'
      register: junos_version_result

    - name: 結果を表示 (Cisco IOS)
      debug: # デバッグ用モジュール
        var: ios_version_result.stdout_lines # 実行結果の標準出力を行リストで表示
      when: ios_version_result is defined # 前のタスクが実行された場合のみ

    - name: 結果を表示 (Juniper Junos)
      debug:
        var: junos_version_result.stdout_lines
      when: junos_version_result is defined

Playbook のポイント:

  • --- で始まり、インデント(字下げ)が重要な意味を持ちます。
  • hosts: でインベントリ内のどのホスト/グループを対象にするか指定します。コロン : で複数指定も可能です。
  • tasks: の下に実行したい処理を順番に記述します。
  • 各タスクでは name: で分かりやすい名前をつけ、適切なモジュールを指定します。
  • when: で特定の条件(ここではOSタイプ)の場合のみタスクを実行するように制御できます。
  • register: でモジュールの実行結果(標準出力など)を変数に保存し、後のタスク (debug など) で利用できます。

実行方法:

# パスワード認証の場合 (-k オプションで実行時にパスワード入力)
ansible-playbook -i inventory.yml get_info.yml -k

# SSH鍵認証の場合 (鍵ファイルはインベントリ or ~/.ssh/config で指定)
ansible-playbook -i inventory.yml get_info.yml

# 特定のホスト(r1)のみ実行する場合 (-l オプション)
# ansible-playbook -i inventory.yml get_info.yml -l r1 -k

# 実行前にどのタスクがどのホストで実行されるか確認 (--check オプション、実際には変更しない)
# ansible-playbook -i inventory.yml get_info.yml --check -k

# 詳細な実行ログを表示 (-v, -vv, -vvv オプション)
# ansible-playbook -i inventory.yml get_info.yml -k -vv

[コード例: 上記 ansible-playbook コマンドの実行結果のサンプル]

例2: NTPサーバー設定の変更 (configure_ntp.yml)


  • name: NTPサーバーを設定するPlaybook
    hosts: cisco_routers:juniper_switches
    gather_facts: no
    connection: network_cli vars: # Playbook内で使う変数を定義
    ntp_servers:
    • 192.0.2.100
    • 198.51.100.200
    tasks:
    • name: Cisco IOS – NTPサーバーを設定
      cisco.ios.ios_config: # 設定変更用モジュール
      lines: # 投入したい設定コマンドのリスト
      • no ntp server 192.0.2.99 # 不要な設定を削除する例
      • ntp server {{ item }} # 変数を使ってループ処理
        loop: “{{ ntp_servers }}" # varsで定義したリストをループ
      save_when: modified # 設定変更があった場合のみ保存(write memory)を実行するオプションもある when: ansible_network_os == 'cisco.ios.ios’
      notify: Save Cisco Config # 変更があった場合にHandlerを呼び出す
    • name: Juniper Junos – NTPサーバーを設定
      junipernetworks.junos.junos_config:
      lines:
      • set system ntp server {{ item }}
        loop: “{{ ntp_servers }}"
        # commit_changes: yes # Junosの場合、commitをモジュール内で実行するオプションもある
        when: ansible_network_os == 'junipernetworks.junos.junos’
        notify: Commit Juniper Config
    handlers: # notify で指定された名前を持つ特別なタスク
    • name: Save Cisco Config
      cisco.ios.ios_command:
      commands: write memory
      listen: “Save Cisco Config" # notify の名前と一致させる
    • name: Commit Juniper Config
      junipernetworks.junos.junos_command:
      commands: commit comment “Configured NTP by Ansible"
      listen: “Commit Juniper Config"

Playbook のポイント:

  • vars: で Playbook 内で共通して使う値(NTPサーバーのIPアドレスなど)を変数として定義できます。
  • 設定変更には ios_configjunos_config などのモジュールを使います。lines: に設定コマンドを記述します。
  • loop: を使うと、リスト(ここでは ntp_servers)の各要素に対して同じタスクを繰り返し実行できます。{{ item }} でリストの要素を参照します。
  • 冪等性: ios_configjunos_config モジュールは、通常、指定した設定が既に存在すれば何もせず、存在しないか異なる場合にのみ変更を行います。これにより、何度実行しても意図した状態になります。
  • notify:handlers: を使うことで、「タスクによって設定変更が行われた場合のみ」、後続の処理(コンフィグの保存やコミット)を実行するように定義できます。変更がなければ Handler は実行されません。これは非常に重要な機能です。

実行方法: get_info.yml と同様に ansible-playbook コマンドで実行します。

ansible-playbook -i inventory.yml configure_ntp.yml -k

【重要】 いきなり本番環境で設定変更の Playbook を実行するのは非常に危険です。必ず事前に --check オプションでドライラン(実行内容の確認)を行ったり、検証環境で十分にテストしたりしてください。また、ansible-vault を使ってパスワードなどの機密情報を暗号化することを強く推奨します。

まとめと次回予告

今回は、ネットワーク自動化ツール Ansible の基本的な概念から、インベントリファイルの作成、そして情報収集と設定変更を行う Playbook の具体的な作成・実行方法までを解説しました。

  • Ansible はエージェントレスで導入しやすく、YAMLで記述できるため学習しやすい。
  • インベントリで管理対象を定義し、Playbook で自動化タスクを記述する。
  • 豊富なネットワークモジュールと冪等性により、安全で効率的な自動化が可能。
  • vars, loop, when, notify/handlers などの機能を活用することで、より柔軟な Playbook を作成できる。
  • 必ず検証環境でテストし、認証情報は安全に管理すること!

Ansible を使えば、これまで手作業で行っていた多くのネットワーク運用タスクを自動化できる可能性が見えてきたのではないでしょうか? まずは簡単な変更なしの情報収集から試してみましょう。

さて、Ansible は非常に強力なツールですが、より複雑なロジックを組んだり、他のシステム(監視ツール、チケットシステムなど)と連携したり、あるいは Ansible モジュールでは対応できないような細かい処理を行いたい場合も出てきます。

次回、【第3回】では、もう一つの強力な選択肢である「Python」を用いたネットワーク自動化について解説します。 Python のネットワークライブラリ (Netmiko, NAPALM) を使って、より柔軟な自動化スクリプトを作成する方法や、Ansible と Python をどう使い分けるか、そして自動化導入における注意点などを掘り下げていきます。