Blend day's Note

思い立ったことをメモする

Ansible で 自動化 大作戦

事始め

元々は、vagrantshellで自動環境構築をしていたとある開発環境を、
調度良い機会だったので、Ansibleを使って自動化することにしました。

が、Ansibleの書き方が今ひとつ慣れていないのと、様々な制約に引っかかったので、
後々の私のためにメモを残しておきます。

↓目次



↑さっき見つけて早速使ってみました。意外と便利そう

構築する環境

自動化で入れるもの

大まかには次のもの。

その他必要な物は、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を用意
  • unarchivesrcでホストPCのtgzをゲスト内に展開。
  • make & make altinstallは、commandモジュールで実行する。

ということになりました。 が、commandモジュールを使おうとすると新たな問題が。

「冪等性」 どうするんだよ

一ヶ月前の私 「冪等性って何ですか?」

今の私 「頭痛いです」

冪等性とは?

大雑把に言って、ある操作を1回行っても複数回行っても結果が同じであることをいう概念である。 (Weblio 辞典より)

ansible が予め用意している モジュールでは、冪等性は保たれるようになっている様です。(ちゃんと確かめてないですが)
しかし、commandモジュールの場合は、結局 shell を垂れ流ししているだけで、冪等性が保たれる保証は無いのです。
頭が痛い内容No.1ですが、今回の自動化の目的でもあります。

で、Pythonの場合、結局どうしたかというと…

  • Makefileがあるかどうかを command: lsで確かめる。
  • makemake altinstall の時に、whenで条件分岐させる。

ということをしました。ansibleのwhenは便利です。

これで、インストールがされるはずですし、既にインストールされている場合はmakeされず、 しっかりと冪等性が保たれてるはずです。

PATHの追加

shellのコマンドで言うところの export PATH=$PATH:/usr/local/bin的な何かをしたかったのです。

environment モジュール

Ansibleには、environmentモジュールなる物が存在していた。(らしい)

hexa.hatenablog.com

しかし、使おうとすると、エラーが発生して動かないという罠にハマりました。*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

タイトルの通りのエラー文が出てきてしまって大汗でした。 結果はよくわかってませんが、chownchmodを適切にする & ~/.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が無いからダメですよ〜的エラー文でした。ちゃんとは覚えてないです。