tkuchikiの日記

新ブログ https://blog.tkuchiki.net

【CentOS 6, Amazon Linux 対応】 unbound と ldns の RPM 作成方法

epel repo から unbound が削除されました。

追記: CentOS6 の extras に unbound が入っているという情報をいただきました。@hfm さんありがとうございます!

無いなら作りましょう、ということで RPM 作成方法です。

検証環境

手順

CentOS 6 は unbound の tarball を取得して、同梱されている spec ファイルを少し書き換えて build すれば良いのですが、Amazon Linux には unbound が依存している ldns-devel がありません。
そのため、まず ldns の RPM を作ります。

yum-builddep と spectool を使うので、以下の package をインストールします。

yum install -y yum-utils rpmdevtools

ldns

まず、ldns の tarball に spec ファイルが同梱されているので取り出します。

curl -sO https://www.nlnetlabs.nl/downloads/ldns/ldns-1.6.17.tar.gz
tar zxf ldns-1.6.17.tar.gz ldns-1.6.17/packaging/fedora/ldns.spec

ldns.spec の改行コードに CR がついているため rpmbuild に失敗するので削除します。

cat ldns-1.6.17/packaging/fedora/ldns.spec | tr -d \\r > ~/rpmbuild/SPECS/ldns.spec
## nkf でも OK
# nkf -Lu --overwrite ldns-1.6.17/packaging/fedora/ldns.spec
# mv ldns-1.6.17/packaging/fedora/ldns.spec ~/rpmbuild/SPECS/ldns.spec

そのまま spec ファイルを使うと Amazon Linux だとエラーがでます。
具体的には、

  • %{__python}python
    • /usr/bin/python が python2.7 になっていても %{__python} が python2.6 となるため、dist-package の path が 2.6 になるので no such file or directory でエラー
  • Source: の URL の typo でエラー

diff は以下のとおりです。

4,5c4,5
< %{!?python_sitelib: %global python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")}
< %{!?python_sitearch: %global python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)")}
---
> %global python_sitelib %(python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")
> %global python_sitearch %(python -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)")
10c10
< Version: 1.6.13
---
> Version: 1.6.17
14c14
< Source: http://www.nlnetlabs.nl/downloads/%{%name}/%{name}-%{version}.tar.gz
---
> Source: http://www.nlnetlabs.nl/downloads/%{name}/%{name}-%{version}.tar.gz

diff には含めていないですが、%changelog も更新しましょう。

次に、依存パッケージをインストールします。

yum-builddep -y ~/rpmbuild/SPECS/ldns.spec

tarball を ~/rpmbuild/SOURCES 以下に配置します。

spectool -R -g ~/rpmbuild/SPECS/ldns.spec
## mv でも OK
# mv ldns-1.6.17.tar.gz ~/rpmbuild/SOURCES/

準備が整ったので build します。

rpmbuild -ba ~/rpmbuild/SPECS/ldns.spec

これで ldns の RPM ができました。

unbound

まず、unbound の tarball に spec ファイルが同梱されているので取り出します。

curl -sO http://unbound.net/downloads/unbound-1.5.10.tar.gz
tar zxf unbound-1.5.10.tar.gz unbound-1.5.10/contrib/unbound.spec
mv unbound-1.5.10/contrib/unbound.spec ~/rpmbuild/SPECS/

unbound はバージョン以外は修正しなくても build できるので、 Version を書き換えます。 diff は以下のとおりです。

3c3
< Version: 1.4.18
---
> Version: 1.5.10

こちらも diff には含めていないですが、%changelog も更新しましょう。

次に、依存パッケージをインストールします。 自前の yum repo に ldns を追加していない場合は、build した RPM を予めインストールする必要があります。

rpm -ivh ~/rpmbuild/RPMS/x86_64/ldns-1.6.17-1.amzn1.x86_64.rpm ~/rpmbuild/RPMS/x86_64/ldns-devel-1.6.17-1.amzn1.x86_64.rpm
yum-builddep -y ~/rpmbuild/SPECS/unbound.spec

tarball を ~/rpmbuild/SOURCES 以下に配置します。

spectool -R -g ~/rpmbuild/SPECS/unbound.spec
## mv でも OK
# mv unbound-1.5.10.tar.gz ~/rpmbuild/SOURCES/

Docker Container 上で RPM を build する場合に root で作業を行った際、spec ファイルの permission を変更しないと error: Bad owner/group /path/to/unbound.spec というエラーがでました。
その場合は以下のコマンドを実行します。

chown root: ~/rpmbuild/SPECS/unbound.spec

準備が整ったので build します。

rpmbuild -ba ~/rpmbuild/SPECS/unbound.spec

これで unbound の RPM ができました。

まとめ

ldns と unbound は spec ファイルが用意されているので少し書き換えるだけで RPM を作ることができました。
改行コードでエラーになるという問題は初めて遭遇したので勉強になりました。

追記(2017-03-31 17:05)

unbound.spec の useradd-m がついてないため /var/unbound が作成されない問題があるようです。
以下のように修正すればよいです。

- useradd -r -g unbound -d /var/unbound -s /sbin/nologin \
+ useradd -r -g unbound -m -d /var/unbound -s /sbin/nologin \

あと、configure--with-libevent をつけて build して libevent を使うようにしないと、

$ unbound -c /var/unbound/unbound.conf
Mar 31 08:17:33 unbound[9597:0] warning: too many file descriptors requested. The builtinmini-event cannot handle more than 1024. Config for less fds or compile with libevent
Mar 31 08:17:33 unbound[9597:0] warning: continuing with less udp ports: 477

のようなエラーがでる場合がありました(パラメータを調整すれば出ないようにすることもできました)。

setusergroups の RPM spec ファイル

setusergroups については、作者の tokuhirom さんのブログを御覧ください。

supplementary groups をサポートする setuidgid であるところの setusergroups.c 書いた

supplementary groups をサポートした setuidgid が欲しいケースがある。

これを相談されたので RPM の spec ファイルを書きました。
以下を ~/rpmbuild/SPECS/setusergroups.spec として保存して、

curl -L https://github.com/tokuhirom/setusergroups/archive/master.zip > ~/rpmbuild/SOURCES/master.zip
rpmbuild -ba ~/rpmbuild/SPECS/setusergroups.spec

RPM を作成できます。
autoconf のバージョンが 2.68 以上でないと build できないので、
CentOS 6 で build する場合は base repo 以外のものを使う必要があります。

git 2.2.0 の rpm 作成方法

rpm を作成した環境は、CentOS 6.4、git 1.7.1 です。

執筆時(2014/12/15) の git 最新版は 2.2.0 でした。
git.spec が極端に変更されない限りは、
多少バージョンが前後しても同様の手順で作業できると思います。

perl-Git に、subversion-perl, perl-YAML が必要なのと、build 時に perl-ExtUtils-MakeMaker が必要だったので、BuildRequires を追加する patch を用意しました(git.spec.patch)。
patch があてられないときは、BuildRequires を直接書き換えてください。

@@ -8,7 +8,7 @@
 Group:                 Development/Tools
 URL:           http://kernel.org/pub/software/scm/git/
 Source:        http://kernel.org/pub/software/scm/git/%{name}-%{version}.tar.gz
-BuildRequires: zlib-devel >= 1.2, openssl-devel, curl-devel, expat-devel, gettext  %{!?_without_docs:, xmlto, asciidoc > 6.0.3}
+BuildRequires: zlib-devel >= 1.2, openssl-devel, curl-devel, expat-devel, gettext, subversion-perl, perl-YAML, perl-ExtUtils-MakeMaker %{!?_without_docs:, xmlto, asciidoc > 6.0.3}
 BuildRoot:     %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)

 Requires:      perl-Git = %{version}-%{release}

あと、Changelog を適宜修正すると良いと思います。
patch を作成したら、以下を実行します。

wget https://www.kernel.org/pub/software/scm/git/git-2.2.0.tar.gz
tar zxf git-2.2.0.tar.gz
mv git-2.2.0.tar.gz ~/rpmbuild/SOURCES/
yum install -y zlib-devel openssl-devel curl-devel expat-devel gettext subversion-perl perl-YAML xmlto asciidoc perl-ExtUtils-MakeMaker
patch -u git-2.2.0/git.spec < ./git.spec.patch
mv git-2.2.0/git.spec ~/rpmbuild/SPECS/
rpmbuild -ba ~/rpmbuild/SPECS/git.spec

ここまで実行すると、以下のファイルが作成されます。

git のバージョンを上げるだけであれば、
git-2.2.0-1.el6.x86_64.rpmperl-Git-2.2.0-1.el6.x86_64.rpm を入れれば良さそうなので、

rpm -Uvh ~/rpmbuild/RPMS/x86_64/git-2.2.0-1.el6.x86_64.rpm ~/rpmbuild/RPMS/x86_64/perl-Git-2.2.0-1.el6.x86_64.rpm

で upgrade 完了です。
git と perl-Git は相互に依存しているようなので、同時に upgrade(install) しないとだめでした。

$ git --version
git version 2.2.0

yum でインストールした rpm がどの repository のものか調べる

インストール済みの rpm がどの repository のものかは、yumdb コマンドで調べられます。
YumDB - yum - Trac に詳しく書いてありますが、

$ yum install -y yum-utils

して、yumdb コマンドを入れたあとに、

$ yum search from_repo REPO_NAME

で以下のような結果を得られます。

$ yumdb search from_repo epel
Plugin "replace" can't be imported
Loaded plugins: fastestmirror, remove-with-leaves
GeoIP-1.4.8-1.el6.x86_64
     from_repo = epel

GeoIP-devel-1.4.8-1.el6.x86_64
     from_repo = epel

PyYAML-3.10-3.el6.x86_64
     from_repo = epel
...

from_repo 以外にも以下の key が使えるようです。

  • checksum_data
  • checksum_type
  • command_line
  • from_repo_revision
  • from_repo_timestamp
  • reason
  • releasever
  • installonly

それぞれの key については man を参照してください。

ただし、

Since yum 3.2.26 yum has started storing additional information about installed packages in a location outside of the rpmdatabase.

とあり、

yum の version が 3.2.22 な CentOS 5 では使えないようで、
yum-utils を install しても yumdb コマンドは install されませんでした(確認した CentOS 6 は 3.2.29)。

PhantomJS 1.10 の RPM を生成できない場合の対処法

git checkout 1.9 をしないで、master の PhantomJS 1.10(development) を rpmbuild する際の手順です。
1.9 では、問題ありませんでした。

Build | PhantomJS

の手順で、RPM の作成まで行おうとしたところ、

$ ./mkrpm.sh phantomjs
=> Copying sources...
=> Creating source tarball under /tmp/tmp.A71VPm58dp/SOURCES...
=> Building RPM...
cp: missing destination file operand after `/tmp/'
Try `cp --help' for more information.

cp できなくて、rpmbuild がこけました。

デバッグのため、mkrpm.sh を以下のように修正して実行してみると、

- rpm=$(rpmbuild --define "_topdir ${topdir}" --buildroot ${buildroot} --clean -bb  ${name}.spec 2>/dev/null | \
+ rpmbuild --define "_topdir ${topdir}" --buildroot ${buildroot} --clean -bb ${name}.spec
*******************************************************************************
*
* WARNING: 'check-rpaths' detected a broken RPATH and will cause 'rpmbuild'
*          to fail. To ignore these errors, you can set the '$QA_RPATHS'
*          environment variable which is a bitmask allowing the values
*          below. The current value of QA_RPATHS is 0x0000.
*
*    0x0001 ... standard RPATHs (e.g. /usr/lib); such RPATHs are a minor
*               issue but are introducing redundant searchpaths without
*               providing a benefit. They can also cause errors in multilib
*               environments.
*    0x0002 ... invalid RPATHs; these are RPATHs which are neither absolute
*               nor relative filenames and can therefore be a SECURITY risk
*    0x0004 ... insecure RPATHs; these are relative RPATHs which are a
*               SECURITY risk
*    0x0008 ... the special '$ORIGIN' RPATHs are appearing after other
*               RPATHs; this is just a minor issue but usually unwanted
*    0x0010 ... the RPATH is empty; there is no reason for such RPATHs
*               and they cause unneeded work while loading libraries
*    0x0020 ... an RPATH references '..' of an absolute path; this will break
*               the functionality when the path before '..' is a symlink
*
*
* Examples:
* - to ignore standard and empty RPATHs, execute 'rpmbuild' like
*   $ QA_RPATHS=$[ 0x0001|0x0010 ] rpmbuild my-package.src.rpm
* - to check existing files, set $RPM_BUILD_ROOT and execute check-rpaths like
*   $ RPM_BUILD_ROOT=<top-dir> /usr/lib/rpm/check-rpaths
*
*******************************************************************************
ERROR   0002: file '/usr/bin/phantomjs' contains an invalid rpath '/usr/local/src/phantomjs-1.9/src/qt/lib' in [/usr/local/src/phantomjs-1.9/src/qt/lib]
error: Bad exit status from /var/tmp/rpm-tmp.IQMf9c (%install)

RPM build errors:
    Bad exit status from /var/tmp/rpm-tmp.IQMf9c (%install)

のようなエラーがでました。
このエラーが出ていた場合は、RPM のビルド環境を整えるときの Tips | Carpe Diem に書いてある手順で対応できます。
以前、引っかかった時にお世話になりました。ありがとうございます。

以下では、3つの解決方法を示します。

QA_RPATHS を設定する

エラーメッセージに書いてあるとおり、

QA_RPATHS=$[ 0x0002 ]

をつけて実行すれば、
check-rpaths のエラーを回避できます。
したがって、以下のように mkrpm.sh を修正して実行すれば rpmbuild に成功します。

- rpm=$(rpmbuild --define "_topdir ${topdir}" --buildroot ${buildroot} --clean -bb ${name}.spec 2>/dev/null | \
+ rpm=$(QA_RPATHS=$[ 0x0002 ] rpmbuild --define "_topdir ${topdir}" --buildroot ${buildroot} --clean -bb ${name}.spec 2>/dev/null | \

.rpmmacros の %__arch_install_post を無効にする

$HOME/.rpmmacros の、

%__arch_install_post   /usr/lib/rpm/check-rpaths   /usr/lib/rpm/check-buildroot

を削除するか、コメントアウトすれば check-rpaths が走らないので、
同様に回避できます。

spec ファイルで %__arch_install_post を無効にする

phantomjs.spec に以下を追記する方法もあります。

%undefine __arch_install_post

この方法だと、.rpmmacros に %__arch_install_post が書いてあったとしても、
rpmbuild 実行時にそれを無効にするので、
第三者にrpmbuild してもらう際に、QA_RPATHS を設定したり、%__arch_install_post をコメントアウトする必要がないので楽になります。

mkrpm.sh を再度実行

いずれかの修正を加えた上で、もう一度実行すると rpmbuild に成功します。

$ ./mkrpm.sh phantomjs
=> Copying sources...
=> Creating source tarball under /tmp/tmp.csVFRJRG6l/SOURCES...
=> Building RPM...
/tmp/phantomjs-1.9-1.x86_64.rpm

生成される rpm は 1.9-1 になっていますが、インストールすると 1.10 になっています。

まとめ

check-rpaths でエラーが出た際には、上記の方法で解決できます。
ただ、check-rpaths を無効にすることの是非についてはなんともいえないところがあります...

Oracle の RPM で install した MySQL 5.5 から 5.6 への upgrade 手順

例として、5.5.28 -> 5.6.17 への upgrade 手順を記します。
OracleRPM を使う場合の手順です。
Oraclemysql-community repo から yum で入れている場合は、
yum upgrade でできると思います。

RPM 取得
$ wget http://dev.mysql.com/get/Downloads/MySQL-5.6/MySQL-server-5.6.17-1.el6.x86_64.rpm
$ wget http://dev.mysql.com/get/Downloads/MySQL-5.6/MySQL-client-5.6.17-1.el6.x86_64.rpm
$ wget http://dev.mysql.com/get/Downloads/MySQL-5.6/MySQL-shared-5.6.17-1.el6.x86_64.rpm
$ wget http://dev.mysql.com/get/Downloads/MySQL-5.6/MySQL-devel-5.6.17-1.el6.x86_64.rpm
$ wget http://dev.mysql.com/get/Downloads/MySQL-5.6/MySQL-shared-compat-5.6.17-1.el6.x86_64.rpm
MySQL-server 以外を upgrade

MySQL-server も一緒に upgrade しない理由は後述します。

$ rpm -U MySQL-client-5.6.17-1.el6.x86_64.rpm MySQL-devel-5.6.17-1.el6.x86_64.rpm MySQL-shared-5.6.17-1.el6.x86_64.rpm MySQL-shared-compat-5.6.17-1.el6.x86_64.rpm
upgrade MySQL-server (失敗)

rpm -U でできるとおもいきや、以下の様なエラーがでます。

$ rpm -U MySQL-server-5.6.17-1.el6.x86_64.rpm

******************************************************************
A MySQL server package (MySQL-server-5.5.28-1.el6.x86_64) is installed.

Upgrading directly from MySQL 5.5 to MySQL 5.6 may not
be safe in all cases.  A manual dump and restore using mysqldump is
recommended.  It is important to review the MySQL manual's Upgrading
section for version-specific incompatibilities.

A manual upgrade is required.

- Ensure that you have a complete, working backup of your data and my.cnf
  files
- Shut down the MySQL server cleanly
- Remove the existing MySQL packages.  Usually this command will
  list the packages you should remove:
  rpm -qa | grep -i '^mysql-'

  You may choose to use 'rpm --nodeps -ev <package-name>' to remove
  the package which contains the mysqlclient shared library.  The
  library will be reinstalled by the MySQL-shared-compat package.
- Install the new MySQL packages supplied by Oracle and/or its affiliates
- Ensure that the MySQL server is started
- Run the 'mysql_upgrade' program

This is a brief description of the upgrade process.  Important details
can be found in the MySQL manual, in the Upgrading section.
******************************************************************
error: %pre(MySQL-server-5.6.17-1.el6.x86_64) scriptlet failed, exit status 1
error:   install: %pre scriptlet failed (2), skipping MySQL-server-5.6.17-1.el6

まとめると、

  • mysqldump をとっておいたほうが良い
  • MySQL-server を uninstall してから入れなおしましょう
  • MySQL-server を起動して、mysql_upgrade を実行しましょう

と言った感じでしょう。

mysqldump

念のため backup を取ります。

$ mysqldump -u root --all-databases --single-transaction > backup.sql
remove MySQL-server
$ rpm -e MySQL-server
install MySQL-server 5.6.17
$ rpm -ivh MySQL-server-5.6.17-1.el6.x86_64.rpm
start MySQL-server
$ chkconfig mysql on
$ service mysql start
mysql_upgrade

user, password は適宜入力します。

$ mysql_upgrade -u USER -p PASSWORD

以上で完了です。
はじめに述べましたが、mysql-community repo から yum で入れている場合は、

$ service mysql stop
$ yum upgrade MySQL-....
$ service mysql start
$ mysql_upgrade

みたいな手順で終わると思います(service 名が mysql ではない気がしますが)。

Redis の rpm を簡単に作成できるようにした

以前、CentOS 6 用 Redis 2.6.13 の RPM 作成手順 - tkuchikiの日記 という記事を書いたが、
毎回記事を見ながら作業するのは面倒なので、変数を少し変えただけで作れるようにした。

rpmbuild の環境がない場合は、以下を予め実行。

yum install -y rpmbuild rpmdevtools
rpmdev-setuptree

以下がシェルスクリプト
バージョンが上がっても、VERSION を 書き換えれば基本的には動作する(はず)。

テンプレートの gist ↓

https://gist.github.com/tkuchiki/7674158

テンプレートを gist から取ってくる部分、書き換えるたびに URL が変わって面倒なので、repository に移動したい...

最後に

spec ファイルは、Silas Sewell さん作成のものを流用させていただきました。
ありがとうございます。

Many thanks, Mr. Silas Sewell.