ansible のお試しがてら、 Raspberry に Python MPI 環境を作ってみる

サーバを同一用途で複数台用意してある環境って、仕事関係ではフツーにある環境なわけですが、それらの設定変更となると、同じ手順を台数分だけ繰り返し。なるべく作業者のレベルに左右されないような手順を用意したとしても、稀に手順ミスってトラブルなんてことも起きちゃうわけですよ。
作業者しても、出来る限り楽したいですし、定型化可能な作業だったら、コマンド一発で対象全台に設定適用したり、必要なファイルを配布したり出来れば、余計な手順やミス発生のリスクも減らせて、万々歳。

というわけで、オープンソース界隈でも「構成管理ツール」と言われるものが、いくつか開発されているんですが、その中でも ansible が、最近はお薦めらしので、ちょっといじってみようかと思った次第。

Ansible seamlessly unites workflow orchestration with configuration management, provisioning, and application deployment in one easy-to-use and deploy platform.

[From Ansible Use Cases]

Ansible(アンシブル)は、レッドハットが開発するオープンソースの構成管理ツールである。構成管理に加え、オーケストレーションやソフトウェアデプロイメントの機能を持つ。

[From Ansible (ソフトウェア) - Wikipedia]

同じようなツールだと、 Chef や Puppet と言うものもあるようですが、

  • エージェントレスで、管理したい側へは ssh 接続出来れば良い

と、利用するまでの敷居が低い、というのもお薦めのポイントになっているようです。

とりあえず、ラズパイ Cluster (モドキ)を構成してみる準備

まずは構成

今のところ、Raspberry Pi3 は1台しかないので、それを管理対象に。それと別に管理サーバとして Debian sid を仮想マシンで準備して、ここに ansible をインストール、という非常にミニマムな構成です。

ansibleのテスト環境

図にも書いてある通り、ホントは何台も並べて、クラスタリングしたいんですけどね…。

これに関してはどっちかというと、親である自分のほうが複数台並べて Rasp Pi クラスタ組んでみたいという気持ちのほうが大きかったりしますけど、息子もプログラミング自体には興味があるようなので、作ったクラスタで一緒に遊ぶってのも出来るなぁ、とかとか。

[From 子供に PC を渡そうと思ってるんですけどね - Soukaku's HENA-CHOKO Blog]

ま、 ansible に慣れることが目的なので、このまま進めます。


ansible インストールと簡単な動作確認

インストール自体は、簡単。
念のため、シミュレーションモードで依存関係を確認。以下のパッケージがインストールされるようなので、 '-s' を外して

root@RPiHQ:~# aptitude -s install ansible
以下の新規パッケージがインストールされます:
ansible ieee-data{a} libyaml-0-2{a} python-cffi-backend{a} python-crypto{a} python-cryptography{a}
python-enum34{a} python-idna{a} python-ipaddress{a} python-jinja2{a} python-markupsafe{a} python-netaddr{a}
python-paramiko{a} python-pyasn1{a} python-selinux{a} python-setuptools{a} python-yaml{a}
更新: 0 個、新規インストール: 17 個、削除: 0 個、保留: 0 個。
アーカイブの 3,928 kB を取得する必要があります。展開後に 23.9 MB のディスク領域が新たに消費されます。

注意: 'シミュレーション' モードを使用します。
先に進みますか? [Y/n/?] y
パッケージのダウンロード/インストール/削除を行います。

インストールが終わったら、管理対象となる Raspberry の IP アドレスを記述したファイルを用意します。
今回はこんな感じ。

soukaku@RPiHQ:~$ ls -l ansible/inventory/hosts
-rw-r--r-- 1 soukaku soukaku 45 11月 7 22:03 ansible/inventory/hosts
soukaku@RPiHQ:~$ more ansible/inventory/hosts
[raspberry]
172.16.0.131 hostname=RPiClstr01

ansible/inventory/hosts の '[]' で括られているところがグループ名で、その下にあるのが、管理対象の IP アドレス。IP アドレスに続けて書いてある 'hostname=RPiClstr01' の部分は、後ほど…。

これで、最低限必要な準備ができたので、動作を確認。 ansible/inventory/hosts で記述したグループに対して ping というモジュールを利用して疎通確認をしてみると言うやつなんですが、'ansible グループ名 -i inventoryファイル -m ping’ とやってみるも

soukaku@RPiHQ:~$ ansible raspberry -i ansible/inventory/hosts -m ping
172.16.0.131 | UNREACHABLE! => {
"changed": false,
"msg": "msg": "SSH Error: data could not be sent to the remote host. Make sure this host can be reached over ssh",
"unreachable": true
}

と、’UNREACHABLE!’ と返ってきて、確認に失敗している模様。'SSH Error: data could not be sent to the remote host.' というメッセージも出ているので、どうやら ssh での接続に失敗している模様。
ping モジュールのドキュメント読んでみたら、’This is NOT ICMP ping,’ と記述されているとおり、ネットワーク的な ping ではなく、 ssh で接続できるかどうか、をチェックすることで管理対象の状態を確認する為のモジュールだと…。

管理サーバ側が 'soukaku' というユーザで操作していたために ansible 実行時に 管理対象に存在しないユーザで ssh 接続しようとしていたのでエラーになっていたようです。
コレを回避するためには、 '-u' オプションで管理対象にあるユーザ(Raspbian に用意済みの pi ユーザ)を指定、 '-k (--ask-password)' オプションでパスワード入力させるようにして実行すると…。

soukaku@RPiHQ:~$ ansible raspberry -i ansible/inventory/hosts -u pi -m ping -k
SSH password:
172.16.0.131 | SUCCESS => {
"changed": false,
"ping": "pong"
}

'SUCCESS' と表示されて、確認完了となりました。

Python MPI 環境を構築するために playbook を書いてみる

動作することがわかったので、 管理対象側に必要なパッケージのインストールや設定を行うための playbook を書いてみる、ということになるんですが、こんなのを作ってみました。

- hosts: raspberry
remote_user: pi
sudo: yes
tasks:
- name: 変数の表示
debug: msg="hostname {{ hostname }}"

- name: SSH公開鍵認証の設定
authorized_key: user=pi key="{{ lookup('file','/home/soukaku/.ssh/id_rsa.pub') }}" manage_dir=yes

- name: ホスト名変更
lineinfile: >
dest=/etc/hostname
regexp='.*'
line='{{ hostname }}'

- name: インストール済みパッケージのアップグレード
apt:
update_cache: yes
upgrade: safe
autoremove: yes

- name: MPI関連パッケージのインストール
apt: name={{item}}
with_items:
- mpich
- python3-mpi4py
- zenmap
- zabbix-agent

ちょこちょこと説明を加えていくと

  • 1 〜 3 行目
    • 設定対象となるグループ名を '- host:' 、管理対象への接続時に使うユーザ名を 'remote_user:' 、sudo によるコマンドが実行できるよう 'sudo: yes' を指定
  • 4 行目の ’tasks:’ から下が、実際に処理させたい内容
  • 6 行目
    • ここで、inventory ファイルに書いた 'hostname=' という変数に続く部分を表示させています。ここで表示させた内容で、管理サーバの /etc/hostname の内容を更新する処理がこのあとに出てきます。
    • 別に、表示させなくてもいいんですが、確認のため…。
  • 9 行目
    • 管理対象サーバのユーザ pi に対して、管理サーバのユーザ soukaku から公開鍵認証でログインできるように、秘密鍵を転送
  • 11 行目
    • lineinfileモジュールを使って、管理対象の /etc/hostname の中身を inventory ファイルに記述した 'hostname=' の内容で書き換え
  • 18 〜 19 行目
    • apt モジュールを使って、パッケージデータベースの更新(update_cache: yes)、'aptitude safe-upgrade' 実行と同様のパッケージ更新を実施(upgrade: safe)、不要パッケージを消去(autoremove: yes
  • 24 〜 29 行目
    • 同じく apt モジュールを利用して、指定パッケージ(+その依存パッケージ)をインストール
    • インストールしたいパッケージは 'with_itmes:' 以降に羅列

という感じ。途中 ’- name: ’ とある部分に簡単な処理の説明を書いておくと、 playbook のどの辺を実行しているの目安になるので、コマメに書いておくと良いかも。

この内容で、管理サーバに ~/ansible/rpi_cluster.yml という名前で保存します。

まずは、テスト

このまま実行してもいいんですが、playbook にミスがないかチェックを兼ねて、チェックモードで実行してみます。
playbook を実行するときは ansible-playbook コマンドを使います。'-i' でinventory ファイルを指定、続けて playbook 、'-k' でパスワードプロンプト表示。 '--check' を指定することで管理対象側の変更を行わずに実行、となります。

で、実行してみた結果が、以下の内容。

soukaku@RPiHQ:~$ ansible-playbook -i ansible/inventory/hosts ansible/rpi_cluster.yml -k --check
SSH password:
[DEPRECATION WARNING]: Instead of sudo/sudo_user, use become/become_user and make sure
become_method is 'sudo' (default).
This feature will be removed in a future release. Deprecation warnings can be disabled by setting

PLAY [raspberry] ***************************************************************

TASK [setup] *******************************************************************
ok: [172.16.0.131]

TASK [変数の表示] *******************************************************************
ok: [172.16.0.131] => {
"msg": "hostname RPiClstr01"
}

TASK [SSH公開鍵認証の設定] *************************************************************
changed: [172.16.0.131]

TASK [ホスト名変更] ******************************************************************
changed: [172.16.0.131]

TASK [インストール済みパッケージのアップグレード] ***************************************************
ok: [172.16.0.131]

TASK [MPI関連パッケージのインストール] *******************************************************
changed: [172.16.0.131] => (item=[u'mpich', u'python3-mpi4py', u'zenmap', u'zabbix-agent'])

PLAY RECAP *********************************************************************
172.16.0.131 : ok=6 changed=3 unreachable=0 failed=0

soukaku@RPiHQ:~$

タスクで指定しているパッケージのアップデートやインストールのところ、時間がかかりますが、じっと待ちます。

'PLAY RECAP' の下に対象サーバの IP アドレスとタスクの実行結果が表示されれば、 playbook の内容は問題なし、となります。
自分がよく引っかかったのは、playbook でインデントがかかっている部分に tab 使ってしまってそこで失敗するパターン。インデントするときはスペースしか使えないようですので、 playbook 作成時に使うエディタの設定には要注意。

実行してみた

実際に、 Raspberry の設定を変更してみるわけですが、前段のチェックモードでの実行から ’--check’ を外した形で ansible-playbook コマンドを実行するだけなんですけど、その前に管理対象側のファイルの状態とかを確認しておきましょう。
とりあえず、管理対象に SSH でログインして、パスワード認証が求められること、公開鍵認証に必要な ~/.ssh/authorized_keys ファイルがないこと、 python3-mpi4py パッケージがインストールされていないことを確認。

soukaku@RPiHQ:~$ ssh pi@172.16.0.131
pi@172.16.0.131's password:

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Tue Nov 8 23:38:12 2016 from 172.16.0.99
pi@raspberrypi:~ $ ls -l .ssh/
合計 0
pi@raspberrypi:~ $ aptitude show python3-mpi4py
パッケージ: python3-mpi4py
状態: インストールされていません
バージョン: 1.3.1+hg20131106-2
優先度: 特別
セクション: python
メンテナ: NeuroDebian Team
アーキテクチャ: armhf
展開サイズ: 1,256 k
依存: libc6 (>= 2.4), libhwloc5 (>= 1.10.0), libopenmpi1.6, python3 (< 3.5), python3 (>= 3.4~)
推奨: mpi-default-bin
提案: python3-numpy
説明: bindings of the Message Passing Interface (MPI) standard
MPI for Python (mpi4py) provides bindings of the Message Passing Interface (MPI) standard for
the Python programming language, allowing any Python program to exploit multiple processors.

mpi4py is constructed on top of the MPI-1/MPI-2 specification and provides an object oriented
interface which closely follows MPI-2 C++ bindings. It supports point-to-point (sends,
receives) and collective (broadcasts, scatters, gathers) communications of any picklable Python
object as well as optimized communications of Python object exposing the single-segment buffer
interface (NumPy arrays, builtin bytes/string/array objects).
ホームページ: http://code.google.com/p/mpi4py/

pi@raspberrypi:~ $ exit
ログアウト
Connection to 172.16.0.131 closed.
soukaku@RPiHQ:~$

で、おもむろに実行。

soukaku@RPiHQ:~$ ansible-playbook -i ansible/inventory/hosts ansible/rpi_cluster.yml -k
SSH password:
[DEPRECATION WARNING]: Instead of sudo/sudo_user, use become/become_user and make sure
become_method is 'sudo' (default).
This feature will be removed in a future release. Deprecation warnings can be disabled by setting

PLAY [raspberry] ***************************************************************

TASK [setup] *******************************************************************
ok: [172.16.0.131]

TASK [変数の表示] *******************************************************************
ok: [172.16.0.131] => {
"msg": "hostname RPiClstr01"
}

TASK [SSH公開鍵認証の設定] *************************************************************
changed: [172.16.0.131]

TASK [ホスト名変更] ******************************************************************
changed: [172.16.0.131]

TASK [インストール済みパッケージのアップグレード] ***************************************************
ok: [172.16.0.131]

TASK [MPI関連パッケージのインストール] *******************************************************
changed: [172.16.0.131] => (item=[u'mpich', u'python3-mpi4py', u'zenmap', u'zabbix-agent'])

PLAY RECAP *********************************************************************
172.16.0.131 : ok=6 changed=3 unreachable=0 failed=0

soukaku@RPiHQ:~$

と、コレだけだと、’--check’ 付けて実行したのと、ほとんど変わったように見えないので、先ほどと同じように管理対象側にログインして確認。

soukaku@RPiHQ:~$ ssh pi@172.16.0.131

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Tue Nov 8 23:50:54 2016 from 172.16.0.99
pi@raspberrypi:~ $ more /etc/hostname
RPiClstr01
pi@raspberrypi:~ $ ls -l .ssh/
合計 4
-rw------- 1 pi pi 395 11月 8 23:50 authorized_keys
pi@raspberrypi:~ $ aptitude show python3-mpi4py
パッケージ: python3-mpi4py
状態: インストール済み
自動的にインストールされた: いいえ
バージョン: 1.3.1+hg20131106-2
優先度: 特別
セクション: python
メンテナ: NeuroDebian Team
アーキテクチャ: armhf
展開サイズ: 1,256 k
依存: libc6 (>= 2.4), libhwloc5 (>= 1.10.0), libopenmpi1.6, python3 (< 3.5), python3 (>= 3.4~)
推奨: mpi-default-bin
提案: python3-numpy
説明: bindings of the Message Passing Interface (MPI) standard
MPI for Python (mpi4py) provides bindings of the Message Passing Interface (MPI) standard for
the Python programming language, allowing any Python program to exploit multiple processors.

mpi4py is constructed on top of the MPI-1/MPI-2 specification and provides an object oriented
interface which closely follows MPI-2 C++ bindings. It supports point-to-point (sends,
receives) and collective (broadcasts, scatters, gathers) communications of any picklable Python
object as well as optimized communications of Python object exposing the single-segment buffer
interface (NumPy arrays, builtin bytes/string/array objects).
ホームページ: http://code.google.com/p/mpi4py/

pi@raspberrypi:~ $ exit
ログアウト
Connection to 172.16.0.131 closed.
soukaku@RPiHQ:~$

ログイン時のパスワードは要求されないし、/etc/hostname が書き換わり(RasPi の再起動していないのでプロンプトは変更前のホスト名のまま)、~/.ssh/authorized_keys ファイルも生成され、 python3-mpi4py もインストール済み、となっていますので、 playbook で指定したとおりに設定やパッケージのインストールが行われているようです。

ところで、「冪等性」って何?

さて、ansible と使うことの利点の一つとして「冪等性が保証される」というのがあるそうです。

AnsibleのPlaybookでは、対象リソースに対して「何を実行するのか」ではなく、「どういう状態があるべき姿なのか」を記述します。そのため、同じ処理を何回実行しても同じ結果になります。この性質を冪等性(べきとうせい)と呼びます。

[From 構成管理ツールとしてAnsibleを選ぶべき理由 | Think IT(シンクイット)]

サーバのスケールアウトをしたいので、以前使った playbook をそのまま利用すれば、既存サーバはそのままに、追加サーバは既存サーバと同じ設定に、ということが容易に出来ると…。

そのあたりは、2 台目、 3台目 の RasPi を入手してから、いろいろ試してみたいですね。あと、ansible で使えるモジュールもいろいろ試してみたいものがチラホラあるし…。

肝心の Python + MPI のほうですが、こちらはしっかりハマってますんで、いろいろ解消したところで、またエントリーとしてまとめるつもり。
#情報があるようで、ドンピシャなのが見つからない…。

トラックバック(0)

コメントする