Files
K3S/addons/harbor/role/templates/harbor-configure-job.yaml.j2
Sergey Antropoff 5dc0fbcd3a feat: harbor — proxy cache зеркалирование + tag retention policy
Proxy cache (harbor_proxy_cache_enabled: true):
- Автоматически создаёт registry endpoints + proxy cache проекты для:
  docker.io, gcr.io, quay.io, ghcr.io, registry.k8s.io, mcr.microsoft.com, public.ecr.aws
- При pull образа через harbor.example.com/<registry>/<image> он кэшируется
- Реализовано через alpine:3.19 + curl + jq Kubernetes Job (вызывает Harbor REST API изнутри кластера)

Tag retention (harbor_retention_enabled: true, harbor_retention_max_tags: 3):
- Политика "latestPushedN=3" применяется ко ВСЕМ проектам (включая proxy cache)
- Пропускает проекты с уже существующей политикой (idempotent)
- Запуск: ежедневно в 03:00 UTC (cron schedule в Harbor)

Механизм: Job запускается после Helm install, достучивается до harbor-core по
internal service DNS, ждёт API готовности (40 попыток × 15 сек = 10 мин max).
2026-04-25 11:54:43 +03:00

142 lines
5.9 KiB
Django/Jinja
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
# ConfigMap со скриптом конфигурации Harbor
# Настраивает proxy-cache registry и tag retention policies через REST API
apiVersion: v1
kind: ConfigMap
metadata:
name: harbor-configure
namespace: {{ harbor_namespace }}
data:
configure.sh: |
#!/bin/sh
set -e
apk add -q curl jq
BASE="http://harbor.{{ harbor_namespace }}.svc.cluster.local"
AUTH="admin:{{ harbor_admin_password }}"
# ── Ждём готовности Harbor API ────────────────────────────────────────────
echo ">>> Ожидаю готовности Harbor API..."
for i in $(seq 1 40); do
STATUS=$(curl -sf -o /dev/null -w "%{http_code}" -u "$AUTH" \
"$BASE/api/v2.0/systeminfo" 2>/dev/null || echo "000")
[ "$STATUS" = "200" ] && echo "Harbor API готов" && break
echo "Попытка $i/40 (HTTP $STATUS), жду 15 сек..."
sleep 15
[ "$i" -eq 40 ] && echo "ОШИБКА: Harbor API недоступен" && exit 1
done
{% if harbor_proxy_cache_enabled %}
# ── Proxy Cache: создать registry endpoints и проекты ─────────────────────
echo ""
echo ">>> Настройка proxy-cache реестров..."
{% for reg in harbor_proxy_cache_registries %}
echo "--- {{ reg.description }} ({{ reg.name }}) ---"
# Создать registry endpoint (409 = уже существует — ок)
curl -sf -X POST -u "$AUTH" -H "Content-Type: application/json" \
-d '{"name":"{{ reg.name }}","type":"{{ reg.type }}","url":"{{ reg.url }}","description":"{{ reg.description }}","insecure":false}' \
"$BASE/api/v2.0/registries" \
-o /dev/null -w " Endpoint: HTTP %{http_code}\n" || true
# Получить ID endpoint-а
REG_ID=$(curl -sf -u "$AUTH" \
"$BASE/api/v2.0/registries?name={{ reg.name }}" | jq -e '.[0].id' 2>/dev/null || echo "")
if [ -z "$REG_ID" ] || [ "$REG_ID" = "null" ]; then
echo " ПРЕДУПРЕЖДЕНИЕ: не удалось получить ID для {{ reg.name }}, пропускаю"
else
# Создать proxy cache проект (409 = уже существует — ок)
curl -sf -X POST -u "$AUTH" -H "Content-Type: application/json" \
-d "{\"project_name\":\"{{ reg.name }}\",\"public\":true,\"registry_id\":$REG_ID,\"metadata\":{\"public\":\"true\"}}" \
"$BASE/api/v2.0/projects" \
-o /dev/null -w " Проект: HTTP %{http_code}\n" || true
fi
{% endfor %}
echo ">>> Proxy-cache реестры настроены"
echo " Примеры pull через Harbor:"
{% for reg in harbor_proxy_cache_registries %}
echo " {{ harbor_ingress_host }}/{{ reg.name }}/<image>:<tag>"
{% endfor %}
{% endif %}
{% if harbor_retention_enabled %}
# ── Tag Retention: применить ко всем проектам ─────────────────────────────
echo ""
echo ">>> Настройка retention policy (max {{ harbor_retention_max_tags }} тегов на репозиторий)..."
# Получить все проекты и сохранить в файл (избегаем subshell через pipe)
curl -sf -u "$AUTH" "$BASE/api/v2.0/projects?page_size=100" \
| jq -c '.[]' > /tmp/projects.json
while IFS= read -r project; do
PROJ_ID=$(echo "$project" | jq '.id')
PROJ_NAME=$(echo "$project" | jq -r '.name')
# Пропустить если retention уже настроен
EXISTING_RET=$(echo "$project" | jq -r '.metadata.retention_id // empty')
if [ -n "$EXISTING_RET" ]; then
echo " $PROJ_NAME: retention уже настроен (id: $EXISTING_RET), пропускаю"
continue
fi
# Создать retention policy для проекта
RET_RESP=$(curl -sf -X POST -u "$AUTH" -H "Content-Type: application/json" \
-d "{
\"algorithm\": \"or\",
\"rules\": [{
\"disabled\": false,
\"action\": \"retain\",
\"template\": \"latestPushedN\",
\"params\": {\"latestPushedN\": {{ harbor_retention_max_tags }}},
\"tag_selectors\": [{\"kind\": \"doublestar\", \"decoration\": \"matches\", \"pattern\": \"**\"}],
\"scope_selectors\": {
\"repository\": [{\"kind\": \"doublestar\", \"decoration\": \"repoMatches\", \"pattern\": \"**\"}]
}
}],
\"trigger\": {\"kind\": \"Schedule\", \"settings\": {\"cron\": \"0 0 3 * * *\"}},
\"scope\": {\"level\": \"project\", \"ref\": $PROJ_ID}
}" \
"$BASE/api/v2.0/retentions" 2>/dev/null || echo "{}")
RET_ID=$(echo "$RET_RESP" | jq '.id // empty' 2>/dev/null || echo "")
if [ -n "$RET_ID" ] && [ "$RET_ID" != "null" ]; then
echo " $PROJ_NAME (id: $PROJ_ID): retention policy #$RET_ID установлена"
else
echo " $PROJ_NAME: не удалось создать retention (возможно уже настроено)"
fi
done < /tmp/projects.json
echo ">>> Retention policies настроены (запуск: ежедневно в 03:00 UTC)"
{% endif %}
echo ""
echo ">>> Конфигурация Harbor завершена!"
---
apiVersion: batch/v1
kind: Job
metadata:
name: harbor-configure
namespace: {{ harbor_namespace }}
spec:
ttlSecondsAfterFinished: 600
backoffLimit: 3
template:
spec:
restartPolicy: OnFailure
containers:
- name: configure
image: alpine:3.19
command: ["/bin/sh", "/scripts/configure.sh"]
volumeMounts:
- name: scripts
mountPath: /scripts
volumes:
- name: scripts
configMap:
name: harbor-configure
defaultMode: 0755