はじめに
従来のエンタープライズ向けネットワークでは、ルータやファイアウォール等の機能毎に専用のハードウェアを用意して導入していました。一方ここ数年、身近でもNFV(Network Functions Virtualization)を利用してネットワーク機能を仮想化し、汎用デバイス上に構築するケースが少しずつ増えてきました。
Ciscoが提供するエンタープライズNFVを例にとると、NFVは以下のコンポートから構成されます。
(加えて、これらを管理するコントローラもあり。)
- VNF(Virtual Network Functions) ・・・ ルータ、ファイアウォール、WLC、WAAS等の仮想プラットフォーム
- ハイパーバイザー ・・・ NFVIS、ESXi、Hyper-V、KVM等(VNFによってサポート対象が異なる)
- ハードウェア ・・・ Cisco UCS-C、UCS-E、ENCS等
Cisco Live! US 2019 - Enterprise Network Functions Virtualization (ENFV) Architecture, Configuration and Troubleshooting - BRKARC-2012 p8から引用
今回の記事でご紹介するCisco NFVISは、ハイパーバイザーとしての機能に加え、REST-APIを通じた仮想サービスの制御やゼロタッチ展開(PnP)機能も提供されています。
詳細は、Cisco DevNet Lerning Labsの以下セッションで分かりやすく説明されています。
NFVIS API を使用したネットワーク機能の仮想化の紹介
このセッションでは、後述するCisco dCloud環境上で、VNFのデプロイ・情報取得・削除をGUIやREST-API(Postman、Python)経由で行うハンズオンが体験できます。
本記事は、同様の内容をAnsibleのuri
モジュールで行った時のメモになります。
~その他参考URL~
- GitHub - CiscoDevNet/dnav3-code
- [NFVIS APIドキュメント]
(https://www.cisco.com/c/en/us/td/docs/routers/nfvis/user_guide/b-api-reference-for-cisco-enterprise-nfvis.html)
2. 用意した環境
以下のCisco dCloud環境を利用させて頂きました。
Cisco DevNet Express Cisco DNA Sandbox v3.0a
dCloud接続方法の詳細は割愛しますが、以下の流れでセットアップしています。
- Cisco AnyConnectを使って、自分のPCからVPN経由で図中のcentos(DevBox)へリモートデスクトップ接続。
- DevBoxにインストールされていたPython3.6.5を使ってvenv仮想環境を構築し、その上でAnsible2.9.2をインストール。
- DevBoxからNFVISへWebアクセス or Ansible経由でREST-APIコール。
これ以降で、Ansible Inventory/Playbookの内容と実行結果をご紹介します。
3. Inventoryファイル
NFVISへのHTTPSアクセスに必要な情報を記載します。
[cisco]
nfvis ansible_host=[NFVISのIPアドレス] ansible_port=443
[cisco:vars]
username=[NFVISのユーザ名]
password=[NFVISのパスワード]
4. VNFのデプロイ
まずは、仮想ルータISRvのデプロイを行ってみます。
4-1. Ansible Playbook
内容は以下の通りです。
- POSTメソッドで、Body内にISRvのデプロイ情報を定義。パラメーターはLearning Labsをそのまま流用。今回はYAML形式の変数
body_data
を、フィルタープラグイン"{{ body_data | to_json }}"
でJSON形式で変換し、Bodyに格納。(JSONファイルをlookupプラグイン"{{ lookup('file', 'body_data.json') }}"
で読み込んでもOK。) - Basic認証を使用し、APIコール毎にユーザ名/パスワードを指定。
- uriモジュールは、デフォルトでStatus Code
200 (OK)
をSuccessとするが、今回は201 (Created)
が返ってくるため、明示的に201を指定。
---
- hosts: cisco
gather_facts: no
connection: local
vars:
body_data:
deployment:
name: "ISRv"
vm_group:
name: "ROUTER"
image: "isrv-universalk9.16.06.02.tar.gz"
flavor: "ISRv-small"
bootup_time: 600
recovery_wait_time: 0
interfaces:
interface:
- nicid: 0
network: "int-mgmt-net"
- nicid: 1
network: "wan-net"
- nicid: 2
network: "lan-net"
kpi_data:
kpi:
event_name: "VM_ALIVE"
metric_value: "1"
metric_cond: "GT"
metric_type: "UINT32"
metric_collector:
type: "ICMPPing"
nicid: 0
poll_frequency: 3
polling_unit: "seconds"
continuous_alarm: false
rules:
admin_rules:
rule:
event_name: "VM_ALIVE"
action:
- "ALWAYS log"
- "FALSE recover autohealing"
- "TRUE servicebooted.sh"
config_data:
configuration:
dst: "bootstrap_config"
variable:
- name: "TECH_PACKAGE"
val: "ax"
tasks:
- name: Deploy ISRv
uri:
url: https://{{ansible_host}}:{{ansible_port}}/api/config/vm_lifecycle/tenants/tenant/admin/deployments
method: POST
headers:
Content-Type: application/vnd.yang.data+json
Accept: application/vnd.yang.data+json
body_format: json
body: "{{ body_data | to_json }}"
# body: "{{ lookup('file', 'body_data.json') }}"
status_code:
- 201
url_username: "{{ username }}"
url_password: "{{ password }}"
force_basic_auth: yes
validate_certs: no
ignore_errors: yes
4-2. Playbook実行ログ
特にエラーなく終了しました。
$ ansible-playbook -i inventory_nfvis.ini playbook_nfvis_post.yml
PLAY [cisco] *************************************************************************************************
TASK [Deploy ISRv] *******************************************************************************************
ok: [nfvis]
PLAY RECAP ***************************************************************************************************
nfvis : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
4-3. GUI画面
ここでNFVISのGUI画面を見ると、Active状態のVNFが1つ表示され、ネットワークwan-net
とlan-net
に論理接続されていました。
5. ステータス情報の取得
続いて、各種ステータス情報をGETメソッドで取得してみます。
5-1. Ansible Playbook
各タスクの内容は以下の通りです。
- イメージ情報を取得。Status Codeは
200 (OK)
に加え、情報がない場合204 (No Content)
が返ってくる可能性があるため、2つをSuccess対象に指定。 - タスク1で取得した情報を表示。
- 起動中のVNF情報を取得。
- タスク3で取得した情報を表示。
- 起動中のVNF情報詳細を取得。
- タスク5で取得した情報を表示。
---
- hosts: cisco
gather_facts: no
connection: local
tasks:
- name: Get images # (1)
uri:
url: https://{{ansible_host}}:{{ansible_port}}/api/config/vm_lifecycle/images
method: GET
headers:
Content-Type: application/vnd.yang.data+json
Accept: application/vnd.yang.data+json
status_code:
- 200
- 204
url_username: "{{ username }}"
url_password: "{{ password }}"
force_basic_auth: yes
validate_certs: no
register: result_images
- name: Display images # (2)
debug:
msg: "{{ result_images.json | default('None') }}"
when: result_images.json is defined
- name: Get running VNFs # (3)
uri:
url: https://{{ansible_host}}:{{ansible_port}}/api/config/vm_lifecycle/tenants/tenant/admin/deployments
method: GET
headers:
Content-Type: application/vnd.yang.data+json
Accept: application/vnd.yang.data+json
status_code:
- 200
- 204
url_username: "{{ username }}"
url_password: "{{ password }}"
force_basic_auth: yes
validate_certs: no
register: result_vnfs
- name: Display running VNFs # (4)
debug:
msg: "{{ result_vnfs.json | default('None') }}"
- name: Get running VNFs (detail) # (5)
uri:
url: https://{{ansible_host}}:{{ansible_port}}/api/config/vm_lifecycle/tenants/tenant/admin/deployments?deep
method: GET
headers:
Content-Type: application/vnd.yang.data+json
Accept: application/vnd.yang.data+json
status_code:
- 200
- 204
url_username: "{{ username }}"
url_password: "{{ password }}"
force_basic_auth: yes
validate_certs: no
register: result_vnfs_detail
- name: Display running VNFs # (6)
debug:
msg: "{{ result_vnfs_detail.json | default('None') }}"
5-2. Playbook実行ログ
タスク2で、dCloud環境に元々存在しているASAvとISRvのイメージが表示されました。続いて、タスク4でVNFISRv
、タスク6でその詳細情報が表示されてる事が分かります。
$ ansible-playbook -i inventory_nfvis.ini playbook_nfvis_get.yml
PLAY [cisco] *************************************************************************************************
TASK [Get images] ********************************************************************************************
ok: [nfvis]
TASK [Display images] ****************************************************************************************
ok: [nfvis] => {
"msg": {
"vmlc:images": {
"image": [
{
"name": "asav961.tar.gz"
},
{
"name": "isrv-universalk9.16.06.02.tar.gz"
}
]
}
}
}
TASK [Get running VNFs] **************************************************************************************
ok: [nfvis]
TASK [Display running VNFs] **********************************************************************************
ok: [nfvis] => {
"msg": {
"vmlc:deployments": {
"deployment": [
{
"name": "ISRv"
}
]
}
}
}
TASK [Get running VNFs (detail)] *****************************************************************************
ok: [nfvis]
TASK [Display running VNFs] **********************************************************************************
ok: [nfvis] => {
"msg": {
"vmlc:deployments": {
"deployment": [
{
"name": "ISRv",
"vm_group": [
{
"bootup_time": 600,
"config_data": {
"configuration": [
{
"dst": "bootstrap_config",
"variable": [
{
"name": "TECH_PACKAGE",
"val": [
"ax"
]
}
]
}
]
},
"flavor": "ISRv-small",
"image": "isrv-universalk9.16.06.02.tar.gz",
"interfaces": {
"interface": [
{
"network": "int-mgmt-net",
"nicid": 0
},
{
"network": "wan-net",
"nicid": 1
},
{
"network": "lan-net",
"nicid": 2
}
]
},
"kpi_data": {
"kpi": [
{
"event_name": "VM_ALIVE",
"metric_collector": {
"continuous_alarm": false,
"nicid": 0,
"poll_frequency": 3,
"polling_unit": "seconds",
"type": "ICMPPing"
},
"metric_cond": "GT",
"metric_type": "UINT32",
"metric_value": "1"
}
]
},
"name": "ROUTER",
"recovery_wait_time": 0,
"rules": {
"admin_rules": {
"rule": [
{
"action": [
"ALWAYS log",
"FALSE recover autohealing",
"TRUE servicebooted.sh"
],
"event_name": "VM_ALIVE"
}
]
}
}
}
]
}
]
}
}
}
PLAY RECAP ***************************************************************************************************
nfvis : ok=6 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
6. VNFの削除
最後に、作成したVNFをすべて削除してみます。
6-1. Ansible Playbook
各タスクの内容は以下の通りです。
- (事前)起動中のVNF情報を取得。
- (事前)タスク1で取得した情報を表示。
↓ これ以降はblock
とwhen
を用いて、VNFが1つでもデプロイされている場合のみ実施。 - 起動中のVNF名一覧を変数
running_vnfs
に格納。 -
loop
を用いて、各VNFをDELETEメソッドで1つずつ削除。 - (事後)起動中のVNF情報を取得。
- (事後)タスク5で取得した情報を表示。
---
- hosts: cisco
gather_facts: no
connection: local
tasks:
- name: Get running VNFs (before) # (1)
uri:
url: https://{{ansible_host}}:{{ansible_port}}/api/config/vm_lifecycle/tenants/tenant/admin/deployments
method: GET
headers:
Content-Type: application/vnd.yang.data+json
Accept: application/vnd.yang.data+json
status_code:
- 200
- 204
url_username: "{{ username }}"
url_password: "{{ password }}"
force_basic_auth: yes
validate_certs: no
register: result_vnfs_before
- name: Display running VNFs (before) # (2)
debug:
msg: "{{ result_vnfs_before.json | default('None') }}"
- block:
- name: Set running VNFs # (3)
set_fact:
running_vnfs: "{{ result_vnfs_before.json['vmlc:deployments']['deployment'] }}"
- name: Delete running VNFs # (4)
uri:
url: https://{{ansible_host}}:{{ansible_port}}/api/config/vm_lifecycle/tenants/tenant/admin/deployments/deployment/{{item.name}}
method: DELETE
headers:
Content-Type: application/vnd.yang.data+json
Accept: application/vnd.yang.data+json
status_code:
- 200
- 204
url_username: "{{ username }}"
url_password: "{{ password }}"
force_basic_auth: yes
validate_certs: no
loop: "{{ running_vnfs }}"
- name: Get running VNFs (after) # (5)
uri:
url: https://{{ansible_host}}:{{ansible_port}}/api/config/vm_lifecycle/tenants/tenant/admin/deployments
method: GET
headers:
Content-Type: application/vnd.yang.data+json
Accept: application/vnd.yang.data+json
status_code:
- 200
- 204
url_username: "{{ username }}"
url_password: "{{ password }}"
force_basic_auth: yes
validate_certs: no
register: result_vnfs_after
- name: Display running VNFs (after) # (6)
debug:
msg: "{{ result_vnfs_after.json | default('None') }}"
when: result_vnfs_before.json is defined
6-2. Playbook実行ログ
タスク2で表示されていたVNFISRv
が、タスク6で消えている事が分かります。
$ ansible-playbook -i inventory_nfvis.ini playbook_nfvis_delete.yml
PLAY [cisco] *************************************************************************************************
TASK [Get running VNFs (before)] *****************************************************************************
ok: [nfvis]
TASK [Display running VNFs (before)] *************************************************************************
ok: [nfvis] => {
"msg": {
"vmlc:deployments": {
"deployment": [
{
"name": "ISRv"
}
]
}
}
}
TASK [Set running VNFs] **************************************************************************************
ok: [nfvis]
TASK [Delete running VNFs] ***********************************************************************************
ok: [nfvis] => (item={'name': 'ISRv'})
TASK [Get running VNFs (after)] ******************************************************************************
ok: [nfvis]
TASK [Display running VNFs (after)] **************************************************************************
ok: [nfvis] => {
"msg": "None"
}
PLAY RECAP ***************************************************************************************************
nfvis : ok=6 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
6-3. GUI画面
NFVISのGUI画面でも、該当のVNFが削除されました。
最後に
今回は汎用モジュールuri
使いましたが、Cisco DevNetでansible-nvfisやnfvis-opsも開発されているようです。Playbookもよりシンプルになりそうですので、実運用する場合はこちらも検討したいと思います。