Добавлены скрипты для полного рендера манифестов и точка входа образа.

This commit is contained in:
emelinda 2026-08-11 03:33:56 +03:00
parent 492d31b253
commit a713c46ed0
4 changed files with 190 additions and 0 deletions

25
.dockerignore Normal file
View File

@ -0,0 +1,25 @@
# В контекст сборки нужны только манифесты: clusters/, apps/, infrastructure/
# и скрипты из hack/. Всё остальное — история, IDE, секреты — только раздувает
# контекст и рискует уехать в образ.
.git
.gitignore
.idea
.claude
CLAUDE.md
.env
.env.*
docs
*.md
aero
inventory.yaml
tmp
.tmp/
snapshots
out
# Секреты и ключи не должны попадать в контекст сборки даже случайно.
*.pem
*.key
*.p12
kubeconfig*
*service-account*.json

77
Dockerfile Normal file
View File

@ -0,0 +1,77 @@
# Полная сборка манифестов IaC-репозитория для одного контура.
#
# docker build --build-arg CONTOUR=aero -t iac:aero .
# docker run --rm iac:aero list # что собралось
# docker run --rm iac:aero cat clusters # слои Flux одним потоком
# docker run --rm -v "$PWD/out:/export" iac:aero export
#
# Контур — имя каталога в clusters/ (aero, brusnika-prod, dsinv, wb, ...).
# Тот же идентификатор служит именем overlay внутри apps/* и infrastructure/*,
# поэтому одного аргумента хватает на весь рендер.
#
# Сборка офлайновая: kustomize build разворачивает оверлеи и патчи, а
# HelmRelease остаётся Custom Resource'ом — чарты тянет Flux уже в кластере.
# Ни helm, ни доступ к OCI-реестру здесь не нужны. Исключение — валидация:
# схемы CRD kubeconform берёт из сети (отключается VALIDATE=0).
ARG KUSTOMIZE_VERSION=v5.4.3
ARG KUBECONFORM_VERSION=v0.6.7
FROM registry.k8s.io/kustomize/kustomize:${KUSTOMIZE_VERSION} AS kustomize
FROM ghcr.io/yannh/kubeconform:${KUBECONFORM_VERSION} AS kubeconform
FROM alpine:3.20 AS builder
# Контур обязателен по смыслу, но значение по умолчанию оставлено: сборка без
# --build-arg собирает aero, а не падает на пустой переменной.
ARG CONTOUR=aero
ARG VALIDATE=1
ARG KUBERNETES_VERSION=1.30.0
COPY --from=kustomize /app/kustomize /usr/local/bin/kustomize
COPY --from=kubeconform /kubeconform /usr/local/bin/kubeconform
WORKDIR /src
# Скрипт копируется отдельным слоем: правка манифестов не инвалидирует его,
# а правка скрипта не тянет за собой пересборку базовых слоёв.
COPY hack/render-contour.sh /usr/local/bin/render-contour
RUN chmod +x /usr/local/bin/render-contour
COPY . .
RUN render-contour "${CONTOUR}" /out
# Валидация отдельным слоем: смена версии Kubernetes не пересобирает рендер.
# --ignore-missing-schemas пропускает ресурсы, чьих схем нет в каталоге
# (часть CRD), но не заглушает ошибки в тех, что нашлись.
RUN if [ "${VALIDATE}" = "1" ]; then \
kubeconform \
-kubernetes-version "${KUBERNETES_VERSION}" \
-strict \
-ignore-missing-schemas \
-schema-location default \
-schema-location 'https://raw.githubusercontent.com/datreeio/CRDs-catalog/main/{{.Group}}/{{.ResourceKind}}_{{.ResourceAPIVersion}}.json' \
-summary \
/out/*.yaml ; \
else \
echo "VALIDATE=0 — проверка схемами пропущена" ; \
fi
FROM alpine:3.20
ARG CONTOUR=aero
ENV CONTOUR=${CONTOUR}
LABEL org.opencontainers.image.title="iac-manifests" \
org.opencontainers.image.description="Собранные манифесты контура ${CONTOUR}" \
ru.iac.contour="${CONTOUR}"
COPY --from=builder /out /manifests
COPY hack/entrypoint.sh /usr/local/bin/entrypoint
RUN chmod +x /usr/local/bin/entrypoint
ENTRYPOINT ["/usr/local/bin/entrypoint"]
CMD ["list"]

27
hack/entrypoint.sh Normal file
View File

@ -0,0 +1,27 @@
#!/bin/sh
# Точка входа образа с собранными манифестами.
#
# list — что собралось
# cat [префикс] — весь контур (или его часть) одним потоком
# export [путь] — скопировать манифесты в примонтированный каталог
# <команда> — выполнить как есть
set -eu
case "${1:-list}" in
list)
ls -1 /manifests
;;
cat)
shift
cat /manifests/"${1:-}"*.yaml
;;
export)
dst="${2:-/export}"
[ -d "$dst" ] || { echo "Каталог ${dst} не примонтирован" >&2; exit 1; }
cp /manifests/*.yaml "$dst"/
echo "Выгружено в ${dst}"
;;
*)
exec "$@"
;;
esac

61
hack/render-contour.sh Normal file
View File

@ -0,0 +1,61 @@
#!/bin/sh
# Рендер всех kustomization'ов, относящихся к одному контуру.
#
# render-contour.sh <контур> <каталог-результата>
#
# Используется из Dockerfile, но работает и локально — нужен только kustomize.
set -eu
contour="${1:?не задан контур}"
out="${2:?не задан каталог результата}"
if [ ! -d "clusters/${contour}" ]; then
echo "Неизвестный контур: ${contour}" >&2
echo "Доступные:" >&2
ls clusters | sed 's/^/ - /' >&2
exit 1
fi
mkdir -p "$out"
build() {
dir="$1"
# Имя файла повторяет путь: clusters/aero/apps -> clusters.aero.apps.yaml
name=$(echo "$dir" | tr '/' '.')
echo " build ${dir}"
# --load-restrictor LoadRestrictionsNone: слои ссылаются на apps/ и
# infrastructure/ через ../../.., то есть выходят за корень kustomization.
kustomize build --load-restrictor LoadRestrictionsNone "$dir" > "${out}/${name}.yaml"
}
# Каталоги контура: сам clusters/<contour> и все его слои (controllers, configs,
# apps, infrastructure — набор у контуров разный, поэтому ищем, а не перечисляем).
# flux-system исключён: gotk-components.yaml генерирует `flux bootstrap`,
# он и так лежит в репозитории готовым.
echo "Контур ${contour}: слои Flux"
find "clusters/${contour}" -name kustomization.yaml -not -path '*/flux-system/*' \
| sed 's#/kustomization.yaml$##' | sort > /tmp/layers.txt
while read -r dir; do
build "$dir"
done < /tmp/layers.txt
# Оверлеи приложений и инфраструктуры. Через слои они уже отрендерились, но
# отдельные файлы дают поресурсный diff и ловят оверлей, который в слои пока
# не подключён, — такой ломался бы уже при подключении.
for root in apps infrastructure; do
[ -d "$root" ] || continue
echo "Контур ${contour}: оверлеи ${root}/*/${contour}"
for dir in "$root"/*/"$contour"; do
[ -f "${dir}/kustomization.yaml" ] || continue
build "$dir"
done
done
# Пустой результат почти наверняка означает опечатку в имени контура —
# лучше упасть на сборке, чем отдать пустой образ.
if [ -z "$(ls -A "$out")" ]; then
echo "Для контура ${contour} не собрано ни одного манифеста" >&2
exit 1
fi
echo "Готово: $(ls -1 "$out" | wc -l) файлов в ${out}"