※この記事はエキサイトAdvent Calendar 2017 9日目の記事です。
みなさん、こんにちは!
エキサイトで Owly や 電話占い、ウーマン占い、フレンズ などの開発を担当している、エンジニア2年生の伊藤です!
本記事では、先日リリースしたばかりの Owly のサーバ構築で利用している Ansible についての簡単な紹介、
導入するにあたって気をつけたことを述べようと思います!
Ansibleとは
python製の構成管理ツールで、同じ環境の複数のサーバを統一して管理するなどの目的で利用されます。
構成管理ツールとしては Chef や Puppet がよくとりあげられますが、Ansible はこれらと比べて以下の違いがあります。
yaml形式の設定ファイル
ChefはRubyで、Puppetは独自のDSLで、サーバの設定を記述しなければなりませんが、Ansibleはyamlで設定ファイルを記述することができるので、
初学者でも比較的容易に設定ファイルを記述することができます!
エージェントレス
ChefやPuppetは、管理対象のサーバに予めエージェントと呼ばれるソフトウェアをインストールしておく必要がありますが、
Ansibleはsshで管理対象のサーバに接続して操作を行うため、管理対象のサーバに対する事前準備がほとんど必要ありません!
長い,3行で
・Python製の構成管理ツール
・設定ファイルの記述にyamlが使える
・エージェントレス
Ansibleを導入するにあたって気をつけたこと
再利用性
Owly では、フロントのサーバの他に、API、管理ツール、DB、キャッシュサーバ、etc... のサーバ群で構成されており、DBを除く全てのサーバの構成を
Ansibleで管理しています。
複数のサーバを管理する場合には、再利用性 を考慮して設計する必要があります。
下記のコードは、Playbookと呼ばれるAnsible設定ファイルの例です。
- name: Setup Front
hosts: all
become: yes
become_user: root
tasks:
- name: install nginx
apt:
name: nginx-common
state: present
update_cache: yes
- name: copy nginx conf
copy:
src: /home/owner/ansible/conf/nginx/default.conf
dest: /etc/nginx/sites-available/default.conf
- name: install php
apt:
name: php7.0-fpm
state: present
update_cache: yes
...
この例のように、フロントサーバ用のPlaybookに直接taskを記述してしまうと、他のサーバに対してもNginxやPHPをインストールしたい!
という場面で、ふたたび同じ処理を記述することになってしまいます。
そこで、例えば Nginx に関連したtaskを1つのRoleにまとめておくと、他のサーバのPlaybookを作成するときにNginxのRoleをincludeして使いまわすことが出来ます。
setup_front.yml
roles/
common/
tasks/
main.yml
nginx/
tasks/
main.yml
php/
tasks/
main.yml
...
このような感じのディレクトリ構成でroleを用意しておいて、
- name: Setup Front
hosts: all
become: yes
become_user: root
roles:
- 'common'
- 'nginx'
- 'php'
...
Playbookで各roleをinclude!
再利用できるだけでなく、playbookの可読性も改善されます!
冪等性 (べきとうせい)
冪等性とはなにか。wikipediaによると、
数学において、冪等性(べきとうせい、英: idempotence 「巾等性」とも書くが読み方は同じ)は、大雑把に言って、ある操作を1回行っても複数回行っても結果が同じであることをいう概念である。 まれに等冪(とうべき)とも。
-- Wikipedia(日本語訳)
とあります。
Ansibleなどの構成管理ツールは、サーバに対して実行する処理を管理するものではなく、サーバの状態そのものを管理します。
それはつまり、あるサーバに対してPlaybookをN回実行したとしても、状態は常に変わらないということが担保されている必要があります。
例えば、
- name: Setup Front
hosts: all
become: yes
become_user: root
tasks:
- name: install nginx
apt:
name: nginx-common
state: present
update_cache: yes
このPlaybookで、task install nginx
が実行された時、対象のサーバにNginxがインストールされていなければ、
TASK [install nginx] ******************************************************
changed: [Front]
Nginxがインストールされ、サーバの状態が変更された旨を表す changed
を示します。
対象のサーバにnginxがインストールされているならば、
TASK [install nginx] ******************************************************
OK: [Front]
Nginxのインストール処理は実行されず、サーバの状態が変更されずに処理を終えたことを表す OK
を示します。
2回、3回と実行しようがサーバーの状態は常に一定。つまり上記のPlaybookは冪等性が担保されているといえます。
一方、下記のような、指定のディレクトリが存在するか否かによって実行処理が分岐するPlaybookを実行した場合、
- name: check exist cache dir
command: ls /var/hoge/owly/htdocs
register: cachedir
- name: make cache dir
file:
path: /var/hoge/owly/htdocs/cache
state: directory
owner: root
group: root
mode: 0755
when: cachedir.stdout
task check exist cache dir
は、/var/hoge/owly/htdocs
の存在有無にかかわらず、
TASK [check exist cache dir] ******************************************************
changed: [Front]
changedを示してしまいます。
このPlaybookは、2回、3回と実行するたびにchanged
を示してしまうために、冪等性が担保されません。
冪等性を破壊しているのは、command
モジュールで、これは対象サーバに対して指定のコマンドを実行し、常にchanged
を示します。
task check exist cache dir
は、ファイルの存在確認を行うだけで、サーバの状態に影響を与えるものではないです。
そこで、サブ構文changed_when: False
を追記し、常にサーバに影響を与えないtaskであるということを明記しておくことで、冪等性を担保することが出来ます。
(冪等性の説明のために、ファイルの存在確認処理をcommand
モジュールを用いて記述していますが、stat
モジュールを用いることでより簡潔に記述することも出来ます)
終わりに
いかがでしたでしょうか。
Ansibleは非常に便利なプロダクトですが、再利用性や冪等性を考慮しなければ、その利便性を十分に活かすことは出来ません。
Owlyのサーバ構築時には、特に再利用性について、どれくらいの粒度でRoleを分けるのかという点も含めて設計が大変でした。
別の機会があれば、jinja2を活かした効率的なconfの配置など、より込み入った話が出来たらと思います。
明日のアドベントカレンダーは、iOSアプリについてです!お楽しみに!