Ansible で 自動化 大作戦
事始め
元々は、vagrant の shell
で自動環境構築をしていたとある開発環境を、
調度良い機会だったので、Ansibleを使って自動化することにしました。
が、Ansibleの書き方が今ひとつ慣れていないのと、様々な制約に引っかかったので、
後々の私のためにメモを残しておきます。
↓目次
- 事始め
- 構築する環境
- 自動化で入れるもの
- (個人的に)詰まった点
- 最後に
↑さっき見つけて早速使ってみました。意外と便利そう
構築する環境
- ゲストOS : CentOS7 minimum
- ホストOS : OSX Yosemite
- Virtualbox : ver 5.0.4
- Vagrant : ver 1.7.4
- Ansible : ver1.8.1
自動化で入れるもの
大まかには次のもの。
その他必要な物は、yumでインストールしました。
(個人的に)詰まった点
個人的に詰まった点をメモ。もしかしたらできるのかもしれないですが、無知なのでその辺りはご愛嬌。
ansible の仕様(?)
例えば、このような書き方。
- name: install httpd yum: name=httpd state=present service: name=httpd state=stared enabled=true
やろうと思ったら、ansibleでエラーを吐かれました。
ERROR: multiple actions specified in task: 'service' and 'install httpd' Ansible failed to complete successfully. Any error output should be visible above. Please fix these errors and try again.
複数処理は、ダメみたいです。 こういう時は、素直に分けましょう。
- name: install httpd yum: name=httpd state=present - name: start & enable httpd service: name=httpd state=stared enabled=true
これは完全に私がぽかしてます。が、これで流れるなら結果オーライです。
yum での複数パッケージインストール
最初はこう書いてました。とてもきたないです。
- name: install packages yum: name=httpd state=latest yum: name=mariadb state=latest yum: name=gcc state=latest yum: name=wget state=latest ...
よくよく見ると、とてもきたない。エラーは吐かないけど汚い。
なので、Ansibleの変数を使ってみる。
- name: install packages yum: name={{ item }} state=latest with_items: - httpd - mariadb - gcc - wget ...
こうすると、綺麗(に見える。) ちなみに、最初は↓下の様に書いてましたが、盛大にエラーを吐かれました。
# エラーを起こす書き方 - name: install packages yum: name={{ item }} state=latest with_items: > httpd mariadb gcc wget
考えてみれば当たり前でした…これは完全に反省。 template とは違うんだよ templateとは!!
Pythonのインストール from ソース
ソースを持ってきて、make
してmake altinstal
するという作業。
そもそもmakeがあんまり好きじゃ(ry
これまで(Shellの時)のやり方。
コマンドを撃ちこむようにshellを書いてました。
#install & configure python3.3 sudo curl -O https://www.python.org/ftp/python/3.3.3/Python-3.3.3.tgz && sudo tar zxf Python-3.3.3.tgz cd ./Python-3.3.3 sudo ./configure --prefix=/opt/local sudo make && sudo make altinstall sudo echo 'export PATH="/opt/local/bin:${PATH}"' >> /root/.bashrc
まあ、ある意味便利でした。はい。 ansibleに移行するときにここまで面倒だとは思わなかったのですが(汗)
ansible で引っかかったところ
curl でのダウンロード
保存場所を決め打ちすれば問題なさそうに感じましたが、ファイルダウンロードをするのがどうも面倒くさい。
ansibleではget_url
なる物がある(公式ドキュメント)
ここまではまだ良かったのだが、この後の展開で方向転換をさせられてしまったのである。
python-3.3.3.tgz の展開
ansibleでは、アーカイブなどの展開を行ってくれるモジュールunarchive
があるので、それを全力で活用させて頂きました。
が、これのソースの指定で大ブレーキを喰らいました。
(実際のコード↓)
- name: unarchibve Python-3.3.3 unarchive: src=Python-3.3.3.tgz dest=/home/vagrant/
src
は、ホストPCでのファイル位置 を指定するものです。これ重要。
これに気づかずに数時間は頭を抱えてました…
Pythonのインストールは結果的に…
- ホストPC内に
Python-3.3.3.tgz
を用意 unarchive
のsrc
でホストPCのtgzをゲスト内に展開。make
&make altinstall
は、command
モジュールで実行する。
ということになりました。
が、command
モジュールを使おうとすると新たな問題が。
「冪等性」 どうするんだよ
一ヶ月前の私 「冪等性って何ですか?」
↓
今の私 「頭痛いです」
冪等性とは?
ansible が予め用意している モジュールでは、冪等性は保たれるようになっている様です。(ちゃんと確かめてないですが)
しかし、command
モジュールの場合は、結局 shell を垂れ流ししているだけで、冪等性が保たれる保証は無いのです。
頭が痛い内容No.1ですが、今回の自動化の目的でもあります。
で、Pythonの場合、結局どうしたかというと…
Makefile
があるかどうかをcommand: ls
で確かめる。make
とmake altinstall
の時に、when
で条件分岐させる。
ということをしました。ansibleのwhenは便利です。
これで、インストールがされるはずですし、既にインストールされている場合はmakeされず、 しっかりと冪等性が保たれてるはずです。
PATHの追加
shellのコマンドで言うところの export PATH=$PATH:/usr/local/bin
的な何かをしたかったのです。
environment
モジュール
Ansibleには、environmentモジュールなる物が存在していた。(らしい)
しかし、使おうとすると、エラーが発生して動かないという罠にハマりました。*1 これは使えません。
Pathは結局…?
良い策とは言えませんが、~/.bashrc
を、template
モジュールで書き換えるという戦法に。
個人的にもこれはひどい技だと思う次第であります。
ディレクトリが無くてエラーを吐かれる
rbenvをgitで落とす ( git
モジュールなるものがあった。とっても便利 ) ときに、
保存先ディレクトリが無いと、エラーが発生していました。これは一行で解決です。
- file: path=/hogehoge/fugafuga state=directory mode=0755
rbenvを無理やり動かす ( 冪等性付き )
rbenvとansible の連携があると思っていたが、調べても調べてもcommand
を使っていたので、
ここは諦めてcommand
を使おうかと…あ、ちゃんと冪等性も保つ様に心がけました。
rbenvが動かない
ファイルパーミッションの問題でした。gitでデータを入れるところの、ownerとgroupを適切に設定すれば大丈夫でした。
- name: change file permision file: path=/usr/local/rbenv owner={{ username }} group= {{ groupname }} recurse=yes
後は、そもそもディレクトリが作られていなかったとか言う
単純(それぐらい補完してくれと思うのですが ^_^; ) な悲劇があったので、これも追加しておきました。
- file: path=/usr/local/rbenv state=directory mode=0755
ディレクトリも作った。sshして確認してもファイルもある。だがしかしrbenvが動かない。
結論的には、rbenvの環境変数が適応されていない のが原因でした。
が、- command: source ~/.bashrc
をやっても、意味が無い様子。
なので、別の手段を使いました。
- name: check can use 'rbenv' command shell: /bin/bash -lc "/usr/local/rbenv/bin/rbenv"
こうすると、~/.bashrc
を適応して shell ( command ) を実行してくれるようです。
rbenv install
command not found
タイトルの通りのエラー文が出てきてしまって大汗でした。
結果はよくわかってませんが、chown
やchmod
を適切にする & ~/.bashrc
を適応させる方法(shell: /bin/bash -lc
)
をやれば動くみたいです。
gem モジュールが動かない
Ansible には gem
モジュールが用意されている。これで冪等性が保たれるという訳。便利。
しかし、rbenv経由の場合は、ansible の gem
モジュールをそのまま動かすのはできない。
そのため、executable
というオプションを付けて、gemコマンドの使用元を指定する必要がある。
- name: install gem ruby-mysql gem: name=ruby-mysql state=latest user_install=no executable=/usr/local/rbenv/shims/gem
そうすると、うまく動く様になる。
rbenvでrubyインストール時の冪等性の保ち方
とても単純ですが、
command: rbenv -versions
でインストールバージョンの確認- Ansibleの条件分岐
when
で、目的のバージョンが含まれているかを、.stdout_lines.count("{{ version }}")
で分岐。 - なかったらinstallの実行
的な風にして何とか保つという方法で今回はGoしました。
最後に
ansible がよくわかってないというのもあったが、やっぱりうまく動かない部分もあってなんだかなぁって感じでした。
また、MBAでの作成で、テストするためにガリガリ動かしてたら、Pythonのmakeとrbenvのruby インストールで、MBAのファンが唸りを上げました…どんだけ高負荷なのだろうか…
更に、WindowsでもMacでもLinuxでも、どこに行ってもコマンド一行で環境構築だーとか喜んで作ったが、
いざWindowsに持って行くとAnsibleを動かすのに一苦労というオチ…
色々と踏んだり蹴ったりでした。
*1: actionが無いからダメですよ〜的エラー文でした。ちゃんとは覚えてないです。