Upgrade to Pro — share decks privately, control downloads, hide ads and more …

OpenStackをAnsibleで操る! - Ansible Night in Tokyo 2017.12

OpenStackをAnsibleで操る! - Ansible Night in Tokyo 2017.12

Ansible Night in Tokyo 2017.12
https://ansible-users.connpass.com/event/71613

D5a83165b9644ddf8718fc32c577e74e?s=128

Noboru Iwamatsu

December 21, 2017
Tweet

More Decks by Noboru Iwamatsu

Other Decks in Technology

Transcript

  1. Ansible Night in Tokyo 2017.12 「OpenStackをAnsibleで操る!」 富士通株式会社 岩松昇、下國治、本田亮弘 0 Copyright

    2017 FUJITSU LIMITED
  2. 自己紹介  FUJITSU Cloud Service K5の開発チームメンバー サービス・運用・構築の設計から実装までを担当 1 Copyright 2017

    FUJITSU LIMITED 岩松 昇 下國 治 本田 亮弘  OS・仮想化・クラウドの研究からIaaS事業部門へ  Xen, OpenStackなどOSSと10年以上の付き合い  最近はOpenStack kolla/kolla-ansibleに貢献  並列分散処理・クラウドの研究から事業部門へ  扱うマシンの量は、20年前の1000倍  10年前はexpectを使ってた。つらかった  ここ7年ほどはクラウド周辺技術が主な業務  Chefからの移行組  下の子が深夜に徘徊するのが最近の悩み
  3. 本日のAgenda FUJITSU Cloud Service K5 とリリース業務 Ansible Tips & Examples

    適用版数を厳密に守る 手順を間違えない 適用対象を間違えない 履歴をのこす まとめ 2 Copyright 2017 FUJITSU LIMITED
  4. OpenStackとは  オープンソースのクラウド基盤ソフトウェア VM、ストレージ、ネットワークなどを提供するIaaS環境 3 Copyright 2017 FUJITSU LIMITED Compute

    Node VM VM VM VM Controller Node Nova Keystone Cinder VM VM … Neutron
  5. OpenStackのアーキテクチャ―  多数のサービスが組み合わさった分散構成 4 Copyright 2017 FUJITSU LIMITED https://docs.openstack.org/arch-design/design.html

  6.  世界9リージョンで提供中のIaaS  OpenStack がベース  月間数百件のリリース業務をこなす FUJITSU Cloud Service

    K5 5 Copyright 2017 FUJITSU LIMITED JP-east-1 JP-east-2 UK Nordic Germany Spain US Australia Singapore Available Region New Region (planning) JP-west-2 JP-west-1
  7. 典型的なリリース業務  OpenStack CLIを駆使して、状態・正常性を確認 しながら手順書通りに行う高度な作業 6 Copyright 2017 FUJITSU LIMITED

    新機能提供・機能修正のため、サービス全体を 停止せず、ソフトウェアを更新する LB nova nova 切り離す LB nova nova LB nova nova 更新 復帰 LB nova nova 繰り返し
  8. リリース業務の鉄則 7 Copyright 2017 FUJITSU LIMITED 適用版数を厳密に守る 手順をまちがえない 適用対象をまちがえない 作業履歴を残す

  9. リリース業務: Before Ansible 8 Copyright 2017 FUJITSU LIMITED ※写真はイメージです 適用版数

    指さし確認 手順書  行確認、指さし確認 適用対象 指さし確認 作業履歴  ターミナルログ
  10.  効果  数百台への緊急修正適用時間を大幅短縮、作業ミスゼロ  Playbook開発とテストは1.5時間 リリース業務: After Ansible 9

    Copyright 2017 FUJITSU LIMITED After Before 60時間*人 10分に短縮
  11.  ソフトウェア版数の組み合わせの完全性を保証する Ansible Tips & Examples 「適用版数を厳密に守る」 10 Copyright 2017

    FUJITSU LIMITED
  12. 適用版数を厳密に守る  更新するパッケージ群とそのバージョンは 厳密に指定する 指定バージョンのパッケージがインストールされる それ以外のものはインストールされていない  予期せぬパッケージが紛れ込む事で発生する 事故(脆弱性など)を防ぐ 11

    Copyright 2017 FUJITSU LIMITED
  13. 例: Ansibleをインストールする場合 12 Copyright 2017 FUJITSU LIMITED Dependencies Resolved ===============================================================================

    Package Arch Version Repository Size =============================================================================== Installing: ansible noarch 2.4.1.0-1.el7 extras 7.6 M Installing for dependencies: python-cffi x86_64 1.6.0-5.el7 base 218 k python-enum34 noarch 1.0.4-1.el7 base 52 k python-httplib2 noarch 0.9.2-1.el7 extras 115 k python-idna noarch 2.4-1.el7 base 94 k python-ipaddress noarch 1.0.16-2.el7 base 34 k python-paramiko noarch 2.1.1-2.el7 extras 267 k python-passlib noarch 1.6.5-2.el7 extras 488 k python-ply noarch 3.4-11.el7 base 123 k python-pycparser noarch 2.14-1.el7 base 104 k python2-cryptography x86_64 1.7.2-1.el7_4.1 updates 502 k python2-jmespath noarch 0.9.0-3.el7 extras 39 k python2-pyasn1 noarch 0.1.9-7.el7 base 100 k sshpass x86_64 1.06-2.el7 extras 21 k Transaction Summary =============================================================================== Install 1 Package (+13 Dependent packages)  依存関係で色々インストールされる
  14. パッケージ版数を厳密に管理する Copyright 2017 FUJITSU LIMITED 世代1 B C A 13

    世代2 B C A’ D 世代3 B’ C A’ D Aをアップデート Dをインストール Bをアップデート
  15. ダメな例(1) Copyright 2017 FUJITSU LIMITED 世代1 B C A 14

    世代2 B C A’ D Aをアップデート Dをインストール 世代2 B C A’ D E ダメなやつ
  16. ダメな例(2) Copyright 2017 FUJITSU LIMITED 世代1 B C A 15

    世代2 B C A’ D Aをアップデート Dをインストール 世代2 B’ C A’ D ダメなやつ
  17. 我々のやり方  意図しないパッケージの混入を把握・対応する 1. パッケージとバージョンのリストを用意 2. インストール前後のパッケージ一覧を取得 3. 比較 16

    Copyright 2017 FUJITSU LIMITED rpm_packages: - name: curl version: 7.29.0-42.el7 - name: dhcp-common version: 4.2.5-58.el7.centos - … # rpm -qa {{ list1 | difference(list2) }}
  18. パッケージリストの比較例 17 Copyright 2017 FUJITSU LIMITED - name: Difference from

    before to after set_fact: _diff_rpms: >- {{ after_rpms.stdout_lines | difference(before_rpms.stdout_lines) }} - name: Remove arch name from package list set_fact: diff_rpms: "{{ diff_rpms|default([]) + [item.rsplit('.', 1)[0]] }}" with_items: "{{ _diff_rpms }}" - name: Find unspecified packages set_fact: unexp_rpms: "{{ diff_rpms | difference(install_targets) }}" - name: Ensure Unexpected modules are not installed assert: that: unexp_rpms == [] msg: "Unexpected packages are found: {{ unexp_rpms }}" 適用前後での rpm-qaの差分 意図しないパッケージが存 在した場合にエラーとし、是 非を判断する 適用前後の差分リスト からarchを除外 意図したパッケージと適用 前後の差分を比較
  19.  複雑なデータを扱う  自作フィルターでデータを全てJSONにする  JMESPATHを駆使する Ansible Tips & Examples

    「手順をまちがえない」 18 Copyright 2017 FUJITSU LIMITED
  20. 複雑なデータをパースする  ダメな例(手順書) Grep, Awk, Shellでパース  我々の戦略 すべてJSONにし、json_queryフィルタで扱う 19

    Copyright 2017 FUJITSU LIMITED 以下のコマンドを実行します。出力が1であることを確認します。 # AVERAGE=`zgrep "neutron.wsgi" /var/log/neutron/server.log{.1.gz,} | grep -v accepted | tail -n 100 | sed -e "s/ None//" | awk '{x+=$NF}END{print x/NR}'` # echo "$AVERAGE 5.0" | awk '{if($1 < $2) print 1 ;else print 0}'
  21. json_queryフィルタとは  複雑なJSONデータをqueryするフィルタ JSONのメンバやスライスを抽出 構造体のリストから、条件に合致する項を抽出して、 リストとして出力  Ansible 2.2から導入された http://docs.ansible.com/ansible/latest/playbooks_fil

    ters.html#json-query-filter  “jmespath”のqueryを使う http://jmespath.org 20 Copyright 2017 FUJITSU LIMITED
  22. json_queryの例とチュートリアル  メンバを取り出す例:  チュートリアルページでqueryがテストできる 21 Copyright 2017 FUJITSU LIMITED

    http://jmespath.org/tutorial.html {"name": "foo", "id": "1111-1111", "val": 5} | json_query('name') 実行 "foo"
  23. Json_queryフィルタでの処理  OpenStackのデータ抽出を簡潔に実現 pythonならこう書けるのに… json_queryなら書けます 22 Copyright 2017 FUJITSU LIMITED

    - name: json query example debug: msg: "{{cli_res.stdout |from_json |json_query(qstr)}}" vars: qstr: "[?Status=='ACTIVE']" [ { "ID": "6d905280-9174-4343-88ba-b8f030447575", "Name": "night", "Networks": "private-net=172.29.6.37", "Status": "ACTIVE" } ] 実行結果 [x for x in server_list if x.Status == “ACTIVE” ]
  24. json_queryでの抽出  フィルタロジックは、論理式が書ける  フィルタを適用した後、メンバを抽出  メンバは複数個抽出し、リストやdictにできる  もっと詳しくはjmespathのwebで! 23

    Copyright 2017 FUJITSU LIMITED "[? alive==':-)' && admin_state_up==‘true’]" "[? agent_type==‘DHCP agent'].host" "[?agent_type=='DHCP agent'].{id: id, host: host}"
  25. JSON化の基本戦略  可能な限り全てJSONで出力 API, Ansible Module, CLI 24 Copyright 2017

    FUJITSU LIMITED $ openstack server list -f json [ { "Status": "ACTIVE", "Networks": "private-net=172.29.6.37", "ID": "6d905280-9174-4343-88ba-b8f030447575", "Name": "night" }, { "Status": "SHUTOFF", "Networks": "private-net=172.29.6.36, 10.25.177.56", "ID": "fa3be49e-33aa-4ffa-aa50-13dca8f2b226", "Name": "ansible" } ] 最近のOpenStackは JSONで出力可!
  26. 王道パターン データ取得 • Ansible module • API • CLI (-f

    jsonオプション) 加工 • json_query • jinja2 使用 • モジュール 25 Copyright 2017 FUJITSU LIMITED register set_fact
  27. Prettytable出力  旧来のCLIはprettytableで出力した 人間には見やすい? ansibleには扱いにくい  互換性のため、旧来のCLIが必要な事態も多い 26 Copyright 2017

    FUJITSU LIMITED $ openstack server list +--------------------------------------+---------+---------+----------------------- ----------------+ | ID | Name | Status | Networks | +--------------------------------------+---------+---------+----------------------- ----------------+ | 6d905280-9174-4343-88ba-b8f030447575 | night | ACTIVE | private- net=172.29.6.37 | | fa3be49e-33aa-4ffa-aa50-13dca8f2b226 | ansible | SHUTOFF | private- net=172.29.6.38, 10.25.177.56 | +--------------------------------------+---------+---------+----------------------- ----------------+
  28. Prettytableデータの加工  モノの本には、awkやsedを駆使したplaybookが 紹介されている shellスクリプトを持ってきただけ。つらい。 27 Copyright 2017 FUJITSU LIMITED

    - name: Collect post-migration instance details shell: nova --os-username={{ OS_USERNAME }} --os-password={{ OS_ PASSWORD }} --os-tenant- name={{ OS_TENANT_NAME }} --os-auth- url={{ OS_AUTH_URL }} list --name {{ instance }} -- fields OS-EXT-SRV-ATTR:host,status | awk 'NR > 3' | awk '{ print $4 " and has a status of " $6 }' | awk 'NR == 1' register: postinststat
  29. Prettytable to dictフィルタ 28 Copyright 2017 FUJITSU LIMITED +--------+--------+--------+-------+ |

    key_a | key_b | key_c | ... | +--------+--------+--------+-------+ | val_1a | val_1b | val_1c | ... | | val_2a | val_2b | val_2c | ... | | val_3a | val_3b | val_3c | ... | | ... | ... | ... | ... | +--------+--------+--------+-------+ [ {'key_a': 'val_1a', 'key_b': 'val_1b', 'key_c': 'val_1c', ...}, {'key_a': 'val_2a', 'key_b': 'val_2b', 'key_c': 'val_2c', ...}, {'key_a': 'val_3a', 'key_b': 'val_3b', 'key_c': 'val_3c', ...}, {...}, ] prettytableをJSON (dict) に変換 公開予定
  30. Prettytable例: ホストのVM一覧取得  Nova コマンド出力からIDのリストを取り出す 29 Copyright 2017 FUJITSU LIMITED

    - name: list instances belonging to the migration source host command: >- nova --os-username={{ OS_USERNAME }} --os-password={{ OS_PASSWORD }} --os-tenant-name={{ OS_TENANT_NAME }} --os-auth-url={{ OS_AUTH_URL }} hypervisor-servers {{ inventory_hostname }} register: nova_hypervisor_servers - name: set pre-migration instance list as fact set_fact: instances: "{{ nova_hypervisor_servers.stdout | table_to_list | json_query('[].ID') }}" +--------------------------------------+-------------------+---------------+---------------------+ | ID | Name | Hypervisor ID | Hypervisor Hostname | +--------------------------------------+-------------------+---------------+---------------------+ | 49c70075-bac0-41fd-bb98-159c1779356e | instance-00000012 | 1 | <compute node name> | | 65957279-4871-4168-aea0-f0d9be48ed81 | instance-00000013 | 1 | <compute node name> | +--------------------------------------+-------------------+---------------+---------------------+ このListが得られる
  31. XML出力  Libvirtや特定機器など様々な出力で使用。 高度な構造を扱えるが、Ansibleでは扱いにくい。 コマンドと出力例 30 Copyright 2017 FUJITSU LIMITED

    # virsh dumpxml 49c70075-bac0-41fd-bb98-159c1779356e <domain type='qemu' id='1'> <name>instance-00000012</name> <uuid>49c70075-bac0-41fd-bb98-159c1779356e</uuid> <metadata> <nova:instance xmlns:nova=¥"http://openstack.org/xmlns/libvirt/nova/1.0¥"> .... </metadata> <memory unit='KiB'>524288</memory> <currentMemory unit='KiB'>524288</currentMemory> <vcpu placement='static'>1</vcpu> .... <interface type='bridge'> <mac address='fa:16:3e:20:42:1b'/> .... </interface> .... </domain> MAC addressをNova/Neutronの 結果と比較したい場合がある
  32. XML to JSON フィルタ  XMLからJSONへの変換フィルタを実装 “Converting Between XML and

    JSON”仕様に準拠 • http://www.xml.com/pub/a/2006/05/31/converting-between-xml-and-json.html 31 Copyright 2017 FUJITSU LIMITED 公開予定
  33. XML to JSON例: virsh/nova/neutronのMAC値比較 32 Copyright 2017 FUJITSU LIMITED -

    name: get instance dumpxml from libvirt command: > virsh dumpxml {{ inventory_hostname }} register: virsh_dumpxml - name: set kvm_dumpxml fact set_fact: kvm_dumpxml: "{{ virsh_dumpxml.stdout | fromxml }}" - name: set interfaces' integrity to true set_fact: intf_integrity: yes when: - nova_details_network | symmetric_difference(neutron_net_show|json_query('[].name')) == [] - kvm_dumpxml | json_query(dumpxml_mac_query) | symmetric_difference(nova_intf_list | json_query(nova_intf_mac_query)) == [] vars: id_to_mac_query: "[?¥"Net ID¥"=='{{ item.id }}'].¥"MAC Addr¥" | [0]" dumpxml_mac_query: "domain.devices.interface[].mac.¥"@address¥"" nova_intf_mac_query: "[].¥"MAC Addr¥""
  34. さらなるデータ加工  map, reduceのような加工をしたい時 jinja2やjson_queryにもmap関数はある。 しかし、関数定義できないので使いづらい  [f_x() for x

    in source_list]を ansibleのタスクで実現 33 Copyright 2017 FUJITSU LIMITED - name: template of map process set_fact: ls: “{{ ls |default([]) + [f_x] }}” with_items: "{{ source_list }} vars: f_x: “{{ some_process_of(item) }}” lsの初期値 リスト同士の結合
  35. リスト処理の例  prettytable to dictくらいは書ける 34 Copyright 2017 FUJITSU LIMITED

    # table :input:, odcit :output: - name: get token from table set_fact: tokens: "{{ tokens | default([]) + [ln_token] }}" vars: ln_token: "{{ (item[1:-1].split('|'))| map('trim')|list }}" with_items: "{{ table.splitlines() }}" when: item.startswith('|') and item.endswith('|') - name: define keys set_fact: keys: "{{ tokens[0] }}" - name: make output dict set_fact: odict: "{{ odict|default([]) + [dict(keys |zip(item) |list)] }}" with_items: - "{{ tokens[1:]}}"
  36.  Ansibleだけでは、Playbook・適用対象を管理しきれない  Jenkins + gitによるpipelineによるPlaybook管理  Foreman DBをもとにしたDynamic Inventory

     Jenkinsのログを使う Ansible Tips & Examples 「適用対象を間違えない」 「作業履歴を残す」 35 Copyright 2017 FUJITSU LIMITED
  37. Ansibleを取り巻くツール群 36 Copyright 2017 FUJITSU LIMITED サーバー管理 (Dynamic Inventory) Playbook,ジョブは

    バージョン管理する PlaybookはJenkinsの ジョブで実行管理する
  38. Playbookを版数管理する 37 Copyright 2017 FUJITSU LIMITED

  39. JenkinsからAnsibleを実行する  Jenkinsfileでジョブを定義  テキストなのでGitで管理できる  ブランチ毎にジョブを作成 (multibranch pipeline) 

    ジョブ内で、Playbookを指定し実行 38 Copyright 2017 FUJITSU LIMITED
  40. 対象を間違っては意味がない  Excelによるサーバー管理 39 Copyright 2017 FUJITSU LIMITED

  41. Excel から YAMLへ  リージョン単位にインベントリを管理する 40 Copyright 2017 FUJITSU LIMITED

    inventory/ ├── g2pstg-1 │ ├── group_vars │ │ └── all │ │ ├── common.yml │ │ └── node_config.yml │ └── hosts.yml ├── g2pstg-2 │ ├── group_vars │ │ └── all │ │ ├── common.yml │ │ └── haproxy_conf.yml │ └── hosts.yml └── ops ├── group_vars │ └── all │ ├── common.yml │ └── node_config.yml └── hosts.yml
  42. ExcelからYAMLへ  リージョン単位にインベントリを管理する 41 Copyright 2017 FUJITSU LIMITED inventory/ ├──

    g2pstg-1 │ ├── group_vars │ │ └── all │ │ ├── common.yml │ │ └── node_config.yml │ └── hosts.yml ├── g2pstg-2 │ ├── group_vars │ │ └── all │ │ ├── common.yml │ │ └── haproxy_conf.yml │ └── hosts.yml └── ops ├── group_vars │ └── all │ ├── common.yml │ └── node_config.yml └── hosts.yml
  43.  リージョン単位にインベントリを管理する 手動の管理はそもそも無理 42 Copyright 2017 FUJITSU LIMITED inventory/ ├──

    g2pstg-1 │ ├── group_vars │ │ └── all │ │ ├── common.yml │ │ └── node_config.yml │ └── hosts.yml ├── g2pstg-2 │ ├── group_vars │ │ └── all │ │ ├── common.yml │ │ └── haproxy_conf.yml │ └── hosts.yml └── ops ├── group_vars │ └── all │ ├── common.yml │ └── node_config.yml └── hosts.yml
  44. 手動の管理はそもそも無理 Dynamic Inventory 43 Copyright 2017 FUJITSU LIMITED  外部DBを使ってインベントリを管理する

     コミュニティ版多数 (2017/12/20現在51種) openstack, ec2, foreman, …
  45. Foreman概要  OSSのサーバープロビジョニングツール https://theforeman.org/, 2009年開始 ライセンス: GPL v3  特徴

    DHCP/DNS/TFTP/PXEを統合管理 プラグインによるGUIを含む機能拡張 REST APIによる操作が可能 Dynamic Inventory対応 RedHat Satellite 6で採用 44 Copyright 2017 FUJITSU LIMITED
  46. Foreman Dynamic Inventory  $ ansible-playbook –i foreman.py 45 Copyright

    2017 FUJITSU LIMITED
  47. Foreman Dynamic Inventory 出力例  $ python foreman.py --list (抜粋)

    46 Copyright 2017 FUJITSU LIMITED { "_meta": { "hostvars": { "foreman1.ops.flab.fujitsu.co.jp": { "foreman": { ... "foreman_hostgroup_kt122": [ "k1-c28-14-sv.v122.local", "k1-c28-15-sv.v122.local", "k1-c28-16-sv.v122.local", "k1-c28-17-sv.v122.local", "k1-c28-18-sv.v122.local" ], ... }
  48. Jenkinsで履歴管理  作業者、結果等すべてJenkinsから参照可能 47 Copyright 2017 FUJITSU LIMITED

  49. まとめと今後  複雑なOpenStackの運用にも、Ansibleは使える 厳密な処理確認をplaybook化 出力データをJSON化し、json_queryで確実な処理 Foremanの構成DBを元としたDynamic inventoryに よる適用対象の管理 実行管理、記録はJenkinsを使用 

    今後の課題 Ansibleコミュニティへの貢献 作った人がいなくなっても持続できる運用 48 Copyright 2017 FUJITSU LIMITED
  50. None