Vagrantのshell provisionerでApacheのビルド済tarボールをOSバージョン毎に作る術

Pepabo AdventCalendar 2014の10日目の記事です。昨日はあんちぽサンタ記事を見て入社したlaughkでした。明日はhisaichi5518です。

ソフトウェアのビルド方法について。

  • 今年は特にセキュリティ関連でCVE対応が多かったり
  • 経年したサービスのOSは刷新したいけど同じミドルウェアのバージョンを使いたかったり

な時に、rpmをビルドするのはしんどい(弊社は主にRHELクローンなディストリを使っています)ということで、今年は社内でVagrantを利用した、ビルド済ソフトウェアのtarボールを作るのが流行りました。

今日はその一例としてApacheのビルドについて。サンプルのプロジェクトを tnmt/vagrant-build-apache22に置きました。

git clone https://github.com/tnmt/vagrant-build-apache22
vagrant up cent6_build_apache22
vagrant up cent7_build_apache22

するだけで、CentOS6, CentOS7用のApache 2.2のビルド済tarボールが出来て、vagrant up したカレントディレクトリに配置されます。

ディレクトリ配置は

├── Vagrantfile -> vagrant/Vagrantfile
└── vagrant
    ├── Vagrantfile
    ├── build-apache2.2.sh
    └── install-facter.sh

で、スクリプトは

の2つです。今回はVagrantのVirtualBoxのイメージにhfmvagrantcloudのイメージを使っています。Vagrantfileに記載されている hfm4/centos6, hfm4/centos7がそれぞれそうですね。ビルド済みのtarボールは各OSに配置して展開するだけですぐ使えます、お手軽。

以降は何故この方法をとったかと、工夫しているについて。

何故シェルスクリプトか

大きくは2つ

  • ちょっとした修正を加えやすいようにしたい
  • OSのバージョンが変わってもそのまま同じスクリプトを利用したい

というところでしょうか。もしこれがrpmをビルドしようとするとspecファイルで差異を吸収することになりますが、シェルスクリプトの方が読み書きに慣れている人が多いのでメンテしやすさでもメリットがありました。スクリプトの内容自体はなるべく実際にビルドする手順を再現するだけのシンプルに保つように心がけています。

また、ソースの取得もシェルスクリプト内で行っているのでビルドに必要な環境(今回のサンプルにあるようなgitリポジトリ)はVagrantfileとスクリプトだけで良く、管理が楽というのもあります。1枚のスクリプトにしておくと取り回しも便利です。

Apacheの場合もパッチの追加やモジュールを同時ビルドしたり(サンプルプロジェクトではmod_extract_forwardedも同時にビルドしています)、他サービスに持っていってconfigureオプションを変えたりが簡単に出来ますし、先の例の通りOSのバージョン差も全く気にせずに済んでいるのが分かるかと思います。

facterを使ってる

これは工夫というほどではないですが。

弊社では構成管理ツールにPuppetを利用しており、社内で共用しているベースのVMイメージは既にPuppetがインストールされているため、Facterもインストール済ですが、最小構成のOSインストールイメージにはFacterがインストールされていないため、今回のスクリプトでは build-apache2.2.sh から install-facter.sh を呼び出しています。

さて、そのFacterは何に使っているかですが build-apache2.2.shこちら でOSのバージョンなどの取得に利用しています。シェルでも取れるけどこんな感じで値が取れるという例です。

platform=$(
    arch=$( facter architecture )
    os=$( facter operatingsystem )
    release=$( facter operatingsystemrelease)
    echo ${os}${release%.?}-${arch}
)

スクリプト内ではこれをビルド済みのtarボールの名前のsuffixに利用しています。

実際これをどう運用しているか

先にPuppetを利用していると書きましたが、そのリポジトリにtarボールをコミットしておき

define tarball_deploy (
  $source,
  $dest
) {

  $command = "tar xzf ${name} -C ${dest}"

  file { $name:
    source => $source,
    notify => Exec[$command],
  }

  exec { $command:
    refreshonly => true,
  }

}

のようなdefineを作っておけば

$version = "2.2.29-0"
tarball_deploy {
  "/usr/local/src/apache-${version}.tar.gz":
    source => "puppet:///modules/web/usr/local/src/apache-${version}-${os}.tar.gz",
    dest => '/usr/local';
}

といったマニフェストで展開が可能です(※ ${os}はカスタムファクター)

以上、最近はパッケージと適材適所でこのように素朴にビルドするのを組み合わせて効率化を図っています。素朴にビルドする例としては他にもanybuildを利用したものなどがあります。こちらは@lamanotramaスライドがありますので御覧ください。

はー今年は何だか色々なものをいっぱいビルドしたなー、来年は平和だといいですね…。