Ansible(1)Ansibleとは

Ansibleは、Infrastructure as Codeを実現可能な自動構成管理ツール。Hedhatが提供するオープンソースソフトウェアである。PuppetやChefと違いエージェントレスで動作し、Ansible自体は中央サーバや実行先のサーバの状態の情報を保有しない。SSHで各サーバにログインし、任意の処理を実行する。Infrastructure as Codeの概念を実現するために、Ansibleでは、同じコードを何度実行しても同じ結果となる、冪等性を重視している。

Ansibleは、各機能を司るコマンド群であるModuleと、それを組み合わせたスクリプトであるPlaybookから構成される。Playbookは、再利用性を高めるために、機能別にRoleに分けて管理される。また、これらのスクリプトは、YAML形式で記述され、変数や分岐処理などは、Pythonのテンプレートエンジンであるjinja2が使用される。AnsibleはPythonで動作するため、Ansibleを実行させるサーバも、実際に処理を行う対象ホストにもPythonがインストールされている必要がある。

Inventory

Ansibleが制御する対象ホストを定義したものをInventoryと呼ぶ。Inventoryは、ini形式で記述する静的なInventoryファイル、もしくは、JSON形式で記述されるDynamic Inventoryで記述する。Inventoryファイルにグループ変数等を記述することが可能だが、Inventoryファイルに真偽値を記述する際には、True/Falseのように大文字で記述する必要がある。また、グループ変数やホスト変数をInventoryファイルに記述すると可読性が下がるために、

  • host_vars
  • group_vars

という名のディレクトリを作成し、この中にYAML形式で変数を記述することが一般的である。YAMLのファイル名は、グループ名・ホスト名と同一の名称にしなければならない。また、全てのグループ、ホストに適用される変数は、group_vars/all.ymlに記述する。Ansibleが取得するOSディストリビューション情報を元に自動的にグループ化することも可能で、この場合は、 group_byモジュールを使用する。

実行するグループ名をPlaybookで指定する場合は、

# 全てのホスト
hosts: all
# 特定のホスト
hosts: 192.168.0.2
# Ansibleを実行しているホスト
hosts: 127.0.0.1
connection: local
# 特定のグループ
hosts: webservers

のように指定する。

変数

Ansibleで使用する変数は、先頭に数字を使用することはできない。またアンダースコアは使用できるがハイフンは使用できない。変数はあらかじめファイル内に記述しておくことが一般的であるが、実行時にextra_varsという引数で動的に与えることも可能である。host_varsやgroup_vars以外に、外部から変数ファイルを取り込む必要がある場合には、

vars_files:
    - ../common_playbook/vars/common.yml

vars_filesディレクティブでファイル名を指定することができる。

また、Ansibleが各ホストなどから取得するマジック変数は、以下のような値が存在する。

変数名 内容
inventory_hostname inventoryに記述されたホスト名 hoge
ansible_default_ipv4.address 対象ホストのIPアドレス 192.168.0.1
ansible_hostname 対象ホストのホスト名 localhost
ansible_architecture 対象ホストのアーキテクチャ x86_64
ansible_distribution 対象ホストのディストリビューション名 CentOS
ansible_distribution_major_version 対象ホストのディストリビューションメジャーバージョン 7
ansible_date_time.epoch エポック秒 1501513200

jinja2

Ansibleでは、変数や分岐処理、真偽値の判定などは、Pythonのテンプレートエンジンであるjinja2が使用される。変数は「{{ 変数名 }}」で記述される。YAMLの文法上の制約から文字列の先頭もしくは終わりに変数を挿入する場合は、文字列全体を””で囲う必要がある。

- name: "show full status of Apache"
  command: "{{ httpd.ctlbin }} fullstatus"

実行制御

実行制御に用いる真偽値判定は以下の記述を用いる。

# 真偽値
when: ansible_os_family == "Debian"
when: val
when: not val
# 値が定義されていた場合
when: val is defined
# 値が定義されていなかった場合
when: val is undefined
# AND/OR
when: a and b
when: a or b
# 値が含まれているか否か
when: a in b
# タスクの実行
when: hogetask | success

タスクの実行結果は以下が用意されている。また、ignore_errorsディレクティブを使用すると、タスクに失敗したとしても処理は継続される。

判定句 内容
succeeded タスク成功
changed タスク変更
failed タスク失敗
skiped タスクスキップ

条件判定句は以下が用意されている。

判定句 内容 備考
changed_when 状態変更(=changed)となる条件を定義 falseに指定すると常に状態変化なし
failed_when 失敗(=failed)となる条件を定義
when taskが実行される条件を定義

notify

taskの状態に変更(=changed)があった場合、handlersで定義しnotifyで指定したtaskが実行される。taskは、playbookの中で複数回呼ばれた場合であっても、全てのtaskが終了した段階で1度だけ実行される。下の例では、httpd.confの書き換えが行われたときのみ、Apacheデーモンの再起動が行われる。

- name: "put a apache config file if it does not exist"
  template: src=httpd.conf.j2 dest="{{ httpd.conf }}" backup=yes
  notify:
    - restart httpd
- name: restart httpd
  service: name=httpd state=restarted

デバッグ

Ansibleでコマンドの出力結果を表示したい場合には、出力結果をregisterオプションで変数に一度格納し、debugコマンドでこれを表示するという手順を取る。このとき、commandコマンドは、実行の度に状態の変更(=changed)が行われてしまうため、changed_whenオプションによって、状態変更を無効化する。また、debugコマンドによる出力結果の表示は、whenオプションを用いて、直前の処理が成功したときのみ実行する設定とする。

- name: "show version number of Apache"
  command: "{{ httpd.ctlbin }} -v"
  register: httpd_version
  changed_when: False

- name: "debug version number of Apache"
  debug: var=httpd_version.stdout_lines
  when: httpd_version | success

Tips

Amazon Linux対応

Amazon LinuxはRHEL6ベースで開発されているため、Amazon Linuxの場合はRHEL6と同じ処理を行う。そのために、ディストリビューション名がAmazonであった場合は、ディストリビューションメジャーバージョンを6に指定する。

  pre_tasks:
    - set_fact: ansible_distribution_major_version=6
      when: ansible_distribution == "Amazon" and ansible_distribution_major_version == "NA"

プロキシの指定

プロキシ環境下で処理を行う場合は、変数ファイルにプロキシ設定情報を記述し、Playbookでプロキシ設定を行う。プロキシ指定から除外するアドレスが存在する場合は、no_proxyディレクティブを追加する。

proxy_env:
  http_proxy: http://XXX.XXX.XXX.XXX:8080
  https_proxy: http://XXX.XXX.XXX.XXX:8080
  environment: 
    - "{{proxy_env}}"

機械学習(1)TensorFlowをMacにインストールする

TensorFlowは、Googleが開発し公開している機械学習ライブラリ。

インストール方法

Pythonパッケージ管理ツール「easy_install」を使うとよいとのことなので、以下のコマンドを実行。このとき、XCodeのコマンドラインツールのインストールも求められる。

sudo easy_install pip
sudo easy_install --upgrade six
sudo pip install --upgrade https://storage.googleapis.com/tensorflow/mac/tensorflow-0.8.0-py3-none-any.whl

tensorflow-0.8.0-py3-none-any.whl is not a supported wheel on this platform.

TensorFlowを入れるためにはpip3(python3)が必要とのこと。
brewからpython3のインストールを行う。

このときpythonのバージョン管理を行うことのできるpyenvを入れておくと、Python2.7とPython3を切り替えることができるので便利。

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
brew install pyenv

現在のPythonバージョンを確認することができる。

pyenv versions
* system (set by /Users/***/.pyenv/version)

まだ何も入れていないので、systemのみ。

ここで、~/.profileファイル(ログイン時に読み込むbash設定)に以下を追加。
設定を読み込ませるためにOS再起動。

vi ~/.profile

export PATH="$HOME/.pyenv/bin:$PATH"
eval "$(pyenv init -)"

インストール可能なバージョンを確認して、Python3(今回は3.5.1)をインストール。

pyenv install --list
pyenv install 3.5.1

使用するPythonのバージョンを3.5.1に変更。

pyenv global 3.5.1
pyenv versions
  system
* 3.5.1 (set by /Users/eiji/.pyenv/version)

このときにもし以下のようなエラーが発生する場合は…

Downloading Python-3.5.1.tgz...
-> https://www.python.org/ftp/python/3.5.1/Python-3.5.1.tgz
Installing Python-3.5.1...

BUILD FAILED (OS X 10.11.4 using python-build 20160130)

Inspect or clean up the working tree at /var/folders/my/txp4p33n1lzf2hbzp0vmqbc40000gn/T/python-build.20160515224141.3027
Results logged to /var/folders/my/txp4p33n1lzf2hbzp0vmqbc40000gn/T/python-build.20160515224141.3027.log

Last 10 log lines:
  File "/private/var/folders/my/txp4p33n1lzf2hbzp0vmqbc40000gn/T/python-build.20160515224141.3027/Python-3.5.1/Lib/ensurepip/__main__.py", line 4, in <module>
    ensurepip._main()
  File "/private/var/folders/my/txp4p33n1lzf2hbzp0vmqbc40000gn/T/python-build.20160515224141.3027/Python-3.5.1/Lib/ensurepip/__init__.py", line 209, in _main
    default_pip=args.default_pip,
  File "/private/var/folders/my/txp4p33n1lzf2hbzp0vmqbc40000gn/T/python-build.20160515224141.3027/Python-3.5.1/Lib/ensurepip/__init__.py", line 116, in bootstrap
    _run_pip(args + [p[0] for p in _PROJECTS], additional_paths)
  File "/private/var/folders/my/txp4p33n1lzf2hbzp0vmqbc40000gn/T/python-build.20160515224141.3027/Python-3.5.1/Lib/ensurepip/__init__.py", line 40, in _run_pip
    import pip
zipimport.ZipImportError: can't decompress data; zlib not available
make: *** [install] Error 1

XCodeのコマンドラインツールもインストールする。

xcode-select --install

最後に、TensorFlowをインストール。

sudo pip3 install --upgrade https://storage.googleapis.com/tensorflow/mac/tensorflow-0.8.0-py3-none-any.whl

インストールされたかどうかの確認は、以下のコマンドを打ってエラーが発生しないことを確認する。

python

Python 3.5.1 (default, May 15 2016, 09:29:31) 
[GCC 4.2.1 Compatible Apple LLVM 7.3.0 (clang-703.0.31)] on darwin
Type "help", "copyright", "credits" or "license" for more information.

import tensorflow as tf