OpenStackをアップグレードしたら心臓止まりかけた話

  • 33
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

本記事は、OpenStack Advent Calendar 2015 の12月3日の記事である。

はじめに

先日、OpenStack環境をJunoからLibertyに一気にアップグレードしてみた。

なんでそんなことしたのかっていうと、先日のOpenStack Summit TokyoでPayPalがFolsomからKiloまでアップグレードしたっていうセッション見たら、自分にもできるって思ったからだ。

いや、結果、アップグレードできたんだけどさ。

まぁそんなわけで、見事に人柱になれたと思うので、ここではその時のことを記すことにした。

なお、そんなPayPal様のセッションはこちら。

PayPal's Cloud Journey From Folsom to Kilo -- What We Learned in the Upgrade

アップグレード前の構成

Component Type
OS Ubuntu 14.04
OpenStack Juno
Hypervisor KVM
Neutron Driver VLAN + OVS (L3 Agentは動いてない)
Cinder 知らん

アップグレード

Keystone -> Glance -> Nova -> Neutronの順番でやるのが一般的なんじゃないだろうか。Design Summitでは、各コンポーネントでバージョンがバラバラだって言う企業もいたから、順番は参考程度なんだが、全コンポーネントをアップグレードするならこの順番がいいと思う。

ちなみに、無停止アップグレードは絶対無理だからアキラメロン。って、Design Summitに居たハッカーのおっちゃんたちが言っとりました。

おっしゃる通りでございます。

. . . 閑話休題 . . .

ロードバランサの紐付け解除

Keystoneのフロントにあるロードバランサの5000番ポートに対する紐付けを解除し、完全に外部からの通信を止める。35357番ポートはそのままで問題ないと思われる。

Libertyリポジトリ導入

まずは、全てのサーバにLibertyリリースのリポジトリを入れよう。

$ sudo echo "deb http://ubuntu-cloud.archive.canonical.com/ubuntu trusty-updates/liberty main" > /etc/apt/sources.list.d/cloudarchive-liberty.list
$ sudo apt-get update

Keystone前準備

KeystoneのDBに溜まっているtokenを削除する。LibertyからはデフォルトでMemcachedをtoken用途で利用するようになっているので、そちらを使うことにした。つまり、事前にMemcached用サーバを用意する必要がある。

$ sudo su -s /bin/sh -c "keystone-manage token_flush" keystone

DBのTokenを綺麗に消したら次は定期実行していたCronを停止する。

$ sudo crontab -e -u keystone

以下の行を削除する。

@hourly /usr/bin/keystone-manage token_flush > /var/log/keystone/keystone-tokenflush.log 2>&1

潔く、Keystoneを止めましょう。

$ sudo service keystone stop

データベースのバックアップ

DBサーバにログインして以下のコマンドでDBのバックアップを取得する。

$ sudo mysqldump -uroot -p --opt --add-drop-database --single-transaction --master-data=2 keystone > liberty-keytone-db-backup.sql
$ sudo mysqldump -uroot -p --opt --add-drop-database --single-transaction --master-data=2 glance > liberty-glance-db-backup.sql
$ sudo mysqldump -uroot -p --opt --add-drop-database --single-transaction --master-data=2 nova > liberty-nova-db-backup.sql
$ sudo mysqldump -uroot -p --opt --add-drop-database --single-transaction --master-data=2 neutron > liberty-neutron-db-backup.sql

Keystoneアップグレード

ここでKeystoneのアップグレードを行う。いろんなパラメータが新規に追加されたり廃止予定になったりしているが、それについては書ききれないのでConfiguration Referenceを参照してほしい。アップグレード自体は、apt-get install XXXXして、その後、keystone.confを書き換えて、プロセスを起動するだけである。基本的にはインストール手順のとおりに行えば問題ない(はず)。

ちなみに、confにDEBUGオプションを入れていると、プロセス起動直後のログに、confの各項目に何の値が設定されているのかが全て出力される。親切なことに、廃止予定の項目も指摘してくれる。これは全コンポーネント共通の仕組みなので、覚えておいて損はない。そういえば、Novaのusernameという項目で、usernameは廃止予定だから使うのやめてuser-nameを使えってログに出ていたから、使うのやめてuser-name使ったらエラー吐きまくってNovaが動かなくなった。ツンデレか。

話が逸れた。

keystone.confを配置したら以下のコマンドでLibertyリリースまでDBのスキーマのマイグレーションを行う。Kilo以降、KeystoneはApacheで稼働するようになったので、事前にKeystoneプロセスが止まっていることを確認してApacheを起動しておこう。

$ sudo service keystone stop
$ sudo service apache2 restart
$ sudo su -s /bin/sh -c "keystone-manage db_sync" keystone

エラーが出なければKeystoneのアップグレードは完了である。

一応、openstackコマンドが実行可能かどうかを確認しておこう。

$ ADMIN_TOKEN=${keystone.confに記載されているadmin_tokenの文字列}
$ export OS_TOKEN=${ADMIN_TOKEN}
$ export OS_URL=http://${Keystoneが稼働しているどれかのサーバのIPアドレス}:35357/v3
$ export OS_IDENTITY_API_VERSION=3
$ openstack service list

Glanceアップグレード

Keystone同様にConfiguration Referenceや公式のインストールガイドを確認しながら、環境にあったglance-api.confglance-registry.confを配置しよう。

その後、Glanceのdb syncを行う。

$ sudo service glance-api restart
$ sudo service glance-registry restart
$ sudo su -s /bin/sh -c "glance-manage db_sync" glance

エラーが出なければGlanceのアップグレードは完了である。

nova-apiアップグレード(Nova db sync 失敗編)

最大の難関である。NovaのDBを上手くLibertyまでマイグレーション出来ればアップグレードできたも同然である。がしかし、現実はそうそう上手くはいかなかった。

なので、この項ではアップグレードが上手くいかなかった時の状況をそのまま記すことにした。

まずは一気にLibertyまでアップグレードしてみる

まず、nova-apiが稼働しているサーバ上で、nova-apiをLibertyまでアップグレードした。

$ sudo apt-get install nova-api python-novaclient

その後db syncを行って、問題なければそのまま他のコンポーネントもアップグレードして完了となる(はずだった)。

で、以下のコマンドを叩くのだが、

$ sudo su -s /bin/sh -c "nova-manage db sync" nova

エラー発生:(

奇妙なnova-manageのオプション

エラーの内容としては、

  • db sync する前にnova-manage db migrate_flavor_dataというコマンドを実行しろ

である。

が、実はLibertyリリースのnova-manageコマンドにはこのオプションが入ってないのである。 ソースコードまで読んで調べたが本当になかった。んなアホなと思ったんだが、この時点でDBのスキーマ自体はかなり中途半端に変更されてしまっていた。

この状態で以下のことを行った。

  • DBをドロップ(1度目)してリストア
  • リポジトリをJunoリリースまで戻してパッケージを再インストール

次に疑ったのが、Kiloリリースである。なので、以下のことを行った。

  • Kiloリリースのnova-apiインストール
  • nova-manage db migrate_flavor_data実行
  • nova-manage db sync実行

Kiloリリースのリポジトリを追加してインストールしたnova-apiにはnova-manageのオプションにmigrate_flavor_dataがあった。キタコレ!と思って、さっそくnova-manage db migrate_flavor_dataを実行した。そしたら成功したもんだから、そのまま一旦Kiloリリースまで上げてからLibertyリリースにしようと思って、Kiloリリース時点までdb syncした。

そしたら、またエラーが出た:(

flavor のテーブルのスキーマがおかしいという旨のエラーだった。嘘だろって思ったがマジだった。エラーの内容と状況を整理すると、Kiloリリースのdb syncの後で、かつLibertyリリースのdb syncの前に、nova-manage db migrate_flavor_dataを実行しろ、ということである。

つまり、正解はこうだ。

  • Kiloリリースのnova-apiインストール
  • nova-manage db sync実行
  • nova-manage db migrate_flavor_data実行
  • Libertyリリースのnova-apiインストール
  • nova-manage db sync実行

apt 壊れた

この時点でまたもやDBのスキーマは中途半端に変更されてしまっていたため、Junoリリース時点まで戻して、またDBのドロップ(2度目)とリストアを行った。その後、Junoリリース時点のnova-apiに戻そうとしたのだが、今度はaptが壊れた....

JunoとKiloとLibertyを何度も行き来していたせいで、依存パッケージがおかしなことになりインストールも削除もできなくなってしまった。しょうがないので、dpkgコマンドで全3バージョン(Juno, Kilo, Liberty)のNovaに依存が貼られている依存パッケージ全てを削除した。そしたらaptが動くようになったので、またJunoリリースまで戻して再チャレンジすることとなる。

実はこれやってる最中に、この前テレビでやっていた「学校へ行こう!」の軟式globeの曲が脳内でループしていた。

「アホだなぁー」「そうだよアホだよ」

名曲である。

. . . 閑話休題 . . .

nova-apiアップグレード(Nova db sync 成功編)

ここまでを踏まえて、成功した手順を記す。

Kiloリリースをインストールする。

$ sudo echo "deb http://ubuntu-cloud.archive.canonical.com/ubuntu trusty-updates/kilo main" > /etc/apt/sources.list.d/cloudarchive-kilo.list
$ sudo apt-get update
$ sudo apt-get install nova-api python-novaclient

Kiloリリース時点のスキーマまでマイグレーションする。

$ sudo service nova-api restart
$ sudo su -s /bin/sh -c "nova-manage db sync" nova
$ sudo su -s /bin/sh -c "nova-manage db migrate_flavor_data" nova

その後、Libertyリリースに上げる。

$ sudo echo "deb http://ubuntu-cloud.archive.canonical.com/ubuntu trusty-updates/liberty main" > /etc/apt/sources.list.d/cloudarchive-liberty.list
$ sudo apt-get update
$ sudo apt-get install nova-api python-novaclient

Libertyリリース時点のスキーマまでマイグレーションする。

$ sudo service nova-api restart
$ sudo su -s /bin/sh -c "nova-manage db sync" nova

これで、nova-apiのアップグレードとNovaのDBのマイグレーションが完了となる。

ちなみに、このDBマイグレーション手順については、実はKiloのリリースノートに1行だけ記載があった。が、それでもあまり親切な書き方ではないから、事前に確認していてもハマってたと思う。

neutron-serverアップグレード

nova-apiがアップグレードできたら、次にneutron-serverをアップグレードする。

Keystone同様にConfiguration Referenceや公式のインストールガイドを確認しながら環境にあったneutron.confや、その他諸々を配置しよう。なお、Open vSwitchはml2の設定ファイルが分割されているので注意が必要である。

その後、Neutronのdb syncを行う。

$ sudo service neutron-server restart
$ sudo su -s /bin/sh -c "neutron-db-manage --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/plugins/ml2/ml2_conf.ini upgrade head" neutron

エラーが出なければNeutronのDBはLibertyリリース時点のスキーマまでマイグレーションされている。

Nova/Neutronの残りのパッケージのアップグレード

ここまで完了すれば後は残っているパッケージを全てアップグレードしよう。ここから先は、特に問題は起こらない(はず)である。何をどうやってアップグレードするのかについては各環境に依存するので、ここでは記さないこととする。

ロードバランサの紐付け

Keystoneのフロントにあるロードバランサの5000番ポートに対してリアルサーバを紐付ける。

Horizonアップグレード

Horizonは、ぶっちゃけると、他のコンポーネントとバージョンが食い違っていても全く問題ないので、OpenStackがリリースされるたびにアップグレードしても何も問題ない。

が、Libertyリリースに限って言うと、というか、Libertyリリースのdebパッケージに限って言うと、アップグレードが失敗する。

なぜうまくいかなかったのかについて詳しい事象は判明していない。とりあえず、起こった事象を書き記すことにした。申し訳ない。

deb パッケージの謎

自分は今回deb パッケージが新規インストール時とアップグレード時で挙動が違うという事象に遭遇した。普通は(きっと)そんなことはない(はず)なのだが、LibertyリリースのHorizonのdebパッケージに限って言えば、挙動が違った。

Junoリリースで稼働していたHorizonのサーバで、apt-get upgrade、もしくはapt-get install openstack-dashboardでHorizonのバージョンを上げた場合、CSSが読み込まれず、Horizonが2000年あたりの何とも簡素なWebページのようなデザインになる。

Horizonもコンポーネントが増えてごちゃごちゃしてきたから、ここで一つ Simple is Best ってことでデザイン変更したのかなって一瞬だけ思ったが、そんなことは全く無かった。いくらなんでも時代に逆行しすぎである。

. . . 閑話休題 . . .

ひとまずアップグレードプロセスに問題があるのだろうと踏んだので、調べるためにLibertyリリースのdeb-src行をリポジトリに追記して、openstack-dashboardのdebパッケージを落としてくる。

$ sudo echo "deb-src http://ubuntu-cloud.archive.canonical.com/ubuntu trusty-updates/liberty main" >> /etc/apt/sources.list.d/cloudarchive-liberty.list
$ sudo apt-get update
$ sudo apt-get source openstack-dashboard
$ tar zxvf horizon_8.0.0-0ubuntu2~cloud0.debian.tar.gz
$ cd debian

README.sourceを開くと早速以下の様なことが書いてあった。

During the Juno/14.10 development cycle, use of xstatic packages was introduced
so that CSS, JS and other static assets did not have to be embedded in the
horizon source tree.

怪しい、すごく怪しい。

ついでに、Icehouseリリースに遡ってソースを落としてくると、今度はREADME.compressionというファイルに以下のことが書いてある。

Until this can be scripted and integrated into package build, updating the
pre-compressed static CSS and JS requires a some manual steps:

   sudo apt-get install python-lesscpy python-openstack-auth python-compressor
   quilt pop top
   ./debian/rules refresh-static-assets

ふむ。

rulesファイルとかちゃんと読めば、きちんとした原因が判明するだろう。

が、僕はこの時点で完全に力尽きていた。

唯一分かっていることは、一度JunoリリースのHorizon(Django含む)のパッケージを全て削除してLibertyリリースのパッケージを入れなおせば、問題なく動くということである。なお、この事象は、JunoからKiloに上げた際には発生しない。JunoからLiberty、もしくはKiloからLibertyにアップグレードした場合にのみ発生するのである。

というわけで、詳細知ってる人がいたら教えて下さい、お願いします;)

あと、Canonicalの中の人はこのdebパッケージどうにかして下さい:-(

アップグレードの終わり

ここまででOpenStack環境のアップグレードが完了となる。当然だが、こんな作業をマニュアルでやっていたら、いつか腱鞘炎になる。それが嫌なら、ChefとかPuppetとかAnsibleとかそういうの使ってやったほうがいい。たぶん。

お疲れ様でした:-)

その後の話

RFC3442(クラスレス静的ルート)問題

これはneutron-dhcp-agentのお話である。皆さん、RFC3442をご存知だろうか?僕は最近まで知りませんでした(すいません)。基本的にアドレスやルートの配布はDHCPに頼ることとなる。そこで、DHCPの仕様を拡張し、IPアドレスをアサインする際に静的ルートテーブルも同時に配布する仕組みが導入された。それが、『クラスレス静的ルート』(RFC3442)である。

RFC 3442 - The Classless Static Route Option for Dynamic Host Configuration Protocol (DHCP) version 4

Junoリリース時点でRFC3442実装に対する対応はされていたそうだが、どうやらきちんと動いていなかったようだ。それがKiloリリース時点でバグ改修されており、見事Libertyリリースではちゃんと動くようになったのである。

何がどう問題だったのかというと、この実装がキチンと動いたことにより、使用していたExternal Networkのサブネットの組み方が間違っていたことが判明したのである。どう間違っていたのかを記すことは止めておくが、一つ言えるのはとにかく大変だったということである。

サブネットについてはネットワークのCIDRを変更すると事象が治るということが分かったのだが、Neutron APIからCIDRの変更が出来ないということも判明した。仕方ないので、Neutronデータベースのsubnetsテーブルに対して直接UPDATE文を実行する、という最終手段を取ることで解決した(おい)。

アップグレード作業から得た教訓

事前の検証は絶対必要

本番環境でのアップグレードを実施するまでに、本番と同等構成による新規でLiberty構築を1回と、事前にJunoの同等構成の検証環境を作っておき、そこからのアップグレードテストを1回やった。ちなみに今回の話は検証環境で起こった話です。おかげで本番環境ではすんなりアップグレードが出来ました。

どうしてもアップグレードが必要というわけでないのならやらないに越したことはない

OpenStackの各バージョンはリリースから約14ヶ月でEOLを迎える。つまり、リリースから約14ヶ月はBugfixがバックポートされるので、それでお茶を濁すというのもあり。もしくは、リリースタイイングごとにKeystoneだけアップグレードして、その他のコンポーネントはRegionをきちんと定義して小さくOpenStackクラスターを作っていくという手もある。当然、構築したOpenStackクラスターそのもののEOLを定義していく必要がある。

問題はアップグレード後にも起こる

アップグレード後に初めて気付く問題もたくさんある。事前にLaunchpadからバグやKnown Issueは確認して、アップグレードをするかどうかの判断基準にするとよい。とはいえ、リリース直後にアップグレードするとなると、それはただの人柱であり、バグがそもそもLaunchpadに登録されてない、なんてこともある。

最後に

ちなみに今日は僕の誕生日。