yumによる多数のサーバーへのパッチ適用を自動化する | A Day In The Boy's Life

A Day In The Boy's Life

とあるエンジニアのとある1日のつぶやき。

サーバーの台数が増えてくると個々のサーバーへのパッチの適用作業というのは結構手間になってきたりもします。
しかも、パッチを適用することでそれらのパッケージを利用したプログラムとかに影響が出たりして、十分に検証期間を取った上で本番環境に適用したいというニーズが出てきたりもします。


というわけで、単純なyum関連のコマンド(yum、yumdownloader、createrepo)を利用してパッチの適用作業を自動化する方法について書いてみたいと思います。
なお、環境はRedHat5系をベースにして書いています。



社内配布用のリポジトリサーバーを構築する


まず、システム構成のイメージとしては下記のようになります。


A Day In The Boy's Life
社内用のリポジトリ兼検証用サーバーは通常通り外部のリポジトリから最新パッチを適用していき、その影響調査および本番サーバーに配布するためのリポジトリサーバーという役割を担います。
詳しくは後述しますが、もう少し本番適用までを慎重にしたいとか、複数のサーバーで影響調査をしたいという場合は、リポジトリサーバーをもう1台増やしたりして、1台目は最新を常に当てる、2台目は検証が取れた本番適用予定のパッチだけがリポジトリに登録されている、というような構成も取れたりします。


まず最初に、検証用サーバーでは通常通りyum updateで最新のパッチを適用していきます。


# yum update -y

この辺もCronに設定しておけば自動化できるでしょう。
当てたくないパッチなどがある場合は、yum.confのexcludeに適用対象外のパッケージ名を指定しておきます。


exclude=kernel*

次に、検証用サーバーに適用したパッケージをダウンロードしてリポジトリを生成します。
このリポジトリを本番サーバーが参照します。
以下のようなバッチを作成して、検証用サーバーに適用しているパッケージのソースをダウンロードします。


#!/bin/sh
DESTDIR=/path/to/htdocs/rpm/rhel-x86_64-server-5/dev/
rpm -qa | xargs rpm -q --qf '%{NAME}\n' | sort | uniq | xargs yumdownloader --destdir=$DESTDIR
createrepo -q --update $DESTDIR

yumdownloader(createrepoやreposyncコマンドも同様)は、yum-utilsに含まれますので環境に存在しない場合はyum経由でインストールしておきましょう。
後述するreposyncコマンドを使って、外部リポジトリ(rhelやrpmforgeなど)を丸ごとコピーしてもよいですが、かなり容量も大きくなりますし不要なものも多いので、サーバーに適用しているパッケージだけをダウンロードするようにしています。
パッケージダウンロード後は、createrepoコマンドでリポジトリを生成しています。
リポジトリのディレクトリは別のサーバーからHTTP経由でアクセスするため、ドキュメントルート以下にしておきます。


yum update後に上記のバッチによってパッケージをダウンロードしておけば、検証環境に適用しているパッケージとリポジトリに登録しているパッケージのバージョンをそろえることができます



本番環境のリポジトリ参照先を変更


社内配布用のリポジトリができたので、次は本番サーバーがこのリポジトリを参照するように設定変更します。
yum-fastestmirrorを導入している場合、参照先のリポジトリが自動的に選択されるので、まずはこれらのプラグインを動かさないようにしておきます。


[main]
enabled = 0
gpgcheck = 1

enabledを0にしてプラグインの読み込みを禁止します。
次に、検証用のリポジトリを参照するようにyumの設定ファイルを追加します。


[dev]
name = RHEL $releasever - www.example.com -
baseurl = http://192.168.0.100/rpm/rhel-x86_64-server-5/dev/
enabled = 1
protect = 0
gpgkey = file:///etc/pki/rpm-gpg/RPM-GPG-KEY-rpmforge-dag
gpgcheck = 0

baseurlには、検証用のサーバーのリポジトリのURIを指定します。
設定後は、yumコマンドでリポジトリの参照先が検証用サーバーを向いているか確認しておきましょう。


# yum check-update
Loaded plugins: security
Excluding Packages in global exclude list
Finished
Skipping security plugin, no data

httpd.x86_64                2.2.3-83.el5_10           dev
httpd-devel.i386            2.2.3-83.el5_10           dev
httpd-devel.x86_64          2.2.3-83.el5_10           dev
httpd-manual.x86_64         2.2.3-83.el5_10           dev

右端に参照しているリポジトリ名(dev)が表示されます。
あとは、任意のタイミングでyum updateを本番サーバーで動かすようにCronにでも登録しておけばパッチが適用されていきます。

この仕組みでは、検証用サーバーのリポジトリを更新しない限り、本番サーバーへ勝手にパッチが当たることがありません
検証用サーバーで十分に検証期間を取った上で本番に適用していきたいということであれば、この辺は運用の組み立て方の話でありますが、


1. 検証用サーバーのパッチ適用は手動で行う(毎週月曜日とか。その週は検証期間としておく)

2. 検証期間で問題なければ日曜日の深夜に検証用サーバーのリポジトリを自動更新する

3. 毎週月曜日の早朝にCronでパッチを自動適用する

4. 以下、次の最新パッチを検証用サーバーにあてていく


というような動かし方ができます。
要は2.を実行しない限り、3.のパッチの本番適用は空振りします(その前に全てのパッチが当たっているはずなので)。
1.2.にどれだけの期間をおくのか、全部自動化してしまうのか、心配だから2.までを手動で行うのか、といった調整でどうにかなるんじゃないでしょうか。


予断にはなりますが、社内リポジトリサーバーを複数たてる(ステージング用のサーバーを作るとか)場合ですが、リポジトリ間の同期が必要です。
その場合は、reposyncコマンドを使ってリポジトリのコピーを作成することができます。
こちらも下記のようなバッチを作っておけば便利です。


#!/bin/sh
DESTDIR=/path/to/htdocs/rpm/rhel-x86_64-server-5/
reposync -p $DESTDIR
createrepo -q --update $DESTDIR/dev/

検証用サーバーでは、外部のリポジトリを参照してパッチを全て当てておき、適用したパッチも含めた最新のリポジトリを作成する。
ステージングサーバーでは、検証用サーバーのリポジトリを上記のバッチで複製しておく(複製のタイミングは少しずらしておく)。
本番サーバーのリポジトリはステージングサーバーのリポジトリを参照する。


といったことをしておけば、万が一検証用サーバーに変なパッチが当たってもそのパッチの本番適用を防ぐことはできると思います。


yum updateだけで対処しようとすると、適用するタイミングでパッチの種類やバージョンが変わったりするので、社内向けにリポジトリサーバーを立てるだけでも結構この辺の作業は楽になるんじゃないかと思います。