こんにちは。@jedipunkz です。

OpenStack を運用する中でコントローラは重要です。コントローラノードが落ちると、 仮想マシンの操作等が利用出来ません。コントローラの冗長構成を取るポイントは公式 wiki サイトに記述あるのですが PaceMaker を使った構成でしんどいです。何より運用 する人が混乱する仕組みは避けたいです。

RackSpace 社の管理している Chef Cookbooks の Roles に ‘ha-controller1’, ‘ha-controller2’ というモノがあります。今回はこれを使った HA 構成の構築方法に ついて書いていこうかと思います。

構成

最小構成を作りたいと思います。HA のためのコントローラノード2台, コンピュートノー ド1台, Chef ワークショテーション1台, Chef サーバノード1台。

+----------------+----------------+----------------+----------------+--------------- public network
|                |                | eth0           |                |                10.0.0.0/24
+--------------+ +--------------+ +--------------+ +--------------+ +--------------+
| controller01 | | controller01 | |  compute01   | | chef server  | | workstation  |
+--------------+ +--------------+ +--------------+ +--------------+ +--------------+
                                  | eth1
                                  +------------------------------------------------- fixed range network
                                                                                     172.16.0.0/24

特徴

  • ‘controller01’, ‘controller02’ で HA 化コントローラ
  • ‘compute01’ はコンピュートノード
  • ‘chef server’ は Chef サーバ、Chef11 推奨
  • ほとんどの作業を行う ‘workstaion’ は Chef ワークステーション
  • nova-network 構成

Chef サーバの構築

Chef サーバの構築方法は本題から外れるので割愛します。今は Omnibus インストーラで一発です。

wokstation ノードでの準備

  • workstation で knife を使えるまでの準備についても割愛します。
  • プロンプトに何もホスト名が記されていないモノは全て workstation ノード上での操作です。

Rackspace 管理の Cookbook を取得します。

% git clone https://github.com/rcbops/chef-cookbooks.git ~/openstack-chef-repo
% cd ~/openstack-chef-repo

v4.0.0 というタグ (現在 2013/07/16 最新リリース版) をチェックアウトします。また submodue update で関連 する Cookbooks を全て取得する事ができます。

% git checkout v4.0.0
% git submodule init
% git submodule sync
% git submodule update

取得した Cookbooks を Chef サーバにアップロードします。

% knife cookbook upload -o cookbooks -a

同様に Roles も Chef サーバにアップロードします。

% knife role from file roles/*rb

environment ファイルを生成します。ここで指定するパラメターは各々の Cookbooks の Attributes を上書き出来ます。 また、Recipe 内でノードサーチする際に同じ environment 名が指定されているノードをクラスタ構成の一部と判断出来る といった仕組みです。

% ${EDITOR} environments/Cluster01.json
{
  "name": "Cluster01",
  "description": "",
  "cookbook_versions": {
  },
  "json_class": "Chef::Environment",
  "chef_type": "environment",
  "default_attributes": {
  },
  "override_attributes": {
    "package_component": "grizzly",
    "osops_networks": {
      "management": "10.0.0.0/24",
      "public": "10.0.0.0/24",
      "nova": "10.0.0.0/24"
    },
    "nova": {
      "networks": [
        {
          "bridge": "br100",
          "num_networks": "1",
          "dns2": "8.8.4.4",
          "dns1": "8.8.8.8",
          "ipv4_cidr": "172.16.0.0/24",
          "network_size": "256",
          "label": "private",
          "bridge_dev": "eth1"
        }
      ],
      "config": {
        "use_single_default_gateway": false,
        "ram_allocation_ratio": "1",
        "cpu_allocation_ratio": "16"
      },
      "network": {
        "dmz_cidr": "172.18.0.0/24",
        "public_interface": "eth0",
        "multi_host": true,
        "fixed_range": "172.16.0.0/24"
      },
      "apply_patches": true,
      "libvirt": {
        "vncserver_listen": "0.0.0.0",
        "virt_type": "kvm"
      },
      "db": {
        "password": "nova"
      }
    },
    "cinder": {
      "db": {
        "password": "cinder"
      }
    },
    "keystone": {
      "admin_user": "admin",
      "tenants": [
        "admin",
        "service"
      ],
      "users": {
        "admin": {
          "password": "secrete",
          "roles": {
            "admin": [
              "admin"
            ]
          }
        },
        "demo": {
          "password": "demo",
          "default_tenant" : "service",
          "roles": {
            "service": [ "service" ]
          }
        }
      },
      "db": {
        "password": "keystone"
      }
    },
    "horizon": {
      "theme": "Rackspace",
      "db": {
        "password": "horizon"
      }
    },
    "mysql": {
      "root_network_acl": "%",
      "allow_remote_root": true
    },
    "monitoring": {
      "procmon_provider": "monit",
      "metric_provider": "collectd"
    },
    "glance": {
      "images": [
        "precise", "cirros"
      ],
      "image": {
      },
      "image_upload": true,
      "db": {
        "password": "glance"
      }
    },
    "vips": {
      "cinder-api": "10.0.0.22",
      "glance-api": "10.0.0.22",
      "glance-registry": "10.0.0.22",
      "horizon-dash": "10.0.0.22",
      "horizon-dash_ssl": "10.0.0.22",
      "keystone-admin-api": "10.0.0.22",
      "keystone-service-api": "10.0.0.22",
      "keystone-internal-api": "10.0.0.22",
      "mysql-db": "10.0.0.21",
      "nova-api": "10.0.0.22",
      "nova-ec2-public": "10.0.0.22",
      "nova-novnc-proxy": "10.0.0.22",
      "nova-xvpvnc-proxy": "10.0.0.22",
      "rabbitmq-queue": "10.0.0.23"
    },
    "developer_mode": false
  }
}

作成した environment を Chef サーバにアップロードします。

% knife environment from file environments/Cluster01.json

HA コントローラデプロイ

controller01, controller02 ノードを HA 化するわけですが、この操作を全て Chef で行います。

% knife bootstrap <ip_controller01> -N controller01 -r 'role[ha-controller1]' -E Cluster01 --sudo -x jedipunkz
% knife bootstrap <ip_controller02> -N controller02 -r 'role[ha-controller2]' -E Cluster01 --sudo -x jedipunkz

chef サーバに node の情報が登録されました。ここから environment で指定した VIP を利用した HA 構成を組むため再度 chef-client を実行します。chef-client をデーモン化しておいた場合は 時間と共に自動で構築されるはずです。

controller01# chef-client
controller02# chef-client

Cinder の利用に関しては片系のコントローラノードに寄せる必要があります。‘cinder-volumes’ という名前の Volume Group を controller01 ノードに作成し下記の操作を行います。

% knife node run_list add controller01 'role[cinder-volume]'
controller01# chef-client
controller01# service cinder-volume restart

Compute ノードのデプロイ

compute ノードのデプロイも同様に Chef を用います。

% knife bootstrap <ip_compute01> -N compute01 -r 'role[single-compute]' -E Cluster01 --sudo -x jedipunkz

compute ノードの追加に関しても同様に行なっていくことで仮想マシンの数を拡張出来ます。

デプロイされた HA 構成の内部

PaceMaker は今回使われていないようです。デプロイされた構成の内部を覗いてみると下記のような特徴がありました。

各 OpenStack APIs

Keepalived で VRRP 構成。active/passive 構成で明示的な Master は存在しない。その都度、評価の高いノードが VIP を引き継ぎサービスリクエストに応じる。また、リクエストを受けたコントローラノードは haproxy により HA の2台に対して それぞれリクエストを分散。ラウンドロビンの冗長が取られている。

RabbitMQ

Keepalived で VRRP 構成。APIs と同様に active/passive 構成。その後は HA 内片系のコントローラの RabbitMQ が全てのリクエストに 応え処理を行う。

MySQL

Keepalived で VRRP 構成。APIs と同様に active/passive 構成。MySQL はミドルウェアベースで master/master, active/passive レプリケーションが組まれている。

障害系の対処

ここまで来ると、HA 構成が壊れた際に Chef で復旧を自動化してみたくなります。試したところ HA 構成の MySQL 的な passive 側 が壊れた際には knife bootstrap で直ちに復旧することが出来ました。ただし active (master) 側が壊れた際にはバックアップした データからのリストア作業が必要でした。つまり Chef での自動復旧はできませんでした。

まとめ

keepalived と haproxy によるシンプルな HA 構成のため運用する人間が理解・対処する事も容易になると考えられます。 コントローラノード障害といっても、大抵は disk 交換や筐体交換で復旧出来るわけですから、HA さえ組まれていればかなり 安心して運用が出来そうです。今回は nova-network を試してみましたが、neutron 構成も組める Cookbooks になっているので 時間を見つけてやってみようかなと考えています。