樹莓派 CentOS 7 建置 LAP 環境

其實在 Raspberry 安裝 CentOS 後,已經是一個完整的 CentOS Linux 作業系統,要建置通用的 LAMP(Linux+Apache+MySQL+PHP)環境,基本上只要利用內含的套件管理工具(yum)安裝即可。

yum install httpd mariadb mariadb-server php php-pdo php-mysql

但 CentOS 是 RHEL 的社群版本,所以在版本及套件維護上是依循 RHEL。而 RHEL 作為企業級部署運用的作業系統,核心理念就是「穩定」和「相容」,有興趣可以參考 RedHat 的官方說明:Security Backporting Practice - Red Hat Customer Portal。因此,不管是套件的版本維護或更新,相對來說,是屬於比較保守的作法。例如,Apache 的版本仍維持在 2.4.6(Apache 官方最新版本則是 2.4.28),PHP 則是 5.4.16(PHP 官方已 phase out,參見:PHP: Supported Versions)。但這可不代表 RedHat 不再維護更新安全漏洞,事實上,RedHat 是 Linux 各路大神的集中地,各種 bug 或安全漏洞的修補速度最快,貢獻數也是最多的。而 RHEL 的支援年限可是長達 10 年(不含 Extended Life Phase 延長年限),細節可以參見:Red Hat Enterprise Linux Life Cycle - Red Hat Customer Portal,至於植基於 RHEL 的 CentOS 亦同(參見:FAQ/General - CentOS Wiki),例如目前最新的 CentOS 7 支援是到 2024 年才會終止維護及修補/更新。

當然,對於有些程式或系統開發者(商)來說,這樣的維護政策就不免顯得過於保守了。雖然目前有 EPEL - FedoraProject (Extra Packages for Enterprise Linux) 這樣的資源庫,可以用來解決某些額外的套件需求。但若是要求系統套件(例如 Apache、PHP、Python 等)更新的版本,除了 tarball 自行編譯安裝外,就是另尋第三方維護的資源庫。以系統管理角度來說,這多少是有些風險存在的,例如,與原生套件發生衝突或若干時日後不再維護更新等。

其實 RedHat 也知道這樣的需求存在,所以提出了 RHSCL (Red Hat Software Collections) 這樣的解決方式:

For certain applications, more recent versions of some software components are often needed in order to use their latest new features. Red Hat Software Collections is a Red Hat offering that provides a set of dynamic programming languages, database servers, and various related packages that are either more recent than their equivalent versions included in the base Red Hat Enterprise Linux system, or are available for this system for the first time.

CentOS 自然也有相對應的 SCL Repository: AdditionalResources/Repositories/SCL - CentOS Wiki

例如,這次的 Raspberry Pi 系統建置,開發團隊的需求就是要 PHP 5.6 以上版本。如果是普通 x86 平台,基本上只要使用 SCL 的方式可以很快就完成安裝及設置。但 Raspberry Pi 用的卻是 ARM,所以不管是 SCL 或甚至常見的第三方資源庫,目前看來都是沒有提供 ARM 套件。

因此,我採取的方式是自行重新打包 rpm 套件的方式來解決,雖然骨子裡還是 source tarball 的重新編譯,但加上 rpm 包裝,在後續的維護上還是較好管理。記錄一下過程及步驟:

EPEL 資源庫

EPEL 提供非常多的額外套件,若能引入自然又可以省一些工夫,所幸在 SpecialInterestGroup/AltArch/Arm32 - CentOS Wiki 上已提供做法:

cat > /etc/yum.repos.d/epel.repo << EOF
[epel]
name=Epel rebuild for armhfp
baseurl=https://armv7.dev.centos.org/repodir/epel-pass-1/
enabled=1
gpgcheck=0

EOF

依據說明,這是 CentOS 利用自動方式重建的資源庫,並未經過任何 QA 測試,所以不能保證 100% 沒問題:

Please note that it's just an automatic rebuild without any QA/test, and also resulting pkgs aren't signed either.

設置 rpmbuild 環境

參照 HowTos/RebuildSRPM - CentOS Wiki 以及 HowTos/SetupRpmBuildEnvironment - CentOS Wiki 文件說明,設置好 rpmbuild 環境:

yum install rpm-build redhat-rpm-config
yum install wget gcc automake autoconf libtool make

rpmbuild 時最好不要用 root 的帳號及權限,以免不小心對系統造成預期外的損壞。在此新增一個普通使用者帳號:

adduser berry
passwd berry
usermod -aG wheel berry
su - berry

新增工作目錄:

mkdir -p ~/rpmbuild/{BUILD,RPMS,SOURCES,SPECS,SRPMS}

設定環境變數值:

echo '%_topdir %(echo $HOME)/rpmbuild' > ~/.rpmmacros
echo "%debug_package %{nil}" >> ~/.rpmmacros
echo "%dist .el7" >> ~/.rpmmacros
echo "%_unpackaged_files_terminate_build 0" >> ~/.rpmmacros
echo "%__isa_name armv7hl" >> ~/.rpmmacros

下載及安裝原始碼(SRPM)套件

需求為 PHP 5.6,因此我是使用目前最通用及活躍的 Remi Repository

wget https://rpms.remirepo.net/SRPMS/php56-php-5.6.31-2.remi.src.rpm
rpm -ivh php56-php-5.6.31-2.remi.src.rpm 

rpm 指令會依據先前設定的 _topdir 變數值將原始檔(source tarball、patch 檔)、套件設定檔(spec)分別安裝到使用者 home 目錄 rpmbuild 下相對應的目錄:SOURCES、SPECS。

重建(Rebuild)套件 RPM

進入 SPECS 目錄:

cd ~/rpmbuild/SPECS/

重新建立套件 RPM:

rpmbuild -ba php.spec

在經過一段時間後,rpm 檔建立完成……才怪,世界當然不可能如此美好!當下完指令後,很快就會看到螢幕顯示錯誤的訊息,當然就是缺少各式各樣相依的 develop 套件,所以就是得一一將這些開發用套件用 yum 的方式安裝起來。

如果已經非常熟悉 rpm 的建立及維護,對 spec 檔也很有經驗的話,可以先行瀏覽 php.spec 檔來確認或甚至修改所需的相依套件,而不用等待 rpmbuild 時才依錯誤訊息慢慢除錯及編譯。這部份就只能視原 SRPM 維護者撰寫的 spec 檔來實際作業及除錯,大致上就是訊息報錯缺少什麼套件就補安裝上去,基本上都會是 xxxx-devel 的套件。當然,也會發生維護者設定的相依套件「版本」新於系統原生套件,而是自行打包的套件,那還是得再下載這個相依套件的 SRPM 檔先行再編譯及安裝。

以下是這次我在 rpmbuild PHP 5.6 時需要的相依套件:

sudo yum install bzip2-devel curl-devel pam-devel sqlite-devel libedit-devel libtool-ltdl-devel systemtap-sdt-devel libacl-devel systemd-devel libc-client-devel postgresql-devel uw-imap-devel unixODBC-devel firebird-devel net-snmp-devel libxslt-devel libjpeg-devel libpng-devel freetype-devel libXpm-devel t1lib-devel gmp-devel tokyocabinet-devel libmcrypt-devel libtidy-devel freetds-devel aspell-devel recode-devel libicu-devel enchant-devel gettext-devel libtiff-devel libvpx-devel

另外,還有維護者自行維護的 gd-2.1.1-1.remi.src.rpm、php-pear-1.10.5-2.remi.src.rpm、php-pecl-jsonc-1.3.10-2.remi.src.rpm、php-pecl-zip-1.15.1-2.remi.src.rpm 以及 libzip5-1.3.0-1.remi.src.rpm 等套件,也需要分別一一編譯。

在經過一段漫長時間後(大概近 3 小時)順利編譯完成,系統會將打包好的 RPM 及 SRPM 檔,分別置放於 RPMS 和 SRPMS 目錄下。這時就可以用 rpm 指令安裝所需的套件了,例如:

cd ~/rpmbuild/RPMS/
sudo rpm -ivh gd-last-2.1.1-1.el7.armv7hl.rpm php-5.6.31-2.el7.armv7hl.rpm php-common-5.6.31-2.el7.armv7hl.rpm php-mcrypt-5.6.31-2.el7.armv7hl.rpm php-bcmath-5.6.31-2.el7.armv7hl.rpm php-gd-5.6.31-2.el7.armv7hl.rpm php-mbstring-5.6.31-2.el7.armv7hl.rpm php-xml-5.6.31-2.el7.armv7hl.rpm php-mysqlnd-5.6.31-2.el7.armv7hl.rpm php-pdo-5.6.31-2.el7.armv7hl.rpm php-opcache-5.6.31-2.el7.armv7hl.rpm php-cli-5.6.31-2.el7.armv7hl.rpm 

另外,也可將打包完成的 rpm 檔備檔起來,或甚至自己建立維護一個私人資源庫。日後若有其他 Raspberry Pi 的設備需要或重建系統時都可以直接安裝使用,不用再重新編譯了。