はじめに
世の中なんでもかんでもRubyで自分もRubyを学び始めようかなとは思うけど、同じことをpythonで書けたら良いなと思う今日この頃、インフラストラクチャ自動化ツールとして有名なchefの陰で、pythonによる自動化ツールがあると聞いて、早速使ってみた。ここではリモート環境をvagrantで立ち上げ、そのリモートマシンをansibleでセットアップする手順を紹介する。ホストの環境はMac OS X Mavericks。
※なお、同じpythonのインフラストラクチャ自動化ツールでも他に有名なソフト(Salt)があるので、別にこれがデファクトスタンダードなわけではない。でも一番シンプルそうなので、使ってみる(sshプロトコル使っているとかも良い)
vagrantのインストール
vagrantのインストールについては、以前にまとめたので、そこを見てほしい。
ansibleのインストール
pipでインストールするだけ。
$ pip install ansible
※ pipのインストール方法はpython環境によってまちまちなので、ここでは割愛。
準備
まず、リモートマシンを用意する。
$ mkdir ansible_test
$ cd ansible_test
$ vagrant box add ubuntu12.04_amd64 https://cloud-images.ubuntu.com/vagrant/precise/current/precise-server-cloudimg-amd64-vagrant-disk1.box
$ vagrant init ubuntu12.04_amd64
既に適当なboxを持っている人は、box addコマンドを実行しなくても良い。今回は諸事情で、ubuntu 12.04のamd64バージョンを使う。他のサイトではcentosで紹介していることが多く、apt-getで扱う方法も書いてあるサイトがあると便利だろうと思って、そうした。
vagrant initを済ませると、作業ディレクトリ中にVagrantfileが作成される。その内容を、ホストとゲスト間でネットワークを構成するように修正する。
config.vm.network :private_network, ip: "192.168.33.10"
具体的には上記のコメントアウトを外すだけ。IPアドレスはデフォルトのままだけど、好みに合わせて変えても良い。
次に、パスワードなしでアクセスできるように~/.ssh/configに設定を書く。
Host 192.168.33.10
User vagrant
IdentityFile /Users/<username>/.vagrant.d/insecure_private_key
最後にansible用のhostsファイルを設定する。これはデフォルトのものでも良いけど、使い勝手が悪いので、作った方が良い
[servers]
192.168.33.10 # ゲストOSのIPを指定する
上記の内容をansible-testディレクトリのhostsという内容のファイルに書き込む。serversの名前のとおり複数書いても構わない。
適宜、自分の環境に合わせて、編集すること。
これで、下準備は完了。
ウォーミングアップ
本当はこの章いらないんだけど、playbookに行く前に基本的なansibleの使い方を紹介。この内容は他のサイトと同じだから、もういいやという人は次に進むと良い。
まずはお決まりのping確認。
$ ansible -i hosts servers -m ping
192.168.33.10 | success >> {
"changed": false,
"ping": "pong"
}
コマンド実行
$ ansible -i hosts servers -a 'pwd'
192.168.33.10 | success | rc=0 >>
/home/vagrant
コピペしてできたら、次へ。
本番:playbookの作成
このツールの真髄は遠隔操作ではなく(遠隔操作ならsshでもできる)、インフラストラクチャの自動構成なので、playbookというyamlファイルを使った環境自動構成を試してみる。
これまでみたページで紹介されているのが、yumを使った方法なので、ここで紹介するplaybookはubuntuのapt-get仕様(もちろん、aptを使うサイトもあります)。
実用的な使い方ができるか試すために、やや複雑な手順が必要な環境を整えてみる。今回は、DeepLearningで使われるPythonのパッケージであるTheanoをインストールしてみる。
- hosts: servers
sudo: true
user: vagrant
tasks:
- name: apt-get update
apt: update_cache=yes
- name: apt-get upgrade
apt: upgrade=yes
- name: apt-get dist-upgrade
apt: upgrade=dist
- name: apt-get install git make python-dev python-setuptools libblas-dev gfortran g++ python-pip python-numpy python-scipy liblapack-dev
apt: name={{ item }} state=latest
with_items:
- git
- make
- python-dev
- python-setuptools
- libblas-dev
- gfortran
- g++
- python-pip
- python-numpy
- python-scipy
- liblapack-dev
- name: pip install nose
pip: name=nose
- name: pip install theano
command: /usr/bin/pip install --upgrade --no-deps git+git://github.com/Theano/Theano.git
- name: get deb package from cuda, http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1204/x86_64/cuda-repo-ubuntu1204_6.0-37_amd64.deb
get_url: url="http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1204/x86_64/cuda-repo-ubuntu1204_6.0-37_amd64.deb" dest="/home/vagrant"
- name: dpkg install cuda repo
command: dpkg -i /home/vagrant/cuda-repo-ubuntu1204_6.0-37_amd64.deb
- name: apt-get update
apt: update_cache=yes
- name: apt-get install cuda
apt: name=cuda state=latest
- name: add cuda path to environmental variable (1/2)
lineinfile: dest=/home/vagrant/.bashrc state=present line="export PATH=$PATH:/usr/local/cuda-6.0/bin:" insertafter=EOF
- name: add cuda path to environmental variable (2/2)
lineinfile: dest=/home/vagrant/.bashrc state=present line="export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/cuda-6.0/lib64:" insertafter=EOF
まず、このyamlが文法的に間違っていないかをチェック。
$ ansible-playbook -i hosts playbook_theano.yaml --syntax-check
間違っていなかったら、実行。
$ ansible-playbook -i hosts playbook_theano.yaml
今回サーバの指定とかが必要ないのは、yamlファイル中で指定されているからで、後は各コマンドを順次実行する。実行結果は以下の通り
PLAY [servers] ****************************************************************
GATHERING FACTS ***************************************************************
The authenticity of host '192.168.33.10 (192.168.33.10)' can't be established.
RSA key fingerprint is XXXXXXXXXXXXXX
Are you sure you want to continue connecting (yes/no)? yes
ok: [192.168.33.10]
TASK: [apt-get update] ********************************************************
ok: [192.168.33.10]
TASK: [apt-get upgrade] *******************************************************
changed: [192.168.33.10]
TASK: [apt-get dist-upgrade] **************************************************
ok: [192.168.33.10]
TASK: [apt-get install git make python-dev python-setuptools libblas-dev gfortran g++ python-pip python-numpy python-scipy liblapack-dev] ***
changed: [192.168.33.10] => (item=git,make,python-dev,python-setuptools,libblas-dev,gfortran,g++,python-pip,python-numpy,python-scipy,liblapack-dev)
TASK: [pip install nose] ******************************************************
changed: [192.168.33.10]
TASK: [pip install theano] ****************************************************
changed: [192.168.33.10]
TASK: [get deb package from cude, http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1204/x86_64/cuda-repo-ubuntu1204_6.0-37_amd64.deb] ***
changed: [192.168.33.10]
TASK: [dpkg install cuda repo] ************************************************
changed: [192.168.33.10]
TASK: [apt-get update] ********************************************************
ok: [192.168.33.10]
TASK: [apt-get install cuda] **************************************************
changed: [192.168.33.10]
TASK: [add cuda path to environmental variable (1/2)] *************************
changed: [192.168.33.10]
TASK: [add cuda path to environmental variable (2/2)] *************************
changed: [192.168.33.10]
PLAY RECAP ********************************************************************
192.168.33.10 : ok=13 changed=9 unreachable=0 failed=0
実際にインストールされているかをチェック。
$ vagrant ssh
vagrant@vagrant-ubuntu-precise-64:~$ python
Python 2.7.3 (default, Feb 27 2014, 19:58:35)
[GCC 4.6.3] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import theano
>>>
vagrant@vagrant-ubuntu-precise-64:~$
大丈夫そうである。なお、今回のyamlファイルでは、theanoをGPUで利用するためのパッケージ一式のインストールもしているが、VirtualBoxでは使用不可能なので、あしからず。
なお、ちゃんとビルドが通るまでに何回かvagrant destroy, vagrant upを繰り返してクリーンインストール可能かを確かめることになると思うが、用いるipアドレスが同じ場合、sshがエラーをはく。毎回、~/.ssh/known_hostsを削除する(か該当部分のみ削除する)ことをお忘れなく。
Playbook Tips
Playbookで使っているtask集について簡単にまとめる
apt-get
aptモジュールというのが用意されている。
- name: apt-get update
apt: update_cache=yes
- name: apt-get upgrade
apt: upgrade=yes
- name: apt-get dist-upgrade
apt: upgrade=dist
- name: apt-get install git
apt: name=git state=latest
上から順番に、apt-get update, apt-get upgrade, apt-get dist-upgrade, apt-get installの設定例である。
複数のパッケージを一括でインストールしたい場合はループを組み込むと良い。
- name: apt-get install git make python-dev python-setuptools libblas-dev gfortran g++ python-pip python-numpy python-scipy liblapack-dev
apt: name={{ item }} state=latest
with_items:
- git
- make
- python-dev
- python-setuptools
- libblas-dev
- gfortran
- g++
- python-pip
- python-numpy
- python-scipy
- liblapack-dev
ソースを外部から取得
パッケージ管理システムを介さずソースからビルドしたいときもある。そうした場合、ソースはget_urlモジュールで取得する。
- name: get deb package from cuda
get_url: url="http://developer.download.nvidia.com/compute/cuda/repos/ubuntu1204/x86_64/cuda-repo-ubuntu1204_6.0-37_amd64.deb" dest="/home/vagrant"
コマンド実行
もっと純粋にコマンド実行をしたい場合はcommandモジュールを使う
- name: dpkg install cuda repo
command: dpkg -i /home/vagrant/cuda-repo-ubuntu1204_6.0-37_amd64.deb
pip実行
pip用のモジュールも用意されている。
- name: pip install nose
pip: name=nose
が、ちょっと複雑なことをしようとすると、はまるので、コマンドで直接指定した方が良いこともある。
- name: pip install theano
command: /usr/bin/pip install --upgrade --no-deps git+git://github.com/Theano/Theano.git
設定ファイルの書き込み
PATHなどの設定を変更するときには、lineinfileモジュールを使う
- name: add cuda path to environmental variable (1/2)
lineinfile: dest=/home/vagrant/.bashrc state=present line="export PATH=$PATH:/usr/local/cuda-6.0/bin:" insertafter=EOF
今回はファイル末尾に行を追加しているだけだが、正規表現で指定行を探して書き換えるといった機能も提供している。
複数行の入力
複数行の入力は単に改行子を入れるだけではうまくいかない。git cloneしてから適当なロケーションにコピーしたり、gistからwgetで取得するほうが素直だが、そこまでするほどでもないという場合は以下のようにループ構造で書く手がある。
- name: add wsgi settings
lineinfile:
dest=/etc/apache2/httpd.conf
state=present
line={{ item }}
insertafter=EOF
with_items:
- "'WSGIScriptAlias / /var/www/hoge/wsgi.py'"
- "'WSGIPythonPath /var/www/hoge/'"
- "'<Directory /var/www/hoge/>'"
- "'<Files wsgi.py>'"
- "'Order deny,allow'"
- "'Allow from all'"
- "'</Files>'"
- "'</Directory>'"
上記はpythonのwsgiをapache2のhttpd.confに追記する場合の設定。シングルクォーテーションとダブルクォーテーションの2つを使って、forループとlineにおけるクォーテーションを入れることがポイント。
最後に
実はここまでではあまりうれしいことはなくて、このvagrant+ansible環境が威力を発揮するのは、amazon ec2サービスと組み合わせた場合だ。次回はその方法についても触れていく。