【Ansible】備忘録【環境構築】

こんばんは、マークアップエンジニアの でございます。

最近なぜかVagrantとAnsibleを使って開発環境を作る事が多いです。
その為Ansibleで困ったときの備忘録。


  • 他の人の環境で動かない(Installing Ansible...で止まってしまう)
  • 環境変数が存在する状態で実行させたい。
  • .bashrcを読み込んでほしい。
  • 変数をごにょごにょにしたい。
  • playbookの一部を暗号化したい。
  • tasks/main.ymlが長い。
  • tasksを途中から実行したい。デバッグしたい。
  • blockinfileで`{`を文字列リテラルとして扱いたい

他人の環境で動かない。(Installing Ansible...で止まってしまう)

The Ansible software could not be found! Please verify


とかでて止まっちゃう。
これはVagrantの問題じゃないかなと思います。


Vagrantfileに下記を記述して解決

config.vm.provision :shell, inline: <<SCRIPT
GALAXY=/usr/local/bin/ansible-galaxy
echo '#!/usr/bin/env python2
import sys
import os

args = sys.argv
if args[1:] == ["--help"]:
  args.insert(1, "info")

os.execv("/usr/bin/ansible-galaxy", args)
' | sudo tee $GALAXY
sudo chmod 0755 $GALAXY
SCRIPT

参考: https://github.com/mitchellh/vagrant/issues/6793


環境変数が存在する状態で実行させたい。

MySQLとかでSQL実行させたい時、「MySQL-python」や「python-mysqldb」が入っている環境ならmysql_user moduleを使えば良いと思いますが
いれれない場合、新しいMySQLだとpasswordを引数に渡して実行

- shell: "mysql -u root -ppassword hoge < test.sql"


を実行する時に警告が発生しちゃったりします。
そのため、環境変数からパスワードをいれてあげましょう。

- shell: "mysql -u root hoge < test.sql"
  environment: 
    MYSQL_PWD: "password"

environmentで渡す事ができます。


参考: http://docs.ansible.com/ansible/playbooks_environment.html


.bashrcを読み込んでほしい。

become_userを使ってユーザーが切り替えて作業している時に
.bashrcにはPATHを追記したけど、shellモジュールで.bashrcの内容を読み込んでくれない時に

- shell: "forever start test.js"


とか実行しても「foreverなんてないよ!」となる場合があります。

- shell: "/bin/bash -lc \"forever start test.js\""


もはやAnsible関係ないけど/bin/bashのオプションに「-l」をつけて「.bashrc」を読み込んだ状態で実行させます。

変数をごにょごにょにしたい。


例えば、PHPのバージョンを変数に保持してるけど
5.6以上か判定したいとき

- shell: "[ $(echo {{ php_version }} | sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\1\2/') -ge 56 ] && echo '1' || echo '0'"
  register: 56over


わざわざregisterに保存しなければいけないところとか非常にめんどくさい。

jinja2 filterが非常に便利です。

- shell: "echo '56over!!!!!'"
  when: {{ php_version | version_compare('5.6', operator='ge', strict=False) }}


こんな感じで変数に制御を行う事ができます。

他にも、大文字の文字列を取得したい場合は

- debug: var={{ lower_str | upper }}

これで変数lower_strに入っている小文字の英語が大文字に変更されて出力されます。

参考: http://docs.ansible.com/ansible/playbooks_filters.html



playbookの一部を暗号化したい。


例えば、
playbookのhost_vars/db_serverに下記の内容がある。


host_vars/db_server

mysql:
    host: localhost
    user: hogehoge
    password: hogehoge
  • サーバー上に置いてサーバーから実行したい。
  • 他人に見られたくない。

そんな時、ansible-vaultが便利です。

$ echo 'ここ暗号化パスワード' > ~/.vault_password
$ ansible-vault decrypt host_vars/db_server.yml --vault-password-file=~/.vault_password

こんな感じでplaybookの一部を暗号化する事ができます。
また、editで複合して編集も可能です。

$ ansible-vault edit host_vars/db_server.yml --vault-password-file=~/.vault_password

playbookを実行するときも「--vault-password-file」でファイル指定か「--ask-vault-pass」でパスワードを対話式にもできます。




tasks/main.ymlが長い。


includeでファイルを分割、blockみたいにwhenやwith_items等もincludeに指定してしまえば一括管理も簡単です。

2018/01/09

include_taskが追加されましたのでinclude_taskを利用すると良いと思います。

roles/php/task/main.yml

- name: php make install
  include_task: php_make_install.yml
  when: {{ php_make_install }}

- name: php remi install
  include_task: php_remi_install.yml
  when: {{ php_make_install == false }}

- name: php config setting
  include_task: php_config_setting.yml

- name: install composer xdebug other
  include_task: php_other_install.yml


参考:
https://docs.ansible.com/ansible/2.4/include_tasks_module.html

tasksを途中から実行したい。デバッグしたい。

Ansibleのstart-at-taskオプションstepオプションを使う事で解決できます。

start-at-task 特定のタスクから実行する事ができます。
step タスク実行毎にどうする?って聞いてくれます。

特定のタスクはnameを各タスク毎に振っていればそれがタスク名になります。

$ ansible-playbook -i hosts site.yml --start-at-task="Run from this task" --step

ベストプラクティクスに沿って作成してある場合は、「ロール名 : タスク名」みたいな感じで
半角スペースを両サイドにおいた「:」でロール名とタスク名を区切る事で「特定のロール」の「特定のタスク」から始めることができます。

その為、mysqldロールのnameにRun from this taskと付与してあるタスクから始めたい場合は下記のような指定でできます。

$ ansible-playbook -i hosts site.yml --start-at-task="mysqld : Run from this task" --step

参考:
Start and Step — Ansible Documentation

blockinfileで`{`を文字列リテラルとして扱いたい

 - name: 上書き可能な変数を定義
   blockinfile:
       dest: "{{ httpd.sysconfig.path }}"
       marker: "# {mark} ANSIBLE MANAGED BLOCK {{ item.key }}"
       content: |
         if [ \"$\{{{ item.key }}\}x\" = \"x\" ];then
             export {{ item.key }}=\"{{ item.value }}\"
        fi

   with_dict: "{{ httpd.sysconfig.overridable_params }}"

こうすると`if [ \"$\{{{ item.key }}\}x\" = \"x\" ];then`の`\{{{ item.key }}\}`のおかげで

fatal: [node_1]: FAILED! => {
    "msg": "Unexpected failure during module execution.", 
    "stdout": ""
}

この様にエラーが発生するのでこの様にして解決しました。

- name: 上書き可能な変数を定義
   blockinfile:
       dest: "{{ httpd.sysconfig.path }}"
       marker: "# {mark} ANSIBLE MANAGED BLOCK {{ item.key }}"
       content: |
         if [ "${{ '{' }}{{ item.key }}{{ '}' }}x" = "x" ];then
             export {{ item.key }}="{{ item.value }}"
        fi

   with_dict: "{{ httpd.sysconfig.overridable_params }}"

{{ 'ここが文字列リテラルとして扱われる' }}