Ansible -実践ガイド(1~3章まで)-
1章 Ansibleの概要
■1-1 Ansibleを取り巻く環境
ビジネスアジリティ(企業の俊敏性)が求められる時代で、システム基盤もオンプレ中心からクラウドへの移行。その中で「DevOps」の誕生によって、構成管理方法も従来のやりかでは上手くいかなくなってきた。また、現状のインフラチームに頼った構成にすると「サイロ化」が生まれてしまい、結果組織としてシステムを考える際に自由(柔軟)な対応が出来にくくなっている。
そこで生まれたのが「Infrastructure as Code」です。ソフトウェア開発のコード管理などの知見をインフラ(構成管理)でも活かして行こうとする考えです。結果として、インフラのコードも「品質管理」「バージョン管理」「テスト」の対象にすることができ、サイロ化を防ぐすべができました。
Infrastructure as Codeの効果
■オペレーション工数の削減
■オペレーション品質の向上
■システム運用の標準化の促進
■作業統制の強化
ここで考えないといけないのが、infrastructure as Codeの対象領域です。ツールとコードを用いて、インフラをコードで管理します。ツールによって、どの領域が得意か不得意かを利用者は理解する必要があります。
こちらの図が非常に分かり易かったので、活用させていいただきます。
Ansibleが得意としているのは、「Setup(Bootstrap)」と「Configuration」になります。
■2-1 Ansibleとは
Python製の構成管理自動化ツールです。
特徴
■設定ファイルの可読性の高さ(Simple)
■エージェントレスの構成(Agentless)
■マルチレイヤの対応(Powerful)
注意点
■複雑な処理の実行が苦手
■実行の完全性を担保できない
■SSHポートが必ず開いている必要がある
構成管理ツールの観点から記載すると。。。。
プッシュ型アーキテクチャ(Ansible)
メリット
■シンプルな仕組み
■コントールの柔軟性
デメリット
■完全自動化の欠如
■スケーラビリティの限界
2章 Ansibleの基礎
■2-1 Ansibleのアーキテクチャ
CLIでの基本的に利用するコマンドは下記になります。
ansible-playbook -i <インベントリ> <プレイブック>
■インベントリ
ターゲットノード(環境を作りたいサーバ)をリストして記載するファイル
■プレイブック
ターゲットノード側で実行したい処理の流れを記載するファイル
Ansibleの内部コンポーネント
Ansibleは各機能(コンポーネント)を利用して、実行されます。
コンポーネント一覧
- モジュール(再利用可能な処理ユニット)
- プレイブック
- インベントリ
- プラグイン(機能拡張などのコンポーネント)
- Python API
- Ansible CLI
下記はモジュール一覧になります。
また、下記にはプラグインの種類を記載します。
プラグインの種類
- Connection Plugins
- Lookup Plugins
- Callback Plugins
- Cache Plugins
- Vars Plugins
- Filters Plugins
こちら非常に参考にしましたので、ご紹介します。
■2-2 Ansibleのインストール
Python製っていうのもあり、複数のインストール方法が存在します。
インストールの種類
- 各OSディストリビューションのパッケージマネージャから
- Pythonのパッケージマネージャから
- 最新ソースコードからのインストール
■2-3 Ansibleの動作確認
事前準備一覧
- Ansible運用ユーザーの作成
- SSH公開鍵認証の設定
- 作業ディレクトリの作成
- ansible.cfgの設定
ansible.cfgとは
Ansibleの設定ファイルです。
格納場所によって読み込まれる優先順位が異なります。
優先順位
1.環境変数(ANSIBLE_CONFIG)にファイルパスを設定
2.カレントディレクトリに存在する設定
3.ホームディレクトリに存在する設定
4./etc/ansible/ansible.cfg
著者が初心者に進める設定です。(設定しました。)
[defaults]
forks = 15
log_path = $HOME/.ansible/ansible.log
host_key_checking = False
gathering = smart
Ansibleを実行する環境
こちらの方の記事とdockerfileを参考にdocker上に環境を構築しました。
3章 プレイブックとインベントリ
■3-1 インベントリの基礎
対応形式
- INI
- YAML
デフォルトのインベントリは「/etc/ansible/hosts」になります。
下記はインベントリの例です。
[web_server]
192.168.101.[1:5]
[oracle]
oracle101
[mysql]
mysql-[a:d]
[db_servers:children] ## oracle, mysqlの上位グループ
oracle
mysql
[]でグループを定義します。
さらに、全ての上位に「all」というグループが存在します。
変数の種類
- ホスト変数
ターゲットノード固有に適用される変数。
インベントリではターゲットノードの後ろに定義
- グループ変数
グループ全体に適用される変数。
インベントリでは"[グループ:vars]"というセクションを作成し、
その下に変数を列記
[web_server]
192.168.101.[1:5]
[oracle]
oracle101 ansible_host=192.168.201.1
[mysql]
mysql-[a:d]
[db_servers:children] ## oracle, mysqlの上位グループ
oracle
mysql
[web_servers:vars]
http_port=8080
[a]ll:vars]
ansible_port=2020 ##[グループ変数]全てのサーバーのSSH接続ポート
ansible_user=ansible ##[グループ変数]SSH接続ユーザ
インベント変数のディレクトリ構造
変数のディレクトリとファイルの命名規則
■グループ変数
- group_vars/<グループ名>.yml
- group_vars/<グループ名>/XXX.xml
■ホスト変数
- host_vars/<ホスト名>.yml
- host_vars/<ホスト名>/XXX.yml
# inventory.ini
[web_server]
192.168.101.[1:3]
[db_servers]
mysql-[a:c]
./sec/
|- inventory.ini
|- group_vars
| |--all.yml # 全てのホストの変数
| |--web_server.yml # web_serversのグループ変数
| |--db_servers.yml # db_serversのグループ変数
|---host_vars
|--192.168.101.1.yml # 192.168.101.1用のホスト変数
|--192.168.101.2.yml # 192.168.101.2用のホスト変数
|--192.168.101.3.yml # 192.168.101.3用のホスト変数
|--mysql-a.yml # mysql-a用のホスト変数
|--mysql-b.yml # mysql-b用のホスト変数
|--mysql-c.yml # mysql-c用のホスト変数
*各ホストごとの変数設定もファイル単位で分割することができます。
■3-2 プレイブックの基礎
YAML型式のため、まずはYAMLを理解する必要があります。そちらの説明は、下記のサイトが詳しくわかりやすいので、載せておきます。あと、wikipediaも!!
プレイブックの構成
ディレクティブとセクションによって構成されています。ディレクティブは処理の塊(play)です。他には「Role Block Task」が存在します。また、各ディレクティブにはセクションがあります。
playbook===============================================================
1Play(ディレクティブ)------------------------------------------------------
host:all # Targetセクション
vars: # Varsセクション
ntp_conf: /tmp/ntp.conf
tasks: # tasksセレクション
- name: Install NTP
yum: name=ntp state=installed
- name: Config NTP
template: src=ntp.conf.j2 dest=/etc/ntp.conf
notify:
- Restart NTP
- name: Enable NTP
service: name=ntp state=running enabled=yes
handles: # Handlersセクション(実行制御)
- name: Restart NTP
service: name=ntp state=running enabled=restred
------------------------------------------------------------------1Play
1Play(ディレクティブ)------------------------------------------------------
host: web-servers # Targetセクション
tasks: # tasksセレクション
- name: Install HTTP
yum: name=httpd state=installed
------------------------------------------------------------------1Play
1Play------------------------------------------------------------------
------------------------------------------------------------------1Play
===============================================================playbook
Targetセクション
- hosts: <ホストパターン>
<ディレクティブ>:<value>
<ディレクティブ>:<value>
Tasksセクション
tasks:
- name:<タスク名>
<モジュール名>:
<arg>:<value>
<arg>:<value>
Handlersセクション
tasksセクションのnotifyを利用してHandlersに制御処理の実行を伝えています。また、listenはv2.2以降ですが、listenを利用することで複数のHandlersセクションを実行することができる。
tasks:
- name:<タスク名>
<モジュール名>:
<arg>:<value>
<arg>:<value>
notify:
- <handlersのタスクname または listenのname>
handlers:
-name:<タスク名>
<モジュール名>:
<arg>:<value>
<arg>:<value>
listen: <notifyのname>
-name:<タスク名>
<モジュール名>:
<arg>:<value>
<arg>:<value>
listen: <notifyのname>
Varsセクション
3つの方法で変数を設定することができます。
vars: # 直接変数を記載する
<変数名>:<変数の値>
<変数名>:<変数の値>
vars_file # 外部のYAMLを参照する
- <変数ファイル名>
vars_prompt #変数を対話的に設定させる
- name:<変数名>
prompt:<表示テキスト>
private:<True/False>
confirm:<True/False>
変数の定義
スコープ別変数
■Global領域の変数
Ansible実行の全体に対して定義される変数
- 環境変数
▶︎enviromentディレクティブを利用して定義する変数
- エクストラ変数
▶︎コマンドラインから指定できる変数
■Play単位の変数
個別のプレイ内で定義される変数
- プレイ変数
▶︎Varsセクションで指定した変数
- タスク変数
▶︎タスク内で指定した変数
- ロール変数
▶︎ロール内で指定した変数
- ブロック変数
▶︎ブロック内で指定した変数
■Host単位の変数
各ターゲットノードに関連付けた変数
- インベントリ変数
▶︎インベントリ内で指定する変数
ターゲットノードごとに指定 → ホスト変数
グループ全体 → グループ変数
- ファクト変数
▶︎ターゲットノードのシステム情報が格納されている変数
- レジスタ変数
▶︎タスクの実行結果の戻り値を書くのするための変数
■マジック変数(定義済み変数)
下記リンク参照
変数の参照
YAMLでは変数を定義できるが参照はできないので、jinja2のテンプレートを利用する。
{{....}}
変数値の結果を表示するタグ
{%....%}
変数に対する制御構文を記述するタグ
vars:
ens160:
ipv4:
address:"192.158.101.1"
broadcast:"192.158.101.255"
netmask:"255.255.255.0"
{{ens160.ipv4.address}}
## "ens160.ipv4.address":"192.158.101.1"
{{ens160['ipv4']['address']}}
## "ens160.ipv4.address":"192.158.101.1"
{{ens160['ipv4']}}
##"ens160['ipv4']":{"address":"192.158.101.1",
"broadcast":"192.158.101.255","netmask":"255.255.255.0"}
# if文
{% if hostvars[host].ansible_host is defined %}
client_ip = {{ hostvars[host].ansible_host}}
{% endif %}
# for文
{% for host in groups['all'] %}
{{hostvars[host1]['ansible_default_ipv4']['address']}}{{host}}
{% endfor %}
変数フィルタなどは、下記を参照してください。
■■特殊なディレクティブ
■■■条件分岐 - whenディレクティブ
特定の条件の時だけに、タスクを実行したい場合に利用する。
tasks:
- name: Install the httpd for web_servers
yum: name=httpd state=installed
when: host_role == 'web'
- name: Install the httpd for db_servers
yum: name=httpd state=installed
when: host_role == 'db'
#ファクト変数との連携
tasks:
- name: Install the ntp in RedHat
yum:
name=ntp
state=installed
when: ansible_os_family == 'RedHat'
- name: Install the ntp in Debian
yum:
name=ntp
state=installed
when: ansible_os_family == 'Debian'
■■■実行結果の取り扱い
tasks:
#タスク後の条件に従ってfailed状態にしてタスクを停止させる場合に利用する
- name: Control status by failed_when
commnand: mkdir /tmp
register: failed_result
failed_when: failed_result.stderr == ""
#タスクを実行した後の条件に従って、chandedという結果を判定する。
#タスク実行結果を書くのするレジスタ変数と一緒に利用される。
- name: Control status by changed_when
commnand: which ansible
register: changed_result
changed_when: changed_result.rc != 0
#igonre_errors: true
#対象のタスクでエラーが生じても無視してタスクが継続される
- name: Igonre failure task
shell: /bin/false
igonre_errors: true
■■■繰り返しの実行
繰り返し利用のディレクティブ
- loop v.2.5以降
- with_loop v.2.5以前(プラグイン)
サンプル
loopを利用する際に{{ item }}という固定の変数名を利用することが必須。
# 基本のループ
- name:Add several users
users:
name: "{{ item }}"
state: present
groups: "wheel"
loop:
- user01
- user02
- user03
# マッピングのループ
- name:Add several users
users:
name: "{{ item.name }}"
state: present
groups: "{{ item.groups }}"
loop:
- { name:'user01', groups: 'wheel'}
- { name:'user02', groups: 'wheel'}
- { name:'user03', groups: 'admin'}
# 多重のループ
- name:Add several users
postgresql_user:
db: "{{ item[0] }}"
name: "{{ item[1] }}"
password: ansible
priv: ALL
state: "present
loop: "{{ db_info[0]|product(db_info[1])|list }}"
vars:
db_info:
- ['org_db', 'provider_db', 'employee_db']
- [ 'user01', 'user02' ]
ループコントロール
loopそのものを管理したい場合に利用する。
- name: Count databases
debug:
msg: ""
loop:
- name: server-a
cpu: 2core
disks: 5Gb
ram: 15Gb
- name: server-b
cpu: 2core
-- 省略 --
- name: server-e
cpu: 2core
disks: 5Gb
ram: 15Gb
loop_control:
index_var: mysql_idx # サーバの数だけインデックスが付与される
pause: 2 # 繰り返しが2秒おきに実行される
label: "{{ item.name }}" # サーバ名でラベルが付与される
■■■タスクのグループ化
Ansible v.2.0から追加された機能です。
task:
- block:
- copy:src=epel.repo dest=/etc/yum.repos.d/epel_ansible.repo
- yum: name='libselinux-python,nginx' state=present
when: ansible_os_family == 'RedHat'
- block:
- apt+reository: repo='ppa:nginx/stable'
- apt: name='python-selinux,nginx' state=installed
when ansible_os_family == 'Debian'
エラーハンドリングの事例
task:
- block:
- command: /bin/false
- debug: msg="上記のタスクでエラーが発生するため、この処理は実行されません。"
rescue:
- debug: msg="エラーが発生"
- command: /bin/false
- debug: msg="上記のタスクでエラーが発生するため、この処理は実行されません。"
always:
- debug: msg="いつも実行されます。"
■3-3 プレイブックの応用
ロールを用いることで、プレイブックを分割して管理することができる。
├── host_vars
│ └── mysql-a.yml
├── inventory
│ └── inentory.ini
├── roles
│ └── mysql
│ ├── README.md
│ ├── defaults
│ │ └── main.yml
│ ├── handlers
│ │ └── main.yml
│ ├── meta
│ │ └── main.yml
│ ├── tasks
│ │ └── main.yml
│ ├── templates
│ │ └── my.cnf.j2
│ └── vars
│ └── main.yml
└── site.yml
defaultsディレクトリ
▶︎変数の初期値を定義したYAMLを配置
filesディレクトリ
▶︎ターゲットノードに転送するファイルを配置
handlersディレクトリ
▶︎Handlersセクションの内容を定義したYAMLを配置
metaディレクトリ
▶︎ロールのメタ情報やロール間の依存関係を定義したYAMLを配置
asksディレクトリ
▶︎Tasksセクションの内容を定義したYAMLを配置
templatesディレクトリ
▶︎テンプレートファイルを配置する(Jinja2)
varsディレクトリ
▶︎変数を定義したYAMLファイルを配置
著書のサンプル
この記事が参加している募集
この記事が気に入ったらサポートをしてみませんか?