В этой статье я хочу рассказать, о том, как можно внедрить систему сборки deb-пакетов для некоторого абстрактного проекта. Плюсов в распространении и развёртывании ПО на основе пакетов несколько:
И так, рассмотрим некоторый web-проект my-app, находящийся под контролем SVN, со следующей файловой структурой:
Для сборки пакетов нам потребуется некоторый набор файлов и скриптов, который мы разместим в папке .package, которую в свою очередь добавим в корень проекта. Структура этой папки будет выглядеть следующим образом:
По сути каталог .structure и есть наш будущий пакет. Подкаталог DEBIAN содержит служебные файлы, о которых будет сказано ниже. Все остальные каталоги полностью повторяют иерархию каталогов файловой системы ОС Debian Linux. Файлы package.xml и package.properties содержат сценарии и настройки для создания пакетов с помощью утилиты Apache Ant. Но обо всём по порядку.
Каталог DEBIAN содержит файлы настроек проекта и скрипты пред/пост установки/удаления.
Файл conffiles содержит список конфигурационных файлов, которые не должны быть перезаписаны во время установки:
В нашем случае здесь будет указан файл настроек проекта.
Файл control содержит общую информацию о пакете:
Отдельного внимания в этом файле заслуживают пункты Version и Depends. Мы специально указываем в качестве версии пакета константу {{{VERSION}}}, так как в дальнейшем при сборке пакета заменим её актуальным значением. В списке зависимостей мы указали только nginx и php, однако, если Ваш проект использует какие-либо дополнительные пакеты (например модули php), Вы можете явно перечислить их, уменьшив тем самым риски неверной работы проекта при выкладке на боевой сервер.
Файл preinst содержит сценарий предустановки:
В нашем случае никаких предварительных действий не требуется, по этому файл пуст.
Файл postinst содержит сценарий постустановки. В данном случае сценарий будет выставлять права, настраивать конфиг с помощью утилиты debconf и создавать директории для временных файлов:
При необходимости в этот файл так же могут быть добавлены сценарии для создания БД проекта. С обновлением БД задача обстоит несколько сложнее. Однако, можно попробовать частично разрешить её хранением в проекте 2-х sql-файлов: с полным набором команд для воспроизведения структуры / данных (первичная установка) и изменениями относительно предыдущего релиза (для обновления).
Файл prerm содержит сценарий предудаления. В данном случае сценарий будет удалять каталоги для временных файлов:
Файл templates содержит шаблоны полей для утилиты debconf:
Подробнее о содержимом каталога DEBIAN можно почитать на opennet или в официальной документации.
Теперь, что бы создать полноценный пакет на основе нашего проекта, нам остаётся заполнить файловую структуру пакета (файловую систему с корнем в каталоге .structure данными). Для этого придётся создать небольшой набор сценариев, копирующих нужные данные из файловой системы проекта в файловую систему пакета. Я использовал для этой цели Apache Ant, в результате чего у меня получились файлы package.xml и package.properties.
Файл package.properties содержит в себе настройки для сборки пакета:
Основной сценарий сборки содержится в файле package.xml:
И так, создание каталога .package завершено. Теперь мы можем закоммитить его в SVN вместе с остальным проектом. Когда же нам понадобится собрать пакет (например, отдать релиз/метку для тестирования или выкладки в бой), будет достаточно перейти в каталог .package и выполнить команду
- Атомарность пакета (представление продукта в виде одного файла);
- Наличие скриптов пред/пост установки/удаления ПО;
- Возможно указания зависимостей для ПО.
Структура проекта
И так, рассмотрим некоторый web-проект my-app, находящийся под контролем SVN, со следующей файловой структурой:
/|-config | |-parameters.ini |-htdocs | |-index.php |-libs |-templates
Структура пакета
Для сборки пакетов нам потребуется некоторый набор файлов и скриптов, который мы разместим в папке .package, которую в свою очередь добавим в корень проекта. Структура этой папки будет выглядеть следующим образом:
/|-.structure | |-DEBIAN | | |-conffiles | | |-control | | |-postinst | | |-postrm | | |-preinst | | |-prerm | | |-templates | |-etc | |-var | | |-log | | |-www |-package.xml |-package.properties
По сути каталог .structure и есть наш будущий пакет. Подкаталог DEBIAN содержит служебные файлы, о которых будет сказано ниже. Все остальные каталоги полностью повторяют иерархию каталогов файловой системы ОС Debian Linux. Файлы package.xml и package.properties содержат сценарии и настройки для создания пакетов с помощью утилиты Apache Ant. Но обо всём по порядку.
Каталог Debian
Каталог DEBIAN содержит файлы настроек проекта и скрипты пред/пост установки/удаления.
Файл conffiles содержит список конфигурационных файлов, которые не должны быть перезаписаны во время установки:
/etc/my-app/parameters.ini
В нашем случае здесь будет указан файл настроек проекта.
Файл control содержит общую информацию о пакете:
Package: my-app
Version: {{{VERSION}}}
Section: user
Priority: optional
Architecture: all
Installed-Size: 0
Maintainer: Mikhail Krestjaninoff <mikhail.krestjaninoff@gmail.com>
Depends: nginx, php5-common (>= 5.2), php5-cli
Description: My application
Отдельного внимания в этом файле заслуживают пункты Version и Depends. Мы специально указываем в качестве версии пакета константу {{{VERSION}}}, так как в дальнейшем при сборке пакета заменим её актуальным значением. В списке зависимостей мы указали только nginx и php, однако, если Ваш проект использует какие-либо дополнительные пакеты (например модули php), Вы можете явно перечислить их, уменьшив тем самым риски неверной работы проекта при выкладке на боевой сервер.
Файл preinst содержит сценарий предустановки:
#!/bin/sh
В нашем случае никаких предварительных действий не требуется, по этому файл пуст.
Файл postinst содержит сценарий постустановки. В данном случае сценарий будет выставлять права, настраивать конфиг с помощью утилиты debconf и создавать директории для временных файлов:
#!/bin/sh
if [ configure = "$1" ]; then
# Set permissions
chown -R www-data:www-data /etc/my-app/
chmod -R 0664 /etc/my-app/
chown -R www-data:www-data /var/www/my-app/
chmod -R 0664 /var/www/my-app/
chown -R www-data:www-data /var/log/my-app/
chmod -R 0664 /var/log/my-app/
# Set up configuration file
. /usr/share/debconf/confmodule
db_input critical db/dsn || true
db_go
db_fset db/dsn seen false || true
db_get db/dsn || true
DSN=$RET
DSN=`echo "$DSN" | sed 's/\//\\\\\//g'`;
sed -i s/{{DSN}}/$DSN/ /etc/my-app/parameters.ini
# Create directories for temporary files
CACHE_DIR="/var/www/my-app/templates/cache"
COMPILED_DIR="/var/www/my-app/templates/compiled"
if [ ! -d $CACHE_DIR ]
then
mkdir -p $CACHE_DIR
chown -R www-data:www-data $CACHE_DIR
chmod -R 0664 $CACHE_DIR
fi
if [ ! -d $COMPILED_DIR ]
then
mkdir -p $COMPILED_DIR
chown -R www-data:www-data $COMPILED_DIR
chmod -R 0664 $COMPILED_DIR
fi
fi
При необходимости в этот файл так же могут быть добавлены сценарии для создания БД проекта. С обновлением БД задача обстоит несколько сложнее. Однако, можно попробовать частично разрешить её хранением в проекте 2-х sql-файлов: с полным набором команд для воспроизведения структуры / данных (первичная установка) и изменениями относительно предыдущего релиза (для обновления).
Файл prerm содержит сценарий предудаления. В данном случае сценарий будет удалять каталоги для временных файлов:
#!/bin/sh
if [ remove == "$1" -o purge == "$1" ];
then
# Remove directories for temporary files
CACHE_DIR="/var/www/my-app/templates/cache"
if [ -e $CACHE_DIR ]; then
rm -rf $CACHE_DIR
fi
COMPILED_DIR="/var/www/my-app/templates/compiled"
if [ -e $COMPILED_DIR ]; then
rm -rf $COMPILED_DIR
fi
fi
Файл templates содержит шаблоны полей для утилиты debconf:
Template: db/dsn
Type: string
Default: postgres://user@passwd:localhost/my-app
Description: Database Source Name. Example: postgres://user@passwd:localhost/my-app
Подробнее о содержимом каталога DEBIAN можно почитать на opennet или в официальной документации.
Скрипты сборки пакета
Теперь, что бы создать полноценный пакет на основе нашего проекта, нам остаётся заполнить файловую структуру пакета (файловую систему с корнем в каталоге .structure данными). Для этого придётся создать небольшой набор сценариев, копирующих нужные данные из файловой системы проекта в файловую систему пакета. Я использовал для этой цели Apache Ant, в результате чего у меня получились файлы package.xml и package.properties.
Файл package.properties содержит в себе настройки для сборки пакета:
package.name=my-app
package.version=1.0.0
Основной сценарий сборки содержится в файле package.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project basedir=".." default="prepare" name="package-builder">
<property file="./.package/package.properties" />
<property name="location" value="."/>
<property name="package.structure" value="${location}/.package/.structure"/>
<property name="package.source" value="${location}/.package/source"/>
<property name="package.target" value="${location}/.package/target"/>
<!-- Init project -->
<target name="init">
<mkdir dir="${package.source}" />
<mkdir dir="${package.target}" />
</target>
<!-- Clean project -->
<target name="clean">
<delete dir="${package.source}" />
<delete dir="${package.target}" />
</target>
<!-- Prepare project files for package -->
<target depends="init" name="prepare">
<copy toDir="${package.source}">
<fileset dir="${package.structure}">
<include name="**/*" />
<exclude name=".svn" />
</fileset>
</copy>
<mkdir dir="${package.source}/etc/${package.name}" />
<copy toDir="${package.source}/etc/${package.name}">
<fileset dir="config">
<include name="**/*" />
<exclude name=".svn" />
</fileset>
</copy>
<mkdir dir="${package.source}/var/www/${package.name}/htdocs" />
<copy toDir="${package.source}/var/www/${package.name}/htdocs">
<fileset dir="htdocs">
<include name="**/*" />
<exclude name=".svn" />
</fileset>
</copy>
<mkdir dir="${package.source}/var/www/${package.name}/libs" />
<copy toDir="${package.source}/var/www/${package.name}/libs">
<fileset dir="libs">
<include name="**/*" />
<exclude name=".svn" />
</fileset>
</copy>
<mkdir dir="${package.source}/var/www/${package.name}/templates" />
<copy toDir="${package.source}/var/www/${package.name}/templates">
<fileset dir="templates">
<include name="**/*" />
<exclude name=".svn" />
<exclude name="cache" />
<exclude name="compiled" />
</fileset>
</copy>
</target>
<!-- Build packege -->
<target depends="prepare" name="build">
<!-- Change owner to root -->
<exec executable="fakeroot" dir="${package.source}">
<arg line="chown -R root:root ." />
</exec>
<!-- Allow execution for installation scripts -->
<exec executable="fakeroot" dir="${package.source}/DEBIAN">
<arg line="chmod 0755 preinst postinst prerm postrm" />
</exec>
<!-- Set package version -->
<exec executable="sed">
<arg line="-i s/{{{VERSION}}}/${package.version}/ ${package.source}/DEBIAN/control" />
</exec>
<!-- Build package -->
<exec executable="dpkg-deb">
<arg line="--build ${package.source} ${package.target}/${package.name}_${package.version}_all.deb" />
</exec>
</target>
</project>
* This source code was highlighted with Source Code Highlighter.
Сборка пакета
И так, создание каталога .package завершено. Теперь мы можем закоммитить его в SVN вместе с остальным проектом. Когда же нам понадобится собрать пакет (например, отдать релиз/метку для тестирования или выкладки в бой), будет достаточно перейти в каталог .package и выполнить команду
ant -f package.xml build
, которая создаст для нас в каталоге .package/target новый deb-пакет, готовый к использованию!