Ответ
В DevOps-практиках версии приложений управляются автоматически и декларативно. Вот основные подходы:
1. Источник истины для версии:
- Git-теги (Semantic Versioning - SemVer): Самый распространенный способ. Версия определяется тегами в репозитории (
v1.2.3,2.0.0-rc.1). - Файлы метаданных: Например,
package.jsonдля Node.js,pyproject.toml/setup.pyдля Python,pom.xmlдля Java. Версия хранится внутри проекта. - Номер сборки из CI/CD: Уникальный инкрементный номер, генерируемый системой CI/CD (например,
$CI_PIPELINE_IIDв GitLab).
2. Как версия "подтягивается" в процесс CI/CD:
Сценарий A: Версия из Git-тега (рекомендуемый для релизов)
# Скрипт в .gitlab-ci.yml или GitHub Actions workflow
# Извлекаем версию из последнего тега
VERSION=$(git describe --tags --abbrev=0)
# Или для коммита с тегом:
VERSION=${CI_COMMIT_TAG}
# Передаем версию как переменную окружения в следующие шаги
export APP_VERSION=${VERSION}
# Используем при сборке Docker-образа
docker build --build-arg VERSION=${APP_VERSION} -t my-registry/app:${APP_VERSION} .
# Или для создания артефакта
echo "Building version: ${APP_VERSION}"
Сценарий B: Версия из файла проекта + хэш коммита (для dev-сборок)
# Для Python проекта (из pyproject.toml)
VERSION=$(python -c "import tomli; print(tomli.load(open('pyproject.toml', 'rb'))['project']['version'])")
COMMIT_SHA=$(git rev-parse --short HEAD)
FULL_VERSION="${VERSION}-dev+${COMMIT_SHA}"
# Используем для тегирования образа
docker tag my-app:latest my-registry/app:${FULL_VERSION}
Сценарий C: Использование специализированных инструментов (например, для Go)
# Можно использовать `goreleaser` или встроенные флаги `ldflags`
go build -ldflags "-X main.version=$(git describe --tags)" -o app .
3. Инъекция версии в артефакты и runtime:
- В Docker-образ: Через
ARGиENV.ARG VERSION="unknown" ENV APP_VERSION=$VERSION # Далее версия доступна внутри контейнера как $APP_VERSION - В бинарники/приложения: Через переменные сборки (как в примере с Go выше) или запись в файл
version.json. - В Helm-чарты: Версия передается через
--setили вvalues.yamlи подставляется в шаблоны, а также используется как метка (label) для ресурсов Kubernetes.helm upgrade my-app ./chart --set image.tag=${CI_COMMIT_TAG}
4. Best Practices:
- Автоматизация: Версия должна определяться автоматически в CI/CD, а не вручную.
- Идемпотентность: Сборка с одним и тем же тегом (например,
v1.0.0) должна производить бинарно идентичный артефакт. - Прозрачность: Версия должна быть легко определяема у запущенного приложения (через эндпоинт
/version, метки в Kubernetes, переменную окружения). - Соответствие SemVer: Использование семантического версионирования облегчает понимание характера изменений (мажорная/минорная/патч-версия).