
はじめに
私たちのチームでは、OpenStackを活用して利用者に仮想環境を提供しています。OpenStackは、オープンソースソフトウェア(OSS)のクラウド・コンピューティング・プラットフォームです。仮想環境上でのマシン、ストレージ、ネットワークなどのリソースを統合管理できるインフラストラクチャを提供します。私たちはこのOpenStackをオンプレミス環境で数年前に導入しました。しかし、当時購入したサーバーの保守期限が近づいていたため、これを機にサーバーの更改作業を進めることになりました。前回に引き続き、この記事ではblockノードのサーバー更改中に発生したトラブルと、その対応内容について紹介します。
サーバー更改の概要
既存OpenStack環境
構築当初のOpenStackのバージョンはMitakaでしたが、その後バージョンアップを行い更改当時はQueensを使用していました。ノードの構成は以下のとおりです。
No. | ノード | 台数 | OS | 更改する台数 |
---|---|---|---|---|
1 | controller | 2 | CentOS 7.5.1804 | 2 |
2 | network | 2 | CentOS 7.5.1804 | 2 |
3 | compute | 8 | CentOS 7.5.1804 | 4 |
4 | block | 4 | CentOS 7.5.1804 | 3 |
5 | object | 3 | CentOS 7.5.1804 | 3 |
OpenStackのblockノードの主なコンポーネントはCinder※1になります。CinderのバックエンドにはCeph※2を使用しています。
※1:OpenStackが提供するブロック・ストレージ・サービスです。仮想マシンに対して永続的なブロックストレージを提供し、データの読み書きを行うためのインターフェースを実現します。ユーザーは、ボリュームの作成、スナップショットの管理、ボリュームのアタッチとデタッチを簡単に行うことができます。詳細についてはOpenStack公式 ⧉を参照してください。
※2:OSSの分散ストレージソフトウェアです。OpenStackのCinderと連携して高可用性、冗長性、スケーラビリティーを提供します。詳細についてはOpenStack環境でBlockストレージを増設する - 基礎知識編を参照してください。
OS選定と更改方針
OSは「Ubuntu」を採用しました。選定理由は以下のとおりです。OSのバージョンに関する詳細は、前回の記事を参照してください。
候補 | 採否の理由 |
---|---|
Ubuntu | OpenStack公式 ⧉でサポートが明記されており、LTS(Long-Term Support)のバージョンがあるため |
CentOS Stream | 安定版の先行確認環境の位置付けであり、運用上の安定性に懸念があるため |
Rocky Linux AlmaLinux | CentOSの後継として利用されているが、OpenStack公式 ⧉ではサポートが明記されていないため |
サーバー更改後の構成は以下のとおりです。
No. | ノード | 台数 | OS | 更改対象 |
---|---|---|---|---|
1 | controller | 2 | Ubuntu 18.04.6 LTS | ○ |
2 | network | 2 | Ubuntu 18.04.6 LTS | ○ |
3 | compute | 4 | CentOS 7.5.1804 | ー |
4 | compute | 4 | Ubuntu 18.04.6 LTS | ○ |
5 | block | 1 | CentOS 7.5.1804 | ー |
6 | block | 3 | Ubuntu 18.04.6 LTS | ○ |
7 | object | 3 | Ubuntu 18.04.6 LTS | ○ |
blockノードは初期構築時には3台で構成されていましたが、その後、運用の拡張に伴い1台を追加しており、サーバーの保守期限が異なるため今回の更改対象は3台となります。この結果、旧blockノードと新blockノードではOSバージョンが異なるため、互換性に注意が必要です。
更改方法
OpenStackで作成したボリュームは、バックエンドのCephによって複数のblockノードに分散して格納されます。この際、ボリュームが管理されるblockノードはいずれか1台のノードに関連付けられます。そのため、ボリュームの管理ノードを移行する必要があり、構築当初の手順書とOpenStack公式 ⧉の手順を参考に、以下の手順で移行を計画しました。まず、新blockノードをOpenStack環境に追加します。その後、旧blockノードが管理しているボリュームの管理ノードを新blockノードに移行し、最後に旧blockノードをOpenStackから削除します。この手順を繰り返し、すべてのボリュームの移行を完了させる計画です。
移行対象ボリューム
旧blockノードが管理ノードとなっている以下の全てのボリュームの管理ノードを新blockノードに移行する必要があります。
※3:OpenStackが提供するデータベースサービスです。データベースのデプロイ、管理、スケーリングを簡単に実行できる仕組みを提供します。詳細についてはOpenStack公式 ⧉を参照してください。
※4:OpenStackが提供する共有ファイル・システム・サービスです。仮想マシンやアプリケーションが利用可能な共有ファイルシステムの作成、管理をサポートします。詳細についてはOpenStack公式 ⧉を参照してください。
移行方法
ボリュームの数が多いため、openstack
コマンドを用いたスクリプトを作成し、移行作業を自動化します。このスクリプトは、利用者へのサービス影響を最小限に抑えるために、at
コマンドを使用し、夜間に実行します。
【スクリプトの処理内容】
- ボリュームの状態を確認する。
- ボリュームがインスタンスにアタッチされている場合、インスタンスの状態を確認する。
- インスタンスの状態が起動状態の場合、インスタンスを停止状態にする。
- インスタンスからボリュームをデタッチする。
- 指定したblockノードにボリュームを移行する。
- 2.でボリュームがインスタンスにアタッチされていた場合、インスタンスにボリュームをアタッチする。
- 3.でインスタンスの状態が起動状態だった場合、インスタンスを起動状態にする。
- 上記1~7の処理を全ボリュームについて繰り返す。
スクリプトで使用するopenstack
コマンドは以下のとおりです。
openstackコマンド | 用途 |
---|---|
openstack volume show <ボリュームID> | 指定したボリュームの状態を確認する |
openstack server add volume <インスタンスID> <ボリュームID> | 指定したインスタンスに指定したボリュームをアタッチする |
openstack server remove volume <インスタンスID> <ボリュームID> | 指定したインスタンスから指定したボリュームをデタッチする |
openstack volume migrate --host <blockノード名>@ceph#ceph <ボリュームID> | 指定したblockノードに指定したボリュームを移行する |
openstack server show <インスタンスID> | 指定したインスタンスの状態を確認する |
openstack server stop <インスタンスID> | 指定したインスタンスを停止状態にする |
openstack server start <インスタンスID> | 指定したインスタンスを起動状態にする |
トラブルシューティングで説明しますが、この移行方法で問題が発生したため、スクリプトは使用しませんでした。
トラブルシューティング
ボリュームの移行ができない
検証環境でopenstack volume migrate
コマンドを実行した結果、エラーは表示されなかったもののボリュームの移行には失敗しました。
# openstack volume show 6727920d-aec0-4eea-ac73-20aa766a4b40+--------------------------------+--------------------------------------+| Field | Value |+--------------------------------+--------------------------------------+:| id | 6727920d-aec0-4eea-ac73-20aa766a4b40 |:| os-vol-host-attr:host | block2@ceph#ceph |:# openstack volume migrate --host block202dev@ceph 6727920d-aec0-4eea-ac73-20aa766a4b40# openstack volume show 6727920d-aec0-4eea-ac73-20aa766a4b40+--------------------------------+--------------------------------------+| Field | Value |+--------------------------------+--------------------------------------+:| id | 6727920d-aec0-4eea-ac73-20aa766a4b40 |:| os-vol-host-attr:host | block2@ceph#ceph |:
そこで、問題解決のためにcinder
コマンドを調査したところ、ボリューム移行に関連するcinder migrate
コマンドを見つけました。このコマンドを使って再度ボリュームの移行を試みましたが、同様にエラーメッセージは表示されず、ボリュームの移行も成功しませんでした。さらにcinder
関連のコマンドを調査していると、cinder-manage volume update_host
というコマンドが存在することに気付きました。このコマンドは、--currenthost
オプションで現在の管理ノードを指定し、--newhost
オプションで新しい管理ノードを指定することで、ボリュームの管理ノードを変更できます。実際にこのコマンドを実行したところ、ボリュームの管理ノードが無事に移行されました。
# cinder migrate 6727920d-aec0-4eea-ac73-20aa766a4b40 block202dev@ceph# openstack volume show 6727920d-aec0-4eea-ac73-20aa766a4b40+--------------------------------+--------------------------------------+| Field | Value |+--------------------------------+--------------------------------------+:| id | 6727920d-aec0-4eea-ac73-20aa766a4b40 |:| os-vol-host-attr:host | block2@ceph#ceph |:# cinder-manage volume update_host --currenthost block2@ceph --newhost block202dev@ceph# openstack volume show 6727920d-aec0-4eea-ac73-20aa766a4b40+--------------------------------+--------------------------------------+| Field | Value |+--------------------------------+--------------------------------------+:| id | 6727920d-aec0-4eea-ac73-20aa766a4b40 |:| os-vol-host-attr:host | block202dev@ceph |:
この操作はボリューム単位ではなく、ノード単位での移行が可能であるため、移行方法で説明した当初予定していたスクリプトによる夜間実行ではなく、更改作業の中で手動によるコマンド実行としました。
CephのOSD IDが若番から採番される
Cephはオープンソースの分散ストレージシステムで、柔軟性と拡張性が高い特徴を持っています。CephのOSD(Object Storage Device)は、通常、1つの物理ディスクまたはパーティションを管理します。OSDは、Cephストレージクラスター内でデータオブジェクトを保存し、データの読み取り、書き込み、レプリケーションを行います。今回更改する各blockノードには、Cephのデータを格納するためのディスクが6つあります。それに対して、OSDはそれぞれ6つ構成されており、これによりストレージの冗長性とスケーラビリティーが確保されています。具体的には、複数のOSDが協力し合ってデータの管理を行い、どのOSDが故障してもデータが失われないように設計されています。当環境のCephのバージョンはJewelです。OSDの追加はceph-deploy osd prepare
コマンドを使用して、新しいOSDを準備します。OSDの削除にはceph osd rm
コマンドを使用して、不要になったOSDをクラスターから削除します。
検証環境で新blockノード1にOSDを追加すると、新blockノード1にOSD IDは24~29が採番されました。
項番 | 旧block ノード1 | 旧block ノード2 | 旧block ノード3 | 旧block ノード4 | 新block ノード1 |
---|---|---|---|---|---|
1 | osd.0 | osd.6 | osd.12 | osd.18 | osd.24 |
2 | osd.1 | osd.7 | osd.13 | osd.19 | osd.25 |
3 | osd.2 | osd.8 | osd.14 | osd.20 | osd.26 |
4 | osd.3 | osd.9 | osd.15 | osd.21 | osd.27 |
5 | osd.4 | osd.10 | osd.16 | osd.22 | osd.28 |
6 | osd.5 | osd.11 | osd.17 | osd.23 | osd.29 |
旧blockノード1のOSDを削除すると、旧blockノード1に割り当てられていたOSD IDの0~5がなくなりました。
項番 | 旧block ノード1 | 旧block ノード2 | 旧block ノード3 | 旧block ノード4 | 新block ノード1 |
---|---|---|---|---|---|
1 | osd.0 | osd.6 | osd.12 | osd.18 | osd.24 |
2 | osd.1 | osd.7 | osd.13 | osd.19 | osd.25 |
3 | osd.2 | osd.8 | osd.14 | osd.20 | osd.26 |
4 | osd.3 | osd.9 | osd.15 | osd.21 | osd.27 |
5 | osd.4 | osd.10 | osd.16 | osd.22 | osd.28 |
6 | osd.5 | osd.11 | osd.17 | osd.23 | osd.29 |
新blockノード2にOSDを追加すると、新blockノード2にOSD IDが若番の0~5で採番されました。
項番 | 旧block ノード1 | 旧block ノード2 | 旧block ノード3 | 旧block ノード4 | 新block ノード1 | 新block ノード2 |
---|---|---|---|---|---|---|
1 | osd.0 | osd.6 | osd.12 | osd.18 | osd.24 | osd.0 |
2 | osd.1 | osd.7 | osd.13 | osd.19 | osd.25 | osd.1 |
3 | osd.2 | osd.8 | osd.14 | osd.20 | osd.26 | osd.2 |
4 | osd.3 | osd.9 | osd.15 | osd.21 | osd.27 | osd.3 |
5 | osd.4 | osd.10 | osd.16 | osd.22 | osd.28 | osd.4 |
6 | osd.5 | osd.11 | osd.17 | osd.23 | osd.29 | osd.5 |
私たちの期待としては、以下のように新しいblockノード2に対してOSD IDが連番で採番されることでした。
項番 | 旧block ノード1 | 旧block ノード2 | 旧block ノード3 | 旧block ノード4 | 新block ノード1 | 新block ノード2 |
---|---|---|---|---|---|---|
1 | osd.0 | osd.6 | osd.12 | osd.18 | osd.24 | osd.30 |
2 | osd.1 | osd.7 | osd.13 | osd.19 | osd.25 | osd.31 |
3 | osd.2 | osd.8 | osd.14 | osd.20 | osd.26 | osd.32 |
4 | osd.3 | osd.9 | osd.15 | osd.21 | osd.27 | osd.33 |
5 | osd.4 | osd.10 | osd.16 | osd.22 | osd.28 | osd.34 |
6 | osd.5 | osd.11 | osd.17 | osd.23 | osd.29 | osd.35 |
旧blockノード1のOSDを削除したことで、OSD IDが空きとなり、その空いたIDが新しいblockノードに採番されてしまったようです。運用上は特に問題はありませんが、管理上、途中から空きになったOSD IDが採番されてしまうことは避けたかったため、当初予定していた更改方法を変更しました。具体的には、すべての新blockノードでOSDを追加した後に、旧blockノードのOSDを削除する方法を採用することにしました。
ボリュームがアタッチされたインスタンスが起動できない
この問題は以前から認識していましたが、インスタンスにアタッチされたボリュームが特定の条件を満たすと、インスタンスを停止し、再び起動した際に起動できないことがありました。この条件とは、Novaのblock_device_mapping
テーブル(ボリュームの情報を管理するテーブル)のconnection_info
カラム(ボリュームにアクセスするために必要な接続情報が格納されたカラム)に含まれるCeph Monitorの情報に、変更後のblockノードの情報が含まれないことになります。ただし、この条件下でもWindowsメニューからの再起動、Linuxのrebootコマンド、OpenStackダッシュボードのインスタンスのソフトリブートなど、通常の再起動方法ではインスタンスは正しく起動することができます。block_device_mapping
のレコードは、インスタンスにボリュームをアタッチする際に作成され、その時点のCeph Monitorの情報がconnection_info
カラムのフィールドに保持されます。一方、ボリュームをデタッチすると、そのレコードは削除されます。Ceph Monitorは、OSDクラスター全体の状態を管理し、ファイルシステムやblockノードの情報を集約して一元的に監視を行います。私たちの環境では各blockノードにCeph Monitorを配置しています。そのため、私たちの環境におけるCeph Monitorの情報の組み合わせは、構築時期によって異なり、次のようになります。
構築時期 | Ceph Monitor情報 |
---|---|
初期構築時 | 旧blockノード1、旧blockノード2、旧blockノード3 |
1台追加時 | 旧blockノード1、旧blockノード2、旧blockノード3、旧blockノード4 |
今回のサーバー更改時 | 旧blockノード4、新blockノード1、新blockノード2、新blockノード3 |
初期構築時にボリュームをアタッチしたインスタンスを、今回のサーバー更改後に、インスタンスを停止して、再び起動すると同様の事象が発生することになります。インスタンスからボリュームをデタッチしてアタッチすることでこの問題を回避することは可能ですが、利用者に作業影響が出ることを考慮しました。そこで、Novaのblock_device_mapping
テーブルのconnection_info
カラムをSQLを用いて初期構築時のCeph Monitor情報から今回のサーバー更改時の状態に変更しました。
変更前:192.168.1.XX、192.168.1.YY、192.168.1.ZZは旧blockノードのIPアドレス
{ "driver_volume_type": "rbd", "connector": { "initiator": "iqn.1994-05.com.redhat:ad82a7d845b8", "ip": "192.168.1.AA", "platform": "x86_64", "host": "compute", "do_local_attach": false, "os_type": "linux2", "multipath": false }, "serial": "53378c48-6475-4e2b-92e6-39285bb9a0b1", "data": { "secret_type": "ceph", "name": "volumes/volume-53378c48-6475-4e2b-92e6-39285bb9a0b1", "encrypted": false, "keyring": null, "cluster_name": "ceph", "secret_uuid": "fd3012f4-a00c-4925-9b19-ce975271837a", "qos_specs": null, "auth_enabled": true, "hosts": [ "192.168.1.XX", "192.168.1.YY", "192.168.1.ZZ" ], "volume_id": "53378c48-6475-4e2b-92e6-39285bb9a0b1", "discard": true, "access_mode": "rw", "auth_username": "cinder", "ports": [ "6789", "6789", "6789" ] }}
変更後:192.168.1.aa、192.168.1.bb、192.168.1.ccは新blockノードのIPアドレス
{ "driver_volume_type": "rbd", "connector": { "initiator": "iqn.1994-05.com.redhat:ad82a7d845b8", "ip": "192.168.1.AA", "platform": "x86_64", "host": "compute", "do_local_attach": false, "os_type": "linux2", "multipath": false }, "serial": "53378c48-6475-4e2b-92e6-39285bb9a0b1", "data": { "secret_type": "ceph", "name": "volumes/volume-53378c48-6475-4e2b-92e6-39285bb9a0b1", "encrypted": false, "keyring": null, "cluster_name": "ceph", "secret_uuid": "fd3012f4-a00c-4925-9b19-ce975271837a", "qos_specs": null, "auth_enabled": true, "hosts": [ "192.168.1.AAA", "192.168.1.aa", "192.168.1.bb", "192.168.1.cc" ], "volume_id": "53378c48-6475-4e2b-92e6-39285bb9a0b1", "discard": true, "access_mode": "rw", "auth_username": "cinder", "ports": [ "6789", "6789", "6789", "6789" ] }}
ここで、Ceph Monitorの情報はdataセクション内のhostsとportsの部分になります。この部分を変更するSQLを実行します。今後、旧blockノード4を更改するときには、1台追加時の情報も同様に対処が必要になります。
おわりに
この記事では、OpenStackのblockノードを更改した際に発生したトラブルへの対応内容を紹介しました。この記事が、OpenStackを運用されている方や、これから導入やサーバー更改を検討される方々のお役に立てば幸いです。今後、controllerノードやnetworkノードなど、他のノードの移行に関するノウハウについても順次紹介していく予定です。