以下のテキストは、執筆時当時の情報を元に書いたものであり、 現在の情勢にそぐわないことを含む場合があるので注意されたい。 また、テキストは最終提出原稿で校正を経る前のものなので、実際にUNIXUSER 本誌に記載されたものとは異なる。誤字脱字等そのままである。
致命的な誤り以外は加筆修正等は行なわないので情報の鮮度に気をつけつつ 利用して欲しい。
→目次
註: 本記事は当初Part2として執筆したが前後の記事のバランスを 考えてPart3として掲載された。
Part II ファイルサーバ管理テクニック
■バックアップの必要性
UNIXを利用しはじめた人によるFAQに次のようなものがある。
「間違ってファイルを消してしまいましたが復活できませんか?」
残念ながら、ほぼ間違いなく「不可能」である。最近では復活を試みるツールが
あるようだが、それを使う場合も、誤って消したあと直ちにシステムをシングル
ユーザモードに落さないと、その他のプログラムによって消されたファイルの占
有していた領域を再利用され、復活の可能性は急速にゼロに近づいていく。いず
れにせよ、「一度消してしまったものを戻そう」というアプローチは、非常にコ
ストがかかる割りに成功率も低い。また、ファイルを失うことは、人為的ミスで
起きるばかりでなく、ハードディスクの破損など、システムトラブルでも起きる
ことがある。このようなことを考慮すると、あらかじめ「バックアップを取って
おく」ことのほうがはるかに低コストで、なおかつ失ったファイルを取り戻せる
可能性も非常に高い。
このようなことは、実は誰でも「頭では」理解していることなのだが、なかなか
実行に移せないことが多い。いくらバックアップの方がコストがかからないといっ
ても、最初にバックアップを行なうまでには、やり方を調べたり、バックアップ
計画を立てたり、実際にその設定をしたりと、多少の手間はかかる。また、結局
のところ、バックアップの重要性は実際に身をもって痛感しないと(実際に大事
なファイルを消失する体験をしないと)本当の意味では理解できない。
「備えあれば憂いなし」
これを災難に遭う前に実践できる管理者が良き管理者といえよう。
■バックアップのいろいろ
「バックアップ」とはどういう意味だろう。単純に英単語の意味に立ち戻って考
えると、もともとあるファイルシステムの「予備」をつくる、という意味である。
一般的に最初に思い浮かべるバックアップとしては、ファイルシステムをテープ
ドライブなどにコピーするものがあるだろう。テープドライブ以外のメディアに
コピーを取る場合を含め、ある時点でのファイルシステムの「スナップショット」
を別の場所に取ることは、いわば「静的なバックアップ」を取ることにあたる。
いっぽう、記憶デバイスを二重化(あるいはそれ以上に)して、ファイルの書き込
みに冗長性を持たせておくと、デバイスのどれかが故障しても、「生き残った」
デバイスだけを使うことで、すぐに最新の状態のまま継続運用ができる。このよ
うな「動的なバックアップ」は、一般的には「ミラーリング」と呼ばれ、代表的
なものでは RAID-1 が該当する。
主に利用者が抱く良くある誤解の一つに「RAID-1でミラー化しておけば万全だ」
といったものがある。確かにHDDの単体故障が起きた場合は最小限の時間で何ご
ともなかったように復旧できる。しかし実際にはディスクコントローラ自体が逝っ
てしまったり、計算機本体に故障が発生したりする場合もありえ、その場合は代
替部品が届くまでの間、ファイルシステムにアクセスできない状態が続く。そし
て何よりも忘れてならないのは、「動的バックアップ(ミラーリング)では人為的
なミスによるファイル消失は保護できない」という点である。実際のところ、ハー
ドウェアトラブルよりも、オペレーションミスによる誤消去の方が発生頻度は高
く、それも大事なファイルに限ってミスを冒してしまうことも多い。もちろん、
ファイルの移動/削除操作は慎重に慎重を重ねて行なうべきなのは言うまでもな
いが、「転ばぬ先の杖」を用意しておくことはそれ以上に重要だ。
■動的バックアップ(HDDのミラー化)
形あるものは必ず壊れる。というのは文学的表現だけでなく、計算機を利用して
いるときにも痛感させられる。「形あるもの」といえば全ての部品が該当するが、
そのなかでも「可動部を持つもの」はとくに壊れやすい。まさにハードディスク
がその運命下にある。とはいえ、メモリなどの可動部の無い部品と比較しての話
であって現在では故障率は十分に低い。確率論を利用するとこのような装置を使
う場合、並列利用すると故障率が無視できる程に低減できる。たとえば、1年後
の故障率を1%とした場合、これを2台並列利用すると装置全体の1年後の故障率は
2台とも故障した場合であるから0.01%となりかなり低下する。実際には、複数台
のHDDの故障は完全な独立事象ではないし、ディスクコントローラの故障確率を
考える必要もあるので計算どおりには行かない。しかしデータが取りだせなくな
るのは、2台がほぼ同時に壊れた場合に限られることを考えれば、HDDを並列利用
することの効果の高さは理解できるだろう。
一般的には、HDDの並列化には RAID-1 方式を利用する。RAID(Redundent Array
of Independent/Inexpensive Disks) には、ディスクアレイをどのように利用す
るかに応じて RAID-0, RAID-1, RAID-3, RAID-4, RAID-5, RAID-0+1, ... など
いくつかの分類があるが、ディスク内容の単純な多重化を行なうのが RAID-1 で
ある。
RAID-1 では同じサイズの二つのディスクを並列に使う。一つのデータの書き込
みを二つのハードディスクに同時に行なう【図 ち】。
----[図 ち RAID-1の動作イメージ]-----------------------------------------
ABCDE (データの書き込み)
↓
↓
__←← →→ __
/ \ / \
|\__/| |\__/|
| | | |
| A | | A |
| | | |
| B | | B |
| C | | C |
| D | | D |
| | | |
| E | | E |
| | | |
\__/ \__/
-------------------------------------------------------------------------
RAIDの実現方式には以下の二つがある。
* Hardware RAID
ハードウェアレベルでRAIDを実現。システムからは単一ディスクに見
えるので利用にあたっての特別な設定作業は不要。専用ハードウェア
を導入することになるのでそれなりの金額的コストはかかる。
* Software RAID
OSやディスクドライバレベルでソフトウェア的に実現されているRAID
システム。最近のUNIXシステムでは標準装備されているケースが多く
なっているので、並列化用のHDD以外の費用は発生しない。システム
内部で実現している分、Hardware RAID に比べてパフォーマンス的に
少々不利である。OSが起動してからRAIDを認識するので、ブートパー
ティションには使えない場合が多い。
最近では個人レベルで十分購入可能な RAID コントローラも出回っているので、
Hardware RAIDの導入を検討しても良いだろう。Software RAID も
DiskSuite(Solaris), RAIDframe(NetBSD, OpenBSD), ccd-driver(NetBSD,
FreeBSD, OpenBSD), vinum(FreeBSD), raidtools(Linux 2.4, etc.) などが手軽
に利用できるようになっているため、これを機会に設定に取り組んでみてもらい
たい【コラム】。データの安全性を重視するパーティションにはすくなくとも
RAID-1 は装備しておきたい。
----[コラム 1 ccd-driver による RAID-1]-----------------------------------
NetBSD, FreeBSD, OpenBSD と、PC-UNIXのなかで最も多くのシステムで共通して
利用できるのが ccd - Concatenated Disk Driver である。ファイルシステムの
ミラーリングを行なう実際の例を見て雰囲気を感じとってもらいたい。
ccdは、その名の通り複数のディスク(パーティション)を複数つなげて一つの
virtual disk を作るためのドライバだ。ccdでは複数のディスクを
* 直列に繋いで(ストライピングして)利用
* 並列に繋いで(ミラーリングして)利用
* 両者の組み合わせ
で結合して使うことができる。ストライピングとは【図 り】のように、データ
の書き込みを複数のディスクに分散させることで、データの読み書きを向上させ
ることを狙っている(もちろん各ディスクが独立してデータ書き込みが行なえる
デバイス構成でないと効果は期待できない)。
----[図 り ストライピングの動作イメージ]-----------------------------------
ABCDE (データの書き込み)
↓
↓ (倍容量のディスク)
__←← →→ __ ____
/ \ / \ / \
|\__/| |\__/| / \
| | | | (論理的には ) |\ /|
| A | | | (右のように見える) | \____/ |
| | | | → | |
| | | B | | A |
| C | | | | B |
| | | D | | C |
| | | | | D |
| E | | | | E |
| | | | \ /
\__/ \__/ \____/
-------------------------------------------------------------------------
ここではccd-driverを利用したディスクのミラーリングの設定を紹介する。
ccdを利用するには ccd-driver の組込みが必要である。カーネルconfigファイ
ルに
pseudo-device ccd 4 # concatenated disk devices
を追加してカーネルを作りなおしてリブートする。FreeBSD(4.x)の場合はccdド
ライバもモジュール化されているのでこの作業は不要である。
続いて二つのディスクを確保する。IDEドライブを利用する場合は、プライマリ
IDEとセカンダリIDEに分けて配置してあるものが望ましい。それぞれに全く同じ
サイズのパーティションを作成する。パーティションの作成方法については
disklabel(8) を参照して欲しい。たとえば、二つのHDD上に作成した同サイズの
パーティションをそれぞれ /dev/wd1e, /dev/wd2e と仮定する。
続いて、ミラーリングに必要な情報を /etc/ccd.conf ファイルに作成する。た
とえば以下のように記述する。
# /etc/ccd.conf
# Configuration file for concatenated disk devices
# ccd ileave flags component devices
ccd0 64 6 /dev/wd1e /dev/wd2e
flagsの部分はミラーリングを意味する 0x4 が含まれるようにしておく(表C1-1)。
[表C1-1 ccdconfig(8)のflags値]
CCDF_SWAP 0x01 Interleave should be dmmax
CCDF_UNIFORM 0x02 Use uniform interleave
CCDF_MIRROR 0x04 Support mirroring
CCDF_PARITY 0x08 Support parity (not implemented yet)
ここでシステムをリブートするか、
# ccdconfig -C
とすることで、ccd0 デバイスが有効になる。/dev/ccd0 はあたかも新しいディ
スクデバイスのように利用できるので、ディスク全体を利用したい場合は
/dev/ccd0c を newfs したのちに、いずれかのディレクトリにマウントして全く
普通どおりに使うことができる。また、大きなままでは使いづらいという場合も
ccd0 をさらにdisklabelコマンドでパーティション分けして
8 partitions:
# size offset fstype [fsize bsize bps/cpg]
c: 58879232 0 unused 0 0 # (Cyl. 0 - 28749*)
e: 2032622 0 4.2BSD 1024 8192 16 # (Cyl. 0 - 992*)
f: 12195738 2032622 4.2BSD 1024 8192 16 # (Cyl. 992*- 6947*)
g: 44650872 14228360 4.2BSD 1024 8192 16 # (Cyl. 6947*- 28749*)
のように細切れで使うこともできる。この例では、ccd0(58879232blocks=28GB)の
論理ディスクを ccd0e(約990MB), ccd0f(約6GB), ccd0g(約21GB) のパーティショ
ンに分割して利用している。
このように、ccdによるディスクミラーリングの設定を行なうことは非常に簡単
で、しかも一度設定してしまえばその後はいっさい管理の手間が掛からない。問
題は設定するときよりもむしろ障害発生時で、一台のHDDが壊れたときの予行演
習をしておかないと肝腎なときに役に立たない。
かりに、今回の例の2台目のディスク(wd2)が壊れたとしよう。これはシステムの
メッセージログにエラーが表示され始めるので常に観察していれば気がつくだろ
う。ディスクのハードウェアエラーを確認したら、システムを止めシングルユー
ザモードで再起動し /etc/ccd.conf を修正する。
# ccd ileave flags component devices
#ccd0 64 6 /dev/wd1e /dev/wd2e
ccd0 64 2 /dev/wd1e
flagsからミラーリングを表す値4を引き、コンポーネントデバイスから不調になっ
た /dev/wd2e を削除する。ccd.conf の修正が終わったら
# ccdconfig -C
# mount /dev/ccd0c /mnt
などとしてみて、中のファイルを正常に見ることができるか確認する。問題が無
さそうなら、念のためリブートからやりなおし、何ごともなかったかのように平
常運転に復帰することを確認する。
さらにいえば、調達した新品のHDDをもう一度ccd0に組み込むところまでの予行
演習をしなければ万全な備えとはいえない。これについては、ccd-driver はす
こし面倒で、最初に二つのコンポーネントデバイスの中味を完全に同期させない
とうまくいかないため、一度ccd0の内容を別パーティションに待避してから、
ccd0を組みなおし元に戻す方が早いかもしれない。DiskSuiteやvinumでは自動的
に同期の取り直しをしてくれるのでこれらが使える環境の人はそちらを試してみ
るのも良いだろう。
以上のように、たいした投資も必要とせず設定的にも簡単な Software RAID は
手軽に信頼性を向上させる手段として有効である。今後HDDを増設する場合は必
ず2本単位で導入するようにして常にミラーリング化して利用することをお勧め
する。
--[コラム 1 ここまで]--------------------------------------------------------
■静的バックアップ
ファイルシステムのある時点のスナップショットをとる、静的バックアップにつ
いて考えよう。バックアップを取るメディアとしては身近なところで、
* テープデバイス
* MOやCD-R(W)などの可換ディスク
* HDD
などが考えられる。このうち、MOやCD-Rは容量の観点からファイルシステム全体
のバックアップを取るには厳しい。その分、取り扱いが簡単なので個人レベルで
重要なファイルを含むディレクトリのバックアップを取るのには適していると言
える。この場合は、単純にディレクトリのコピーを行なえば良いだけなので、本
稿では扱わないものとする。残る、テープデバイスとHDDをバックアップ先とす
る方法について、その方針と周辺技術を解説しよう。
●テープデバイスへのバックアップ
伝統的なバックアップと言えばやはりテープデバイスへのものだろう。ここで
は標準的なバックアップツールとして、dump/restore, tar を利用する方法を
簡単に解説する。
・テープデバイスファイル
テープデバイスファイルはシステムによって異なる。テープドライブがどの
デバイス名でアクセスできるかはmt(1)のman pageを見れば分かるだろう。
代表的なシステムとデバイスの例を【表 わ】にまとめておく。
----[表 わ テープデバイスファイル名の例]------------------------------
システム デバイスファイル(raw)
*BSD /dev/rst*, /dev/nrst*
CAM化後のFreeBSD /dev/rsa*, /dev/nrsa*
Linux /dev/st*, /dev/nst*
SunOS 4.x /dev/rst*, /dev/nrst*
SunOS 5.x /dev/rmt/*, /dev/rmt/*n
----------------------------------------------------------------------
デバイス名について共通していえることは、デバイスファイルの先頭にnの
ついたものとそうでないものが用意されているということである。一般に、
磁気テープには、音楽用テープと同様、複数のファイルをシーケンシャルに
書き込むことができる。nのつくデバイス名でアクセスすると、一つのファ
イルのアクセスが終わっても、テープを「巻戻さない」(No rewind)。複数
のファイルを持つテープを作ったり読んだりする場合には「nつき」を参照
するようにする。
・テープ利用上の注意
dump/restore、tarいずれを使うにせよ、テープに保存したらあとでどうやっ
て戻すかの情報をメモしておかないと肝心のときにリストアに苦労すること
になる。また、複数のファイルを含むテープを利用するときは戻したい内容
を含むファイル位置までテープを読み進める。このために利用するmtコマン
ドについても習熟しておく必要があるだろう。
たとえば、テープデバイスが /dev/nrst0 であるとし、3番目のファイルの
先頭位置にテープを進めたい場合は、
(/bin/sh)
# TAPE=/dev/nrst0
# export TAPE
# mt fsf 3
とする。mtコマンドは環境変数TAPEをテープデバイスとして認識するので、
繰り返しmtコマンドを利用する場合は設定しておくと良いだろう。mtで利用
できる標準的なテープ操作コマンドを【表 か】にまとめておく。
----[表 か mtで利用できるコマンドの抜粋]------------------------------
コマンド 働き
rewind テープの巻戻し
fsf N ファイルをN個分読み進める
bsf N ファイルN個分戻る
asf N 絶対指定のファイル位置移動
offline テープを巻戻してからテープを取りだす
erase テープの全消去
----------------------------------------------------------------------
テープにバックアップを取っているときも同様だが、巻戻し処理、erase処
理などは時間のかかる処理なのでハングしたと思ってむやみに C-c で止め
たりしないよう注意したい。
・dump/restoreでの磁気テープへのバックアップ
dumpコマンドは、ファイルやディレクトリを対象とするのではなく、一つの
ファイルシステムのバックアップを取るためのユーティリティである。バッ
クアップに特化したものであるためさまざまなオプションが用意されている。
単純に一つのファイルシステムのバックアップを取る場合は以下のようにな
る。
# dump 0Buf テープの大まかな容量(KB) /dev/nrst0 /home
----[表 よ dumpコマンドの主なオプション]------------------------------
オプション 意味
-0 .. -9 ダンプレベルの指定
-B R レコードサイズ(単位は-bで指定したもの)
-b B ブロックサイズをBに(kilobytes)
-f FILE ダンプ先ファイルの指定
-u ダンプした日付を記録
----------------------------------------------------------------------
ダンプレベルの数値は0が「フルバックアップ」を意味する。ダンプレベル
が0より大きい場合は、「インクリメンタルバックアップ」を意味し、それ
以前の、ダンプレベルがより低いバックアップ時以降に修正されたファイル
のみの「差分バックアップ」を取ることを意味する。また、テープの容量を
指定するオプションがいくつかあるが(-Bもその一つ)、これを指定しないと
ほとんど記録しないうちにテープ交換を求めて来ることがある。本来はテー
プの容量を正しく計算してオプションに与えるべきだが、最近のテープドラ
イブではテープ終端を正しく検出してくれるものが多いので、指定するオプ
ションでは十分大きな値を指定すればよいことが多い(経験則)。このあたり
は利用しているシステムと、テープドライブの組み合わせで決まることなの
で、運用に入る前に実際にさまざまなパラメータを与えて試してみた方が良
いだろう。また、FreeBSDのdumpコマンドのように、テープ終端検出をテー
プドライブ任せにする -a オプションがあるものはそれを利用するのも手だ
ろう。
dumpを用いて取ったバックアップは、restoreコマンドで書き戻す。全ての
ファイルを書き戻す場合は、書き戻したいディレクトリに移動してから
# restore rf /dev/nrst0
などとする。全てのファイルでなく、一部だけ取りだしたいときはインタラ
クティブモードが利用できる。これらに関してはrestore(8)のman pageを参
照して予行演習しておきたい。
・tarによる磁気テープへのバックアップ
tarの使い方は慣れているのではなかろうか。tarコマンドも環境変数TAPEを
参照してデフォルトのテープデバイスを決定することができるので、連続し
て作業する場合は設定しておくと効率的だろう。
(/bin/sh)
# TAPE=/dev/nrst0
# export TAPE
# cd /
# tar cv /home
とすると、/home ディレクトリ以下の内容を全て /dev/nrst0 で表される磁
気テープにtarアーカイブとして格納する。テープから書き戻す場合、xオプ
ションを使えば良い。
# mt rewind
# tar xvp
などとするとカレントディレクトリにテープに保存した内容が展開される。
このように非常に簡単に取り扱えるいっぽう、コマンドの打ち間違いで一瞬
にしてバックアップテープを失うことがあるので気をつけたい。バックアッ
プテープから、データを戻そうとして
# tar cv
と打ってしまってせっかくのバックアップを一瞬にして消してしまうという
のは、良く語り継がれる失敗の一つである(脚注:cとxがqwerty配列の隣同士
なのも恨めしい)。
●HDDへのバックアップ
最近の周辺機器事情を考えると、ハードディスクの大容量化が速いテンポで進
み続け、もはやそのバックアップを取るためにはDDS4などの最新式テープデバ
イスを持って来なければ間に合わない状況となって来た。それもあと1年もし
たらDDS4でも1本では足りない事態が訪れそうである。加えて、ハードディス
クの容量あたりの価格低下もとどまるところを知らない様相で、バックアップ
目的に最新式の大容量テープドライブを買うことを考えたら、IDEのハードディ
スクを何台か買ってしまった方がコスト的にも速度的にも有利であるとさえ言
える。たとえば原稿執筆時の秋葉原価格をみると、コンシューマ向けIDEディ
スクは100GB(7200rpm)のもので3万円中盤で、80GB(5400rpm)のものは2万円を
切っている。これらのディスクほぼいっぱいにデータを格納し、そのバックアッ
プを取ることを考えた場合、もう何台か同じサイズのディスクを買ってそれを
バックアップ先にすることは十分に有利な選択となっている。
・HDDへのバックアップを取る方針
通常HDDは計算機に常に接続して利用するものであるから、そのメリットを
活かしたバックアップ方法を取りたい。静的なバックアップでは人為的なミ
スによるファイル消失にたいする補償も可能なので、できるだけそれが機能
するような方針でバックアップ計画を立てると良い。たとえば、各ユーザの
ホームディレクトリ(/home)のバックアップを別のディスク(/mirror/home)
に取るとしよう(図い)。ここではバックアップ先の、/mirror/home が常に
マウントされているかだとか、ローカルディスクかNFS先だとかは問わない。
----[図 い]--------------------------------------------------------------
+-------------- host-1 ----------------+
| (/) |
| +-------+-----+---+-------+ |
| (/etc) (/home) (/usr) (/mirror) |
| \ +---+ |
| →→→→→→→→→(home)|
+---------------------------------------
-------------------------------------------------------------------------
このような場合、定期的に /home から /mirror/home にバックアップを取
ることになる。この場合どのような頻度で取るかが問題になる。たとえば、
週に一回取ることを考えよう。この場合何かの不具合で /home パーティショ
ンが壊れてしまったときに、/mirror/home に残っている内容は、最長で一
週間、最短で直前のものである。平均値で考えることとすると、3.5日以前
の内容に戻るということは、ここ1〜2日のうちに作成したファイルは取り戻
せないということになる。
では、なるべく最新のファイルも取り戻せるようにバックアップ頻度を上げ
て毎日夜中にバックアップを取るようにしたらどうだろう。この場合(夜中
に大きな作業をする人がいないと仮定すると)前日に作成したファイルもほ
ぼ確実に取り戻せることになるので助けられる確率が高まる。ただ、これは
ハードウェア故障による消失の場合だけで、人為的ミスのファイル消失には
短いバックアップ頻度が仇となることもある。たとえば、間違って消したこ
とに数日後に気づくことも良くあることで、この場合バックアップ頻度が短
ければ短い程、あっというまに「ファイルを消したこと」も /mirror/home
に反映されて、結果的に失ったファイルを取り戻せない。
このようなジレンマを解決するためには、頻度の違うミラーリングを2世代
以上で保持すると良い。たとえば、一日一度、週に一度、月に一度、のミラー
リングを流れるように3世代持たせた例が【図ろ】である。
----[図 ろ]--------------------------------------------------------------
+-------------------+ +---------------------+
| /home | 午前5時 | /mirror/daily/home |
| |→→→→→ | |
+-------------------+ +---------------------+
↓午前4時
+---------------------+ +---------------------+
|/mirror/monthly/home | 午前3時 | /mirror/weekly/home |
| |←←←←← | |
+---------------------+ +---------------------+
-------------------------------------------------------------------------
この例では、より下流側のバックアップを、上流側のバックアップ時刻より
早めに設定しているところがポイントである。こうすることで、当日事故で
消されたファイルが /mirror/daily/home に反映される前に
/mirror/weekly/home にコピーされるので、dailyにないファイルもweekly
を当たれば見付かる、といった可能性が高まる。もちろんこれは、いずれの
バックアップ経路も最大1 時間で終わると仮定しての計画なので、状況に応
じてバックアップ時刻を設定すると良いだろう。1時間というと短く感じる
かもしれないが、以降で解説するrsyncなどの差分バックアップツールを使
えばかなり大きなディレクトリツリーのバックアップもすばやく終わること
が期待できる。
・HDDへのミラーリング手順
実際に、あるディレクトリツリーの内容を別のパーティション内のディレク
トリにコピーする方法をいくつか紹介しよう。ミラーリングには
* フルコピー
ミラー先の内容にかかわらず全てのファイルをコピー
* 差分更新
ミラー元とミラー先を比較して更新があったもののみコピー
の二種類の方式がある。数MB程度のサイズの小さなディレクトリや、全体的
に更新の激しいディレクトリツリーを別箇所に保存する場合はつねにフルコ
ピーしてしまった方が効率が良いだろうし、それ以外なら差分更新が良いだ
ろう。これらは色々な方法が存在するが、「ファイルのパーミッションなど
も全て保存して」コピーする方法は限られている。初心者が陥りがちなミス
として、cp コマンドでディレクトリツリーをコピーすることが挙げられる
が、伝統的な cp -r ではシンボリックリンクもコピーされないし、タイム
スタンプもコピーされないので、元のディレクトリの内容を正確に反映した
ミラーリングはできないことを覚えておかなければならない(★は)。
----[★ は]----------------------------------------------------------------
このような知識はきわめて基本的なものであるが、筆者の経験を思い起こして
みると「ディレクトリコピーにcpはつかっちゃだめだ、tarを使え」ということ
は先輩に叱られて覚え、そして後輩に伝えた知識である。たとえmanを良く読ん
だとしてもこのような知識は得られない。書籍などによりUNIXを使い始めた場
合、ともすればこのようなことは経験せずに時が過ぎてしまうのではなかろう
か。そうした可能性を考えて、できるだけ基本常識にも触れて解説を進めた。
---------------------------------------------------------------------------
シンボリックリンク情報なども保存してディレクトリツリーをコピーする方
法をいくつか紹介しよう。以下の全てのコマンド例は、カレントディレクト
リにある src/ ディレクトリを、/dest/ ディレクトリにコピーする(結果と
して /dest/src/ にコピーができる)ことを行なうものである。後に述べる
もの程近代的(?)なツールである。
* tar
テープドライブへのバックアップや、日常的にファイル群を一つの
.tar アーカイブにまとめる時に利用する tar コマンドをpipeで連鎖
してディレクトリコピーする。
# tar cf - src | (cd /dest; tar xvpf -)
pipe(|)の右辺にある括弧はサブシェルの起動で、括弧内の複数のコ
マンドを一つの環境で実行する。つまり、/destにcdしたら、その状
態を保持したままtarコマンドを起動するので、結果として /dest ディ
レクトリに src/ ディレクトリの tar アーカイブが展開される。多
少古いUNIXでも、/usr/local が壊れてしまったシステムでも、この
伝統的tarコマンドはつかえるので、pipeとサブシェルを使うこの方
法は絶対に覚えておいた方が良い。
* GNU tar
PC-UNIXで標準装備されている tar は GNU tar である。バックアッ
プを、より効率的に取るためのオプションが多数追加されている。完
全なバックアップを望む場合は以下のようにすると良いだろう。
# tar -cf - src --atime-preserve | tar -xvpf - -C /dest
--atime-preserve オプションはミラー元の各ファイルのatime(参照
時刻)を変えないことを指定する。ファイルシステムの掃除をすると
きなど、「長期間参照されていないファイルを消す」ようなジョブを
走らせているようなパーティションでは --atime-preserve をつけた
方が良い。pipeの右辺のgtarにつけた -C は対応するディレクトリに
移動してから処理を行なわせるオプションで、結果として /dest に
src/ が展開される。
また、--one-file-system オプションをつけると指定したソースディ
レクトリのサブディレクトリが違うファイルシステム(パーティショ
ン)だった場合にはそのサブディレクトリ以下はアーカイブしない。
たとえば、
# tar -zcf rootfs.tar.gz -C / . --one-file-system
とすると、ルートパーティションの内容だけを rootfs.tar.gz にま
とめることができる。--one-file-system オプションは1文字オプショ
ン l でも代用可能。
* GNU cp
GNUのcpコマンド。伝統的なcpの機能に加えて、シンボリックリンク
やスペシャルファイルなども正確にコピーできる。また、GNU tar 同
様 --one-file-system オプションもあり、特定のパーティションの
みのバックアップを取ることが容易になっている。ディレクトリまる
ごとコピーは
# cp -a src /dest
のように -a (archive)オプションだけでできてしまうのが魅力だ。
* rsync
以下で説明する差分更新に特化したツールだが全体コピーも手軽にで
きる。リモートホストとのファイル同期で使うことが多いが、ローカ
ルファイルシステム間のコピーも可能である。
# rsync -aH src /dest
以上は、ミラーリングの初期操作として、ミラー元ディレクトリの内容全体
をコピーする方法を紹介した。続いて、既にミラー先にすこし前の時刻のス
ナップショットが存在する場合に、更新されたファイルだけをコピーするツー
ルを紹介する。これができるのは、上で説明した中では GNU cp とrsyncの
みである。
* GNU cp
アーカイブコピーモードの -a オプションにくわえ u オプションを
加えると更新ファイルのみをコピーする。
# cp -auf src /dest
fオプションは、readonly ファイルなども強制的にコピーする(force
オプション)ために必要。実をいうと、筆者は「ディレクトリまるご
とコピー」は永年使ったtar と訣別して GNU cp を愛用するようになっ
た(★に)。
----[★ に]----------------------------------------------------------------
とはいえGNU cpの使えない状態で作業することもあるので、伝統的tarコマンド
のコピーを忘れてもいいというわけではない。
---------------------------------------------------------------------------
ただし、GNU cp では更新ファイルのコピーはできても、消去されたファイ
ルの反映はできない。この場合はrsyncを使う。
* rsync
更新ファイルのみをコピーし、なおかつミラー元で消されたファイル
はミラー先からも消し去り完全に二つのディレクトリの同期を取るた
めには、
# rsync -auH --delete src /dest
とすれば良い。
・ミラーリングの自動化
ミラーリング作業を手動でやっていてはそれだけで忙殺されてしまう。実際
にはバックアップ先のパーティションを用意したら、あとはcronで自動化し
ての運用になるだろう。
ここでは、ケーススタディとして
* 小規模ディレクトリの tar によるバックアップ
* 大規模ディレクトリの rsync によるバックアップ
をとりあげてそれぞれについて処理を自動化する方法の一例を紹介しよう。
【小規模ディレクトリの tar によるバックアップ】
設定ファイルが他数含まれる、/etc などはシステムの根幹にかかわるので
非常に重要である。できれば過去にさかのぼって何世代も取っておきたい。
cvsなど、ソースプログラムを効率良く世代管理するためのツールを使えば
スマートに多世代バックアップが可能だが、もともとバックアップを取るべ
きサイズがちいさいので、毎日まるごと tar アーカイブをつくってしまっ
てもたかがしれている。
そこで、重要なファイルを毎日tar.gzアーカイブにまとめる処理を自動化し
てみよう。毎日 tar.gz アーカイブを作るだけでは、これから先延々ファイ
ルが増えていってしまうので何日かしたら、古いアーカイブファイルを消す、
という工程が必要になる(図 へ)。
----[図 へ]--------------------------------------------------------------
今日のetc.tar.gz
昨日のetc.tar.gz
2日前のetc.tar.gz
3日前のetc.tar.gz
4日前のetc.tar.gz
5日前のetc.tar.gz ← 5日以上経ったものは、もう要らない
6日前のetc.tar.gz ← ので消す!
:
-------------------------------------------------------------------------
このような世代保存管理として真っ先に思い浮かべるのは、syslogによるロ
グファイルのローテートだろう。現在使用しているメッセージファイルは
/var/log/messages に、これがあるサイズを超えたら圧縮して
/var/log/messages.0.gz にうつす。ただし、そのときに既に存在する
messages.0.gz は messages.1.gz に、messages.1.gz は messages.2.gz に、
と循環させて最終的に3番以降は保持せず消す、のようなアルゴリズムであ
る。もちろんその方法を取っても構わないが、筆者の経験から得た結論とし
てはファイルローテート方式は以下の点で芳しくない。
* ファイルの名前が変わるので、本当に見たいファイルを探すのに手間取る
* ちょっと気になるファイルを見た場合でもうっかりすると自動的に消
されてしまう(手許にコピーしておけばいいだけの話だが…)
* ローテート処理はアトミックでないので中断させると整合性が取れな
くなる
* ローテートさせるためのスクリプトを作るのは簡単そうに見えて、様々
な異常時処理を入れなければならず実はそれほど易しくない
これよりも、最初から違うファイル名でアーカイブを作り、ファイルの被参
照時刻が一定期間を過ぎたものを消していく方式にするとスクリプトも組み
易く、あとから参照するときの勝手も良い。/etc ディレクトリをバックアッ
プする場合を例にスクリプトを作成してみたものが【リスト と】である。
----[リスト と]--------------------------------------------------------------
1 #!/bin/sh
2 # /etc ディレクトリの世代バックアップ
3 # tar.gzアーカイブは /mirror/systemfiles/ に置く
4 umask 077
5 today=`date '+%Y%m%d'`
6 backupdir=/mirror/systemfiles/
7
8 # 今日のバックアップの作成
9 cd /
10 tar vzcf $backupdir/etc-$today.tar.gz etc
11
12 # 毎月01日のものは長期バックアップ用として消さないように工夫する
13 find $backupdir -name 'etc-*01.tar.gz' -exec touch '{}' \;
14
15 # 5日以上参照していないものは消す
16 find $backupdir -atime +5 -exec rm '{}' \;
-----------------------------------------------------------------------------
この場合、実際に /etc が修復不可能なほど壊れたときにはシステムが立ち
上がらなくなるので /mirror/systemfiles/ の中味はできればリモートホス
トのファイルシステム上にあった方が役に立つ可能性が高い。これに関して
は、後述するリモートホストへのミラーリングを参考に、【リスト と】と
組み合わせたスクリプトを作って欲しい。
ちなみに筆者は、システムの /etc と、kernelファイルとkernel configファ
イルをこの方法でバックアップし、全てのアーカイブをLAN内の複数のホス
ト全てに保持させている。
【大規模ディレクトリの rsync によるバックアップ】
単純化して【図 ほ】のような2世代ミラーリングを自動化するも
のとし、ミラーリングに用いるツールとしてrsyncを用いることを仮定する。
----[図 ほ]--------------------------------------------------------------
+-------------------+ 上流 +---------------------+
| /home | 午前5時 | /mirror/daily/home |
| |→→→→→ | |
+-------------------+ +---------------------+
↓午前4時 下流
+---------------------+
| /mirror/weekly/home |
| |
+---------------------+
-------------------------------------------------------------------------
まず最初に一つのバックアップ処理にかかる時間の見積りを出しておく。こ
れが2時間程度かかるならば、二つのミラーリング処理の間隔を3時間程度に
すれば良いだろう。これを自動化する場合、次のような crontab エントリ
を作っておけば良いだろう。
#minute hour mday month wday who command
#上流
0 5 * * * root /etc/backup-1
#下流
0 4 * * * root /etc/backup-2
/etc/backup-1, /etc/backup-2 は以下のようなものとする。
--[/etc/backup-1]--------------------------------------------
#!/bin/sh
PATH=$PATH\:/usr/local/bin
rsync -auvH --delete /home /mirror/daily
--[/etc/backup-1]--------------------------------------------
#!/bin/sh
PATH=$PATH\:/usr/local/bin
rsync -auvH --delete /mirror/daily/home /mirror/weekly
●リモートホストへのバックアップ
ネームサーバもメイルサーバも、セカンダリサーバを設置することを前提とし
た設計となっている。それらのセカンダリサーバは、プライマリサーバから地
理的にもネットワーク的にも離れたところに置くのが望ましいとされている。
なぜかというと、サーバがシステムダウンする原因として停電なども考えられ、
そのような場合は同じ組織にセカンダリサーバが置いてあっても同時に落ちて
いることになり、セカンダリとして機能しないことになるからである。
ファイルシステムのミラーリングをする場合も、実はこのことが当てはまる。
もし、日常の活動に密着したファイルをどこかのサーバに置いている場合、出
先からアクセスしようと思ったときにネットワークダウンしていたら、どうあ
がいてもファイルを見ることはできない。また、自然災害などで計算機一式が
壊れるような場合、二重化してあるディスク装置まるごと壊れることもありう
る。そのような可能性を考えると、やはり重要なデータは地理的にも離れたと
ころにバックアップを置いた方が安心だ。
また、離れたホストへのバックアップでなくとも、「firewall の内側に置い
たユーザ用マシンのデータ領域にWWWコンテンツを置かせ、Global IPアドレス
エリアに置いた対外向けWWWサーバにデータをミラーリングする」、などの規
則で運用することなどもあり、リモートホストへのデータのミラーリングは覚
えておきたい技術の一つだろう。
###もしかしたらここに Private IP Network から Global Zone のwwwサーバへ
###のミラーの絵を入れた方が説得力があるかも
・NFSを介したミラー
もっとも単純な方法は、NFSを利用してリモートホストのファイルシステム
をマウントして、ローカルディスクどうしのミラーを行なうのと同じ手順を
取ることである【図ぬ】。
----[図 ぬ NFSを介したミラー]------------------------------------------------
+----------- File Server --------------+
| (/) |
| +-------------+------+-----------+ | +------- Backup Server -------+
| | | | (/)
| (/home) →→→→→|→→|\ +------+-----+
| export | | →(/mnt) (/mirror)
| | | -+---+-----
| | | (home)
うまく書けないんですが、fileserver:/home を backupserver:/mnt にmountし
て backupserver:/mirror/home にミラーしている絵
-----------------------------------------------------------------------------
技術的にとくに難しい点はないので、とくに詳しく掘り下げる必要は無いだ
ろうが、以下の点に注意することは忘れないようにしたい。
* 閉じたネットワークで使う
* File Server 側でexport許可を出しすぎない
* Backup Server 側ではファイルを壊さないように readonly マウント
する(File Server側でreadonly許可のみを出しても良い)
手軽に使えるNFSだが、セキュアなネットワークだけで使うように気をつけ
たい。
・rsyncを利用したリモートホストへのミラー
NFSは利用できる条件が限られるので、必ずしも使えないことが多いだろう。
そのような場合の代替手段としてrsyncを使う方法を紹介しよう。
rsync は通常は rsh を利用してリモートホストとのファイル交換を行なう
が、-eオプションにsshを指定することで ssh を利用するように変更できる。
これにより、リモートホストとファイルを同期させるときのユーザ認証を、
SSHのもつ、より安全な方式で行なうことができるようになる。最終的な目
標はcronによる自動化だが、認証手順が確立するまでの部分は手動で確かめ
よう。今回の仮想目標として
* ファイルサーバホスト(sv)の sv:/home の内容を、
ミラー保持ホスト(mi)の mi:/mirror/sv/home にミラーリングするこ
と
というものを設定しよう【図 る】。
----[図 る]--------------------------------------------------------------
sv mi
+-------------------+ +---------------------+
| /home | rsync | /mirror/sv/home |
| |→→→→→ | |
+-------------------+ +---------------------+
ホスト sv の/home を、ホスト mi の /mirror/sv/home へrsyncでミラーリング
している感じの絵。
-------------------------------------------------------------------------
また、ここで利用するSSH実装系として、OpenSSH 2.x を仮定する。
まず最初に、ミラーリングをroot権限でやるとしたら、mi側でsvからのroot
アクセスを許可する必要がある。この場合、mi側で root ユーザのRSA認証
ログインを許可しておくと良いだろう【註 を】。/etc/sshd_config の
PermitRootLogin を以下の値にする。
------[ ホスト mi の /etc/sshd_config]------
# PermitRootLoginの値を修正↓
PermitRootLogin without-password
without-password という指定は「パスワードなし」という意味ではなく、
「/etc/passwdでは認証しない」という意味で、結果としてRSA認証(または
DSA認証)のみで認証通過することができる。
----[註 を]--------------------------------------------------------------
マニュアルsshd(8)によると、PermitRootLogin の値がnoであっても、「sshでコ
マンドを指定してなおかつRSA認証した場合」はrootアクセスできるとある。し
かし筆者の環境でこのような結果をどうしても得られなかったので
without-password を指定しての解説とした。
-------------------------------------------------------------------------
続いてmiにログインするために必要なRSAキーを、ホストsv上のrootユーザ
にて作成する。サーバ側でrootになり、ssh-keygen コマンドでキーを作成
する。-f オプションにあたえるファイル名は svmi_rsaid でなくとも良い。
sv# ssh-keygen -f ~/.ssh/svmi_rsaid
Generating RSA keys: Key generation complete.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /root/.ssh/svmi_rsaid.
Your public key has been saved in /root/.ssh/svmi_rsaid.pub.
The key fingerprint is:
12:34:56:78:9a:bc:de:f0:12:34:56:78:9a:bc:de:f0 root@sv
途中聞いて来るパスフレーズは空のまま進める。rootユーザのホームディレ
クトリが /root だと仮定すると、/root/.ssh/svmi_rsaid.pub にRSA公開鍵
ができているので、これをmi側の ~root/.ssh/ の authorized_keys に追加
する。この段階で、svからmiにむかってrootログインがRSAauthentication
で可能か確かめる。
sv# ssh -i ~/.ssh/svmi_rsaid mi
Last login: Sat May 26 21:10:12 2001
Copyright (c) 1980, 1983, 1986, 1988, 1990, 1991, 1993, 1994
The Regents of the University of California. All rights reserved.
FreeBSD 4.3-RELEASE (mi) #1: Thu May 24 00:34:54 JST 2001
このように、パスワードなしでログインできるのは sv 側の秘密鍵ファイル
を参照している証拠である。もし/etc/passwd的パスワードを聞いて来るよ
うなら
* 公開鍵の mi:~root/.ssh/authorized_keys への登録がうまくいっていない
* miのsshd定義ファイル(sshd_config) で RSAAuthentication が無効
になっている
などの可能性が考えられるので見直す必要がある。
これで下準備は完了である。確認のためサーバ側で手動で rsync を起動し
てみよう。
sv# rsync -e 'ssh -i /root/.ssh/svmi_rsaid' -auvzH --delete \
/home mi:/mirror/sv/home
パスワード(パスフレーズ)なしでミラーリングが始まれば自動化も可能であ
る(コラム2)。見やすくするため上記のコマンドラインをシェルスクリプト
化し
----[/etc/svmi-backup.sh]-------------
#!/bin/sh
PATH=$PATH\:/usr/local/bin \
RSYNC_RSH="ssh -i $HOME/.ssh/svmi_rsaid" \
rsync -auvzH --delete /home mi:/mirror/sv/home
などとしたものをcronに登録する。
#minute hour mday month wday who command
0 3 * * * root /etc/svmi-backup.sh
これで毎日午前3時に sv から mi へのバックアップが自動的に行なわれる
はずである。ちなみに筆者の実用経験では、rsyncの-zオプション(圧縮)を
利用すると、2GBのパーティションを128kbpsの低速回線を利用しても十分実
用的な所要時間でミラーリングが完了した。xDSLの普及により家庭LANのイ
ンターネット常時接続が手軽に利用できるようになった現在、rsyncを利用
してのリモートバックアップを個人レベルでも検討してみてはいかがだろう。
----[コラム 2 パスフレーズなしでのミラーリングは不安?]--------------------
本文中 sv から mi へのsshログインがパスフレーズなしで行なわれるのを見て
不安に思う読者は多いのではないだろうか。すこし考察してみよう。
まず大前提として、miがsvのバックアップを許すということはmiとsvは互いに信
頼関係にあるホストどうしであると仮定する。どちらかのホストでroot権限をも
てる管理者は、もう一方のホストでもrootになれる。通常、バックアップ先に選
ぶホストはそういう関係にあるホストだろう。その前提をふまえて考えよう。
svからのRSA認証ログインが可能ということは、公開鍵をmi側で
~root/.ssh/authorized_keys に登録している必要があるということで、このた
めにはmi側で正当にrootになれるものの作業が必要ということである。いっぽう、
この公開鍵に対応する秘密鍵はsv側のrootでなければ作れず、なおかつrootでな
いと読み出せないものであるから、この秘密鍵を使ったmiへのrootログインがで
きるということは、sv側でroot権限を持っているということである。ということ
は、このRSAキーを不当に使ったアクセスがあるとしたら、sv側のrootが破られ
ているということにほかならないので、その場合パスフレーズなしのRSA認証を
利用していなかったとしても被害範囲は変わらないだろう。
ただ、それでも「なんとなく不安」という感じが残る場合は、パスフレーズを登
録して運用することもできる。この場合ミラーリングのためのrsyncを起動する
と秘密鍵のパスフレーズを聞いて来るのでcronのような自動処理ができなくなり
そうだが、いくつか回避策がある。
ひとつは、rsyncのオプション --password-file を利用する方法で、これを利用
するとインタラクティブにパスワードを聞かなくなる。ただ、秘密鍵ファイルも
パスワードファイルも同じroot権限でアクセスできるなら、その計算機をどこか
に持ち去り、シングルユーザモードに落とせる人間なら誰でも読めることになり、
それはパスフレーズを付けていないのと等価になる。
もう一つの方法は ssh-agent を利用する方法である。パスフレーズは管理者の
頭の中だけに保存するようにして、システム起動後少なくとも一回は ssh-agent
にパスフレーズを登録するようにすれば、svを持ち去られた場合もmiに被害はお
よばなくなる。このための Tips を紹介しよう。これも、OpenSSH 2.x を前提と
している。
1. sv→miの RSA Key をパスフレーズつきで作成(または ssh-keygen -p でパ
スワードをつける)
2. ssh-agent を起動しssh-addで sv→mi 用のパスフレーズを登録
sv# eval `ssh-agent`
sv# ssh-add ~/.ssh/svmi_rsaid
この処理はシステム起動後一度はインタラクティブに行なう。
3. 起動している(複数の) ssh-agent のうち、svmi_rsaid の RSA key を保持
しているものを探し、それを環境変数 SSH_AUTH_SOCK に自動設定してから
rsync するスクリプトを作成する。たとえばリスト[C-2-1]のようになる。
---[リスト C-2-1]-----------------------------------------------------
#!/bin/sh
SSHsockprefix=/tmp/ssh # ssh-agent socket file prefix(バージョン依存)
ReportTo=root # ssh-agent未登録時のレポート先
dotsshdir=/root/.ssh/ # ~root/.ssh を指定
# ~root/.ssh/svmi_rsaid.pub よりfingerprintを得る
svmi_id=`awk '{print $3}' $dotsshdir/svmi_rsaid.pub|head -1`
PATH=/usr/local/bin:$PATH
setSocket () { # $1に指定されたfingerprintをもつagentのソケットファイルを探す
patn="$1"
SSH_AUTH_SOCK=''
socks=`echo ${SSHsockprefix}*/*agent*`
case $socks in
*\*) ;;
*)
for socket in $socks; do
if SSH_AUTH_SOCK=$socket ssh-add -L | fgrep $patn > /dev/null; then
SSH_AUTH_SOCK=$socket
export SSH_AUTH_SOCK
return
fi
done
;;
esac
}
# setSocket()にて $SSH_AUTH_SOCK を獲得
setSocket "$svmi_id"
if [ ${#SSH_AUTH_SOCK} = 0 ]; then
# ssh-addしていない場合の警告をメイルで送信
cat <<_EOM_ | Mail -s "DNS sync failure" $ReportTo
Hi, this is /home rsyncer on `hostname`.
Authorized keys not registered in ssh-agent.
Please invoke ssh-agent with identity keys.
# eval \`ssh-agent\`
# ssh-add /root/.ssh/svmi_rsaid
_EOM_
exit 1
fi
# for debug
## ssh-add -l; ssh mi w
# SSH_AUTH_SOCKを正しく得てrsync
rsync -auvzH --delete -e ssh /home mi:/mirror/sv
----------------------------------------------------------------------
さらにこれでも不安なときは(^^;)、
* mi側で別の sshd_config ファイルを用いてsshdを別ポートで動かす
* そのポートはsvからしか受けないようにする
(パケットフィルタリングにtcp_wrappersを使う場合は、
別ポート用のsshdを違う名前にすると良い)
* root@svからmiにつなぐ場合はroot以外のユーザとしてログインする
(これをたとえば、svmirror ユーザとする)
* mi側でsudoを利用して、svmirror ユーザはrsyncだけ NOPASSWD で起動でき
るような sudoers ファイルを作成しておく
(sudoersの例:)
svmirror mi= NOPASSWD: /usr/local/bin/rsync
* sudo経由でrsyncを起動するスクリプトを作成
(たとえば /etc/sudorsync)
#!/bin/sh
exec /usr/local/bin/sudo /usr/local/bin/rsync "$@"
* mi側の ~svmirror/.ssh/authorized_keys に sv のrootのRSAkeyを登録
* sv 側から
rsync -e 'ssh -l svmirror -i /root/.ssh/svmi_rsaid' \
--rsync-path=/etc/sudorsync \
-auvzH --delete /home mi:/mirror/sv
によりミラーリング。
などとすると良いだろう。いずれにしてもsv側のセキュリティ管理をしっかりし
ているかどうかが大きな鍵をにぎっているので、パスフレーズ登録の有無は誤差
の域を出ないかもしれない。なお、今回紹介した手法はあらゆるユーザのファイ
ルを持つディレクトリのミラーリングを想定したため、root権限での起動となっ
たが、たとえばWWWコンテンツのような場合はwwwユーザの権限で動かせば良いの
でより安全にミラーリングすることが可能だろう。
----[コラム 2 ここまで]---------------------------------------------------
yuuji@