Download - Ansible handson
Ansible入門Ansible Workshop in Okinawa
2016.11.11
Hideki Saito Internet Initiative Japan inc.
本セッションの目的午前の部では、午後に予定されているハンズオンに向けて必要となる、以下の事柄について解説します。そして実際にAnsibleのインストールを行います。
(1) Ansibleとは? (2) AnsibleのインストールとCLIの基本操作 (3) Playbookの記述方法
本セッション終了時点で、午後の部のハンズオンに向けた準備が整います。
自己紹介• 氏名: 齊藤 秀喜 (さいとう ひでき) • TwitterID: @saito_hideki • 所属: • 株式会社インターネットイニシアティブ • 日本OpenStackユーザ会ボードメンバー
• 趣味: OpenStack, Ansible
News ~ Ansibleに関する最近の話題 ~
v2.2 release2系の最新版である、2.2がリリースされています。 TechPreviewとしてPython3対応が入りました。
• 2.2.0リリース情報
• 11-01-2016 "The Battle of Evermore"
• https://goo.gl/IXprJu
• 2.3へのロードマップ
• https://goo.gl/9TojdJ
Galaxyオープンソース化Ansible Galaxyがオープンソース化されました。 GalaxyはGithubやDockerhubのように、Playbookやモジュールのリポジトリを公開して共有し、再利用するサービスです。 オープンソース化されたことにより、自身でGalaxyサイトを構築することが可能となりました。
• ソースコード: https://github.com/ansible/galaxy
• 公式サイト https://galaxy.ansible.com/
Interop Challenge with Ansible世に出ている様々なOpenStack環境で、共通のワークロードを動作させて、相互運用性を検証する試み。 2016.10に開催されたOpenStack Summit Barcelonaでは、キーノートセッションで実演されました。 ワークロードのデプロイにはAnsibleが利用されました。 • Wiki https://wiki.openstack.org/wiki/Interop_Challenge • Video https://www.youtube.com/watch?v=CqNFcuJfZ_Y
Basics ~ Ansibleとは?~
本日のEtherpad本日のハンズオンに利用するEtherpadはコチラです
• http://172.16.51.53:9001/p/ansible_workshop_2016
• https://etherpad.openstack.org/p/ool_ansible_workshop_2016
AnsibleとはInfrastructure as Codeというコンセプトを実現するための自動化ツールで、以下の特徴を持っています。
(1) システム管理にエージェントを必要としない (2) 構成管理データベースを持たない (3) 多くの機能を提供する充実したモジュール群を提供 (4) 公式モジュールでは冪等性が担保される (5) Playbookにワークフローの実現 (6) 数多い利用実績
Ansible関連情報• 公式サイト
• https://www.ansible.com/
• 公式ドキュメント • http://docs.ansible.com/ansible/index.html
• Ansible Galaxy • https://galaxy.ansible.com/
• ソースコードリポジトリ • https://github.com/ansible/ansible • https://github.com/ansible/ansible-modules-core • https://github.com/ansible/ansible-modules-extras
Ansibleの構成要素Ansibleの主な構成要素は以下の通りです。
# 構成要素 概要
1 Configuration Ansibleの振る舞いを決める設定ファイル
2 Inventory 管理対象ホストの一覧が記述されたファイル
3 Module タスクとしてAnsibleが実行するプログラム
4 Command タスクやPlaybookを実行するためのコマンド群
5 Playbook 複数のタスクから構成されるワークフロー定義ファイル
自動化の仕組み(a) UNIXホストに対する操作
(b)Windowsホストに対する操作
(c)ネットワーク機器に対する操作
タスク実行の流れAnsibleがタスクを実行する流れは以下の通りです。
Playbook実行の流れシステムに対して実施する一連の作業を、順序だててYAML形式でPlaybookに記述します。 AnsibleはPlaybookでオペレーションのコード化を実現しています。
Installation ~ Ansibleをインストールする~
インストール方法• インストールガイド
• http://docs.ansible.com/ansible/intro_installation.html
• 公式リポジトリ • https://github.com/ansible/ansible.git
• PIPのパッケージを利用 $ pip install ansible
• OSのパッケージを利用 RPM:$ yum install ansible
APT:$ apt-get install ansible
Ubuntu14.04上のvirtualenv環境に、pipを利用してAnsibleをインストールする。 1.パッケージ更新
$ sudo apt-get update $ sudo apt-get upgrade -y $ sudo apt-get install -y build-essential git $ sudo apt-get install -y python-dev libffi-dev libssl-dev
2.virtualenvのインストールと環境の切り替え $ sudo apt-get install -y python-virtualenv $ virtualenv $HOME/ansible $ source $HOME/ansible/bin/activate (ansible)$
pipを利用したインストール
3.pipを利用したAnsibleのインストール (ansible)$ pip install ansible
4.Ansibleのバージョンを確認 (ansible)$ ansible --version ansible 2.2.0.0 config file = configured module search path = Default w/o overrides
pipを利用したインストール
コマンドラインインターフェイスAnsible v2.2.0.0をpipインストールすると利用できるようになるコマンド一覧
コマンド 役割
ansible ターゲットホスト上でアドホックなタスクを実行する
ansible-console インタラクティブにタスクを実行できるコンソール
ansible-doc モジュールの一覧や利用方法を参照する
ansible-galaxy Ansible Galaxyサイトを利用する
ansible-playbook Playbookを実行する
ansible-pull 外部リポジトリからPlaybookをダウンロードして実行する
ansible-vault Playbookファイルを暗号化する
ansibleコマンドの実行ansibleコマンドが動作するために必要な、Inventoryファイルを作成する。 • inventoryファイル(例: ~/hosts)
[localhost] 127.0.0.1 ansible_connection=local
• pingモジュールでansibleの動作を確認する (ansible)$ ansible localhost -i ~/hosts -m ping 127.0.0.1 | SUCCESS => { "changed": false, "ping": "pong" }
ansibleのタスク実行によって、管理対象のシステムに変更があったかどうかを確認するには、実行結果に含まれる"changed"の値を確認する。 • ターゲットホストの状態が変更された(イエロー)
• changed: true
• ターゲットホストの状態に変化なし(グリーン) • changed: false
実行結果による判断
ホストのリモート管理• 設定ファイル(例:ファイルパス "~/.ansible.cfg")
[defaults] host_key_checking = False
• inventoryファイル(例: ファイルパス"~/hosts") localhost ansible_host=127.0.0.1 ansible_connection=local
[remote] target-1 ansible_host=192.168.131.18 target-2 ansible_host=192.168.131.19 target-3 ansible_host=192.168.131.21 target-4 ansible_host=192.168.131.20
ホストのリモート管理ホストへのssh接続時にパスフレーズの入力を求められるのを抑止するために、ssh-agentを利用する。 (ansible)$ eval `ssh-agent` (ansible)$ ssh-add Enter passphrase for /home/ubuntu/.ssh/id_rsa: ******** Identity added: /home/foo/.ssh/id_rsa (/home/foo/.ssh/id_rsa)
Inventoryファイルに定義されているremoteグループに対してpingモジュールを適用する。
(ansible)$ ansible remote -i hosts -m ping -u <user> -k 192.168.131.11 | SUCCESS => { "changed": false, "ping": "pong" } 192.168.131.12 | SUCCESS => { "changed": false, "ping": "pong" } 192.168.131.10 | SUCCESS => { "changed": false, "ping": "pong" }
接続確認
Inventory
Ansibleがタスクを実行するホストを特定するために利用するファイル。書式はINI形式に近い。 • ホストとグループの定義
192.168.131.10 192.168.131.11 192.168.131.12
[groupA] 192.168.131.10 192.168.131.11
[groupB] 192.168.131.11 192.168.131.12
Inventoryファイル(1)
Inventoryファイル(2)• ホスト変数
該当ホストでタスクを実行する際に定義される 192.168.131.10 foo="Hello, World!"
debugモジュールでfooが定義されたことを確認 (ansible)$ ansible 192.168.131.10 -i hosts \ -m debug -a "msg={{ foo }}" 192.168.131.10 | SUCCESS => { "msg": "Hello, World!" }
Inventoryファイル(3)• グループ変数
該当グループでタスクを実行する際に定義される [groupA] 192.168.131.10 192.168.131.11
[groupA:vars] bar="Hello, Ansible!"
debugモジュールでfooが定義されたことを確認 $ ansible groupA -i hosts -m debug -a "msg={{ bar }}" -o 192.168.131.10 | SUCCESS => { "msg": "Hello, Ansible!" } 192.168.131.11 | SUCCESS => { "msg": "Hello, Ansible!" }
• 複数のグループをまとめる(children) [groupA] 192.168.131.10 192.168.131.11
[groupB] 192.168.131.11 192.168.131.12
[groupC:children] groupA groupB
[groupC:vars] baz="Hello, Okinawa!"
Inventoryファイル(4)
• グループ内のホストをパターンで登録する 数値またはアルファベットでレンジを指定可能 [remotehost] 192.168.131.[10:12] web-[a:g]
Inventoryファイル(5)
• 覚えておくと便利なシステム予約済み変数 [例] web ansible_host=192.168.131.10 ansible_connection=ssh ansible_user=foo
➡ansible_host 接続先IPアドレスまたはホスト名
➡ansible_connection 接続方法: local or ssh or smart
➡ansible_user ssh接続を行う際のユーザID
➡ansible_ssh_pass ssh接続を行う際のパスワード
Inventoryファイル(6)
Ad-Hoc Commands
ansibleコマンドを利用すると、ターゲットホストに対して、アドホックにタスク(モジュール)を実行することができる。 • 引数を必要としないタスクを実行する
タスクとして実行するモジュールは-mオプションで指定する (ansible)$ ansible localhost -i hosts -m ping
ansible command(1)
ansible command(2)• 引数を必要とするタスクを実行する
モジュールパラメータは -a オプションで指定する (ansible)$ ansible localhost -i hosts -m debug \ -a 'msg="Hello, World!"'
複数のパラメータを指定することも可能 (ansible)$ ansible localhost -i hosts -m copy \ -a "src=/etc/hosts dest=/home/<userid>/etc_hosts"
• ターゲットホストで任意のコマンドを実行する ansibleコマンドは -m でモジュールが指定されなかった場合はcommandモジュールを実行する (ansible)$ ansible localhost -i hosts -a "uname -a" localhost | SUCCESS | rc=0 >> Linux ansible 3.13.0-95-generic #142-Ubuntu SMP Fri Aug 12 17:00:09 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
ansible command(3)
• ターゲットホストの情報を収集する ターゲットホストの情報をJSON形式で出力する (ansible)$ ansible localhost -i hosts -m setup localhost | SUCCESS => { "ansible_facts": { "ansible_all_ipv4_addresses": [ "192.168.131.6" ], "ansible_all_ipv6_addresses": [ "fe80::f816:3eff:fe52:49e6" ], "ansible_architecture": "x86_64", ...以下略...
ansible command(4)
• ターゲットホストで任意のコマンドを実行する root権限でコマンドを実行する(passwordなし) (ansible)$ ansible localhost -i hosts \ -a "cat /etc/shadow" --become
root権限でコマンドを実行する(passwordあり) (ansible)$ ansible localhost -i hosts \ -a "cat /etc/shadow" --become --ask-become-pass
ansible command(5)
Modules ~ モジュールの使い方 ~
Ansibleのモジュールansibleコマンドやansible-playbookコマンドが実行する"作業"を記述したプログラムです。 役割やオプションの確認方法は以下の通り。
(ansible)$ ansible-doc <モジュール名>
• 公式サイトのモジュールインデックス http://docs.ansible.com/ansible/list_of_all_modules.html
Playbook ~ Playbookの基本構成 ~
ansible-playbookコマンドは、複数のタスクを実行順に記述し、ワークフローとしてターゲットホストに適用するコマンド。
(ansible)$ ansible-playbook -i hosts playbook.yml
Playbookファイルの最小構成は以下の2つ (1)1つのInventoryファイル
(2)1つのPlaybookファイル
Playbookとは
• AnsibleのPlaybookはYAML形式で記述する。基本的な構造は以下の通り --- - hosts: Target Host or Group vars: Param_A: Value_A Param_B: Value_B tasks: - Task_A - Task_B - Task_C handlers: - Handler_X - Handler_Y
Writing Playbook(1)
• Playbookに記述する各セクションの役割
Writing Playbook(2)
セクション名 概要
hosts playbookを適用するターゲットホスト、またはグループを記述する
vars playbook実行中に利用するパラメータと、その値を定義する
tasks hostsセクションに記載したターゲット上で実行するモジュールと、そのパラメータを実行順に定義する
handlers tasksセクションで定義したモジュールを実行した結果、システムに変更が発生した場合に実行するモジュールを定義する
Writing Playbook(3)• ansible-playbook(例:sample00.yml)を記述する
--- - hosts: localhost vars: message: "Hello, World!" tasks: - name: copy /etc/hosts to /tmp/ copy: src: "/etc/hosts" dest: "/tmp/hosts" notify: - print message handlers: - name: print message debug: msg: "{{ message }}"
• playbookを実行する(1回目) (ansible)$ ansible-playbook -i hosts sample00.yml
PLAY [localhost] ************************************************
TASK [setup] **************************************************** ok: [localhost]
TASK [copy /etc/hosts to /tmp/] ********************************* changed: [localhost]
RUNNING HANDLER [print message] ********************************* ok: [localhost] => { "msg": "Hello, World!" }
PLAY RECAP ****************************************************** localhost : ok=3 changed=1 unreachable=0 failed=0
Writing Playbook(4)
• 2度目の実行では冪等性が担保される (ansible)$ ansible-playbook -i hosts sample00.yml
PLAY [localhost] *************************************************
TASK [setup] ****************************************************************** ok: [localhost]
TASK [copy /etc/hosts to /tmp/] ****************************************************************** ok: [localhost]
PLAY RECAP ****************************************************************** localhost : ok=2 changed=0 unreachable=0 failed=0
Writing Playbook(5)
• Playbookを特定のユーザ権限でタスクを実行する becomeとbecome_userで実行ユーザを指定する tasks: - name: show /etc/shadow by root command: cat /etc/shadow become: true become_user: root
become_user
Playbook essentials ~ 制御構造やBest Practiceなど ~
Loops• 特定のタスクを繰り返し実行する(★は以降で解説)# 構文 繰り返し処理要素1 with_items ★ リストのメンバー2 with_nested ★ [[i],[j]] で表現される i * j のリストのメンバー3 with_dict ★ key:value 形式で表現された辞書型のメンバー4 with_file ファイル名をリストのメンバーとして格納されたテキストファイルの内容5 with_fileglob ファイルグロブにマッチしたファイル名6 with_together 複数のリストの要素をインデックス番号毎に組みしたもの7 with_subelements ★ 辞書型のデータ構造に含まれる共通のキーで構成されるサブセット8 with_sequence ★ 連続した数値9 with_random_choice リストのメンバー
10 until なし。Do-Untilループ11 with_first_found ファイル名のリスト中で最初にマッチ(存在)したファイル名12 with_lines コマンド実行結果の各行13 with_indexed_items インデックスと値がセットになったリストのメンバー14 with_ini iniファイルのセクション内で正規表現にマッチしたキーワードの値のリスト15 with_flattened リストのメンバー。入れ子になったリストも一次元のリストに展開される
• varsセクション vars: members: - "Hello, World!" - "Hello, Ansible!" - "Hello, Okinawa!"
Example: with_items• tasksセクション tasks: - name: test for with_items debug: msg: "{{ item }}" with_items: "{{ members }}"
• varsセクション vars: group_a: - "Hello" group_b: - "World" - "Ansible" - "Okinawa"
Example: with_nested• tasksセクション tasks: - name: test for with_nested debug: msg: "{{ item.0 }}, {{ item.1 }}!" with_nested: - "{{ group_a }}" - "{{ group_b }}"
• tasksセクション tasks: - name: test for with_dict debug: msg: "{{ item.key }}:{{ item.value.name }}" with_dict: "{{ members }}"
• varsセクション vars: members: web: name: instance-a address: 192.168.131.10 app: name: instance-b address: 192.168.131.11 dbs: name: instance-c address: 192.168.131.12
Example: with_dict
• tasksセクション tasks: - name: test for with_subelements debug: msg: "{{ item.1 }}" with_subelements: - "{{ members }}" - address
• varsセクション vars: members: web: address: - 192.168.131.10 app: address: - 192.168.131.11 dbs: address: - 192.168.131.12
Example: with_subelements
• varsセクション vars: counter: 3 start: 10 end: 19 step: 2
Example: with_sequence
• tasksセクション tasks: - name: test for with_sequence (counter) debug: msg: "{{ item }}" with_sequence: count="{{ counter }}"
- name: test for with_sequence (range) debug: msg: "{{ item }}" with_sequence: start="{{ start }}" end="{{ end }}" stride="{{ step }}" format=prefix%02d
Conditionals - when特定の条件が成立した場合のみタスクを実行する。withループのitem要素も条件として設定可能。 • whenを利用してタスクの実行を制御する tasks: - name: install packages by yum yum: name: httpd state: latest when: ansible_os_family == "RedHat"
• タグ(tags)を設定して特定タスクのみを実行する --- - hosts: all tasks: - name: Print World debug: msg: "Hello, World!" tags: - world - name: Print Ansible debug: msg: "Hello, Ansible!" tags: - ansible tags: - everything
Conditionals - tags
• -tオプションでタグを指定してコマンドを実行する (ansible)$ ansible-playbook -i hosts -t ansible sample01.yml PLAY [all] ************************************************** TASK [setup] ************************************************ ok: [192.168.131.10] ok: [192.168.131.12] ok: [192.168.131.11] TASK [Print Ansible] **************************************** ok: [192.168.131.10] => { "msg": "Hello, Ansible!" } ok: [192.168.131.11] => { "msg": "Hello, Ansible!" } ok: [192.168.131.12] => { "msg": "Hello, Ansible!" } PLAY RECAP ************************************************** 192.168.131.10 : ok=2 changed=0 unreachable=0 failed=0 192.168.131.11 : ok=2 changed=0 unreachable=0 failed=0 192.168.131.12 : ok=2 changed=0 unreachable=0 failed=0
Conditionals - tags
Playbookの構成ガイドラインPlaybookのファイルやディレクトリは自由に配置することができます。 しかし、再利用性を高めたりGalaxyでロールを公開したいような場合は、Best Practiceというガイドラインに従った構成にすることが推奨されています(強制ではありません)
• http://docs.ansible.com/ansible/playbooks_best_practices.html
my_app/ # Playbookディレクトリ production # 本番用Inventoryファイル stating # ステージング用Inventoryファイル group_vars/ # グループに適用する変数定義ファイル配置用ディレクトリ my_group1 # "my_group1"に適用する変数を定義したファイル my_group2 # "my_group2"に適用する変数を定義したファイル host_vars/ # ホスト毎にのみ適用する変数定義ファイル配置用ディレクトリ my_host1 # "my_host1"にのみ適用する変数定義ファイル my_host2 # "my_host2"にのみ適用する変数定義ファイル site.yml # ansible-playbookコマンドで指定するマスターとなるPlaybookファイル my_web_servers.yml # site.ymlでincludeされる。管理対象の役割ごとに適用するroleを指定するためのファイル my_app_servers.yml # site.ymlでincludeされる。管理対象の役割ごとの適用するroleを指定するためのファイル roles/ # 管理対象に適用するタスクのグループ(role)を配置するディレクトリ my_role/ # 実際に適用する作業を記述したファイルや作業で使用するファイル群を配置するためのディレクトリ tasks/ # 適用する作業(タスク)を記述したファイルを配置するディレクトリ main.yml # 作業(タスク)を記述したファイル handlers/ # タスクの実行によってシステムに変化がおきた場合に実行されるハンドラを配置するディレクトリ main.yml # ハンドラを記述するファイル templates/ # templateモジュールが利用するJinja2形式のテンプレートを配置するディレクトリ my_template.j2 # Jinja2形式のテンプレートファイル files/ # 管理対象ホストにそのまま転送されるファイルを配置するディレクトリ my_file # 管理対象ホストにそのまま転送されるファイル vars/ # role実行時に適用する変数定義ファイルを配置するディレクトリ main.yml # role実行時に適用する変数定義ファイル defaults/ # role実行時に適用するデフォルト変数定義ファイルを配置するディレクトリ main.yml # role実行時に適用するデフォルト変数定義ファイル meta/ # role間の依存関係を定義したファイルを配置するディレクトリ main.yml # role間の依存関係定義ファイル
基本的なディレクトリ構成
ディレクトリ構造の作成ansible-galaxyコマンドを利用して、Best Practiceでのrole推奨ディレクトリ構成が簡単に作成できます。 (ansible)$ ansible-galaxy init my_role (ansible)$ tree my_role/ my_role/ ├── defaults │ └── main.yml ├── files ├── handlers │ └── main.yml ├── meta │ └── main.yml ├── README.md ├── tasks │ └── main.yml ├── templates ├── tests │ ├── inventory │ └── test.yml └── vars └── main.yml
最後に...
Playbookを書く際の心得(1)ちゃんとしたYAMLの書式で書こう
(2)できるだけBest Practiceに従った構造にしよう
(3)タスクの先頭にはname:セクションをちゃんと書こう
(4)タスク内で即値を書かずにvarsファイルに外出ししよう
(5)名前重要。Playbookの変数の名前空間はフラットです
(6) debugモジュールをつかう場合はverbosityも設定しよう
(7) jinja2テンプレートはできるだけシンプルに書こう
(8)巨大な1つのファイルに書かずに分割してincludeしよう
(9) Playbookをコードレビューできる仕組みを導入しよう
Inventoryを書く際の心得(1) IPアドレスやFQDNよりも、わかりやすい名前をつけよう
(2)環境毎に分けて誤爆を防ごう
(3)適切なパーミッションを設定しよう
(4) --limitを多用するくらいなら、専用にグループを作ろう
(5) Dynamic Inventoryは単一の情報ソースから生成しよう
午後につづく!