こんにちは。@jedipunkz です。

最近 Chef で OpenStack をデプロイすることばかりに興味持っちゃって、他のことも やらんとなぁと思っているのですが、せっかくなので Swift HA 構成を Chef でデプロ イする方法を書きます。

Swift って分散ストレージなのに HA ってなんよ!と思われるかもしれませんが、ご存 知の様に Swift はストレージノード (accout, object, container) とプロキシノード に別れます。今回紹介する方法だとプロキシノードを Keepalived と Haproxy で HA、 また MySQL も KeepAlived で HA の構成に出来ました。いつものように RackSpace 管 理の Cookbooks を使っています。

参考資料

http://www.rackspace.com/knowledge_center/article/openstack-object-storage-configuration

構成

構成は簡単に記すと下記のようになります。特徴としては…

  • swift-proxy01, swift-proxy02 で HA。VRRP + LB な構成。
  • swift-proxy01 で git サーバ稼働。Rings 情報を管理。
  • swift-storageNN がストレージノード
  • OS は Ubuntu server 12.04

です。

|--------- VRRP + Load Balancer ------|

+-----------------+ +-----------------+ +-----------------+ +-----------------+ +-----------------+
|  swift-proxy01  | |  swift-proxy02  | | swift-storage01 | | swift-storage02 | | swift-storage03 |
+-----------------+ +-----------------+ +-----------------+ +-----------------+ +-----------------+
|                   |                   |                   |                   |
+-------------------+-------------------+-------------------+-------------------+------------------
|                   |
+-----------------+ +-----------------+
| chef workstation| |   chef server   |
+-----------------+ +-----------------+

絵は書く意味なかったか…。

手順

chef server 構築

例によって Omnibus パッケージを使います。

% wget https://opscode-omnibus-packages.s3.amazonaws.com/ubuntu/12.04/x86_64/chef-server_11.0.8-1.ubuntu.12.04_amd64.deb
% sudo dpkg -i chef-server_11.0.8-1.ubuntu.12.04_amd64.deb
% sudo chef-server-ctl reconfigure
% knife configure -i
< 適当に答える >

‘knife configure -i’ で自分用の秘密鍵が生成出来ます。

workstation ノードでの準備

ほぼ全ての操作を workstation ノードで行います。knife.rb や秘密鍵の設置等につい ては方法を割愛します。このへんはモヤモヤと説明しますが、皆さんならご存知かと思 いますので..。

github より rackspace 管理の Chef Cookbooks を取得する。

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

v.4.0.0 とい現在 (2013/07/25) 最新リリース版をチェックアウトする。

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

‘chef server’ ノードへ Cookbooks をアップロードする

% knife cookbook upload -o cookbooks -a

‘chef-server’ ノードへ Roles をアップロードする

% knife role from file roles/*rb

今回の構成用の environment ‘swift-ha’ を用意します。ここでは各 Cookbooks の Attributes を上書きし、一つの構成を組みます。Cookbooks 内でこの environment 名 をキーに検索し自ノードと同環境のノードを見つけ出し、関連付けがされます。

{
  "name": "swift-ha",
  "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",
      "swift": "10.0.0.0/24"
    },
    "keystone": {
      "admin_user": "admin",
      "tenants": [
        "admin",
        "service"
      ],
      "users": {
        "admin": {
          "password": "secrete",
          "roles": {
            "admin": [
              "admin"
            ]
          }
        },
        "demo": {
          "password": "demo",
          "default_tenant" : "service",
          "roles": {
            "admin": [ "admin" ]
          }
        }
      },
      "db": {
        "password": "keystone"
      }
    },
    "mysql": {
      "root_network_acl": "%",
      "allow_remote_root": true,
      "server_root_password": "secrete",
      "server_repl_password": "secrete",
      "server_debian_password": "secrete"
    },
    "monitoring": {
      "procmon_provider": "monit",
      "metric_provider": "collectd"
    },
    "vips": {
      "keystone-admin-api": "10.0.0.11",
      "keystone-service-api": "10.0.0.11",
      "keystone-internal-api": "10.0.0.11",
      "mysql-db": "10.0.0.12",
      "swift-proxy": "10.0.0.11"
    },
    "developer_mode": false,
    "swift": {
      "swift_hash": "127005c8ea84",
      "authmode": "keystone",
      "authkey": "1f281c71-cf89-5b27-a2ad-ad873d3f2760"
    }
  }
}

生成した environment ファイル ‘environments/swift-ha.json’ を Chef サーバへアッ プロードします。

% knife environment from file environments/swift-ha.json

disk デバイスの用意

swift-storageNN で オブジェクト格納用の Disk がある場合はパーティションを作成 します。追加の Disk が無くても構わないと思います。後に Chef が使用可能な Disk デバイスを検知してくれます。ここでは例として /dev/sdb として認識されていること を前提に記します。追加の disk が無い場合は /dev/sda6 等、OS インストール時にオ ブジェクト格納用のパーティションを用意してもらえば大丈夫です。また GPT なパー ティションを切る必要があると思いますので (大きいから) fdisk ではなく gdisk を 用いましょう。

% swift-storageNN% sudo apt-get update; apt-get -y install gdisk
% swift-storageNN% sudo gdisk /dev/sdb

各ノードをブートストラップ

いよいよデプロイします。

% knife bootstrap <ip_swift-proxy01> -N swift-proxy01 -r 'role[ha-swift-controller1]' -E swift-ha --sudo -x jedipunkz
% knife bootstrap <ip_swift-proxy02> -N swift-proxy02 -r 'role[ha-swift-controller2]' -E swift-ha --sudo -x jedipunkz
% knife bootstrap <ip_swift-storage01> -N swift-storage01 -r \
'role[swift-object-server]','role[swift-container-server]','role[swift-account-server]' -E swift-ha --sudo -x jedipunkz
% knife bootstrap <ip_swift-sotrage02> -N swift-storage02 -r \
'role[swift-object-server]','role[swift-container-server]','role[swift-account-server]' -E swift-ha --sudo -x jedipunkz
% knife bootstrap <ip_swift-storage03> -N swift-storage03 -r \
'role[swift-object-server]','role[swift-container-server]','role[swift-account-server]' -E swift-ha --sudo -x jedipunkz

Chef サーバにノード情報が登録されているので各ストレージノードの zone 情報にシー ケンシャル番号を付与します。これにより各ノードは自分の zone 情報を Chef サーバ から知ることが出来ます。

% knife exec -E "nodes.find(:name => 'swift-storage01') {|n| n.set['swift']['zone'] = '1'; n.save }"
% knife exec -E "nodes.find(:name => 'swift-storage02') {|n| n.set['swift']['zone'] = '2'; n.save }"
% knife exec -E "nodes.find(:name => 'swift-storage03') {|n| n.set['swift']['zone'] = '3'; n.save }"

Account, Container, Object に対して適切に割り当てられたか確認を行います。

% knife exec -E 'search(:node,"role:swift-account-server") \
  { |n| z=n[:swift][:zone]||"not defined"; puts "#{n.name} has the role \
  role [swift-account-server] and is in swift zone #{z}"; }'
% knife exec -E 'search(:node,"role:swift-container-server") \
  { |n| z=n[:swift][:zone]||"not defined"; puts "#{n.name} has the role \
  [swift-container-server] and is in swift zone #{z}"; }'
% knife exec -E 'search(:node,"role:swift-object-server") \
  { |n| z=n[:swift][:zone]||"not defined"; puts "#{n.name} has the role \
  [swift-object-server] and is in swift zone #{z}"; }'

また、先ほど用意した Swift 用ディスクデバイスを Chef がディスカバ出来るか確認 を行います。

% knife exec -E \
  'search(:node,"role:swift-object-server OR \
  role:swift-account-server \
  OR role:swift-container-server") \
  { |n| puts "#{n.name}"; \
  begin; n[:swift][:state][:devs].each do |d| \
  puts "\tdevice #{d[1]["device"]}"; \
  end; rescue; puts \
  "no candidate drives found"; end; }'

またディスカバされたディスクデバイス /dev/sdb1 が既にマウントされているかどう か確認します。

swift-strageNN# df

‘swift-proxy01’ ノードにて再度 chef-client を実行し /etc/swift/ring-workspace/generate-rings.sh を 更新する。上記 zone 情報に従って内容が更新される。

swift-proxy01# chef-client

生成された generate-rails.sh を実行。‘exit 0’ の行をコメントアウトして実行すること。

swift-proxy01# cd /etc/swift/ring-workspace
swift-proxy01# ./generate-rings.sh

/etc/swift/ring-workstation/rings 配下に Rings ファイルが生成されたはずです。確 認してみてください。この Rings ファイルを git サーバにプッシュします。git サー バは既に ‘swift-proxy01’ ノード上に構築されています。

swift-proxy01# cd /etc/swift/ring-workspace/rings
swift-proxy01# git add account.builder container.builder object.builder
swift-proxy01# git add account.ring.gz container.ring.gz object.ring.gz
swift-proxy01# git commit -m "initial commit"
swift-proxy01# git push

git サーバにプッシュされた Rings ファイルを各ノードに配布します。配布の方法は 各ノードで chef-client を実行することです。これは knife ssh 等を用いても構いま せん。

swift-proxy01# chef-client
swift-proxy02# chef-client
swift-storage01# chef-client
swift-storage02# chef-client
swift-storage03# chef-client

swift-storageNN の計3台が登録されたかどうかを確認します。

swift-proxy# swift-recon --md5

動作確認

動作確認をしましょう。

swift-storage01# source swift-openrc
swift-storage01# swift post container01
swift-storage01# echo "test" > test
swift-storage01# swift upload container01 test
swift-storage01# swift list
swift-storage01# swift list container01

また、これらの操作が swift-proxy01, swift-proxy02 の片系を落とした状態でも可能 かどうかも確認しましょう。

まとめ

swift-proxy 片系の障害時にも読み込み系・書き込み系の操作が可能なことを確認出来 ました。復旧に関しても MySQL 的な Slave 系 (今回だと swift-proxy02(後からブー トストラップしたノード)) に関しては knife bootstrap で出来ます。Master 系の復 旧は簡単にはいきません。この事態に備えるには Rings 情報のバックアップ (Git レ ポジトリバックアップ) と MySQL のダンプの定期的取得が必要になるでしょう。

また、今回 VRRP で HA しているので2台構成になります。Swift プロキシは本来、ノー ドを増やすことでより多くのリクエストを受けられる (何がボトルネックになるかで状 況は変わりますが) 利点があるため、この2台構成がベストかどうかは状況に合わせて 考えた方が良いかもしれません。この構成の場合、ロードバランサが必要ない点がメリッ トだったりします。