AnsibleでLinuxサーバのSolidfire iSCSIボリューム マウント 自動化

# AnsibleでLinuxサーバのSolidfire iSCSIボリューム マウント 自動化
インフラ構築・運用のフェーズで、繰り返し・定期的に実施する作業、対象サーバ数・ボリューム数が多数ある作業は、自動化をしておくと何かと便利かと思います。 今回は Ansibleのmoduleを利用して、Linuxサーバから Solidfire の iSCSIボリューム をマウントするためのLinuxサーバ上での作業をAnsibleで自動化してみたものを紹介します。


なお、 Ansible管理サーバは構築済みで、Storage側のiSCSIボリュームも作成・設定が完了済みの前提です。

Ansible導入・SolidFire ボリューム作成については[Ansibleを利用したiSCSIボリューム作成](https://qiita.com/yoihoka/private/63313f0532b3a61c215c)の記事で触れているので、よろしければそちらもどうぞ。なお、「Ansibleを利用したiSCSIボリューム作成」の記事ではCHAP認証ではなくVAG認証方式を利用しています。ご注意ください。

##前提
以下の環境で試しています

- Cent 7.7
- Solidfire 12.2
- Ansible 2.10
- Python 3.6.8
- solidfire-sdk-python 1.7.0.152

なお、この記事で書かれている 手順やPlayBookは動作を保証されたものではありません。
各環境に合わせてテスト・確認をしたうえで自己責任にて利用していただければと思います。

##作業の流れ
1. Ansible Collection & Package追加 
2. ディレクトリ構成準備 
3. インベントリファイル作成 
4. Playbookファイル作成
5. Playbook実行

## 1. Ansible Collection & Package追加 
Ansible 2.10からは、モジュールがCollectionで管理されるようになり、Ansible-baseと一緒に導入されるモジュール以外は必要に応じて明示的に追加する必要があります。

今回利用するモジュール用のCollectionをansible-galaxyコマンドで追加します。

また、今回は、ansible実行時の管理対象サーバへのsshアクセスはパスワード認証を利用するので、
必要なパッケージをyumで導入します。

```shell:
$ ansible-galaxy collection install community.general
$ ansible-galaxy collection install ansible.posix
$ sudo yum install -y sshpass
- 出力は省略：必要に応じて "y" を入力 -

```
なお、NetAppモジュールのCollectionのリリースは、[こちら](https://netapp.io/2019/09/17/coming-together-nicely/)で簡単に紹介されているので 興味ある方は確認してみてください。


## 2. ディレクトリ構成準備  
ansibleの各種ファイルを配置するディレクトリを準備します。

```shell:ディレクトリ・ファイル構成
~/ansible-lin
├─ hosts
|  └─ hosts
├─ tasks
|  └─ main.yaml
└─ vars
   ├─ sf-common.yaml
   └─ chap-auth.yaml
   
```

```shell:
$ mkdir -p ~/ansible-lin/hosts ~/ansible-lin/tasks ~/ansible-lin/vars

```
## 3. インベントリファイル作成  
~/hosts/ディレクトリは配下にインベントリファイルを作成し、iSCSiボリュームマウント処理を行う対象サーバを登録します。
iscsi_clientというグループに、client01 , client02の２台のサーバを所属させます。



```plaintext:①hosts
[iscsi_client]
client01 ansible_host=<< client01のIPアドレス >>
client02 ansible_host=<< client02のIPアドレス >>

[iscsi_client:vars]
ansible_ssh_port=22
ansible_ssh_user=<< sshユーザ >>
ansible_ssh_pass=<< sshユーザ パスワード >>
ansible_ssh_common_args='-o StrictHostKeyChecking=no'

```

## 4. Playbookファイル作成  
次にPlaybookファイルを作成します。

利用するパラメータ値は以下となります。

| パラメータ名 | 値 | 備考
|:---:|---|---|
|VG名| vgnX |
|LV名| lvnX |
|マウントポイント| /iscmntX |

　※ Xは連番数字

####パラメータファイルの準備
~/ansible/varsディレクトリ配下に、sf-common,yaml ,chap-authyaml の2つのパラメータファイルを作成します。

```yaml:①sf-common.yaml
cluster_svip      : "<< Solidfire Storage VIP >>"

```

```yaml:②chap-auth.yaml
chap_ps    : << CHAP Initiator Secret >>
chap_ps_in : << CHAP Target Secret >>

```

####Playbookファイルの準備
次に、~/ansible/tasksディレクトリ配下に main.yamlファイルを準備します。

以下の流れで設定をおこなうプレイブックになっています。

1. iSCSIパッケージ導入
2. /etc/iscsi.confファイル編集
3. iSCSIボリューム検出＆ログインしてデバイスとして認識
4. iSCSIボリュームマウント

なお、このプレイブックの記述では、対象サーバが、"/dev/sda"デバイスをシステム領域用ディスクとして利用している前提で、"/dev/sda"デバイス以外は、ディスクを認識しておらず接続もされていない想定での記述となっています。

追加するiSCSIボリュームは/dev/sdb以降のデバイスとして認識される想定です。
認識したデバイスはLVMボリュームとして自動的にマウント・/etc/fstab登録まで実行されます。


```yaml:main.yaml
---
- name: iscsi mount
  hosts: iscsi_client
  gather_facts: no
  vars:
    vgname     : vgn
    lvname     : lvn
    mntname    : iscmnt
  vars_files:
    - ../vars/chap-auth.yaml
    - ../vars/sf-common.yaml
  tasks:
    - name: yum install iscsi-initiator-utils
      yum:
        name: "{{ packages }}"
        state: latest
        update_cache: yes
      vars:
        packages:
          - iscsi-initiator-utils
      register: iscsi


    ### Setting iscsid.conf Phase

    - name: set iscsid.conf file
      blockinfile:
        path: /etc/iscsi/iscsid.conf
        block: |
          node.session.auth.authmethod = CHAP
          node.session.auth.username = {{ inventory_hostname }}
          node.session.auth.password = {{ chap_ps }}
          node.session.auth.username_in = {{ inventory_hostname }}
          node.session.auth.password_in = {{ chap_ps_in }}

          discovery.sendtargets.auth.authmethod = CHAP
          discovery.sendtargets.auth.username = {{ inventory_hostname }}
          discovery.sendtargets.auth.password = {{ chap_ps }}
          discovery.sendtargets.auth.username_in = {{ inventory_hostname }}
          discovery.sendtargets.auth.password_in = {{ chap_ps_in }}
      register: iscsid_conf


    - name: start iscsid
      systemd:
        name : iscsid.service
        state: restarted
        enabled: yes


    ### iSCSI discovery & connect Phase

    - name: iscsi target discovery
      community.general.open_iscsi:
        show_nodes: yes
        discover  : yes
        portal    : '{{ cluster_svip }}'
      register: iscsi_target

    - name: iscsi targets connect
      open_iscsi:
        target: "{{ item }}"
        login: yes
      with_items: "{{ iscsi_target.nodes }}"
      when: iscsi_target.changed


    ### iSCSI Mount Phase

    - name: find all iscsi devices
      find:
        paths: /dev
        file_type: any
        patterns: "^sd[b-z]$"
        use_regex: yes
      register: found_devices

    - name: create volume group
      lvg:
        vg : "{{ vgname }}{{ item.0 }}"
        pvs: "{{ item.1.path }}"
      with_indexed_items: '{{ found_devices.files }}'

    - name: create logical volume
      lvol:
        vg : "{{ vgname }}{{ item.0 }}"
        lv : "{{ lvname }}{{ item.0 }}"
        size: +100%FREE
        shrink: no
      with_indexed_items: '{{ found_devices.files }}'


    - name: make filesystem
      filesystem:
        fstype: xfs
        dev: /dev/mapper/{{ vgname }}{{ item.0 }}-{{ lvname }}{{ item.0 }}
      with_indexed_items: '{{ found_devices.files }}'

    - name: mount disk
      mount:
        path: /{{ mntname }}{{ item.0 }}
        src: /dev/{{ vgname }}{{ item.0 }}/{{ lvname }}{{ item.0 }}
        fstype: xfs
        opts: _netdev
        state: mounted
      with_indexed_items: '{{ found_devices.files }}'

```
##5. Playbook実行
プレイブックを実行してみます。
実行時は"-i"オプションで明示的に利用するインベントリファイルを指定しています。

```shell:実行例
$ cd ~/ansible-lin/tasks
$ ansible-playbook -i ../hosts/hosts main.yaml

PLAY [iscsi mount] *****************************************************************************************************

TASK [yum install iscsi-initiator-utils] *******************************************************************************
changed: [client01]
changed: [client02]

TASK [set iscsid.conf file] ********************************************************************************************
changed: [client02]
changed: [client01]

TASK [start iscsid] ****************************************************************************************************
changed: [client02]
changed: [client01]

TASK [iscsi target discovery] ******************************************************************************************
changed: [client02]
changed: [client01]

TASK [iscsi targets connect] *******************************************************************************************
changed: [client01] => (item=iqn.2010-01.com.solidfire:wwnr.sfvol101.643)
changed: [client02] => (item=iqn.2010-01.com.solidfire:wwnr.sfvol201.645)
changed: [client02] => (item=iqn.2010-01.com.solidfire:wwnr.sfvol202.646)
changed: [client01] => (item=iqn.2010-01.com.solidfire:wwnr.sfvol102.644)

TASK [find all iscsi devices] ******************************************************************************************
ok: [client02]
ok: [client01]

TASK [create volume group] *********************************************************************************************
changed: [client02] => (item=[0, {'uid': 0, 'woth': False, 'mtime': 1614744046.6572943, 'inode': 24227, 'isgid': False, 'size': 0, 'roth': False, 'isuid': False, 'isreg': False, 'pw_name': 'root', 'gid': 6, 'ischr': False, 'wusr': True, 'xoth': False, 'rusr': True, 'nlink': 1, 'issock': False, 'rgrp': True, 'gr_name': 'disk', 'path': '/dev/sdc', 'xusr': False, 'atime': 1614744046.6572943, 'isdir': False, 'ctime': 1614744046.6572943, 'isblk': True, 'xgrp': False, 'dev': 5, 'wgrp': True, 'isfifo': False, 'mode': '0660', 'islnk': False}])
changed: [client01] => (item=[0, {'uid': 0, 'woth': False, 'mtime': 1614744046.6707006, 'inode': 28111, 'isgid': False, 'size': 0, 'roth': False, 'isuid': False, 'isreg': False, 'pw_name': 'root', 'gid': 6, 'ischr': False, 'wusr': True, 'xoth': False, 'rusr': True, 'nlink': 1, 'issock': False, 'rgrp': True, 'gr_name': 'disk', 'path': '/dev/sdc', 'xusr': False, 'atime': 1614744046.6707006, 'isdir': False, 'ctime': 1614744046.6707006, 'isblk': True, 'xgrp': False, 'dev': 5, 'wgrp': True, 'isfifo': False, 'mode': '0660', 'islnk': False}])
changed: [client02] => (item=[1, {'uid': 0, 'woth': False, 'mtime': 1614744045.3072782, 'inode': 24955, 'isgid': False, 'size': 0, 'roth': False, 'isuid': False, 'isreg': False, 'pw_name': 'root', 'gid': 6, 'ischr': False, 'wusr': True, 'xoth': False, 'rusr': True, 'nlink': 1, 'issock': False, 'rgrp': True, 'gr_name': 'disk', 'path': '/dev/sdb', 'xusr': False, 'atime': 1614744045.3072782, 'isdir': False, 'ctime': 1614744045.3072782, 'isblk': True, 'xgrp': False, 'dev': 5, 'wgrp': True, 'isfifo': False, 'mode': '0660', 'islnk': False}])
changed: [client01] => (item=[1, {'uid': 0, 'woth': False, 'mtime': 1614744045.2946823, 'inode': 28000, 'isgid': False, 'size': 0, 'roth': False, 'isuid': False, 'isreg': False, 'pw_name': 'root', 'gid': 6, 'ischr': False, 'wusr': True, 'xoth': False, 'rusr': True, 'nlink': 1, 'issock': False, 'rgrp': True, 'gr_name': 'disk', 'path': '/dev/sdb', 'xusr': False, 'atime': 1614744045.2946823, 'isdir': False, 'ctime': 1614744045.2946823, 'isblk': True, 'xgrp': False, 'dev': 5, 'wgrp': True, 'isfifo': False, 'mode': '0660', 'islnk': False}])

TASK [create logical volume] *******************************************************************************************
changed: [client02] => (item=[0, {'uid': 0, 'woth': False, 'mtime': 1614744046.6572943, 'inode': 24227, 'isgid': False, 'size': 0, 'roth': False, 'isuid': False, 'isreg': False, 'pw_name': 'root', 'gid': 6, 'ischr': False, 'wusr': True, 'xoth': False, 'rusr': True, 'nlink': 1, 'issock': False, 'rgrp': True, 'gr_name': 'disk', 'path': '/dev/sdc', 'xusr': False, 'atime': 1614744046.6572943, 'isdir': False, 'ctime': 1614744046.6572943, 'isblk': True, 'xgrp': False, 'dev': 5, 'wgrp': True, 'isfifo': False, 'mode': '0660', 'islnk': False}])
changed: [client01] => (item=[0, {'uid': 0, 'woth': False, 'mtime': 1614744046.6707006, 'inode': 28111, 'isgid': False, 'size': 0, 'roth': False, 'isuid': False, 'isreg': False, 'pw_name': 'root', 'gid': 6, 'ischr': False, 'wusr': True, 'xoth': False, 'rusr': True, 'nlink': 1, 'issock': False, 'rgrp': True, 'gr_name': 'disk', 'path': '/dev/sdc', 'xusr': False, 'atime': 1614744046.6707006, 'isdir': False, 'ctime': 1614744046.6707006, 'isblk': True, 'xgrp': False, 'dev': 5, 'wgrp': True, 'isfifo': False, 'mode': '0660', 'islnk': False}])
changed: [client02] => (item=[1, {'uid': 0, 'woth': False, 'mtime': 1614744045.3072782, 'inode': 24955, 'isgid': False, 'size': 0, 'roth': False, 'isuid': False, 'isreg': False, 'pw_name': 'root', 'gid': 6, 'ischr': False, 'wusr': True, 'xoth': False, 'rusr': True, 'nlink': 1, 'issock': False, 'rgrp': True, 'gr_name': 'disk', 'path': '/dev/sdb', 'xusr': False, 'atime': 1614744045.3072782, 'isdir': False, 'ctime': 1614744045.3072782, 'isblk': True, 'xgrp': False, 'dev': 5, 'wgrp': True, 'isfifo': False, 'mode': '0660', 'islnk': False}])
changed: [client01] => (item=[1, {'uid': 0, 'woth': False, 'mtime': 1614744045.2946823, 'inode': 28000, 'isgid': False, 'size': 0, 'roth': False, 'isuid': False, 'isreg': False, 'pw_name': 'root', 'gid': 6, 'ischr': False, 'wusr': True, 'xoth': False, 'rusr': True, 'nlink': 1, 'issock': False, 'rgrp': True, 'gr_name': 'disk', 'path': '/dev/sdb', 'xusr': False, 'atime': 1614744045.2946823, 'isdir': False, 'ctime': 1614744045.2946823, 'isblk': True, 'xgrp': False, 'dev': 5, 'wgrp': True, 'isfifo': False, 'mode': '0660', 'islnk': False}])

TASK [make filesystem] *************************************************************************************************
changed: [client01] => (item=[0, {'uid': 0, 'woth': False, 'mtime': 1614744046.6707006, 'inode': 28111, 'isgid': False, 'size': 0, 'roth': False, 'isuid': False, 'isreg': False, 'pw_name': 'root', 'gid': 6, 'ischr': False, 'wusr': True, 'xoth': False, 'rusr': True, 'nlink': 1, 'issock': False, 'rgrp': True, 'gr_name': 'disk', 'path': '/dev/sdc', 'xusr': False, 'atime': 1614744046.6707006, 'isdir': False, 'ctime': 1614744046.6707006, 'isblk': True, 'xgrp': False, 'dev': 5, 'wgrp': True, 'isfifo': False, 'mode': '0660', 'islnk': False}])
changed: [client02] => (item=[0, {'uid': 0, 'woth': False, 'mtime': 1614744046.6572943, 'inode': 24227, 'isgid': False, 'size': 0, 'roth': False, 'isuid': False, 'isreg': False, 'pw_name': 'root', 'gid': 6, 'ischr': False, 'wusr': True, 'xoth': False, 'rusr': True, 'nlink': 1, 'issock': False, 'rgrp': True, 'gr_name': 'disk', 'path': '/dev/sdc', 'xusr': False, 'atime': 1614744046.6572943, 'isdir': False, 'ctime': 1614744046.6572943, 'isblk': True, 'xgrp': False, 'dev': 5, 'wgrp': True, 'isfifo': False, 'mode': '0660', 'islnk': False}])
changed: [client01] => (item=[1, {'uid': 0, 'woth': False, 'mtime': 1614744045.2946823, 'inode': 28000, 'isgid': False, 'size': 0, 'roth': False, 'isuid': False, 'isreg': False, 'pw_name': 'root', 'gid': 6, 'ischr': False, 'wusr': True, 'xoth': False, 'rusr': True, 'nlink': 1, 'issock': False, 'rgrp': True, 'gr_name': 'disk', 'path': '/dev/sdb', 'xusr': False, 'atime': 1614744045.2946823, 'isdir': False, 'ctime': 1614744045.2946823, 'isblk': True, 'xgrp': False, 'dev': 5, 'wgrp': True, 'isfifo': False, 'mode': '0660', 'islnk': False}])
changed: [client02] => (item=[1, {'uid': 0, 'woth': False, 'mtime': 1614744045.3072782, 'inode': 24955, 'isgid': False, 'size': 0, 'roth': False, 'isuid': False, 'isreg': False, 'pw_name': 'root', 'gid': 6, 'ischr': False, 'wusr': True, 'xoth': False, 'rusr': True, 'nlink': 1, 'issock': False, 'rgrp': True, 'gr_name': 'disk', 'path': '/dev/sdb', 'xusr': False, 'atime': 1614744045.3072782, 'isdir': False, 'ctime': 1614744045.3072782, 'isblk': True, 'xgrp': False, 'dev': 5, 'wgrp': True, 'isfifo': False, 'mode': '0660', 'islnk': False}])

TASK [mount disk] ******************************************************************************************************
changed: [client01] => (item=[0, {'uid': 0, 'woth': False, 'mtime': 1614744046.6707006, 'inode': 28111, 'isgid': False, 'size': 0, 'roth': False, 'isuid': False, 'isreg': False, 'pw_name': 'root', 'gid': 6, 'ischr': False, 'wusr': True, 'xoth': False, 'rusr': True, 'nlink': 1, 'issock': False, 'rgrp': True, 'gr_name': 'disk', 'path': '/dev/sdc', 'xusr': False, 'atime': 1614744046.6707006, 'isdir': False, 'ctime': 1614744046.6707006, 'isblk': True, 'xgrp': False, 'dev': 5, 'wgrp': True, 'isfifo': False, 'mode': '0660', 'islnk': False}])
changed: [client02] => (item=[0, {'uid': 0, 'woth': False, 'mtime': 1614744046.6572943, 'inode': 24227, 'isgid': False, 'size': 0, 'roth': False, 'isuid': False, 'isreg': False, 'pw_name': 'root', 'gid': 6, 'ischr': False, 'wusr': True, 'xoth': False, 'rusr': True, 'nlink': 1, 'issock': False, 'rgrp': True, 'gr_name': 'disk', 'path': '/dev/sdc', 'xusr': False, 'atime': 1614744046.6572943, 'isdir': False, 'ctime': 1614744046.6572943, 'isblk': True, 'xgrp': False, 'dev': 5, 'wgrp': True, 'isfifo': False, 'mode': '0660', 'islnk': False}])
changed: [client01] => (item=[1, {'uid': 0, 'woth': False, 'mtime': 1614744045.2946823, 'inode': 28000, 'isgid': False, 'size': 0, 'roth': False, 'isuid': False, 'isreg': False, 'pw_name': 'root', 'gid': 6, 'ischr': False, 'wusr': True, 'xoth': False, 'rusr': True, 'nlink': 1, 'issock': False, 'rgrp': True, 'gr_name': 'disk', 'path': '/dev/sdb', 'xusr': False, 'atime': 1614744045.2946823, 'isdir': False, 'ctime': 1614744045.2946823, 'isblk': True, 'xgrp': False, 'dev': 5, 'wgrp': True, 'isfifo': False, 'mode': '0660', 'islnk': False}])
changed: [client02] => (item=[1, {'uid': 0, 'woth': False, 'mtime': 1614744045.3072782, 'inode': 24955, 'isgid': False, 'size': 0, 'roth': False, 'isuid': False, 'isreg': False, 'pw_name': 'root', 'gid': 6, 'ischr': False, 'wusr': True, 'xoth': False, 'rusr': True, 'nlink': 1, 'issock': False, 'rgrp': True, 'gr_name': 'disk', 'path': '/dev/sdb', 'xusr': False, 'atime': 1614744045.3072782, 'isdir': False, 'ctime': 1614744045.3072782, 'isblk': True, 'xgrp': False, 'dev': 5, 'wgrp': True, 'isfifo': False, 'mode': '0660', 'islnk': False}])

PLAY RECAP *************************************************************************************************************
client01                   : ok=10   changed=9    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0
client02                   : ok=10   changed=9    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

$ 
```


これでclient01,02で、iSCSIボリュームがマウントされ、/etc/fstabに登録がされました。

client01,02にログインして、dfコマンド等でボリュームマウントしてみると
/iscmntXディレクトリとしてマウントされていることを確認できます。


## まとめ
LinuxサーバでiSCSIボリュームをマウントする操作を自動化してみました。

今回はPlaybookファイルをあえて１ファイルで作成してみましたが、複数の処理要素を含んでいるのでファイル分割したり、Role化したりすることで利便性等があがるかと思います。また、インベントリファイルは、都度入力を省略するためにsshユーザ・パスワード等を記述しましたが、公開鍵認証方式にするとかAnsible Vault使うとか要件や環境に合わせて変更ができます。

そういった点は、実際に運用する際は考慮ポイントになって来るかと思います。