Ansible handson

65
Ansible入門 Ansible Workshop in Okinawa 2016.11.11 Hideki Saito Internet Initiative Japan inc.

Transcript of Ansible handson

Page 1: Ansible handson

Ansible入門Ansible Workshop in Okinawa

2016.11.11

Hideki Saito Internet Initiative Japan inc.

Page 2: Ansible handson

本セッションの目的午前の部では、午後に予定されているハンズオンに向けて必要となる、以下の事柄について解説します。そして実際にAnsibleのインストールを行います。

(1) Ansibleとは? (2) AnsibleのインストールとCLIの基本操作 (3) Playbookの記述方法

本セッション終了時点で、午後の部のハンズオンに向けた準備が整います。

Page 3: Ansible handson

自己紹介• 氏名: 齊藤 秀喜 (さいとう ひでき) • TwitterID: @saito_hideki • 所属: • 株式会社インターネットイニシアティブ • 日本OpenStackユーザ会ボードメンバー

• 趣味: OpenStack, Ansible

Page 4: Ansible handson

News ~ Ansibleに関する最近の話題 ~

Page 5: Ansible handson

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

Page 6: Ansible handson

Galaxyオープンソース化Ansible Galaxyがオープンソース化されました。 GalaxyはGithubやDockerhubのように、Playbookやモジュールのリポジトリを公開して共有し、再利用するサービスです。 オープンソース化されたことにより、自身でGalaxyサイトを構築することが可能となりました。

• ソースコード: https://github.com/ansible/galaxy

• 公式サイト https://galaxy.ansible.com/

Page 7: Ansible handson

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

Page 8: Ansible handson

Basics ~ Ansibleとは?~

Page 9: Ansible handson

本日のEtherpad本日のハンズオンに利用するEtherpadはコチラです

• http://172.16.51.53:9001/p/ansible_workshop_2016

• https://etherpad.openstack.org/p/ool_ansible_workshop_2016

Page 10: Ansible handson

AnsibleとはInfrastructure as Codeというコンセプトを実現するための自動化ツールで、以下の特徴を持っています。

(1) システム管理にエージェントを必要としない (2) 構成管理データベースを持たない (3) 多くの機能を提供する充実したモジュール群を提供 (4) 公式モジュールでは冪等性が担保される (5) Playbookにワークフローの実現 (6) 数多い利用実績

Page 11: Ansible handson

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

Page 12: Ansible handson

Ansibleの構成要素Ansibleの主な構成要素は以下の通りです。

# 構成要素 概要

1 Configuration Ansibleの振る舞いを決める設定ファイル

2 Inventory 管理対象ホストの一覧が記述されたファイル

3 Module タスクとしてAnsibleが実行するプログラム

4 Command タスクやPlaybookを実行するためのコマンド群

5 Playbook 複数のタスクから構成されるワークフロー定義ファイル

Page 13: Ansible handson

自動化の仕組み(a) UNIXホストに対する操作

(b)Windowsホストに対する操作

(c)ネットワーク機器に対する操作

Page 14: Ansible handson

タスク実行の流れAnsibleがタスクを実行する流れは以下の通りです。

Page 15: Ansible handson

Playbook実行の流れシステムに対して実施する一連の作業を、順序だててYAML形式でPlaybookに記述します。 AnsibleはPlaybookでオペレーションのコード化を実現しています。

Page 16: Ansible handson

Installation ~ Ansibleをインストールする~

Page 17: Ansible handson

インストール方法• インストールガイド

• 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

Page 18: Ansible handson

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を利用したインストール

Page 19: Ansible handson

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を利用したインストール

Page 20: Ansible handson

コマンドラインインターフェイスAnsible v2.2.0.0をpipインストールすると利用できるようになるコマンド一覧

コマンド 役割

ansible ターゲットホスト上でアドホックなタスクを実行する

ansible-console インタラクティブにタスクを実行できるコンソール

ansible-doc モジュールの一覧や利用方法を参照する

ansible-galaxy Ansible Galaxyサイトを利用する

ansible-playbook Playbookを実行する

ansible-pull 外部リポジトリからPlaybookをダウンロードして実行する

ansible-vault Playbookファイルを暗号化する

Page 21: Ansible handson

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" }

Page 22: Ansible handson

ansibleのタスク実行によって、管理対象のシステムに変更があったかどうかを確認するには、実行結果に含まれる"changed"の値を確認する。 • ターゲットホストの状態が変更された(イエロー)

• changed: true

• ターゲットホストの状態に変化なし(グリーン) • changed: false

実行結果による判断

Page 23: Ansible handson

ホストのリモート管理• 設定ファイル(例:ファイルパス "~/.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

Page 24: Ansible handson

ホストのリモート管理ホストへの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)

Page 25: Ansible handson

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" }

接続確認

Page 26: Ansible handson

Inventory

Page 27: Ansible handson

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)

Page 28: Ansible handson

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!" }

Page 29: Ansible handson

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!" }

Page 30: Ansible handson

• 複数のグループをまとめる(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)

Page 31: Ansible handson

• グループ内のホストをパターンで登録する 数値またはアルファベットでレンジを指定可能 [remotehost] 192.168.131.[10:12] web-[a:g]

Inventoryファイル(5)

Page 32: Ansible handson

• 覚えておくと便利なシステム予約済み変数 [例] 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)

Page 33: Ansible handson

Ad-Hoc Commands

Page 34: Ansible handson

ansibleコマンドを利用すると、ターゲットホストに対して、アドホックにタスク(モジュール)を実行することができる。 • 引数を必要としないタスクを実行する

タスクとして実行するモジュールは-mオプションで指定する (ansible)$ ansible localhost -i hosts -m ping

ansible command(1)

Page 35: Ansible handson

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"

Page 36: Ansible handson

• ターゲットホストで任意のコマンドを実行する 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)

Page 37: Ansible handson

• ターゲットホストの情報を収集する ターゲットホストの情報を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)

Page 38: Ansible handson

• ターゲットホストで任意のコマンドを実行する 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)

Page 39: Ansible handson

Modules ~ モジュールの使い方 ~

Page 40: Ansible handson

Ansibleのモジュールansibleコマンドやansible-playbookコマンドが実行する"作業"を記述したプログラムです。 役割やオプションの確認方法は以下の通り。

(ansible)$ ansible-doc <モジュール名>

• 公式サイトのモジュールインデックス http://docs.ansible.com/ansible/list_of_all_modules.html

Page 41: Ansible handson

Playbook ~ Playbookの基本構成 ~

Page 42: Ansible handson

ansible-playbookコマンドは、複数のタスクを実行順に記述し、ワークフローとしてターゲットホストに適用するコマンド。

(ansible)$ ansible-playbook -i hosts playbook.yml

Playbookファイルの最小構成は以下の2つ (1)1つのInventoryファイル

(2)1つのPlaybookファイル

Playbookとは

Page 43: Ansible handson

• 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)

Page 44: Ansible handson

• Playbookに記述する各セクションの役割

Writing Playbook(2)

セクション名 概要

hosts playbookを適用するターゲットホスト、またはグループを記述する

vars playbook実行中に利用するパラメータと、その値を定義する

tasks hostsセクションに記載したターゲット上で実行するモジュールと、そのパラメータを実行順に定義する

handlers tasksセクションで定義したモジュールを実行した結果、システムに変更が発生した場合に実行するモジュールを定義する

Page 45: Ansible handson

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 }}"

Page 46: Ansible handson

• 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)

Page 47: Ansible handson

• 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)

Page 48: Ansible handson

• Playbookを特定のユーザ権限でタスクを実行する becomeとbecome_userで実行ユーザを指定する tasks: - name: show /etc/shadow by root command: cat /etc/shadow become: true become_user: root

become_user

Page 49: Ansible handson

Playbook essentials ~ 制御構造やBest Practiceなど ~

Page 50: Ansible handson

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 リストのメンバー。入れ子になったリストも一次元のリストに展開される

Page 51: Ansible handson

• 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 }}"

Page 52: Ansible handson

• 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 }}"

Page 53: Ansible handson

• 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

Page 54: Ansible handson

• 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

Page 55: Ansible handson

• 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

Page 56: Ansible handson

Conditionals - when特定の条件が成立した場合のみタスクを実行する。withループのitem要素も条件として設定可能。 • whenを利用してタスクの実行を制御する tasks: - name: install packages by yum yum: name: httpd state: latest when: ansible_os_family == "RedHat"

Page 57: Ansible handson

• タグ(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

Page 58: Ansible handson

• -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

Page 59: Ansible handson

Playbookの構成ガイドラインPlaybookのファイルやディレクトリは自由に配置することができます。 しかし、再利用性を高めたりGalaxyでロールを公開したいような場合は、Best Practiceというガイドラインに従った構成にすることが推奨されています(強制ではありません)

• http://docs.ansible.com/ansible/playbooks_best_practices.html

Page 60: Ansible handson

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間の依存関係定義ファイル

基本的なディレクトリ構成

Page 61: Ansible handson

ディレクトリ構造の作成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

Page 62: Ansible handson

最後に...

Page 63: Ansible handson

Playbookを書く際の心得(1)ちゃんとしたYAMLの書式で書こう

(2)できるだけBest Practiceに従った構造にしよう

(3)タスクの先頭にはname:セクションをちゃんと書こう

(4)タスク内で即値を書かずにvarsファイルに外出ししよう

(5)名前重要。Playbookの変数の名前空間はフラットです

(6) debugモジュールをつかう場合はverbosityも設定しよう

(7) jinja2テンプレートはできるだけシンプルに書こう

(8)巨大な1つのファイルに書かずに分割してincludeしよう

(9) Playbookをコードレビューできる仕組みを導入しよう

Page 64: Ansible handson

Inventoryを書く際の心得(1) IPアドレスやFQDNよりも、わかりやすい名前をつけよう

(2)環境毎に分けて誤爆を防ごう

(3)適切なパーミッションを設定しよう

(4) --limitを多用するくらいなら、専用にグループを作ろう

(5) Dynamic Inventoryは単一の情報ソースから生成しよう

Page 65: Ansible handson

午後につづく!