diff --git a/20.10.20/Dockerfile b/20.10.20/Dockerfile new file mode 100644 index 0000000..118e359 --- /dev/null +++ b/20.10.20/Dockerfile @@ -0,0 +1,44 @@ +FROM alpine:3.16.9 + +# Метаданные для CI/CD +LABEL maintainer="Alexander Zhirov " +LABEL version="0.1.0" +LABEL description="Адаптированный для Docker <=20.10.20 образ сборщика APK-файлов для Alpine Linux 3.16.9" + +# Задаем стандартные значения через переменные окружения +ENV USER=builder \ + PACKAGE_DIR=/package \ + NFS_SERVER= \ + NFS_PATH= \ + PRIVATE_KEY= \ + PUBLIC_KEY= \ + REPODEST_DIR= \ + NAME_KEY=builder + +# Копируем скрипт запуска в контейнер +COPY apk-build /usr/bin/apk-build + +# Устанавливаем необходимые пакеты для сборки APK и NFS +RUN echo "http://mirror.yandex.ru/mirrors/alpine/v3.16/main" > /etc/apk/repositories && \ + echo "http://mirror.yandex.ru/mirrors/alpine/v3.16/community" >> /etc/apk/repositories && \ + apk update && \ + apk upgrade --no-cache && \ + apk add --no-cache build-base alpine-sdk abuild sudo git nfs-utils && \ + adduser -D builder && \ + addgroup builder abuild && \ + echo "builder ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/builder && \ + chmod 0755 /usr/bin/apk-build && \ + mkdir /home/builder/package && \ + chown builder:builder /home/builder/package + +# Переключаемся на пользователя builder +USER builder + +# Создаем рабочую директорию +WORKDIR /home/builder/package + +# Указываем точку входа для CI/CD +ENTRYPOINT ["/usr/bin/apk-build"] + +# Указываем команду по умолчанию с переменными окружения +CMD ["-p", "/package"] diff --git a/27.3.1/Dockerfile b/27.3.1/Dockerfile new file mode 100644 index 0000000..885856d --- /dev/null +++ b/27.3.1/Dockerfile @@ -0,0 +1,43 @@ +FROM alpine:3.16.9 + +# Метаданные для CI/CD +LABEL maintainer="Alexander Zhirov " +LABEL version="0.1.0" +LABEL description="Адаптированный для Docker >=27.3.1 образ сборщика APK-файлов для Alpine Linux 3.16.9" + +# Задаем стандартные значения через переменные окружения +ENV USER=builder \ + PACKAGE_DIR=/package \ + NFS_SERVER= \ + NFS_PATH= \ + PRIVATE_KEY= \ + PUBLIC_KEY= \ + REPODEST_DIR= \ + NAME_KEY=builder + +# Копируем скрипт запуска в контейнер +COPY --chmod=0755 apk-build /usr/bin/apk-build + +# Устанавливаем необходимые пакеты для сборки APK и NFS +RUN < /etc/apk/repositories + echo "http://mirror.yandex.ru/mirrors/alpine/v3.16/community" >> /etc/apk/repositories + apk update + apk upgrade --no-cache + apk add --no-cache alpine-sdk abuild sudo git nfs-utils + adduser -D builder + addgroup builder abuild + echo "builder ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/builder +EOF + +# Переключаемся на пользователя builder +USER builder + +# Создаем рабочую директорию +WORKDIR /home/builder/package + +# Указываем точку входа для CI/CD +ENTRYPOINT ["/usr/bin/apk-build"] + +# Указываем команду по умолчанию с переменными окружения +CMD ["-p", "/package"] diff --git a/README.md b/README.md index d994741..6616e37 100644 --- a/README.md +++ b/README.md @@ -1,174 +1,3 @@ # apk-builder -Образ предназначен для автоматизации настройки окружения для сборки пакетов в Alpine Linux. Он создаёт пользователя, настраивает права, подключает NFS-сервер (если указан), управляет ключами для подписи пакетов и выполняет сборку пакетов с помощью утилиты abuild. - -## Сборка образа - -Скрипт `build.sh` предназначен для автоматизации сборки и, при необходимости, отправки Docker-образов в указанный registry. Скрипт поддерживает настройку имени образа, версии, базового образа, выбор Dockerfile, а также указание дополнительных репозиториев и параметров registry. - -### Использование: -Скрипт запускается с обязательными и опциональными аргументами. Общий синтаксис: - -```bash -./build.sh -n <имя> -v <версия> -b <версия_базового_образа> [-R <репозитории>] [-o] [-r <адрес_registry>] [-p <порт>] [-h] -``` - -### Опции: -- `-n, --name` (обязательно): Имя собираемого образа. -- `-v, --version` (обязательно): Версия собираемого образа в формате `X.Y.Z`. -- `-b, --base-image-version` (обязательно): Версия базового образа Alpine Linux. -- `-R, --repositories`: Список репозиториев через точку с запятой для использования в Docker образе. -- `-o, --old`: Использовать метод сборки для устаревшей версии Docker. -- `-r, --push-to-registry`: Адрес registry для отправки образов. -- `-p, --port`: Порт registry (по умолчанию `5000`). -- `-h, --help`: Показать справку. - -### Примеры использования: - -1. **Простая сборка образа без отправки в registry**: - ```bash - ./build.sh -n my-app -v 1.0.0 -b 3.21 - ``` - - Скрипт соберет образ `my-app:1.0.0` на основе базового образа Alpine Linux версии `3.21`. - -2. **Сборка с использованием метода сборки для устаревшей версии Docker**: - ```bash - ./build.sh -n my-app -v 1.0.0 -b 3.21 -o - ``` - - Скрипт соберет образ `my-app:1.0.0` на основе базового образа Alpine Linux версии `3.21`. -3. **Сборка и отправка в registry**: - ```bash - ./build.sh -n my-app -v 1.0.0 -b 3.21 -r registry.example.com -p 5000 - ``` - - Скрипт соберет образ `my-app:1.0.0`. - - Создаст теги: `registry.example.com:5000/my-app:latest`, `registry.example.com:5000/my-app:1.0.0`, `registry.example.com:5000/my-app:1.0`, `registry.example.com:5000/my-app:1`. - - Отправит все теги в registry по адресу `registry.example.com:5000`. - -4. **Сборка с дополнительными репозиториями**: - ```bash - ./build.sh -n my-app -v 1.0.0 -b 3.21 -R "https://mirror.yandex.ru/mirrors/alpine/v3.21/main;https://mirror.yandex.ru/mirrors/alpine/v3.21/community" - ``` - - Скрипт соберет образ `my-app:1.0.0` на основе базового образа Alpine Linux версии `3.21` с использованием списка переданных репозиториев. - ---- - -## Использование образа - -Для запуска контейнера используйте команду `docker run` с необходимыми параметрами и монтированием директорий. Пример команды: - -```bash -docker run -it --rm \ - -v /path/to/source:/source \ - -v /path/to/repository:/repository \ - -e BUILDER_USER="myuser" \ - -e REPOSITORY_LIST="https://mirror.yandex.ru/mirrors/alpine/v3.18/main;https://mirror.yandex.ru/mirrors/alpine/v3.18/community" \ - -e NFS_SERVER="192.168.1.100" \ - -e NFS_PORT="2049" \ - -e NFS_PATH="/nfs/repository" \ - -e REPOSITORY_NAME_DIR="myrepo" \ - -e NAME_KEY="mykey" \ - -e PUBLIC_KEY="$(cat /path/to/mykey.rsa.pub)" \ - -e PRIVATE_KEY="$(cat /path/to/mykey.rsa)" \ - my-app:1.0.0 -``` - -### Параметры запуска -Вы можете передать следующие параметры через переменные окружения (`-e`) или аргументы командной строки: - -| Параметр | Описание | По умолчанию | Формат | -|----------|----------|--------------|--------| -| `BUILDER_USER` | Имя пользователя для сборки | `builder` | Строка (буквы, цифры, `_`, `-`) | -| `REPOSITORY_DIR` | Директория для хранения собранных пакетов | `/repository` | Путь в контейнере | -| `KEYS_DIR` | Директория для хранения ключей | `/keys` | Путь в контейнере | -| `SOURCE_DIR` | Директория с исходными файлами (`APKBUILD`) | `/source` | Путь в контейнере | -| `REPOSITORY_LIST` | Список репозиториев, разделённых `;` | Пусто | Например: `http://url1;http://url2` | -| `REPOSITORY_NAME_DIR` | Имя поддиректории для репозитория | Версия Alpine (например, `v3.18`) | Строка (буквы, цифры, `_`, `-`) | -| `NFS_SERVER` | Адрес NFS-сервера | Пусто | IP-адрес или доменное имя | -| `NFS_PORT` | Порт NFS-сервера | `5000` | Число от 1 до 65535 | -| `NFS_PATH` | Путь на NFS-сервере | Пусто | Путь, начинающийся с `/` | -| `NAME_KEY` | Имя ключа для подписи | Имя пользователя | Строка (буквы, цифры, `_`, `-`) | -| `PUBLIC_KEY` | Публичный RSA-ключ | Пусто | Формат `BEGIN PUBLIC KEY` | -| `PRIVATE_KEY` | Приватный RSA-ключ | Пусто | Формат `BEGIN RSA PRIVATE KEY` | - -### Монтирование директорий -- `-v /path/to/source:/source`: Локальная директория с файлами `APKBUILD` и другими исходниками. -- `-v /path/to/repository:/repository`: Локальная директория для хранения собранных пакетов. -- `-v /path/to/keys:/keys`: Локальная директория для хранения ключей (если используются). - -### Что происходит при запуске - -1. **Создание пользователя**: - - Создаётся пользователь с именем `` и добавляется в группу `abuild`. - - Настраиваются права `sudo` для этого пользователя. - -2. **Создание директорий**: - - Создаются директории: `/home//package`, `/keys`, `/source`, `/repository`. - - Все директории принадлежат пользователю ``. - -3. **Настройка NFS (если указан)**: - - Монтируется NFS-сервер (`NFS_SERVER:NFS_PATH`) в `/repository` на указанном порту (`NFS_PORT`). - - Проверяется корректность адреса, порта и пути. - -4. **Настройка репозиториев**: - - Если указан `REPOSITORY_LIST`, он записывается в `/etc/apk/repositories`. - -5. **Настройка ключей для подписи**: - - Если переданы `PUBLIC_KEY` и `PRIVATE_KEY`: - - Ключи сохраняются в `/keys/.rsa` (приватный) и `/keys/.rsa.pub` (публичный). - - Настраивается файл `/home//.abuild/abuild.conf` с указанием приватного ключа. - - Публичный ключ копируется в `/etc/apk/keys`. - - Если ключи не переданы, но существуют в `/keys/.rsa` и `/keys/.rsa.pub`: - - Используются существующие ключи. - - Если ключи отсутствуют: - - Генерируются новые ключи с помощью `abuild-keygen`. - -6. **Сборка пакета**: - - Исходные файлы из `/source` копируются в `/home//package`. - - Выполняется команда `abuild -r` для сборки пакета. - - Собранные пакеты сохраняются в `/repository/`. - -### Примеры использования - -#### 1. Минимальный запуск (без NFS и ключей) -Сборка пакета с использованием стандартных репозиториев и автоматической генерации ключей (без сохранения ключей): -```bash -docker run -it --rm \ - -v /path/to/source:/source \ - -v /path/to/repository:/repository \ - -e BUILDER_USER="builder" \ - -e REPOSITORY_LIST="https://mirror.yandex.ru/mirrors/alpine/v3.18/main;https://mirror.yandex.ru/mirrors/alpine/v3.18/community" \ - my-app:1.0.0 -``` - -#### 2. Запуск с NFS и пользовательскими ключами -Сборка пакета с монтированием NFS и использованием собственных ключей: -```bash -docker run -it --rm \ - -v /path/to/source:/source \ - -e BUILDER_USER="myuser" \ - -e NFS_SERVER="192.168.1.100" \ - -e NFS_PORT="2049" \ - -e NFS_PATH="/nfs/repository" \ - -e REPOSITORY_NAME_DIR="myrepo" \ - -e NAME_KEY="mykey" \ - -e PUBLIC_KEY="$(cat /path/to/mykey.rsa.pub)" \ - -e PRIVATE_KEY="$(cat /path/to/mykey.rsa)" \ - my-app:1.0.0 -``` - -#### 3. Запуск с пользовательскими ключами -Сборка пакета с использованием собственных ключей: -```bash -docker run -it --rm \ - -v /path/to/source:/source \ - -v /path/to/keys:/keys \ - -v /path/to/repository:/repository \ - -e BUILDER_USER="myuser" \ - my-app:1.0.0 -``` - ---- - -- **Сохранение ключей**: Если вы генерируете ключи внутри контейнера, сохраните их из директории `/keys` для повторного использования. -- **Повторное использование контейнера**: Используйте одну и ту же директорию `/keys` и `/repository` для сохранения ключей и пакетов между запусками. -- **Подпись пакетов**: Для подписи пакетов и хранения их в существующем репозитории необходимо использовать именования ключей, соответствующих тем наименованиям, которые ранее имели ключи при подписи существующих пакетов в репозитории. Таким образом по умолчанию, если имя для генерации новых ключей не было указано - оно заимствует имя пользователя. Таким образом `имя пользователя` == `имена ключей`. +Образ сборщика APK-файлов для Alpine Linux. diff --git a/apk-build b/apk-build new file mode 100644 index 0000000..0cf6f40 --- /dev/null +++ b/apk-build @@ -0,0 +1,197 @@ +#!/bin/sh + +# Функция для вывода справки +usage() { + echo "Использование: $0 -p <путь_к_APKBUILD> [-s -n ] [-r <приватный_ключ> -u <публичный_ключ>] [-d <путь_к_репозиторию>]" + echo "Параметры:" + echo " -p <путь_к_APKBUILD> Путь к директории с APKBUILD (обязательный)" + echo " -s IP или имя NFS-сервера (опционально)" + echo " -n Путь к NFS-ресурсу (опционально, требуется с -s)" + echo " -r <приватный_ключ> Содержимое файла приватного ключа (опционально)" + echo " -u <публичный_ключ> Содержимое файла публичного ключа (опционально)" + echo " -d <путь_к_репозиторию> Путь к директории репозитория в ~/packages (опционально)" + echo " -k <наименование_ключа> Наименование файла ключа (опционально)" + echo "Пример: $0 -p /package -s 192.168.1.100 -n /nfs/share -r \"<содержимое_ключа.rsa>\" -u \"<содержимое_ключа.rsa.pub>\" -d /repo -k \"mykey\"" + echo "Флаги -s и -n включают монтирование NFS, должны использоваться вместе." + echo "Флаги -r и -u содержат текст приватного и публичного ключей для abuild." + echo "Флаг -d задаёт директорию для сохранения пакетов." + exit 1 +} + +# Устанавливаем стандартные значения из переменных окружения или аргументов сборки +: "${PACKAGE_DIR:=/package}" +: "${NFS_SERVER:=}" +: "${NFS_PATH:=}" +: "${PRIVATE_KEY:=}" +: "${PUBLIC_KEY:=}" +: "${REPODEST_DIR:=}" +: "${NAME_KEY:=builder}" +PACKAGES_DIR="/home/builder/packages" +NFS_ENABLED=0 + +# Обработка флагов +while [ $# -gt 0 ]; do + case "$1" in + -p) PACKAGE_DIR="$2"; shift 2 ;; + -s) NFS_SERVER="$2"; shift 2 ;; + -n) NFS_PATH="$2"; shift 2 ;; + -r) PRIVATE_KEY="$2"; shift 2 ;; + -u) PUBLIC_KEY="$2"; shift 2 ;; + -d) REPODEST_DIR="$2"; shift 2 ;; + -k) NAME_KEY="$2"; shift 2 ;; + *) echo "🚫 Ошибка: Неизвестный флаг $1"; usage ;; + esac +done + +# Проверка наличия обязательного аргумента -p +if [ -z "$PACKAGE_DIR" ]; then + echo "🚫 Ошибка: Не указан обязательный параметр -p" + usage +fi + +# Проверка, что если указан один из -s или -n, то указан и другой +if [ -n "$NFS_SERVER" ] && [ -z "$NFS_PATH" ] || [ -z "$NFS_SERVER" ] && [ -n "$NFS_PATH" ]; then + echo "🚫 Ошибка: Флаги -s и -n должны быть указаны вместе" + usage +fi + +# Устанавливаем флаг NFS_ENABLED, если указаны оба флага -s и -n +if [ -n "$NFS_SERVER" ] && [ -n "$NFS_PATH" ]; then + NFS_ENABLED=1 +fi + +# Проверка существования директории с APKBUILD +if [ ! -d "$PACKAGE_DIR" ]; then + echo "🚫 Ошибка: Директория $PACKAGE_DIR не существует" + exit 1 +fi + +# Проверка наличия APKBUILD +if [ ! -f "$PACKAGE_DIR/APKBUILD" ]; then + echo "🚫 Ошибка: Файл APKBUILD не найден в $PACKAGE_DIR" + exit 1 +fi + +if [ -z "$NAME_KEY" ]; then + echo "🚫 Ошибка: Необходимо указать наименование ключа подписи" + exit 1 +fi + +# Проверка и настройка ключей abuild +if [ -n "$PRIVATE_KEY" ] || [ -n "$PUBLIC_KEY" ]; then + echo "🔑 Настраиваю переданные ключи abuild..." + # Проверяем, что переданы все три компонента + if [ -z "$PRIVATE_KEY" ] || [ -z "$PUBLIC_KEY" ]; then + echo "🚫 Ошибка: Для использования ключей нужны все флаги: -r, -u" + exit 1 + fi + # Создаем директорию .abuild + mkdir -p /home/builder/.abuild + # Записываем abuild.conf + echo "PACKAGER_PRIVKEY=\"/home/builder/.abuild/$NAME_KEY.rsa\"" > /home/builder/.abuild/abuild.conf + if [ $? -ne 0 ]; then + echo "🚫 Ошибка при записи abuild.conf" + exit 1 + fi + # Записываем приватный ключ + echo "$PRIVATE_KEY" > /home/builder/.abuild/$NAME_KEY.rsa + if [ $? -ne 0 ]; then + echo "🚫 Ошибка при записи приватного ключа" + exit 1 + fi + # Записываем публичный ключ + echo "$PUBLIC_KEY" > /home/builder/.abuild/$NAME_KEY.rsa.pub + if [ $? -ne 0 ]; then + echo "🚫 Ошибка при записи публичного ключа" + exit 1 + fi + # Устанавливаем права доступа + chmod 600 /home/builder/.abuild/$NAME_KEY.rsa + chmod 644 /home/builder/.abuild/$NAME_KEY.rsa.pub /home/builder/.abuild/abuild.conf + # Копирование ключа для apk менеджера + sudo cp -v /home/builder/.abuild/$NAME_KEY.rsa.pub /etc/apk/keys/ + echo "✅ Ключи abuild успешно настроены" +else + # Если ключи не переданы, проверяем существующие или генерируем новые + if [ ! -f "/home/builder/.abuild/abuild.conf" ]; then + echo "🔑 Генерирую новые ключи для abuild..." + echo "/home/builder/.abuild/$NAME_KEY.rsa" | abuild-keygen -a -i + if [ $? -ne 0 ]; then + echo "🚫 Ошибка при генерации ключей abuild" + exit 1 + fi + echo "✅ Ключи abuild сгенерированы" + else + sudo cp -v /home/builder/.abuild/$NAME_KEY.rsa.pub /etc/apk/keys/ + echo "✅ Использую существующие ключи abuild" + fi +fi + +# Монтируем NFS-ресурс, если включен +if [ "$NFS_ENABLED" -eq 1 ]; then + echo "🔌 Монтирую NFS-ресурс $NFS_SERVER:$NFS_PATH в $PACKAGES_DIR..." + sudo mkdir -p "$PACKAGES_DIR" + sudo mount -t nfs "$NFS_SERVER:$NFS_PATH" "$PACKAGES_DIR" + if [ $? -ne 0 ]; then + echo "🚫 Ошибка при монтировании NFS-ресурса" + exit 1 + fi + echo "✅ NFS-ресурс успешно смонтирован" +else + echo "ℹ️ NFS не указан, пакеты будут сохранены локально в $PACKAGES_DIR" + mkdir -p "$PACKAGES_DIR" +fi + +# Копируем содержимое директории в рабочую директорию +echo "📂 Копирую файлы проекта в рабочую директорию..." +cp -r "$PACKAGE_DIR"/* /home/builder/package/ +if [ $? -ne 0 ]; then + echo "🚫 Ошибка при копировании файлов проекта" + if [ "$NFS_ENABLED" -eq 1 ]; then + sudo umount "$PACKAGES_DIR" + fi + exit 1 +fi +echo "✅ Файлы успешно скопированы" + +# Переходим в директорию пакета +cd /home/builder/package || { + echo "🚫 Ошибка: Не удалось перейти в директорию /home/builder/package" + if [ "$NFS_ENABLED" -eq 1 ]; then + sudo umount "$PACKAGES_DIR" + fi + exit 1 +} +echo "✅ Перешел в директорию проекта" + +# Проверяем зависимости и собираем пакет +echo "🔨 Проверяю зависимости и собираю APK-пакет..." + +# Устанавливаем флаг NFS_ENABLED, если указаны оба флага -s и -n +if [ -n "$REPODEST_DIR" ]; then + REPODEST_DIR=$(echo "${REPODEST_DIR}" | sed 's|^./||;s|^/||') +fi + +REPODEST="$PACKAGES_DIR/${REPODEST_DIR:=v$(cat /etc/alpine-release | awk -F. '{print $1"."$2}')}" abuild -r + +if [ $? -ne 0 ]; then + echo "🚫 Ошибка при сборке APK-пакета" + if [ "$NFS_ENABLED" -eq 1 ]; then + sudo umount "$PACKAGES_DIR" + fi + exit 1 +fi +echo "✅ Сборка APK-пакета успешно завершена" + +# Размонтируем NFS, если использовался +if [ "$NFS_ENABLED" -eq 1 ]; then + sudo umount "$PACKAGES_DIR" + if [ $? -ne 0 ]; then + echo "🚫 Ошибка при размонтировании NFS-ресурса" + exit 1 + fi + echo "✅ NFS-ресурс размонтирован" + echo "🎉 Сборка завершена, пакеты сохранены в $NFS_SERVER:$NFS_PATH" +else + echo "🎉 Сборка завершена, пакеты сохранены локально в $PACKAGES_DIR" +fi diff --git a/build.sh b/build.sh old mode 100755 new mode 100644 index 8286cc9..395a1b3 --- a/build.sh +++ b/build.sh @@ -1,31 +1,31 @@ #!/bin/sh usage() { - local exit_code="$1" - echo "✏️ Использование: $0 -n <имя> -v <версия> -b <версия_базового_образа> [-o] [-R <репозитории>] [-r <адрес_registry>] [-p <порт>] [-h]" + echo "✏️ Использование: $0 -n <имя> -v <версия> [-a <адрес>] [-p <порт>] [-r]" echo "🔧 Опции:" - echo " -n, --name Имя собираемого образа (обязательно)" - echo " -v, --version Версия собираемого образа в формате X.Y.Z (обязательно)" - echo " -b, --base-image-version Версия базового образа (обязательно)" - echo " -o, --old Использовать Dockerfile.20.10.20 (по умолчанию Dockerfile.27.3.1)" - echo " -R, --repositories Список репозиториев для сборки (через точку с запятой)" - echo " -r, --push-to-registry Адрес registry для отправки образов (например, registry.example.com)" - echo " -p, --port Порт registry (по умолчанию 5000)" - echo " -h, --help Показать эту справку" - exit "$exit_code" + echo " -n, --name Имя образа (обязательно)" + echo " -v, --version Версия образа в формате X.Y.Z (обязательно)" + echo " -a, --address Адрес registry (требуется с -r)" + echo " -p, --port Порт registry (опционально)" + echo " -r, --push-to-registry Создать теги и отправить образы в registry" + echo "" + echo "📌 Примеры:" + echo " Только сборка: $0 -n myapp -v 2.5.7" + echo " Сборка и отправка: $0 -n myapp -v 2.5.7 -a registry.example.com -p 5000 -r" + exit 1 } validate_version() { echo "$1" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+$' || { echo "❌ Ошибка: Версия должна быть в формате X.Y.Z (например, 2.5.7)" - usage 1 + exit 1 } } validate_address() { if [ -z "$1" ]; then - echo "❌ Ошибка: Адрес registry не может быть пустым" - usage 1 + echo "❌ Ошибка: Адрес не может быть пустым" + exit 1 fi } @@ -33,105 +33,58 @@ validate_port() { if [ -n "$1" ]; then echo "$1" | grep -Eq '^[0-9]+$' || { echo "❌ Ошибка: Порт должен быть числом" - usage 1 + exit 1 } fi } -check_dockerfile() { - if [ ! -f "$1" ]; then - echo "❌ Ошибка: Файл $1 не найден в директории docker" - usage 1 - fi -} - push_to_registry=false name="" version="" -base_image_version="" -registry_address="" -port="5000" -use_old=false -dockerfile="Dockerfile.27.3.1" -repositories="" +address="" +port="" -if ! command -v getopt >/dev/null 2>&1; then - echo "❌ Ошибка: утилита getopt не найдена" - usage 1 -fi - -opts=$(getopt -o n:v:b:oR:r:p:h -l name:,version:,base-image-version:,old,repositories:,push-to-registry:,port:,help -n "$0" -- "$@") -if [ $? -ne 0 ]; then - echo "❌ Ошибка парсинга аргументов" - usage 1 -fi - -eval set -- "$opts" - -while true; do - case "$1" in - -n|--name) name="$2"; shift 2 ;; - -v|--version) version="$2"; shift 2 ;; - -b|--base-image-version) base_image_version="$2"; shift 2 ;; - -r|--push-to-registry) push_to_registry=true; registry_address="$2"; shift 2 ;; - -p|--port) port="$2"; shift 2 ;; - -o|--old) use_old=true; shift ;; - -R|--repositories) repositories="$2"; shift 2 ;; - -h|--help) usage 0 ;; - --) shift; break ;; - *) echo "❌ Неверный аргумент $1" >&2; usage 1 ;; +while getopts ":n:v:a:p:r" opt; do + case $opt in + n) name="$OPTARG" ;; + v) version="$OPTARG" ;; + a) address="$OPTARG" ;; + p) port="$OPTARG" ;; + r) push_to_registry=true ;; + \?) echo "❌ Неверный аргумент -$OPTARG" >&2; usage ;; + :) echo "❌ Опция -$OPTARG требует аргумент" >&2; usage ;; esac done -if [ -z "$name" ] || [ -z "$version" ] || [ -z "$base_image_version" ]; then - echo "❌ Ошибка: Не указаны обязательные аргументы (-n, -v и -b)" - usage 1 +if [ -z "$name" ] || [ -z "$version" ]; then + echo "❌ Ошибка: Не указаны обязательные аргументы (-n и -v)" + usage fi validate_version "$version" if [ "$push_to_registry" = true ]; then - if [ -z "$registry_address" ]; then - echo "❌ Ошибка: Для отправки в registry необходимо указать адрес с -r" - usage 1 + if [ -z "$address" ]; then + echo "❌ Ошибка: Для отправки в registry необходимо указать адрес (-a)" + usage fi - validate_address "$registry_address" + validate_address "$address" validate_port "$port" fi -echo "📂 Переход в директорию docker..." -cd docker || { - echo "❌ Ошибка: Не удалось перейти в директорию docker" +echo "🐳 Сборка образа $name:$version..." +docker build . -t "${name}:${version}" || { + echo "❌ Ошибка при сборке образа" exit 1 } -if [ "$use_old" = true ]; then - dockerfile="Dockerfile.20.10.20" -fi - -echo "🔍 Проверка наличия Dockerfile..." -check_dockerfile "$dockerfile" - -echo "🐳 Сборка образа $name:$version с использованием $dockerfile и базового образа версии $base_image_version..." -if [ -n "$repositories" ]; then - echo "📦 Используемые репозитории:" - echo "$repositories" | tr ';' '\n' | while read -r repo; do - echo -e " 🌐 $repo" - done - docker build . -f "$dockerfile" -t "${name}:${version}" --build-arg BASE_IMAGE_VERSION="$base_image_version" --build-arg REPOSITORIES="$repositories" || { - echo "❌ Ошибка при сборке образа" - exit 1 - } -else - docker build . -f "$dockerfile" -t "${name}:${version}" --build-arg BASE_IMAGE_VERSION="$base_image_version" || { - echo "❌ Ошибка при сборке образа" - exit 1 - } -fi - if [ "$push_to_registry" = true ]; then - registry="$registry_address:$port" + if [ -z "$port" ]; then + registry="$address" + else + registry="$address:$port" + fi echo "🏷 Создание тегов для registry..." diff --git a/docker/Dockerfile.20.10.20 b/docker/Dockerfile.20.10.20 deleted file mode 100644 index 9f75040..0000000 --- a/docker/Dockerfile.20.10.20 +++ /dev/null @@ -1,31 +0,0 @@ -ARG BASE_IMAGE_VERSION=latest - -FROM alpine:${BASE_IMAGE_VERSION} - -LABEL maintainer="Alexander Zhirov " -LABEL version="0.1.0" -LABEL description="Адаптированный для Docker <=20.10.20 образ сборщика APK-файлов для Alpine Linux" - -ENV BUILDER_USER=builder \ - REPOSITORY_DIR=/repository \ - KEYS_DIR=/keys \ - SOURCE_DIR=/source \ - REPOSITORY_LIST= \ - REPOSITORY_NAME_DIR= \ - NFS_SERVER= \ - NFS_PORT=5000 \ - NFS_PATH= - -COPY build-apk /usr/bin/build-apk - -ARG REPOSITORIES - -RUN if [ ! -z "${REPOSITORIES}" ]; then \ - echo "${REPOSITORIES}" | tr ';' '\n' > /etc/apk/repositories; \ - fi && \ - apk update && \ - apk upgrade --no-cache && \ - apk add --no-cache build-base alpine-sdk abuild sudo git nfs-utils && \ - chmod 0755 /usr/bin/build-apk - -ENTRYPOINT ["/usr/bin/build-apk"] diff --git a/docker/Dockerfile.27.3.1 b/docker/Dockerfile.27.3.1 deleted file mode 100644 index eabd732..0000000 --- a/docker/Dockerfile.27.3.1 +++ /dev/null @@ -1,32 +0,0 @@ -ARG BASE_IMAGE_VERSION=latest - -FROM alpine:${BASE_IMAGE_VERSION} - -LABEL maintainer="Alexander Zhirov " -LABEL version="0.1.0" -LABEL description="Адаптированный для Docker >=27.3.1 образ сборщика APK-файлов для Alpine Linux" - -ENV BUILDER_USER=builder \ - REPOSITORY_DIR=/repository \ - KEYS_DIR=/keys \ - SOURCE_DIR=/source \ - REPOSITORY_LIST= \ - REPOSITORY_NAME_DIR= \ - NFS_SERVER= \ - NFS_PORT=5000 \ - NFS_PATH= - -COPY --chmod=0755 build-apk /usr/bin/build-apk - -ARG REPOSITORIES - -RUN < /etc/apk/repositories - fi - apk update - apk upgrade --no-cache - apk add --no-cache build-base alpine-sdk abuild sudo git nfs-utils -EOF - -ENTRYPOINT ["/usr/bin/build-apk"] diff --git a/docker/build-apk b/docker/build-apk deleted file mode 100644 index 33ca993..0000000 --- a/docker/build-apk +++ /dev/null @@ -1,148 +0,0 @@ -#!/bin/sh - -: "${BUILDER_USER:=builder}" -: "${REPOSITORY_DIR:=/repository}" -: "${KEYS_DIR:=/keys}" -: "${SOURCE_DIR:=/source}" -: "${REPOSITORY_LIST:=}" -: "${REPOSITORY_NAME_DIR:=}" -: "${NFS_SERVER:=}" -: "${NFS_PORT:=5000}" -: "${NFS_PATH:=}" - -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -NC='\033[0m' -BOLD='\033[1m' -RESET='\033[0m' - -log() { - local type=$1 - local message=$2 - case $type in - "success") printf "${GREEN}${BOLD}✅ %s${RESET}\n" "$message" ;; - "error") printf "${RED}${BOLD}❌ Ошибка: %s${RESET}\n" "$message" ;; - "info") printf "${YELLOW}${BOLD}ℹ️ %s${RESET}\n" "$message" ;; - esac -} - -while getopts "u:r:k:p:n:s:t:m:d:" opt; do - case $opt in - u) BUILDER_USER="$OPTARG" ;; - r) REPOSITORY_LIST="$OPTARG" ;; - k) PUBLIC_KEY="$OPTARG" ;; - p) PRIVATE_KEY="$OPTARG" ;; - n) NAME_KEY="$OPTARG" ;; - s) NFS_SERVER="$OPTARG" ;; - t) NFS_PORT="$OPTARG" ;; - m) NFS_PATH="$OPTARG" ;; - d) REPOSITORY_NAME_DIR="$OPTARG" ;; - \?) log error "Неверный аргумент! 😕 Использование: $0 [-u имя_пользователя] [-r список_репозиториев] [-k публичный_ключ] [-p приватный_ключ] [-n имя_ключа] [-s адрес_NFS_сервера] [-t порт_NFS_сервера] [-m путь_NFS] [-d имя_репозитория]" - exit 1 ;; - esac -done - -if [ -n "$REPOSITORY_NAME_DIR" ]; then - REPOSITORY_NAME_DIR=$(echo "$REPOSITORY_NAME_DIR" | sed 's|^./||;s|^/||;s|/$||') - if ! echo "$REPOSITORY_NAME_DIR" | grep -qE '^[a-zA-Z0-9_-]+$'; then - log error "Недопустимое имя директории репозитория: $REPOSITORY_NAME_DIR 😕 Используйте только буквы, цифры, _ и -" - exit 1 - fi -fi - -adduser -D "$BUILDER_USER" || { log error "Не удалось создать пользователя $BUILDER_USER 😞"; exit 1; } -addgroup "$BUILDER_USER" abuild || { log error "Не удалось добавить пользователя в группу abuild 😞"; exit 1; } -log success "Пользователь $BUILDER_USER успешно создан! 🥳" - -echo "$BUILDER_USER ALL=(ALL) NOPASSWD:ALL" > "/etc/sudoers.d/$BUILDER_USER" -chmod 0640 "/etc/sudoers.d/$BUILDER_USER" || { log error "Не удалось настроить sudo для $BUILDER_USER 😞"; exit 1; } -log success "Sudo успешно настроен для $BUILDER_USER! 🔒" - -DIRS="/home/$BUILDER_USER/package $KEYS_DIR $SOURCE_DIR $REPOSITORY_DIR" -for dir in $DIRS; do - if [ ! -d "$dir" ]; then - mkdir -p "$dir" || { log error "Не удалось создать директорию $dir 😞"; exit 1; } - chown "$BUILDER_USER:$BUILDER_USER" "$dir" - log success "Директория $dir успешно создана! 📁" - fi -done - -if [ -n "$NFS_SERVER" ]; then - if [ -z "$NFS_PATH" ]; then - log error "Путь NFS (-m) обязателен при указании NFS-сервера (-s) 😕" - exit 1 - fi - if ! echo "$NFS_PORT" | grep -qE '^[0-9]+$' || [ "$NFS_PORT" -lt 1 ] || [ "$NFS_PORT" -gt 65535 ]; then - log error "Недопустимый порт NFS-сервера: $NFS_PORT 😕 Используйте число от 1 до 65535" - exit 1 - fi - if ! echo "$NFS_PATH" | grep -qE '^/([a-zA-Z0-9_-]+/)*[a-zA-Z0-9_-]*$'; then - log error "Недопустимый путь NFS: $NFS_PATH 😕 Путь должен начинаться с / и содержать только буквы, цифры, _, - и /" - exit 1 - fi - log info "Настройка подключения к NFS-серверу: $NFS_SERVER:$NFS_PATH на порту $NFS_PORT 🌐" - mount -t nfs -o port="$NFS_PORT" "$NFS_SERVER:$NFS_PATH" "$REPOSITORY_DIR" || { log error "Не удалось подключиться к NFS-серверу $NFS_SERVER:$NFS_PATH 😞"; exit 1; } - log success "NFS-сервер $NFS_SERVER:$NFS_PATH успешно смонтирован в $REPOSITORY_DIR на порту $NFS_PORT! 📡" -fi - -if [ -n "$REPOSITORY_LIST" ]; then - echo "$REPOSITORY_LIST" | tr ';' '\n' > /etc/apk/repositories; - log success "Репозитории успешно обновлены! 📦" -fi - -NAME_KEY="${NAME_KEY:=$BUILDER_USER}" - -if ! echo "$NAME_KEY" | grep -qE '^[a-zA-Z0-9_-]+$'; then - log error "Недопустимое имя ключа: $NAME_KEY 😕 Используйте только буквы, цифры, _ и -" - exit 1 -fi - -if [ -n "$PRIVATE_KEY" ] || [ -n "$PUBLIC_KEY" ]; then - if [ -z "$PRIVATE_KEY" ] || [ -z "$PUBLIC_KEY" ] || [ -z "$NAME_KEY" ]; then - log error "Необходимо указать оба ключа (публичный и приватный) и имя ключа 😞" - exit 1 - fi - - if ! echo "$PRIVATE_KEY" | grep -q "BEGIN RSA PRIVATE KEY"; then - log error "Неверный формат приватного ключа 😕" - exit 1 - fi - if ! echo "$PUBLIC_KEY" | grep -q "BEGIN PUBLIC KEY"; then - log error "Неверный формат публичного ключа 😕" - exit 1 - fi - - mkdir -p "/home/$BUILDER_USER/.abuild" || { log error "Не удалось создать .abuild директорию 😞"; exit 1; } - echo "PACKAGER_PRIVKEY=\"$KEYS_DIR/$NAME_KEY.rsa\"" > "/home/$BUILDER_USER/.abuild/abuild.conf" - - echo "$PRIVATE_KEY" > "$KEYS_DIR/$NAME_KEY.rsa" - echo "$PUBLIC_KEY" > "$KEYS_DIR/$NAME_KEY.rsa.pub" - - chmod 600 "$KEYS_DIR/$NAME_KEY.rsa" || { log error "Не удалось установить права для приватного ключа 😞"; exit 1; } - chmod 644 "$KEYS_DIR/$NAME_KEY.rsa.pub" "/home/$BUILDER_USER/.abuild/abuild.conf" || { log error "Не удалось установить права для файлов 😞"; exit 1; } - - chown "$BUILDER_USER:$BUILDER_USER" "$KEYS_DIR/$NAME_KEY.rsa" "$KEYS_DIR/$NAME_KEY.rsa.pub" "/home/$BUILDER_USER/.abuild/abuild.conf" - - cp "$KEYS_DIR/$NAME_KEY.rsa.pub" /etc/apk/keys/ || { log error "Не удалось скопировать публичный ключ 😞"; exit 1; } - log success "Ключи успешно настроены! 🔑" -else - if [ -f "$KEYS_DIR/$NAME_KEY.rsa" ] && [ -f "$KEYS_DIR/$NAME_KEY.rsa.pub" ]; then - mkdir -p "/home/$BUILDER_USER/.abuild" - chown "$BUILDER_USER:$BUILDER_USER" "/home/$BUILDER_USER/.abuild" - echo "PACKAGER_PRIVKEY=\"$KEYS_DIR/$NAME_KEY.rsa\"" > "/home/$BUILDER_USER/.abuild/abuild.conf" - cp "$KEYS_DIR/$NAME_KEY.rsa.pub" /etc/apk/keys/ - log success "Использованы существующие ключи! 🔄" - else - su - "$BUILDER_USER" -c "echo \"$KEYS_DIR/$NAME_KEY.rsa\" | abuild-keygen -a -i" || { log error "Не удалось сгенерировать ключи 😞"; exit 1; } - log success "Новые ключи успешно сгенерированы! 🆕" - fi -fi - -su - "$BUILDER_USER" -c " - cp -r $SOURCE_DIR/* /home/$BUILDER_USER/package/ || exit 1 - cd /home/$BUILDER_USER/package || exit 1 - REPODEST=\"$REPOSITORY_DIR/\${REPOSITORY_NAME_DIR:-v\$(cat /etc/alpine-release | cut -d. -f1,2)}\" abuild -r -" || { log error "Не удалось собрать пакет 😞"; exit 1; } - -log success "Сборка пакета успешно завершена! 🎉"