OpenStack & Ansible Advent Calendar 2014 12-24

OpenStack & Ansible Advent Calendar 2014 12-24

これは、OpenStack (2枚目) Advent Calendar 2014 と Ansible Advent Calendar 2014 の24日目(クリスマスイヴ!!)の記事です。

OpenStackとAnsibleの、12/24という割と重要な日を同時に担当してしまったので、この2つのキーワードを連携させる内容で書いてみました。

AnsibleからOpenStack上に仮想マシンを作成する

AnsibleではOpenStackを操作するためのモジュール群がいくつか提供されています。 しかしながら、積極的にメンテナンスされているのは、 nova_computeモジュール のみという状態に見えます。 そこで、この記事ではnova_computeモジュールの利用方法を紹介します。

モジュール名 機能
glance_image 仮想マシンイメージの登録・削除
keystone_user プロジェクト/ユーザー/ロールの作成・削除・紐付け
nova_compute 仮想マシンの作成・削除
nova_keypair キーペアの登録・削除
quantum_floating_ip フローティングIPの払い出しと仮想マシンインスタンスへの割り当て
quantum_floating_ip_associate 特定フローティングIPの割り当てと割り当て解除
quantum_network 仮想ネットワークの作成・削除
quantum_router 仮想ルータの作成・削除
quantum_router_gateway 仮想ルータと外部ネットワークセグメントの接続・切断
quantum_router_interface 仮想ルータと仮想ネットワークセグメントの接続・切断
quantum_subnet 仮想ネットワーク内のサブネットの作成・削除

しかしながら、このモジュールは問題含みで本当に限られた環境でしか安全に動作しません。 利用方法を紹介する前に、標準提供されるOpenStack操作関連のモジュールが抱える問題(結構致命傷)を2つ書いておきます。OpenStackの仮想マシン管理にAnsibleを利用したい場合(あるのか?)は、対応しておくことをお勧めします。

<問題1> quantumモジュールとglanceモジュールはマルチリージョン未対応

neutronを操作する全てのモジュール(quantum_*)と、glanceを操作するモジュール(glance_image)はマルチリージョンに対応してません。 Optionでは、Region_nameを指定できますが、実際には利用されておらず、OpenStackのクライアントオブジェクト生成時に渡されていない....

<問題2> nova_computeモジュールがfloating_ipの割り当て時に使用済みアドレスの除外に失敗しています

nova_computeモジュールで仮想マシン新規作成時にfloating_ipを割り当てる際、以下のような動きをします。

本来の動作
  1. floating_ip_poolsを指定すると、払い出し済みの全てのfloating_ipの中から未使用のアドレスを1つを選んで仮想マシンに割り当てる
  2. 未使用のアドレスがなければ、新たに1つfloating_ipを払いだして割り当てる
実際の動作

しかし、実際には、払い出し済みかどうかに関わらず、プール内のすべてのfloating_ipの中から1つを選択して割り当ててしまうのですこれはひどい...

背景

nova_computeモジュールでは、floating_ipが割り当て済みかどうかを、APIから返されるfloating_ipに紐付けられているinstance_idから判断しているのですが、現状のnova apiは、instance_idを空で返してきます。nova_computeモジュールはinstance_idが存在していないため、未使用と判断して、これを仮想マシンへの割り当て候補リストに加えてしまうのです。 ちなみに、HP Public Cloudでは、このnovaの不具合が修正されているので問題ありません。

nova_computeモジュールが持つ致命的な不具合

自前で構築したOpenStack環境だとJuno(2014.2)でもこの不具合を引き当てます。 引き当てるとどうなるかというと、既に他の仮想マシンに割り当てられているfloating_ipが強制的に取り上げられて、新たに作成した仮想マシンに付与してしまいます(novaの仕様)。これは相当やばい。

対策

v1.8系のnova_computeモジュールを使うときは要注意!

対策をちゃんと施したほうが良いです。 Pull Requestしてるんだけど、早くマージしてくれないかなぁ...

実際にnova_computeモジュールを利用してみる

前節の対策はおわすれなく。

必須要件

AnsibleからOpenStackを操作するためには、大きく3つの要件を満たしている必要があります。

  1. OpenStack APIのURL/アカウント/パスワード/テナント名/リージョン名を持っている
  2. OpenStackのPythonクライアントライブラリがインストールされている
  3. nova_computeの不具合に対処済みである

下準備

pythonのvirtualenvを利用して仮想実行環境にAnsibleとOpenStackのクライアントライブラリを閉じ込めます。

1. virtualenv環境構築
$ virtualenv $HOME/advc
New python executable in advc/bin/python
Installing Setuptools..............................................................................................................................................................................................................................done.
Installing Pip.....................................................................................................................................................................................................................................................................................................................................done.
$ source advc/bin/activate
(advc)$
2. Ansibleのインストール

pipを利用してAnsibleをインストールする

(advc)$ pip install jinja2 passlib pycrypto pyyaml
(advc)$ pip install ansible
3. python-novaclientとpython-neutronclientのインストールと環境変数設定

nova_computeモジュールは、python-novaclientが提供するライブラリを利用しているため、利用前にインストールしておく必要があります。

依存関係があるのでpython-keystoneclientもインストールされます。

(advc)$ pip install python-novaclient python-neutronclient
(advc)$ vi openrc
export OS_AUTH_URL=https://認証用URL:ポート/v2.0/
export OS_REGION_NAME=リージョン名
export OS_TENANT_NAME=テナント名
export OS_USERNAME=ユーザ名
export OS_PASSWORD=パスワード
4. nova_computeモジュールの配置
(advc)$ cd $HOME/advc/lib/python2.7/site-packages/ansible/modules/core/cloud/openstack
(advc)$ mv nova_compute.py nova_compute.py.org
(advc)$ wget http://goo.gl/8Vr3QT -O nova_compute.py
5. Ansibleの動作確認
(advc)$ cd $HOME
(advc)$ echo "localhost ansible_connection=local" > ansible_hosts
(advc)$ ansible all -i ansible_hosts -m ping

仮想マシンを作成する

作成に必要な仮想マシンやネットワークの情報は nova コマンドや neutron コマンドで取得しておきましょう!

  • create_vm.yml
---
- hosts: localhost
  tasks:
  - name: ansible_python_interpreter setup
    set_fact: ansible_python_interpreter="{{ lookup('pipe', 'which python') }}"
  - name: create virtual machine instance
    nova_compute:
      state: present
      auth_url: "https://認証URL:ポート/v2.0/"
      region_name: "リージョン名"
      login_tenant_name: "テナント名"
      login_username: "ユーザID"
      login_password: "パスワード"
      availability_zone: "アベイラビリティゾーン名"
      flavor_id: フレーバID
      floating_ip_pools:
      - "パブリックネッーワーク名"
      image_id: "GuestOSイメージID"
      key_name: "キーペア名"
      name: "仮想マシンのホスト名"
      nics:
      - net-id: "内部ネットワークID"
      security_groups: "セキュリティグループ名"

#
# [EOF]
#
  • 実行
(advc)$ ansible-playbook -i ansible_hosts create_vm.yml

PLAY [localhost] **************************************************************

GATHERING FACTS ***************************************************************
ok: [localhost]

TASK: [ansible_python_interpreter setup] **************************************
ok: [localhost]

TASK: [create virtual machine instance] ***************************************
changed: [localhost]

PLAY RECAP ********************************************************************
localhost                  : ok=3    changed=1    unreachable=0    failed=0
  • 作成されたかを確認してみる
(advc)$ nova show test-vm00
+-----------------------------+----------------------------------------------------------+
| Property                    | Value                                                    |
+-----------------------------+----------------------------------------------------------+
| OS-EXT-AZ:availability_zone | アベイラビリティゾーン                                   |
| OS-EXT-STS:power_state      | 1                                                        |
| OS-EXT-STS:task_state       | -                                                        |
| OS-EXT-STS:vm_state         | active                                                   |
| accessIPv4                  |                                                          |
| accessIPv6                  |                                                          |
| config_drive                |                                                          |
| created                     | 2014-12-24T08:52:24Z                                     |
| flavor                      | フレーバ名(フレーバID)                                   |
| hostId                      | 4bd0942b81bcc260be67911e43a43fc91217d78a18e59d32f2bd275b |
| id                          | 4f0a63bb-f79e-4850-ad5f-3156d677940b                     |
| image                       | OSイメージ名 (OSイメージID)                              |
| key_name                    | キーペア名                                               |
| metadata                    | {}                                                       |
| name                        | ホスト名                                                 |
| progress                    | 0                                                        |
| security_groups             | セキュリティグループ名                                   |
| status                      | ACTIVE                                                   |
| tenant_id                   | テナントID                                               |
| updated                     | 2014-12-24T08:52:54Z                                     |
| user_id                     | ユーザID                                                 |
| work-net network            | 10.0.0.23, 15.126.228.53                                 |
+-----------------------------+----------------------------------------------------------+

よし!できた! これを基本にしてvarsなどをうまく利用すれば、novaコマンドを素で叩くよりは楽に仮想マシンが作れそうです!

それではみなさん素敵なクリスマスを!