Ansibleで始める構成管理ツール_Part1
Ansibleとは
**【Ansible】**とは、『構成管理ツール』です。
何を構成管理するかというと、サーバのインフラをコードで管理する**【Infrastructure as a Code】ツールで、【Chef】や【Puppet】**などと同様なツールです。
**【Chef】や【Puppet】**では、高度な管理を行うとするとRubyが前提となっているので、インフラ開発者では学習コストが高く、エージェントが必要となるため導入のハードルが高い。
それに対して**【Ansible】**は、以下の特徴を持っている。
-
エージェントレスな構成管理ツール
-
クライアントは、SSH接続(要鍵認証)でき、Pythonが導入されていること
-
設定がシンプル(そのため、複雑なことは苦手)
-
ツールにより、冪等性(べきとうせい)を担保
ただし、AnsibleはOSにIPアドレスが設定されており、接続条件を満たしている必要があります。
したがって、OSインストールを自動化するには、**【Kickstart】や【Cobbler】**等が必要です。
なぜAnsibleが必要なのか?
【現状】
サーバ構築作業の現状は、
設計書をもとにパラメータシートや構築手順書を作成し、
構築手順書をもとに構築作業を実施し、設定値はパラメータシートを設定作業を実施している。
試験にてパラメータシート通りに設定されているか確認し、設計書通りの動作をするか確認する。
【問題点、リスク】
大量にサーバ構築する場合は、時間的に無駄が多い。(バックアップリストアで問題は一部解消されるが、部分的に設定を修正する必要性がある)
同じことの繰り返しとなることから、オペミス、設定値の取り違えが発生するリスクがある。(試験で問題は解消されるが、確認する側も同じことの繰り返しになることから、間違いをスルーしてしまうリスクがあり時間的な無駄が発生する)
設計書を修正した場合、実機反映漏れが発生するリスクがある。(構築時点でconfigファイルもバージョン管理、CIも実施していれば回避可能)
【結論】
以上より、**【構成管理ツール】**で機械的に構築されたサーバであれば、リスクを軽減でき時間的な工数削減が望める。ただし、プロジェクトメンバーが運用ルールを絶対としているのが条件です。
ただし、現状ベンダーやSIerでは、機械的に構成をしても継続的に単体試験というパラメータの設定確認は実施すると思われる時間的な工数削減は僅かなのかもしれません。
【メリット】
構成管理ツールを導入することで、リスク削減と工数削減はもちろんですが、OS、MWのパラメータシートを構成管理ツールの設定ファイルとして代用することができ、その設定ファイルをバージョン管理することでITインフラもコード**【Infrastructure as a Code】**で管理することができる。
【デメリット】
ツールが多様化することで、実作業は軽減されると思われるが、運用ルールが増加するためルールの管理、運用フローの展開、運用文書化と管理内容の複雑になってしまう。
参考
- Webサイト
公式サイト
ドキュメント
Ansible 入門
Ansibleをはじめる人に。
超ansible入門
日本Ansibleユーザ会
- 書籍
入門Ansible Kindle版
Ansible実践ガイド第2版
0.検証環境
OS:CentOS 7.5
ミドルウェア:ansible 2.7.5
前提ミドルウェア:EPEL
1. Ansibleインストール
1.1 Ansibleインストール
# yum install -y epel-release ※1
# yum install -y ansible
# yum -y install python-pip ※2
# pip install --upgrade pip ※2
# pip install pywinrm ※2
# ansible --version ※3
インストールは、以上で完了で。後は運用設定のみで、構築自体はあっけない程簡単です。
Ansibleの設定は、/etc/ansible/ansible.cfg
でされていますが、このファイルを変更することはあまりなさそうです。(Ansible用hostsファイル、playbookで制御可能なため)
※1:ansibleは標準リポジトリに存在しないためエンタープライズ Linux 用の拡張パッケージ(EPEL)を追加。
※2:構成管理するクライアントがWindowsServerを含む場合は、【pywinrm】を導入する必要がある。
※3:インストール確認のため、バージョンを表示するコマンドを実行しています。
2. Ansibleの構成
2.1. Ansibleの構成要素
-
Ansible用hostsファイル(/etc/ansible/hosts)
構成対象となるクライアントを記述。
-
playbook
モジュールを複数組み合わせて、実行させる【JOB】です。
対象サーバの接続条件(対象サーバ、ユーザ、sudo実行有無、変数)を記載します。
playbookは【YAML形式】で記述します。
【YAML形式】については、プログラマーのための YAML 入門 (初級編)を参照。 -
モジュール
実際の対象サーバで、パッケージをインストールしたり、ファイルコピーしたり、実行する内容を記述します。
playbook中の【task】に【YAML形式】で記述します。
2.2. Ansible用hostsファイル
Ansible用hostsファイル(/etc/ansible/hosts)は、AnsibleおけるDefaltのInventoryとして使用され、以下のように同一の設定をする[WebServerGroup]等のグループに分けて記述すると、【playbook】で実行する内容が簡素化することが可能となる。
もちろん、各サーバ毎に違う設定がある場合は、サーバ毎に記載する必要もあるので**きちんと運用ルールを設け**設定する必要があります。
Ansibleを実行するサーバは、ローカルなのでansible_connection=local
と設定する必要があります。ちなみにdafault
はssh
となっている。
ホスト名は、以下の[DBServerGroup]や [APServerGrroup]のように正規表現でも記述することができます。
接続するポートに関しても、ホスト名の後に:
で繋げ指定することが可能。その他にansible_port
で指定することも可能となっている。ちなみにdefault
のansible_port
はSSH接続が前提となっているため22
となっている。
また、以下の[GatewayServerGroup]のようにansible用の仮のホスト名を指定し、【ansible_host】で実際のIPを指定することも可能です。
[localhost]
127.0.0.1 ansible_connection=local
[WebServerGroup]
192.168.1.100
192.168.1.101
192.168.1.102
[DBServerGroup]
DB-[a:f].example.com:5501
[APServerGrroup]
www[01:10].example.com
[GatewayServerGroup]
Gateway01 ansible_port=1022 ansible_host=192.168.101.92
DefaltのInventory(/etc/ansible/hosts)以外のファイルを使用する場合は、ansibleコマンドのオプションとして-i
(--inventory
)を指定するか、ANSIBLE_HOSTS
環境変数でパスを指定する必要がある。DefaltのInventory以外の指定したファイルであれば、YAML形式で記述することも可能です。
詳細は、公式Documents【Working with Inventory】を参照。
なお、Windowsとの接続する場合は、クライアント側の前提としてWindows Remote Management(WinRM)が起動している必要がある。
[windows]
192.168.99.3
ansible_ssh_user=<Windows側のユーザ名>
ansible_ssh_pass=<Windows側ユーザのパスワード>
ansible_ssh_port=5986
ansible_connection=winrm
ansible_winrm_server_cert_validation=ignore
2.3. playbook設定
hosts
Ansible用hostsファイルで指定したグループ名を指定する。
allを指定することでAnsible用hostsファイルに記述された全てのサーバ対象で同じ内容を実行します。
remote_user
リモート側の実行ユーザを指定する。
Ansibleは、SSH接続なので実行ユーザに鍵認証を設定している必要がある。
sudo(become※1)
sudo
実行する場合は、yes
を指定する。
sudo_user
でsudoで実行するユーザを指定する必要がある。
また、ansible
コマンド実行時に-s(--sudo)
を指定することも可能。
sudo実行するモジュール(task)毎に指定することが可能です。
※1:Ansible1.9以降はbecome
を使用すること。
sudo_user(become_user※2)
sudo実行する際の実行ユーザを指定。
※2:Ansible1.9以降はbecome_user
を使用すること。
become_method
sudo実行ではなく、suを使って権限を変更したい場合は、become_method
でsu
を指定する。
ちなみに、Defaultのbecome_method
は、sudo
となっている。
vars
モジュール(task)を実行する際に設定して変数をここで宣言する。
以下のように宣言しておくと ${HOME}
、${INI_File}
、${TmpDir}
などで参照することが出来ます。
vars:
HOME: "/home/hogeuser"
INI_File: "/etc/local/ansible_local.ini"
TmpDir:/tmp
handlers
task
で状態が変更された場合(changed のイベントが起こった場合)に1回だけ最後に実行されるジョブです。
task
側では notify
を設定し、 handler
側では listen
でそれを待ち受け、紐づけている。
- hosts: localhost
handlers:
- name: TEST handlers JOB
msg:execute handler
listen:Start handler A
tasks:
- name: TEST JOB
msg: message
changed_when: true
dest: /foo/bar/
notify: Start handler A
tasks
playbook のキモとなる項目です。実行するモジュールを列挙していきます。
name 指定すると実行時に出力が為されます。また、name は必須ではないようです。書かなかった場合、モジュール部分の文字列がそのまま出力されるようです。
各taskの詳細モジュールは、【2.5.モジュール(task)】を参照。
when
指定した条件が成り立つときのみタスクを実行する。
以下の場合は、ファイルコピーの結果をregister
に格納しで成功と失敗で処理を分けている。
- copy: src=/etc/hosts dest=/etc/hosts.old
register: result
ignore_errors: True
- debug: msg='File copy succeeded(succedded)'
when: result|succeeded
- debug: msg='File copy failed(failed)'
when: result|failed
with_items
ループ処理。
以下の場合は、記述した配列を変数に代入して[/tmp/test1]、[/tmp/test2]、[/tmp/test3]というディレクトリを作成する。
- name: ディレクトリの作成
file: path=/tmp/{{ item }} state=directory
with_items:
- test1
- test2
- test3
コマンド実行結果を with_items
でループするには、コマンド実行した結果を登録(register)しwith_items
の変数に代入する。
- name: retrieve the list of home directories
command: ls /home
register: home_dirs
- name: add home dirs to the backup spooler
file: path=/mnt/bkspool/{{ item }} src=/home/{{ item }} state=link
with_items: home_dirs.stdout_lines
# same as with_items: home_dirs.stdout.split()
until
ループ処理。
until
がloopから抜ける条件(以下の場合は標準出力に”OK"が出力されるまでループ)
retries
がリトライ回数
delay
がスリープの秒数
- shell: /u
sr/bin/foo
register: result
until: result.stdout.find("OK") != -1
retries: 5
delay: 10
import_playbook
指定したファイルを部品化して呼び出す。
タスク毎に小分けしたplaybookを作成してincludeするのが各playbookを修正した場合影響度が小さくて済む。
- import_playbook: include_1.yml
name
各項目のコメントに使用。playbookの概要などを簡潔に記載しておくと後で見た時に分かり易い。
- name: install via yum
yum: name={{ item }} state=installed
with_items:
- bash
- git
- ntp
msg
標準出力にメッセージを出力する。
デバッグする際のポインターとして利用すると便利。
サンプルは、debug
を参照。
debug
デバックする際に付与すると内容確認できる。
以下の例は、register
に変数が代入されているか確認しています。
ansible-playbookコマンド実行時に-v
もしくは-vv
、-vvv
を付与しても同様にデバック可能。
- name: check file exists
stat:
path: /etc/hosts
register: res_exists
- name: debug var res_exists
debug:
msg: "{{ res_exists }}"
2.4.モジュール(task)
shell
シェル上でコマンドを実行。
shell: sample_script.sh arg1 arg1 >> sample_log.log
command
リモートノードでコマンドを実行する。
[/path/to/database]
が存在すれば、シェルを実行する。
- command: /usr/bin/make_database.sh arg1 arg2 creates=/path/to/database
file
ファイルやディレクトリの作成、パーミッション設定
ただし、以下はstate
がlink
となっているため、シンボリックリンクとなる。
fileの場合は、Ansibleサーバがソースになるので注意すること。
- file:
src=/usr/local/foo.txt
dest=/opt/foo.txt
owner=root
group=root
mode=0755
state=link
lineinfile
ファイルの行単位の書き換え。
以下の場合は、先頭SELINUX=
の行をSELINUX=enforcing
に書き換える。
- lineinfile:
path: /etc/selinux/config
regexp: '^SELINUX='
line: 'SELINUX=enforcing'
template
テンプレートを利用したファイルのコピー。テンプレートファイルは、/etc/ansible/templates/
に配置する必要がある。
- template:
src=template.j2
dest=/opt/file.conf
owner=root
group=root
mode=0644
synchronize
「rsync起動ホスト(Ansibleサーバ)」から「操作対象ホスト(Inventoryで指定したホスト)」へのファイルやディレクトリのコピーを行う。
- synchronize:
src=source_dir
dest=/tmp/target_dir
recursive=yes
copy
- copy:
src=foo.txt
dest=/tmp/foo.txt
owner=root
group=root
mode=0755
yum
yumパッケージマネージャによるパッケージのインストール、アップグレード、削除
yum: name=httpd state=latest
その他
その他のモジュールは、Ansible モジュール一覧を参照。
2.5. Best Practices
Ansible公式サイトで更改しているベストプラクティスは、以下の構成としている。
この辺は、実際の現場の環境や運用ルールに合わせて、作っていくしかないだろう。
/etc/ansible/
├inventories/
│ ├production/
│ │ ├hosts # 本番環境サーバ用のインベントリファイル
│ │ ├group_vars/
│ │ │ ├group1.yml # 特定のグループに変数を割り当て
│ │ │ └group2.yml
│ │ └host_vars/
│ │ ├hostname1.yml # 特定のシステムに変数を割り当てます
│ │ └hostname2.yml
│ │
│ └staging/
│ ├hosts # 開発環境サーバ用のインベントリファイル
│ ├group_vars/
│ │ ├group1.yml # 特定のグループに変数を割り当て
│ │ └group2.yml
│ └host_vars/
│ ├stagehost1.yml # 特定のシステムに変数を割り当てます
│ └stagehost2.yml
│
├library/ # カスタムモジュールを置きます(オプション)。
├module_utils/ # module_utilsを置きます(オプション)。
├filter_plugins/ # カスタムフィルタプラグインを配置します(オプション)。
│
├site.yml # master playbook
├webservers.yml # playbook for webserver tier
├dbservers.yml # playbook for dbserver tier
│
└roles/
├common/ # この階層は「役割」を表します
│ ├tasks/
│ │ └main.yml
│ ├handlers/
│ │ └main.yml
│ ├templates/
│ │ └ntp.conf.j2
│ ├files/
│ │ └source files # コピーリソースで使用するファイル
│ │ └script files # スクリプトリソースで使用するスクリプトファイル
│ ├vars/
│ │ └main.yml # このロールに関連する変数
│ ├defaults/
│ │ └main.yml # このロールのデフォルトの優先順位の低い変数
│ ├meta/
│ │ └main.yml # ロール依存関係
│ ├library/ # カスタムモジュールも含めることができます
│ ├module_utils/ # カスタムmodule_utilsも含めることができます
│ └lookup_plugins/ # 検索のように、または他の種類のプラグイン
├webtier/ # 「common」と同じ構造
├monitoring/
└fooapp/
3. 実行コマンド
3.1. ansibleコマンド
Ansibleで何か一時的な処理をおこなう時のコマンド。
-
「(インベントリファイルに書かれた)対象のホスト」 ( コマンド引数 )
-
「インベントリファイル」 (
-i
) -
「使うモジュール」 (
-m
) -
「モジュールに与える引数」 (
-a
)リモートホストで
echo
コマンドを実行ansible target_host -i inventory_file -m shell -a 'echo "Hello World"'
リモートホストでrootユーザで
ping
コマンドを実行
ansible target_host -m ping -i inventory_file -u root
リモートホストで
httpd
を起動。ansible target_host -m service -a "name=httpd state=started"
リモートホストでユーザを追加
ansible target_host -m user -a "name=username password=<crypted password here>"
3.2.ansible-playbookコマンド
一連の処理の流れを YAML で記述しておいて、それを実行するコマンド。
-
通常実行
ansible-playbook -i inventory_file playbook.yml
-
構文チェック
ansible-playbook -i inventory_file playbook.yml --syntax-check
-
実行されるタスクの一覧を表示
ansible-playbook -i inventory_file playbook.yml --list-tasks
-
verboseオプション(-vvv)で詳細情報の表示する。
ansible-playbook -i inventory_file -u root -k playbook.yml -vvv
-
実行時にパラメータを付与する。
ansible-playbook --extra-vars "xxx=yes" -i inventory_file playbook.yml
ansible-playbook -e "xxx=yes" -i inventory_file playbook.yml
-
実行するときのユーザの秘密鍵を指定して実行する
ansible-playbook -i inventory_file playbook.yml --private-key=/path/key.pem
3.3.ansible-docコマンド
- モジュール確認
ansible-doc -l
最後に
Ansibleの特性上、インフラの各設定を実施することからOSの設定及びMWのインストールまでは、【root】ユーザで実施し、MWの設定はMW用のユーザで実施すべきだろう。
そのため、SSH鍵認証ではplaybookを実行するユーザに秘密鍵認証を配置し、実行されるクライアント側に公開鍵を配置することを忘れないようにすること。
また、Ansibleのplaybookに使用される【キー】(設定項目)がバージョンによって、名前自体が変わってしまうモノもあるのでバージョンアップする際は、注意が必要です。
構成管理ツールは、確かにサーバが数百台ともなれば、何かしらのツールは必要だとは思いますが、仮想マシンの作成やOSインストール、IPの設定までをAnsibleではできません。
そのため、現状私には必要性を強く感じられません。(シェルで十分)
次の課題としてOSインストールを含めたツールを検証し、構成管理ツールの必要性を検証しなければならない考えてます。