12. Playbook アプリケーションとロールの自動化一括インストール例
12.1. yaml の簡単な例
12.2. ansible-playbook コマンド記述と Playbook の書き方の簡単な例:
12.3. Playbook の内容
12.4. タスクリスト
12.4.1. 特徴
12.4.2. 詳細タスクの定義
12.4.3.notify とハンドラー
12.4.4.tag タグ
12.5.include とロール
12.5.1.include
12.5.2.roles
12.6.roles 例: バッチ自動インストール
12. Playbook アプリケーションとロールの自動バッチインストールの例
転載元: https://www.cnblogs.com/f-ck-need-u/p/7567417.html
Playbook は、Ansible がバッチ自動化を実現するための最も重要な手段です。変数、参照、ループなどの関数が使用でき、アドホックに比べて機能が強力です。
12.1.yaml の簡単な例
Ansible の Playbook は yaml 構文を使用します。以下は yaml 形式のファイルです。
---
# Members in Bob’s family
name: Bob
age: 30
gender: Male
wife:
name: Alice
age: 27
gender: Female
children:
- name: Jim
age: 6
gender: Female
- name: Lucy
age: 3
gender: Female
12.2. Ansible-playbook コマンドの説明と Playbook 作成の簡単な例:
以下は簡単なプレイブックの例です。この例では 2 つのタスクを実行します。最初のタスクは /bin/date コマンドを実行することであり、2 番目のタスクは /etc/profile ファイルをターゲット ホスト上の /tmp にコピーすることです。これらはそれぞれ ansible コマンド モジュールとコピー モジュールを使用します。
[root@node2 tmp]# cat test.yaml
---
- hosts: aaa
tasks:
- name: execute date cmd
command: /bin/date
- name: copy profile to /tmp
copy: src=/etc/profile dest=/tmp
[root@node2 tmp]#
ansible のホスト構成は次のとおりであることに注意してください。
[root@node2 ansible]# cat /etc/ansible/hosts
[abc] # 自定义一个组名
172.17.0.3 # 添加被管理主机的IP
[aaa]
172.17.0.4
[bbb]
172.17.0.5
172.17.0.6
[webserver]
172.17.0[3:6]
Playbook を作成したら、ansible-playbook コマンドを使用して実行します。ansible-playbook コマンド オプションは、ansible コマンド オプションとほとんど同じです。しかし、独自のオプションもあります。傍受されたヘルプ情報は次のとおりです。
[root@node2 tmp]# ansible-playbook --help
usage: ansible-playbook [-h] [--version] [-v] [-k]
[--private-key PRIVATE_KEY_FILE] [-u REMOTE_USER]
[-c CONNECTION] [-T TIMEOUT]
[--ssh-common-args SSH_COMMON_ARGS]
[--sftp-extra-args SFTP_EXTRA_ARGS]
[--scp-extra-args SCP_EXTRA_ARGS]
[--ssh-extra-args SSH_EXTRA_ARGS] [--force-handlers]
[--flush-cache] [-b] [--become-method BECOME_METHOD]
[--become-user BECOME_USER] [-K] [-t TAGS]
[--skip-tags SKIP_TAGS] [-C] [--syntax-check] [-D]
[-i INVENTORY] [--list-hosts] [-l SUBSET]
[-e EXTRA_VARS] [--vault-id VAULT_IDS]
[--ask-vault-pass | --vault-password-file VAULT_PASSWORD_FILES]
[-f FORKS] [-M MODULE_PATH] [--list-tasks]
[--list-tags] [--step] [--start-at-task START_AT_TASK]
playbook [playbook ...]
Runs Ansible playbooks, executing the defined tasks on the targeted hosts.
positional arguments:
playbook Playbook(s)
optional arguments:
--ask-vault-pass ask for vault password
--flush-cache clear the fact cache for every host in inventory
--force-handlers run handlers even if a task fails
--list-hosts outputs a list of matching hosts; does not execute
anything else
--list-tags list all available tags
--list-tasks list all tasks that would be executed
--skip-tags SKIP_TAGS
only run plays and tasks whose tags do not match these
values
--start-at-task START_AT_TASK
start the playbook at the task matching this name
--step one-step-at-a-time: confirm each task before running
--syntax-check perform a syntax check on the playbook, but do not
execute it
--vault-id VAULT_IDS the vault identity to use
--vault-password-file VAULT_PASSWORD_FILES
vault password file
--version show program's version number, config file location,
configured module search path, module location,
executable location and exit
-C, --check don't make any changes; instead, try to predict some
of the changes that may occur
-D, --diff when changing (small) files and templates, show the
differences in those files; works great with --check
-M MODULE_PATH, --module-path MODULE_PATH
prepend colon-separated path(s) to module library (def
ault=~/.ansible/plugins/modules:/usr/share/ansible/plu
gins/modules)
-e EXTRA_VARS, --extra-vars EXTRA_VARS
set additional variables as key=value or YAML/JSON, if
filename prepend with @
-f FORKS, --forks FORKS
specify number of parallel processes to use
(default=5)
-h, --help show this help message and exit
-i INVENTORY, --inventory INVENTORY, --inventory-file INVENTORY
specify inventory host path or comma separated host
list. --inventory-file is deprecated
-l SUBSET, --limit SUBSET
further limit selected hosts to an additional pattern
-t TAGS, --tags TAGS only run plays and tasks tagged with these values
-v, --verbose verbose mode (-vvv for more, -vvvv to enable
connection debugging)
Connection Options:
control as whom and how to connect to hosts
--private-key PRIVATE_KEY_FILE, --key-file PRIVATE_KEY_FILE
use this file to authenticate the connection
--scp-extra-args SCP_EXTRA_ARGS
specify extra arguments to pass to scp only (e.g. -l)
--sftp-extra-args SFTP_EXTRA_ARGS
specify extra arguments to pass to sftp only (e.g. -f,
-l)
--ssh-common-args SSH_COMMON_ARGS
specify common arguments to pass to sftp/scp/ssh (e.g.
ProxyCommand)
--ssh-extra-args SSH_EXTRA_ARGS
specify extra arguments to pass to ssh only (e.g. -R)
-T TIMEOUT, --timeout TIMEOUT
override the connection timeout in seconds
(default=10)
-c CONNECTION, --connection CONNECTION
connection type to use (default=smart)
-k, --ask-pass ask for connection password
-u REMOTE_USER, --user REMOTE_USER
connect as this user (default=None)
Privilege Escalation Options:
control how and which user you become as on target hosts
--become-method BECOME_METHOD
privilege escalation method to use (default=sudo), use
`ansible-doc -t become -l` to list valid choices.
--become-user BECOME_USER
run operations as this user (default=root)
-K, --ask-become-pass
ask for privilege escalation password
-b, --become run operations with become (does not imply password
prompting)
[root@node2 tmp]#
上記の test.yaml を実行します。
[root@node2 tmp]# ansible-playbook /tmp/test.yaml
PLAY [aaa] *************************************************************************************************************************************
TASK [Gathering Facts] *************************************************************************************************************************
ok: [172.17.0.4]
TASK [execute date cmd] ************************************************************************************************************************
changed: [172.17.0.4]
TASK [copy profile to /tmp] ********************************************************************************************************************
changed: [172.17.0.4]
PLAY RECAP *************************************************************************************************************************************
172.17.0.4 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@node2 tmp]#
上記の結果から、次のことがわかります。
- (1) デフォルトでは、ansible-playbook は ansible と同じであり、どちらも同期ブロッキング モードであり、タスクは次のタスクに進む前にすべてのホストで実行する必要があります。
- (2) ファクト情報は実行前に自動的に収集されます。
- (3) 表示された結果から、タスクが実際に実行されたのか、冪等性により実行されなかったのかを判断できます。
- (4) 各プレイには複数のタスクが含まれており、応答情報プレイの要約が含まれています。
12.3. プレイブックの内容
Playbook の各 Play に対して、hosts オプションを使用して、これらのタスクを実行するホストまたはホスト グループを定義します。また、remote_user を使用して、リモート ホストでタスクを実行するユーザーを指定することもできます。実際、remote_user は ssh を実行するユーザーです制御されたホストに接続すると、コマンドを実行する ID は当然このユーザーになります。
例えば:
---
- hosts: abc,aaa,172.17.0.5
remote_user: root
tasks: XXXX
ホストやホストではホストグループを「,」で区切ることもできますが、この方法は公式マニュアルでは紹介されていません。さらに、ホストとホスト グループを指定するにはいくつかの方法があります。
- all または *: インベントリ内のすべてのホストを示します。
- :: ユニオンを取ります。たとえば、「host1:host2:group1」は、2 つのホストとホスト グループを意味します。
- :&: 交差点を進みます。たとえば、「group1:&group2」は両方のホストグループに含まれるホストを意味します。
- :!:除外します。たとえば、「group1:!host1」は、host1 ホストを除いた group1 内の残りのホストを意味します。
- ワイルドカード: たとえば、「web*.baidu.com」。
- 番号の範囲: たとえば、「web[0-5].baidu.com」。
- 文字範囲: たとえば、「web[ad].baidu.com」。
- 正規表現:「 」で始まります。たとえば、「 web\d.baidu.com」などです。
さらに、ansible コマンド ラインまたは ansible-playbook コマンド ラインで、「-l」オプションを使用して、タスクを実行するホストを制限できます。例えば:
ansile centos -l host[1:5] -m ping
centos ホスト グループ内の host1 ~ host5 のみが ping モジュールを実行することを示します。
タスク実行の ID をタスク上で個別に定義することも可能で、これによりグローバル定義がオーバーライドされます。
[root@node2 tmp]# cat test2.yaml
---
- hosts: abc,aaa,bbb
remote_user: root
tasks:
- name: run a command
shell: /bin/date
- name: copy a file to /tmp
copy: src=/etc/profile dest=/tmp
remote_user: myuser
[root@node2 tmp]#
运行过程是:
[root@node2 tmp]# ansible-playbook test2.yaml
PLAY [abc,aaa,bbb] *****************************************************************************************************************************
TASK [Gathering Facts] *************************************************************************************************************************
ok: [172.17.0.6]
ok: [172.17.0.5]
ok: [172.17.0.4]
ok: [172.17.0.3]
TASK [run a command] ***************************************************************************************************************************
changed: [172.17.0.5]
changed: [172.17.0.6]
changed: [172.17.0.3]
changed: [172.17.0.4]
TASK [copy a file to /tmp] *********************************************************************************************************************
changed: [172.17.0.4]
changed: [172.17.0.5]
changed: [172.17.0.3]
changed: [172.17.0.6]
PLAY RECAP *************************************************************************************************************************************
172.17.0.3 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
172.17.0.4 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
172.17.0.5 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
172.17.0.6 : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
[root@node2 tmp]#
172.17.0.[3-6] マシンの /tmp ディレクトリに移動して、プロファイルがあるかどうかを確認できます。
権限昇格もサポートしています。
[root@node2 tmp]# cat test2.yaml
---
- hosts: abc,aaa,bbb
remote_user: yourname
tasks:
- name: run a command
shell: /bin/date
- name: copy a file to /tmp
copy: src=/etc/profile dest=/tmp
become: yes
become_method: sudo
become_user: root
上記の例から、remote_user は実際にはタスクを実行するための絶対的な ID ではなく、単なる ssh 接続の ID であることがわかります。しかし、become が指定されていない場合、この ID を使用してタスクを実行します。
12.4.タスクリスト
12.4.1. 特性
各プレイにはホストとタスクが含まれており、ホストはインベントリで制御されるホストを定義し、タスクは各モジュールの呼び出しなどの一連のタスク タスク リストを定義します。これらのタスクは一度に 1 つずつ順番に実行され、選択したすべてのホストがタスクを実行するまで次のタスクに進みません。
フィルタリングされたホストのみが対応するタスクを実行しますが、すべてのホスト (ここでのすべてのホストとは、hosts オプションで指定されたホストを意味します) が同じタスク コマンドを受信し、すべてのホストがコマンドを受信した後、Ansible マスターが特定のホストを選別し、SSH 経由でリモートでタスクを実行します。つまり、ansible-playbook -vvvv の情報を確認すると、一時タスク ファイルは sftp 経由で制御されているすべてのホストに送信されますが、スクリーニングされたホストの一部のみ (スクリーニングされている場合) が送信されることがわかります。 sshパスを実行し、リモートでコマンドを実行します。
制御対象ホストでエラーが発生したり、特定のタスクの実行に失敗したりすると、そのホストはタスク ポーリング リストから削除されます。つまり、特定のホストでは、特定のタスクの実行に失敗した場合、後続のすべてのタスクは再度実行されません。もちろん、これは他のホストのタスク実行には影響しません (ホスト上のタスク間に依存関係がある場合を除く)。
最も重要なことは、ansible のタスクは冪等であり、複数の実行が正常に実行されたタスクに影響を与えないことです。さらに、冪等性は、実行が失敗した後にプレイブックを修正して再実行した場合、たとえ別のホストであっても、正常に実行されたタスクには影響を与えないことも示しています。この点だけでも、ansible はトラブルシューティングに非常に適しています。もちろん、一部の特別なモジュールや特別に定義されたタスクは常に冪等であるわけではありません。たとえば、最も単純な方法は、繰り返し実行されるコマンドまたはシェル モジュールのコマンドを実行することです。コマンド モジュールとシェル モジュールを例に挙げると、これらには create とremoves の 2 つのオプションがあり、それぞれ、指定されたファイルがシステム上に存在する (存在しない) 場合にはコマンドが実行されないことを示します。制御されたホスト。
12.4.2. タスクの詳細を定義する
- (1). 各タスクに名前項目を追加したり、複数のタスクが名前に依存したりすることができます。
例えば以下の2つの例です。2 つの例から、2 つのタスクは実際には同じ名前に属しており、2 番目のタスクには名前を付ける必要がないことがわかります。
例 1:
tasks:
- name: do something to initialize mariadb
file: path=/mydata/data state=directory owner=mysql group=mysql mode=0755
- shell: /usr/bin/mysql_install_db --datadir=/mydata/data --user=mysql creates=/mydata/data/ibdata1
例 2:
tasks:
- name: echo var passed by nginx
shell: echo "{
{ hi_var }}"
register: var_result
- debug: msg="{
{ var_result.stdout }}"
実際、名前は単なる説明文であり、どこにでも定義できます。たとえば、プレーの先頭で定義されます。
---
- name: start a play
hosts: localhost
tasks:
(2) タスクであるため、実行するタスクが 1 つ以上存在する必要があり、その本質は、ansible の対応するモジュールをロードして実行することです。Playbook では、呼び出される各モジュールはアクションと呼ばれます。
たとえば、サービスが確実に開始されるようにタスクを定義するには、次の 3 つのパス モジュール パラメータがあります。
tasks:
- name: be sure the sshd is running
service: name=sshd state=started # 方法一:定义为key=value,直接传递参数给模块
service:
name: sshd
state: started
service:
args:
name: sshd
state: started
ただし、ping モジュール、コマンド、およびシェル モジュールには key=value 形式は必要ないことに注意してください。ping コマンドの場合、key=value は直接省略できます。コマンドとシェルの場合は、コマンドのパスと接続するオプションまたはパラメータを指定するだけでよく、上記の方法 2 は使用できません。たとえば、次の定義は ntpdate コマンドであり、パラメーターを指定するだけで済みます。
tasks:
- name: execute command ntpdate
shell: /usr/sbin/ntpdate ntp1.aliyun.com
- name: ping host
ping:
コマンドまたはシェル モジュールの場合、コマンドの戻りステータス コードを考慮する必要がある場合があります。ゼロ以外のステータス コードを無視してタスクの実行を続行する場合は、次の 2 つの方法を使用できます。
tasks:
- name: ignore non_zero return code
shell: /usr/sbin/ntpdate ntp1.aliyun.com || /bin/true
または
tasks:
- name: another way to ignore the non_zero return code
shell: /usr/sbin/ntpdate ntp1.aliyun.com
ignore_errors: true
(3). アクションの key=value が多すぎてコンテンツが長すぎる場合は、前の行のインデント レベルに基づいてインデントを続けて、継続行を示すことができます。
たとえば、以下の owner は src よりもスペース 4 つ多くインデントされます。
tasks:
- name: Copy ansible inventory file to client
copy: src=/etc/fstab dest=/tmp
owner=root group=root mode=0644
(4). アクションの値部分では、定義された変数、定義されたカスタム変数、または組み込み変数を参照できます。変数については以下を参照してください。
(5). include コマンドを使用して、他の Playbook ファイルをこの Playbook ファイルに含めます。Includeの方法は以下の通りです。
12.4.3. 通知とハンドラー
Ansible のほとんどすべてのモジュールは冪等です。これは、制御されるホストの状態変更をキャプチャできるかどうか、つまり、タスクごとにChanged=trueまたはchanged=falseを取得できるかどうかを意味します。ansible がChanged=trueをキャプチャすると、通知コンポーネントをトリガーできます(コンポーネントが定義されている場合)。
通知はモジュールではなくコンポーネントであり、アクションを直接定義でき、主な目的はハンドラーを呼び出すことです。例えば:
tasks:
- name: copy template file to remote host
template: src=/etc/ansible/nginx.conf.j2 dest=/etc/nginx/nginx.conf
notify:
- restart nginx
- test web page
copy: src=nginx/index.html.j2 dest=/usr/share/nginx/html/index.html
notify:
- restart nginx
これは、テンプレートモジュールのタスクが実行されるときに、changed=trueをキャッチした場合はnotifyがトリガーされ、配布されたindex.htmlが変更された場合はnginxも再起動されます(もちろんこれは必須ではありません)。呼び出されるハンドラは、notify の下に 2 つ定義されています。ハンドラーは主にサービスを再起動したり、システムの再起動をトリガーしたりするために使用され、それ以外の場合にはハンドラーを使用することはほとんどありません。これら 2 つのハンドラーの内容は次のとおりです。
handlers:
- name: restart nginx
service: name=nginx state=restarted
- name: test web page
shell: curl -I http://192.168.100.10/index.html | grep 200 || /bin/false
ハンドラーの定義はタスクの定義とまったく同じです。唯一の制限は、ハンドラー内のタスクの名前が通知で定義された名前と同じでなければならないことです。
通知はプレイ内のすべてのタスクが実行された後にトリガーされ、プレイ内で 1 回だけトリガーされることに注意してください。これは、プレイ内の複数のタスクでChanged=trueが発生した場合、トリガーされるのは1回だけであることを意味します。たとえば、上記の例では、構成ファイルとindex.htmlの両方がnginxにコピーされている場合、変更が発生すると、両方がApacheの再起動操作をトリガーします。ただし、冗長な再起動を避けるために、再生の実行後に 1 回だけ再起動されます。
12.4.4. タグ
Playbook の各タスクはタグ付けできます。タグの主な機能は、ansible-playbook でどのタグ付きタスクを実行するか、またはタグ付きタスクを無視するかを設定することです。
tasks:
- name: make sure apache is running
service: name=httpd state=started
tags: apache
- name: make sure mysql is running
service: name=mysqld state=started
tags: mysql
タグに関する ansible-playbook コマンドのオプションは次のとおりです。
--list-tags # list all available tags
-t TAGS, --tags=TAGS # only run plays and tasks tagged with these values
--skip-tags=SKIP_TAGS # only run plays and tasks whose tags do not match these values
12.5.インクルードとロール
すべてのプレイをプレイブックに記述すると、プレイブック ファイルが肥大化して読みにくくなる可能性があります。したがって、異なる Playbook に複数の異なるタスクを記述し、include を使用してそれらを含めることができます。役割は、プレイブックを統合する方法です。インクルードであってもロールであっても、その目的は大規模なプレイブックを分割し、いくつかの細かいプレイやタスクを再利用することです。
12.5.1.インクルード
タスク リストとハンドラーを別のファイルに個別に記述し、include を使用してそれらを Playbook ファイルに含めることができます。さらに、独立した Playbook ファイルを作成し、include を使用してこのファイルをインクルードすることもできます。
つまり、include はインポート タスク、インポート プレイブックの 2 種類のファイルをインポートできます。
1. 1 つはタスク リスト スタイルのファイル (タスクまたはハンドラー ディレクティブなし) で、タスクまたはハンドラー ディレクティブのサブオプションにのみ含めることができます。このようにして、インクルードされたファイルに変数を渡すことができます。
タスク リスト ファイル /yaml/a.yaml の内容が次のようになっているとします。
---
- name: execute ntpdate
shell: /usr/sbin/ntpdate ntp1.aliyun.com
同じディレクトリ/yaml に test.yaml という名前の Playbook があります (ロールを除く、Playbook 内のすべての相対パスは Playbook に基づいています)。この Playbook に含めるには include を使用します。相対パスを使用する場合は、同じディレクトリに含めます。ファイルの下に含まれます。
---
- hosts: centos7
tasks:
- include: a.yaml sayhi="hello world"
または:
---
- hosts: centos7
tasks:
- include: a.yaml
vars:
sayhi: "hello world"
この変数は、インクルードされたファイル a.yaml で使用できます。例えば:
---
- name: execute ntpdate
shell: /usr/sbin/ntpdate ntp1.aliyun.com
- name: say hi to world
debug: msg=”{
{
sayhi }}”
test.yaml を実行すると、対応する変数値が出力されます。
ansible-playbook /yaml/test.yaml
PLAY [centos7] **************************************************************************
TASK [Gathering Facts] ******************************************************************
ok: [192.168.100.64]
ok: [192.168.100.63]
ok: [192.168.100.65]
TASK [execute ntpdate] *******************************************************************
changed: [192.168.100.64]
changed: [192.168.100.65]
changed: [192.168.100.63]
TASK [sayhi to world] *******************************************************************
ok: [192.168.100.63] => {
"changed": false,
"msg": "hello world"
}
ok: [192.168.100.65] => {
"changed": false,
"msg": "hello world"
}
ok: [192.168.100.64] => {
"changed": false,
"msg": "hello world"
}
PLAY RECAP ******************************************************************************
192.168.100.63 : ok=3 changed=1 unreachable=0 failed=0
192.168.100.64 : ok=3 changed=1 unreachable=0 failed=0
192.168.100.65 : ok=3 changed=1 unreachable=0 failed=0
2. もう 1 つは、プレイブック ファイル全体をインクルードすることです。つまり、インクルードのアクションは 1 つ以上のプレイをロードすることであるため、トップレベル リストのレベルで書き込まれます。
- name: this is a play at the top level of a file
hosts: all
remote_user: root
tasks:
- name: say hi
tags: foo
shell: echo "hi..."
- include: load_balancers.yml sayhi="hello world"
- include: webservers.yml
- include: dbservers.yml
any other operations
ansible バージョン 2.4 では、include と import という 2 つのインポート メソッドが追加され、より詳細な静的インポートと動的インポートをサポートします。一方、ansible 2.3 以前の include ステートメントは廃止されましたが、引き続き使用できることに注意してください。関連する公式マニュアルのアドレス (https://docs.ansible.com/ansible/latest/playbooks_reuse_includes.html)。
12.5.2.役割
ロールとは役割を意味し、主に再利用性を実現するために Playbook をカプセル化するために使用されます。Ansible では、ロールはファイルの組織構造によって表されます。
ロールのファイル構成構造を次の図に示します。
まず、roles ディレクトリが必要です。同時に、roles ディレクトリが配置されているディレクトリには、playbook ファイルも存在する必要があります。ここでは nginx.yml です。nginx.yml ファイルは、ansible-playbook が実行する必要があるファイルであり、ロールが定義されていますロールが実行されると、関連するファイルがロール内の対応するロール ディレクトリに見つかります。
ロール ディレクトリ内のサブディレクトリが各ロールです。たとえば、ここには nginx という名前のロールが 1 つだけあり、ロール ディレクトリには固定名のディレクトリがいくつかあります (存在しない場合は無視します)。これらのディレクトリには、固定名のファイルもいくつか存在する必要がありますが、固定名のファイル以外は自由に名前を付けることができます。各ディレクトリの意味は以下のとおりです。
tasks ディレクトリ: タスクリストを保存します。ロールを有効にするには、このディレクトリにメイン タスク ファイル main.yml が必要です。main.yml では、include を使用して同じディレクトリ内の他のファイル (タスク) をインクルードできます。
handlers ディレクトリ: ハンドラーが保存されているディレクトリ。有効にするには、ファイルの名前を main.yml にする必要があります。
files ディレクトリ: タスクでコピー モジュールまたはスクリプト モジュールを実行するときに、相対パスが使用されている場合は、このディレクトリで対応するファイルが検索されます。
templates ディレクトリ: タスクでテンプレート モジュールを実行するときに、相対パスが使用されている場合は、このディレクトリで対応するモジュール ファイルが検索されます。
vars ディレクトリ: このロールに固有の変数を定義します。var ファイルがある場合、それは main.yml ファイルである必要があります。
defaults ディレクトリ: ロールのデフォルト変数を定義します。ロールのデフォルト変数の優先順位は最も低く、他のレベルにある同じ名前の変数によって上書きされます。var ファイルがある場合、それは main.yml ファイルである必要があります。
meta ディレクトリ: ロールの依存関係を定義するために使用されます。ロールの依存関係がある場合、ファイルは main.yml である必要があります。
したがって、比較的完全なロールのファイル構成構造は次のようになります。
複数のロールがある場合は、ロールの同じレベルのディレクトリに複数のインバウンド (C 言語の main 関数に似た) ファイル (上記の nginx.yml など) を定義し、対応するロール ディレクトリをロール ディレクトリ内に作成します。
もちろん、相対パスが使用されない場合、ロールのファイル構造は重要ではありませんが、ロール関数は、ファイルの混乱とプレイブックの肥大化の問題を解決するために開発されました。したがって、可能であれば、推奨されるロール ファイル構造を使用するようにしてください。
また、ロール内に出現するタスク、var、ハンドラ等が別途定義したオブジェクトと競合する場合は、ロール内の内容が先に実行されます。
以下は、nginx ロールの受信ファイル nginx.yml の内容です。
---
- hosts: centos7
roles:
- nginx
ロールの使用法と組織構造の詳細については、以下の例を参照してください。
12.6.ロールの例: バッチ自動インストール
以下は、ロールを使用して nginx と mysql (CentOS 6) または maridb (CentOS 7) をバッチで自動インストールする例です。制御対象ノードには CentOS 6 と CentOS 7 の 2 つのオペレーティング システムがあるため、対応するデータベースを選択するだけでなく、nginx 構成ファイルを各オペレーティング システムに適合させる必要もあります。これは、nginx がこれら 2 つのバージョンのシステムでコンテンツを構成するためです。違う。ここでは、nginx、mysql、mariadb の 3 つのロールがあり、nginx のロールが mysql または mariadb のロールに依存するようにします。
次の例では、いくつかの無理な動作や冗長な動作がありますが、学習例として、組織構造と役割間の関連業務をよく理解することができます。
1 つ目はファイルの構造です。
このうちsite.ymlはnginx、mysql、mariadbの3つの役割を呼び出すための受信ファイルで、その内容は以下の通りです。これには 3 つの機能があります:
(1) ロールを呼び出す前に、リリース バージョンに従って yum ソース (pre_tasks) を設定します;
(2) nginx ロールを呼び出します (nginx ロールでは mysql と mariadb の 2 つのロールは呼び出されません)。 meta/main.ymlファイルに定義したnginxロールはこれら2つのロールに依存するため、ここで定義する必要はありません;
(3)nginxロール実行後、プロンプトメッセージ(post_tasks)を出力します。
cat /yaml/site.yml
---
- hosts: centos
remote_user: root
# 根据发行版配置好yum源,使用when进行条件判断
pre_tasks:
- name: config the yum repo for centos 7
yum_repository:
name: epel
description: epel
baseurl: http://mirrors.aliyun.com/epel/7/$basearch/
gpgcheck: no
when: ansible_distribution_major_version == "7"
- name: config the yum repo for centos 6
yum_repository:
name: epel
description: epel
baseurl: http://mirrors.aliyun.com/epel/6/$basearch/
gpgcheck: no
when: ansible_distribution_major_version == "6"
roles:
- nginx
# 输出over消息
post_tasks:
- shell: echo 'deploy nginx/mysql over'
register: ok_var
- debug: msg='{
{ ok_var.stdout }}'
nginx ロールの各ファイルの内容は次のとおりです。テンプレートでコピーしたソースファイルはすべてcentos 6 nginxとcentos 7 nginxから抽出されたものですが、名前が変更されているだけです。
/yaml/roles/nginx/tasks/main.yml
---
- name: make sure nginx state is installed
yum: name=nginx state=installed
- name: template nginx.conf
# 基于变量赋值配置文件模板,检查配置文件语法,并在必要的时候触发handler
template: src=nginx{
{
ansible_distribution_major_version }}.conf.j2
dest=/etc/nginx/nginx.conf
validate="/usr/sbin/nginx -t -c %s"
notify:
- restart nginx
# 基于jinja2渲染模板文件,且改变时也触发重启操作
- name: copy index.html
template: src=index.html.j2 dest=/usr/share/nginx/html/index.html
notify:
- restart nginx
- name: make sure nginx service is running
service: name=nginx state=started
# 引用变量 nginx_port,在vars/main.yml中定义了
- name: make sure port is open
wait_for: port="{
{ nginx_port }}"
/yaml/roles/nginx/handlers/main.yml
---
- name: restart nginx
service: name=nginx state=restarted
/yaml/roles/nginx/vars/main.yml
nginx_port: 80
# 定义nginx依赖于MySQL或mariadb,具体依赖于哪个,是通过条件进行判断的,centos 6表示依赖于mysql,centos 7表示依赖于mariadb
# 同时传递了两个值给变量hi_var,由于是在依赖的时候传递的,所以这两个变量可直接在依赖的role(mysql role或mariadb role)的playbook中引用
/yaml/roles/nginx/meta/main.yml
---
dependencies:
- {
role: mysql,hi_var: "hello mysql",when: "ansible_distribution_major_version == '6'" }
- {
role: mariadb,hi_var: "hello mariadb",when: "ansible_distribution_major_version == '7'" }
Index.html.j2 は上記でコピーされており、その内容は次のとおりです。
shell> cat /yaml/roles/nginx/templates/index.html.j2
<h1>hello from {
{
ansible_default_ipv4.address }}<h1>
テンプレートが実行されると、jinja2 エンジンを使用してファイル内の変数が置き換えられるため、別のホストにコピーする場合、index.html の内容はリモート ホストの IP に基づきます。ここで使用される変数は、収集されたファクト内の変数「ansible_default_ipv4.address」です。
以下は、mysql ロールの各ファイルの内容です。MySQL の my.cnf と mariadb の my.cnf はデフォルトでは同じではないことに注意してください (mariadb の my.cnf にはデフォルトで追加の設定「!includeir /etc/my.cnf.d」があり、MySQL はこの項目をキャンセルする必要があります)。したがって、それらは個別に提供する必要があります。
/yaml/roles/mysql/tasks/main.yml
---
- name: make sure mysql is installed
yum: name=mysql-server state=installed
# 特别需要注意下面的初始化命令,由于执行的是shell模块,所以要考虑其幂等性,显然初始化动作是一定要实现幂等性的
- name: do something to initialize mysql
file: path=/mydata/data state=directory owner=mysql group=mysql mode=0755
- shell: /usr/bin/mysql_install_db --datadir=/mydata/data --user=mysql creates=/mydata/data/ibdata1
- name: copy my.cnf
copy: src=my.cnf dest=/etc/my.cnf
notify:
- restart mysql
- name: make sure mysql is running
service: name=mysqld state=started
- name: make sure mysql port is open
wait_for:
port: "{
{ mysql_port }}"
timeout: 10
# 这里输出了nginx/meta/main.yml中传递的变量
- name: echo var passed by nginx
shell: echo "{
{ hi_var }}"
register: var_result
- debug: msg="{
{ var_result.stdout }}"
/yaml/roles/mysql/handlers/main.yml
---
- name: restart mysql
service: name=mysqld state=restarted
/yaml/roles/mysql/vars/main.yml
---
mysql_port: 3306
以下是mariadb role中各文件的内容,和mysql大体上是一致的。注意,MySQL的my.cnf和mariadb的my.cnf默认情况下并不一样,所以需要分别提供。
/yaml/roles/mariadb/tasks/main.yml
---
- name: make sure mariadb is installed
yum: name=mariadb-server state=installed
- name: do something to initialize mariadb
file: path=/mydata/data state=directory owner=mysql group=mysql mode=0755
- shell: /usr/bin/mysql_install_db --datadir=/mydata/data --user=mysql creates=/mydata/data/ibdata1
- name: copy my.cnf
copy: src=my.cnf dest=/etc/my.cnf
notify:
- restart mariadb
- name: make sure mariadb is running
service: name=mariadb state=started
- name: make sure mariadb port is open
wait_for:
port: "{
{ mariadb_port }}"
timeout: 10
- name: echo var passed by nginx
shell: echo "{
{ hi_var }}"
register: var_result
- debug: msg="{
{ var_result.stdout }}"
/yaml/roles/mariadb/handlers/main.yml
---
- name: restart mariadb
service: name=mariadb state=restarted
/yaml/roles/mariadb/vars/main.yml
---
mariadb_port: 3306
以下は 2 つのマシンのテスト結果です。1 つは centos 7 (192.168.100.54)、もう 1 つは centos 6 (192.168.100.70) です。
PLAY [newhosts] *************************************************************************
TASK [Gathering Facts] ******************************************************************
ok: [192.168.100.70]
ok: [192.168.100.54]
TASK [config the yum repo for centos 7] *************************************************
skipping: [192.168.100.70]
changed: [192.168.100.54]
TASK [config the yum repo for centos 6] *************************************************
skipping: [192.168.100.54]
changed: [192.168.100.70]
TASK [mysql : make sure mysql is installed] *********************************************
skipping: [192.168.100.54]
changed: [192.168.100.70]
TASK [mysql : do something to initialize mysql] *****************************************
skipping: [192.168.100.54]
changed: [192.168.100.70]
TASK [mysql : command] ******************************************************************
skipping: [192.168.100.54]
changed: [192.168.100.70]
TASK [mysql : copy my.cnf] **************************************************************
skipping: [192.168.100.54]
changed: [192.168.100.70]
TASK [mysql : make sure mysql is running] ***********************************************
skipping: [192.168.100.54]
changed: [192.168.100.70]
TASK [mysql : make sure mysql port is open] *********************************************
skipping: [192.168.100.54]
ok: [192.168.100.70]
TASK [mysql : echo var passed by nginx] *************************************************
skipping: [192.168.100.54]
changed: [192.168.100.70]
TASK [mysql : debug] ********************************************************************
skipping: [192.168.100.54]
ok: [192.168.100.70] => {
"changed": false,
"msg": "hello mysql"
}
TASK [mariadb : make sure mariadb is installed] *****************************************
skipping: [192.168.100.70]
changed: [192.168.100.54]
TASK [mariadb : do something to initialize mariadb] *************************************
skipping: [192.168.100.70]
changed: [192.168.100.54]
TASK [mariadb : command] ****************************************************************
skipping: [192.168.100.70]
changed: [192.168.100.54]
TASK [mariadb : copy my.cnf] ************************************************************
skipping: [192.168.100.70]
changed: [192.168.100.54]
TASK [mariadb : make sure mariadb is running] *******************************************
skipping: [192.168.100.70]
changed: [192.168.100.54]
TASK [mariadb : make sure mariadb port is open] *****************************************
skipping: [192.168.100.70]
ok: [192.168.100.54]
TASK [mariadb : echo var passed by nginx] ***********************************************
skipping: [192.168.100.70]
changed: [192.168.100.54]
TASK [mariadb : debug] ******************************************************************
skipping: [192.168.100.70]
ok: [192.168.100.54] => {
"changed": false,
"msg": "hello mysql"
}
TASK [nginx : make sure nginx state is installed] ***************************************
changed: [192.168.100.54]
changed: [192.168.100.70]
TASK [nginx : template nginx.conf] ******************************************************
ok: [192.168.100.70]
changed: [192.168.100.54]
TASK [nginx : copy index.html] **********************************************************
changed: [192.168.100.70]
changed: [192.168.100.54]
TASK [nginx : make sure nginx service is running] ***************************************
changed: [192.168.100.54]
changed: [192.168.100.70]
TASK [nginx : make sure port is open] ***************************************************
ok: [192.168.100.70]
ok: [192.168.100.54]
RUNNING HANDLER [mysql : restart mysql] *************************************************
changed: [192.168.100.70]
RUNNING HANDLER [mariadb : restart mariadb] *********************************************
changed: [192.168.100.54]
RUNNING HANDLER [nginx : restart nginx] *************************************************
changed: [192.168.100.54]
TASK [command] **************************************************************************
changed: [192.168.100.54]
changed: [192.168.100.70]
TASK [debug] ****************************************************************************
ok: [192.168.100.54] => {
"changed": false,
"msg": "deploy nginx/mysql over"
}
ok: [192.168.100.70] => {
"changed": false,
"msg": "deploy nginx/mysql over"
}
PLAY RECAP ******************************************************************************
192.168.100.54 : ok=19 changed=14 unreachable=0 failed=0
192.168.100.70 : ok=18 changed=12 unreachable=0 failed=0
上記のロール編成の例を読むと、ロールの使用法とプレイブックについての理解が深まると思います。実際、ansible には、Playbook の倉庫とみなすことができる、多数の Playbook を保存する Web サイトがあります。ダウンロードして少し改造して使うこともできますし、使わない場合でも書き方を学ぶ価値はあります。アドレス:ansible galaxy (https://galaxy.ansible.com/home)
さらに、さまざまな標準に従って役割を整理すると、プレイブックの作成が容易になる可能性があります。たとえば、上記の例では、インストールされているソフトウェアの種類によって役割を分割するよりも、リリース バージョンによって役割を分割する方が簡単になる可能性があります。もちろん、インベントリでcentos 6とcentos 7を分けることも可能です。どちらがより便利で再利用可能であるかは、自分で検討する必要があります。