Ansibleもくもく会(A10編 2019/09/13@Softbank)


# はじめに
Redhatさんが定期的に開催しているAnsibleのもくもく会に参加してきたので、その内容のまとめです。
※この勉強会は「ブログ枠」という参加枠があり、そこで参加した人は内容をレポートすることになっています。(要は許可とってます)

公開されている資料は[こちら](https://github.com/kishizuka4989/ansible_training_a10_thuner_adc/blob/master/README.ja.md)です。
a10用Ansibleモジュールは[こちら](https://github.com/kishizuka4989/ansible_training_a10_thuner_adc/blob/master/1.0-adc-primer/201909_Ansible_Guide.pdf)
※若干注意事項あり(後述)

# A10 vThunderとは
今回の題材はA10 Network社が提供しているThunder ADC(Application Delivery Controller)という機材に対するAnsibleの操作になります。
そもそもこのADCが何なのかすら知らなかったのですが、基本的にはロードバランサーと同じ役割を果たすようです。ただし、セッションをパススルーするのではなく、自身がアプリケーションの応答を返すことができる点が異なるとのこと。今回の資料も通常のロードバランサー的な使い方になっています。

From [F5](https://www.f5.com/ja_jp/services/resources/glossary/application-delivery-controller)
> ADCとは「Application Delivery Controller」の略で、ロードバランサ（負荷分散装置）の機能をさらに高度化したものです。
> ロードバランサはリバース プロキシの一種であり、クライアントからのリクエストを複数のサーバに振り分ける処理を行うことで、サーバの負荷を分散します。従来のロードバランサは、クライアントとサーバとの間でやり取りされるパケットを、単純に中継するだけのものでした。そのため、TCPコネクションの確立やHTTP/HTTPSのセッションは、クライアントとサーバの間で直接行われるのが一般的でした。
> これに対してADCでは、アプリケーション レイヤまでカバーしたフル プロキシとして機能し、クライアントからのリクエストに対し、サーバの代理として応答することが可能になっています。サーバとの間は、クライアントとの間とは別のコネクション/セッションを張ります。このようなアーキテクチャを採用することで、従来のオードバランサに比べて幅広い機能の実現が可能になっています。


# 構成と概要

![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159980/30feb09c-a653-1705-d2c6-a90c195ec40e.png)

今回はvThunderはGatewayモードで構成し、バックエンドにあるHTTPサーバ2台に対する負荷分散を設定します。vThunderは2つのネットワークに接続されていて、それぞれVLANが異なります。
vThunder側で設定する内容としては以下の通り。

1. インターフェース設定(クライアント側と、ウェブサーバ側にそれぞれVLANに対応するインターフェースを作成する)
2. Service Groupの構成(負荷分散の対象となるウェブサーバをグルーピングしたもの)
3. Virtual Serverの設定(外部からアクセスされるIPアドレスの設定と、Service Groupとの関連付け)
4. アクセス確認


# インターフェース設定
## ログインと環境設定
Ansibleが実行可能なサーバにログインし、hostsファイルを作成する。

```txt:hosts
[all:vars]
a10_username=admin
a10_password=a10
a10_port=443

[vThunder]
10.255.0.1
```

ここでは、対象ホストの情報に加えて、ログイン情報を変数として定義しています。

## VLAN作成
次に各インターフェースにVLAN IDを設定します。設定にはa10社が提供する「a10_network_vlan」というモジュールを使用します。
これを含め、a10の提供するモジュールは下記githubにあります。
https://github.com/a10networks/a10-ansible

※ただし、一部修正する必要があるらしく、修正ポイントは同様にgithubに記載されているそうです。
https://github.com/kishizuka4989/ansible_training_a10_thuner_adc/blob/master/1.0-adc-primer/201909_Ansible_Guide.pdf

```yaml:a10_network_vlan_create.yaml
---
- hosts: 10.255.0.1
  connection: local
  gather_facts: no

  vars:
    a10_host: "10.255.0.1"
  tasks:
  - name: Create VLAN
    a10_network_vlan:
      a10_host: "{{ a10_host }}"
      a10_port: "{{ a10_port }}"
      a10_username: "{{ a10_username }}"
      a10_password: "{{ a10_password }}"
      vlan_num: "10"
      untagged_eth_list:
        - untagged_ethernet_start: "1"
          untagged_ethernet_end: "1"
      ve: "10"
      state: present
      partition: shared
```

gather_facts: noについては、vThunderに対する命令はvThunder上ではなく、別のマシンからRESTAPI(aXAPI)で実行されるため、factの収集ができないために必要になります。
a10_network_vlanの下で指定されているパラメータはモジュール特有のパラメータで、設定するインターフェースのID(untagged_eth_list)および設定するVLAN ID(vlan_num)、および作成される仮想インターフェースID(ve, vlan_numとイコールである必要があるらしい)です。
またstateはこの設定が構成された状態にするかどうか(presentはする)、partitionはvThunder上の論理パーティションを指定します(sharedはデフォルトパーティション)。stateの意味合いが少しわかりにくいですが、後でdeleteするときにわかります。ちなみに、各モジュールで設定可能なパラメータは`ansible-doc a10_network_vlan`で確認できます。
このPlaybookを実行してみます。

```shell-session
[root@ansible playbook]# ansible-playbook -i hosts a10_network_vlan_create.yaml

PLAY [10.255.0.1] ****************************************************************************************************************************

TASK [Create VLAN] ***************************************************************************************************************************
changed: [10.255.0.1]

PLAY RECAP ***********************************************************************************************************************************
10.255.0.1                 : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

```

そのあと、vThunder上で設定を確認します。

```shell-session
vThunder#show running-config

vlan 10
  untagged ethernet 1
  router-interface ve 10
!
interface ethernet 1
!
interface ve 10
```

このVLANを削除する場合は、stateをabsentに変えればよいです。

```shell-session
[root@ansible playbook]# cp a10_network_vlan_create.yaml a10_network_vlan_delete.yaml
[root@ansible playbook]# vi a10_network_vlan_delete.yaml
[root@ansible playbook]# diff a10_network_vlan_create.yaml a10_network_vlan_delete.yaml
20c20
<       state: present
---
>       state: absent
[root@ansible playbook]#
[root@ansible playbook]# ansible-playbook -i hosts a10_network_vlan_delete.yaml

PLAY [10.255.0.1] ****************************************************************************************************************************

TASK [Create VLAN] ***************************************************************************************************************************
changed: [10.255.0.1]

PLAY RECAP ***********************************************************************************************************************************
10.255.0.1                 : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
```

これでvThunder上から構成が削除されます。

```shell-session
vThunder#show running-config
interface management
  ip address 10.255.0.1 255.255.0.0
  ip default-gateway 10.255.255.1
!
interface ethernet 1
!
interface ethernet 2
!
!
sflow setting local-collection
!
sflow collector ip 127.0.0.1 6343
!
!
end
```

元に戻すついでに、複数VLANを設定するPlaybookを作成します。

```yaml:a10_network_vlans_create.yaml
---
- hosts: 10.255.0.1
  connection: local
  gather_facts: no

  vars:
    a10_host: "10.255.0.1"
  tasks:
  - name: Create VLAN
    a10_network_vlan:
      a10_host: "{{ a10_host }}"
      a10_port: "{{ a10_port }}"
      a10_username: "{{ a10_username }}"
      a10_password: "{{ a10_password }}"
      vlan_num: "{{ item.vlan_num }}"
      untagged_eth_list:
        - untagged_ethernet_start: "{{ item.untagged_ethernet_start }}"
          untagged_ethernet_end: "{{ item.untagged_ethernet_end }}"
      ve: "{{ item.ve }}"
      state: present
      partition: shared
    with_items:
      - { vlan_num: 10, untagged_ethernet_start: 1, untagged_ethernet_end: 1, ve: 10 }
      - { vlan_num: 20, untagged_ethernet_start: 2, untagged_ethernet_end: 2, ve: 20 }
```

with_itemsを使うことでLoopを使うことができます。

```shell-session
[root@ansible playbook]# ansible-playbook -i hosts a10_network_vlans_create.yaml

PLAY [10.255.0.1] ****************************************************************************************************************************

TASK [Create VLAN] ***************************************************************************************************************************
changed: [10.255.0.1] => (item={'vlan_num': 10, 'untagged_ethernet_start': 1, 'untagged_ethernet_end': 1, 've': 10})
changed: [10.255.0.1] => (item={'vlan_num': 20, 'untagged_ethernet_start': 2, 'untagged_ethernet_end': 2, 've': 20})

PLAY RECAP ***********************************************************************************************************************************
10.255.0.1                 : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
```

実行するとTask内で2回の変更が実行されていることがわかります。変更をvThunder側で確認します。ちなみにOSはCISCOのIOSベースなのか似せているのか、同じようなコマンドが通ります。

```shell-session
vThunder#terminal length 0
vThunder#show running-config
!Current configuration: 399 bytes
!Configuration last updated at 11:59:47 IST Fri Sep 13 2019
!Configuration last saved at 03:07:57 IST Fri Sep 13 2019
!64-bit Advanced Core OS (ACOS) version 4.1.4-GR1, build 78 (Jan-18-2019,16:02)
!
multi-config enable
!
terminal idle-timeout 0
!
vlan 10
  untagged ethernet 1
  router-interface ve 10
!
vlan 20
  untagged ethernet 2
  router-interface ve 20
!
interface management
  ip address 10.255.0.1 255.255.0.0
  ip default-gateway 10.255.255.1
!
interface ethernet 1
!
interface ethernet 2
!
interface ve 10
!
interface ve 20
!
!
sflow setting local-collection
!
sflow collector ip 127.0.0.1 6343
!
!
end
```

またこれもCiscoスイッチ同様、このままでは設定内容が再起動で失われてしまうため、runnning-configの内容を不揮発性メモリ上の設定(startup-config)に保存する必要があり、これには専用のモジュールが存在します。
ちょっと冗長な気がしますが、それ用のPlaybookを以下のように作成します。

```yaml:a10_write_memory.yaml
---
- hosts: 10.255.0.1
  connection: local
  gather_facts: no

  vars:
    a10_host: "10.255.0.1"
  tasks:
  - name: Write memory
    a10_write_memory:
      a10_host: "{{ a10_host }}"
      a10_username: "{{ a10_username }}"
      a10_password: "{{ a10_password }}"
      a10_port: "{{ a10_port }}"
      state: present
      partition: all
```

同様に実行します。

```shell-session
[root@ansible playbook]# ansible-playbook -i hosts a10_write_memory.yaml

PLAY [10.255.0.1] ****************************************************************************************************************************

TASK [Write memory] **************************************************************************************************************************
changed: [10.255.0.1]

PLAY RECAP ***********************************************************************************************************************************
10.255.0.1                 : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
```

## 仮想インターフェース作成
次に物理インターフェースに対して、各VLAN用の仮想インターフェースを作成し、IPアドレスを付与します。a10_interface_ve_ipというモジュールを使用します。

```yaml:a10_interface_ve_ip_create.yaml
---
- hosts: 10.255.0.1
  connection: local
  gather_facts: no

  vars:
    a10_host: "10.255.0.1"
  tasks:
  - name: Add IP to VE
    a10_interface_ve_ip:
      a10_host: "{{ a10_host }}"
      a10_port: "{{ a10_port }}"
      a10_username: "{{ a10_username }}"
      a10_password: "{{ a10_password }}"
      ve_ifnum: "{{ item.ve_ifnum }}"
      address_list:
        - ipv4_address: "{{ item.ipv4_address }}"
          ipv4_netmask: "{{ item.ipv4_netmask }}"
      state: present
      partition: shared
    with_items:
      - { ve_ifnum: "10", ipv4_address: 192.168.1.254, ipv4_netmask: 255.255.255.0 }
      - { ve_ifnum: "20", ipv4_address: 192.168.2.254, ipv4_netmask: 255.255.255.0 }

  - name: Write memory
    a10_write_memory:
      a10_host: "{{ a10_host }}"
      a10_username: "{{ a10_username }}"
      a10_password: "{{ a10_password }}"
      a10_port: "{{ a10_port }}"
      state: present
      partition: all
```

ve_ifnumは先ほど作成したveの番号です。またどうせ実行するため、Write Memoryモジュールの実行も別タスクとして入れてあります。これを実行すると、

```shell-session
[root@ansible playbook]# ansible-playbook -i hosts a10_interface_ve_ip_create.yaml

PLAY [10.255.0.1] ****************************************************************************************************************************

TASK [Add IP to VE] **************************************************************************************************************************
changed: [10.255.0.1] => (item={'ve_ifnum': '10', 'ipv4_address': '192.168.1.254', 'ipv4_netmask': '255.255.255.0'})
changed: [10.255.0.1] => (item={'ve_ifnum': '20', 'ipv4_address': '192.168.2.254', 'ipv4_netmask': '255.255.255.0'})

TASK [Write memory] **************************************************************************************************************************
changed: [10.255.0.1]

PLAY RECAP ***********************************************************************************************************************************
10.255.0.1                 : ok=2    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
```

vThunder上で確認します。

```shell-session
vThunder#show interfaces brief
Port    Link  Dupl  Speed  Trunk Vlan MAC             IP Address          IPs  Name
------------------------------------------------------------------------------------
mgmt    Up    Full  1000   N/A   N/A  2cc2.6064.4ec4  10.255.0.1/16         1
1       Disb  None  None   none  10   2cc2.603c.b0de  0.0.0.0/0             0
2       Disb  None  None   none  20   2cc2.6044.0a45  0.0.0.0/0             0
ve10    Down  N/A   N/A    N/A   10   2cc2.603c.b0de  192.168.1.254/24      1
ve20    Down  N/A   N/A    N/A   20   2cc2.6044.0a45  192.168.2.254/24      1

Global Throughput:0 bits/sec (0 bytes/sec)
Throughput:0 bits/sec (0 bytes/sec)
```

この時点ではVEは有効になっていないため、有効化するPlaybookを用意します。a10_interface_ethernetというモジュールを使用します。Ansibleの話ではないですが、VE自体ではなく、そのベースになっているインターフェースを有効化するところがちょっと気になりました。

```yaml:a10_interfaces_ethernet_enable.yaml
---
- hosts: 10.255.0.1
  connection: local
  gather_facts: no

  vars:
    a10_host: "10.255.0.1"
  tasks:
  - name: Enable ethernet interfaces
    a10_interface_ethernet:
      a10_host: "{{ a10_host }}"
      a10_port: "{{ a10_port }}"
      a10_username: "{{ a10_username }}"
      a10_password: "{{ a10_password }}"
      ifnum: "{{ item.ifnum }}"
      action: enable
      state: present
      partition: shared
    with_items:
      - { ifnum: 1 }
      - { ifnum: 2 }

  - name: Write memory
    a10_write_memory:
      a10_host: "{{ a10_host }}"
      a10_username: "{{ a10_username }}"
      a10_password: "{{ a10_password }}"
      a10_port: "{{ a10_port }}"
      state: present
      partition: all
```

このPlaybookを実行します。

```shell-session
[root@ansible playbook]# ansible-playbook -i hosts a10_interfaces_ethernet_enable.yaml

PLAY [10.255.0.1] ****************************************************************************************************************************

TASK [Enable ethernet interfaces] ************************************************************************************************************
changed: [10.255.0.1] => (item={'ifnum': 1})
changed: [10.255.0.1] => (item={'ifnum': 2})

TASK [Write memory] **************************************************************************************************************************
changed: [10.255.0.1]

PLAY RECAP ***********************************************************************************************************************************
10.255.0.1                 : ok=2    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
```

これでVEの方も有効になります。
ただし自分の場合、1回の実行ではve10しかUpにならず、2回目流すとどちらもUpになりました。(2回目の実行の時はchanged=1(write_memory分のみ)だったが)

```shell-session
vThunder#show interfaces brief
Port    Link  Dupl  Speed  Trunk Vlan MAC             IP Address          IPs  Name
------------------------------------------------------------------------------------
mgmt    Up    Full  1000   N/A   N/A  2cc2.6064.4ec4  10.255.0.1/16         1
1       Up    Full  10000  none  10   2cc2.603c.b0de  0.0.0.0/0             0
2       Down  None  None   none  20   2cc2.6044.0a45  0.0.0.0/0             0
ve10    Up    N/A   N/A    N/A   10   2cc2.603c.b0de  192.168.1.254/24      1
ve20    Down  N/A   N/A    N/A   20   2cc2.6044.0a45  192.168.2.254/24      1

Global Throughput:0 bits/sec (0 bytes/sec)
Throughput:0 bits/sec (0 bytes/sec)
vThunder#show interfaces brief
Port    Link  Dupl  Speed  Trunk Vlan MAC             IP Address          IPs  Name
------------------------------------------------------------------------------------
mgmt    Up    Full  1000   N/A   N/A  2cc2.6064.4ec4  10.255.0.1/16         1
1       Up    Full  10000  none  10   2cc2.603c.b0de  0.0.0.0/0             0
2       Up    Full  10000  none  20   2cc2.6044.0a45  0.0.0.0/0             0
ve10    Up    N/A   N/A    N/A   10   2cc2.603c.b0de  192.168.1.254/24      1
ve20    Up    N/A   N/A    N/A   20   2cc2.6044.0a45  192.168.2.254/24      1
```

# Service Groupの構成
## Serverの追加
初めにService Groupに含める負荷分散対象のサーバを定義します。

```yaml:a10_slb_servers_create.yaml
---
- hosts: 10.255.0.1
  connection: local
  gather_facts: no

  vars:
    a10_host: "10.255.0.1"
  tasks:
  - name: Configure real server
    a10_slb_server:
      a10_host: "{{ a10_host }}"
      a10_port: "{{ a10_port }}"
      a10_username: "{{ a10_username }}"
      a10_password: "{{ a10_password }}"
      name: "{{ item.name }}"
      host: "{{ item.host }}"
      port_list:
        - port_number: "{{ item.port_number }}"
          protocol: "{{ item.protocol }}"
      state: present
      partition: shared
    with_items:
      - { name: "s1", host: "192.168.2.1", port_number: 80, protocol: "tcp" }
      - { name: "s2", host: "192.168.2.2", port_number: 80, protocol: "tcp" }

  - name: Write memory
    a10_write_memory:
      a10_host: "{{ a10_host }}"
      a10_username: "{{ a10_username }}"
      a10_password: "{{ a10_password }}"
      a10_port: "{{ a10_port }}"
      state: present
      partition: all
```

負荷分散の対象となるIPアドレス(192.168.2.1,192.168.2.2)、ポートの組み合わせにs1,s2という名前を付けています。

```shell-session
[root@ansible playbook]# ansible-playbook -i hosts a10_slb_servers_create.yaml

PLAY [10.255.0.1] ****************************************************************************************************************************

TASK [Configure real server] *****************************************************************************************************************
changed: [10.255.0.1] => (item={'name': 's1', 'host': '192.168.2.1', 'port_number': 80, 'protocol': 'tcp'})
changed: [10.255.0.1] => (item={'name': 's2', 'host': '192.168.2.2', 'port_number': 80, 'protocol': 'tcp'})

TASK [Write memory] **************************************************************************************************************************
changed: [10.255.0.1]

PLAY RECAP ***********************************************************************************************************************************
10.255.0.1                 : ok=2    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
```

vThunder側で確認します。

```shell-session
vThunder#show slb server
Total Number of Servers configured: 2
Total Number of Services configured: 2
                   Current = Current Connections, Total = Total Connections
                   Fwd-pkt = Forward packets, Rev-pkt = Reverse packets
Service                   Current    Total      Fwd-pkt    Rev-pkt    Peak-conn  State
---------------------------------------------------------------------------------------
s1:80/tcp                 0          0          0          0          0          Up
s1: Total                 0          0          0          0          0          Up

s2:80/tcp                 0          0          0          0          0          Up
s2: Total                 0          0          0          0          0          Up
```

## Service Group作成

```yaml:a10_slb_service_group_create.yaml
---
- hosts: 10.255.0.1
  connection: local
  gather_facts: no

  vars:
    a10_host: "10.255.0.1"
  tasks:
  - name: Configure service group
    a10_slb_service_group:
      a10_host: "{{ a10_host }}"
      a10_port: "{{ a10_port }}"
      a10_username: "{{ a10_username }}"
      a10_password: "{{ a10_password }}"
      name: "sg1"
      protocol: "tcp"
      lb_method: "round-robin"
      member_list:
        - name: "s1"
          port: "80"
        - name: "s2"
          port: "80"
      state: present
      partition: shared

  - name: Write memory
    a10_write_memory:
      a10_host: "{{ a10_host }}"
      a10_username: "{{ a10_username }}"
      a10_password: "{{ a10_password }}"
      a10_port: "{{ a10_port }}"
      state: present
      partition: all
```

sg1という名前でService Groupを作成し、そこに先ほどのs1,s2をメンバーとして追加します。同時に分散方式(ここではround-robin)も定義します。

```shell-session
[root@ansible playbook]# ansible-playbook -i hosts a10_slb_service_group_create.yaml

PLAY [10.255.0.1] ****************************************************************************************************************************

TASK [Configure service group] ***************************************************************************************************************
changed: [10.255.0.1]

TASK [Write memory] **************************************************************************************************************************
changed: [10.255.0.1]

PLAY RECAP ***********************************************************************************************************************************
10.255.0.1                 : ok=2    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
```

vThunder側で確認します。

```shell-session
vThunder#show slb service-group
Total Number of Service Groups configured: 1
                   Current = Current Connections, Total = Total Connections
                   Fwd-p = Forward packets, Rev-p = Reverse packets
                   Peak-c = Peak connections
Service Group Name
Service                         Current    Total      Fwd-p     Rev-p     Peak-c
-----------------------------------------------------------------------------------
*sg1                  State: All Up
s1:80                           0          0          0         0         0
s2:80                           0          0          0         0         0
```

## NAT設定

```yaml:a10_ip_nat_pool_create.yaml
---
- hosts: 10.255.0.1
  connection: local
  gather_facts: no

  vars:
    a10_host: "10.255.0.1"
  tasks:
  - name: Configure NAT Pool
    a10_ip_nat_pool:
      a10_host: "{{ a10_host }}"
      a10_port: "{{ a10_port }}"
      a10_username: "{{ a10_username }}"
      a10_password: "{{ a10_password }}"
      pool_name: "p1"
      start_address: "192.168.2.100"
      end_address: "192.168.2.100"
      netmask: "/24"
      state: present
      partition: shared

  - name: Write memory
    a10_write_memory:
      a10_host: "{{ a10_host }}"
      a10_username: "{{ a10_username }}"
      a10_password: "{{ a10_password }}"
      a10_port: "{{ a10_port }}"
      state: present
      partition: all
```

Service Groupに関連付ける仮想IPアドレスのプールをp1という名前で作成します。ここではIPアドレスは1つしか入れていません。

```shell-session
[root@ansible playbook]# ansible-playbook -i hosts a10_ip_nat_pool_create.yaml

PLAY [10.255.0.1] ****************************************************************************************************************************

TASK [Configure NAT Pool] ********************************************************************************************************************
changed: [10.255.0.1]

TASK [Write memory] **************************************************************************************************************************
changed: [10.255.0.1]

PLAY RECAP ***********************************************************************************************************************************
10.255.0.1                 : ok=2    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
```

vThunder側で確認。

```shell-session
vThunder#show ip nat pool
Pool Name            Start Address    End Address      Mask  Gateway          Vrid
------------------------------------------------------------------------------------------------
p1                   192.168.2.100    192.168.2.100    /24   0.0.0.0          default
Total IP NAT Pools: 1
```

# Virtual Serverの設定

```yaml:a10_slb_virtual_server_http_create.yaml
---
- hosts: 10.255.0.1
  connection: local
  gather_facts: no

  vars:
    a10_host: "10.255.0.1"
  tasks:
  - name: Configure virtual server
    a10_slb_virtual_server:
      a10_host: "{{ a10_host }}"
      a10_port: "{{ a10_port }}"
      a10_username: "{{ a10_username }}"
      a10_password: "{{ a10_password }}"
      name: "vip1"
      ip_address: "192.168.1.100"
      port_list:
        - port_number: "80"
          protocol: "http"
          service_group: "sg1"
          pool: "p1"
      state: present
      partition: shared

  - name: Write memory
    a10_write_memory:
      a10_host: "{{ a10_host }}"
      a10_username: "{{ a10_username }}"
      a10_password: "{{ a10_password }}"
      a10_port: "{{ a10_port }}"
      state: present
      partition: all
```

vip1というVirtual Serverをip_addressというIPアドレスで設定し、関連付けるService Groupとしてsg1を、バックエンドのIPアドレス用プールとしてp1を指定しています。

```shell-session
[root@ansible playbook]# ansible-playbook -i hosts a10_slb_virtual_server_http_create.yaml

PLAY [10.255.0.1] ****************************************************************************************************************************

TASK [Configure virtual server] **************************************************************************************************************
changed: [10.255.0.1]

TASK [Write memory] **************************************************************************************************************************
changed: [10.255.0.1]

PLAY RECAP ***********************************************************************************************************************************
10.255.0.1                 : ok=2    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
```

vThunder側で確認します。

```shell-session
vThunder#show slb virtual-server
Total Number of Virtual Services configured: 1
Virtual Server Name      IP              Current    Total      Request  Response Peak
Service-Group            Service         connection connection packets  packets  connection
----------------------------------------------------------------------------------------
*vip1 192.168.1.100       All Up

   port 80  http                         0          0          0        0        0
sg1                      80/http         0          0          0        0        0
Total received conn attempts on this port: 0
```

# アクセス確認

この状態で、Virtual Serverに対してアクセスすると、
![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159980/d758e84d-9bed-c870-4d92-36a8f0edac53.png)

![image](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/159980/c19aec63-340e-1ca3-1c6e-af97d5cdf7d0.png)

タイミングによってアクセス先が異なることがわかる。分散状況に関しては、vThunder側で確認できる。きれいに等分されていることがわかる。

```shell-session
vThunder#show slb virtual-server
Total Number of Virtual Services configured: 1
Virtual Server Name      IP              Current    Total      Request  Response Peak
Service-Group            Service         connection connection packets  packets  connection
----------------------------------------------------------------------------------------
*vip1 192.168.1.100       All Up

   port 80  http                         1          5          37       131      0
sg1                      80/http         1          4          31       69       0
Total received conn attempts on this port: 5
```

# 感想
ネットワーク機器がそれほどわかっていなくても普通に構成変更できてしまう。
A10さんの用意した教材が非常によくまとまっているのもあるが、Ansibleはやはりわかりやすい。あとA10のモジュールのつくりもちょっと冗長だけど、その分考え方は単純な気がする。
あと、vThunderは初めて知ったけど、評価版もあるらしく、機会があれば実業務でも使ってみたい。