# Сборка и публикация Docker-образа grabber-ai в реестр контейнеров Gitea. # # Запускается: пуш в main/master, тег v*, вручную (workflow_dispatch). # Нужно один раз настроить (подробно — docs/docker.md, раздел «CI/CD в Gitea»): # * включить Actions в репозитории и зарегистрировать act_runner с доступом к Docker; # * Secrets репозитория: # ACTION_PAT токен Gitea (права write:package и read:package): им образ публикуется в реестр # и скачиваются модели (Secret; Variable с тем же именем тоже подойдёт) # REGISTRY_USER (необязательно) владелец токена; по умолчанию владелец репозитория # MODELS_URL (необязательно) ссылка на models-bundle.tar.gz; без неё образ собирается без моделей name: docker on: push: branches: [main, master] tags: ["v*"] workflow_dispatch: env: IMAGE_NAME: grabber-ai # Публичный адрес реестра (HTTPS). Нельзя брать из GITHUB_SERVER_URL: внутри раннера это внутренний # адрес Gitea (http://192.168.x.x:3000), у него нет HTTPS. Переопределяется переменной REGISTRY_HOST. REGISTRY_HOST: ${{ vars.REGISTRY_HOST || 'git.shx.one' }} jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: lfs: true # модели в docker-models/models лежат в Git LFS - name: Проверка синтаксиса кода сервиса run: | python3 -m compileall -q src python3 -c "import ast,sys; [ast.parse(open(f, encoding='utf-8').read()) for f in ('tools/pack_models.py',)]" - name: Модели (docker-models/models) env: MODELS_URL: ${{ secrets.MODELS_URL }} MODELS_TOKEN: ${{ secrets.ACTION_PAT || vars.ACTION_PAT }} run: | if [ -s docker-models/models/best/model.pt ] && [ "$(stat -c %s docker-models/models/best/model.pt)" -gt 1000000 ]; then echo "модели взяты из репозитория (Git LFS)" ls -la docker-models/models/best docker-models/models/segmenter elif [ -n "$MODELS_URL" ]; then echo "скачиваю модели" if [ -n "$MODELS_TOKEN" ]; then curl -fsSL -H "Authorization: token $MODELS_TOKEN" "$MODELS_URL" -o models-bundle.tar.gz else curl -fsSL "$MODELS_URL" -o models-bundle.tar.gz fi tar -xzf models-bundle.tar.gz -C docker-models test -f docker-models/models/best/model.pt ls -la docker-models/models/best docker-models/models/segmenter else echo "MODELS_URL не задан: образ будет без моделей (их нужно смонтировать: -v ./models:/app/models:ro)" fi - name: Теги образа id: meta run: | REGISTRY="${REGISTRY_HOST}" OWNER="$(echo "${GITHUB_REPOSITORY%%/*}" | tr "[:upper:]" "[:lower:]")" IMAGE="${REGISTRY}/${OWNER}/${IMAGE_NAME}" TAGS="${IMAGE}:sha-${GITHUB_SHA::8}" if [ "${GITHUB_REF_TYPE}" = "tag" ]; then TAGS="$TAGS ${IMAGE}:${GITHUB_REF_NAME}" fi case "${GITHUB_REF_NAME}" in main|master) TAGS="$TAGS ${IMAGE}:latest";; esac echo "registry=${REGISTRY}" >> "$GITHUB_OUTPUT" echo "tags=${TAGS}" >> "$GITHUB_OUTPUT" echo "теги: ${TAGS}" - name: Сборка run: | set -e ARGS="" for t in ${{ steps.meta.outputs.tags }}; do ARGS="$ARGS -t $t"; done docker build $ARGS . - name: Проверка образа (если модели внутри) run: | set -e FIRST="$(echo '${{ steps.meta.outputs.tags }}' | cut -d' ' -f1)" if [ ! -f docker-models/models/best/model.pt ]; then echo "моделей в образе нет — запуск пропущен"; exit 0 fi docker run -d --name grabber-smoke "$FIRST" for i in $(seq 1 60); do if docker exec grabber-smoke python -c "import urllib.request as u; print(u.urlopen('http://127.0.0.1:8000/health', timeout=4).read().decode())" 2>/dev/null; then docker rm -f grabber-smoke; exit 0 fi sleep 5 done docker logs grabber-smoke; docker rm -f grabber-smoke; exit 1 - name: Публикация в реестр Gitea env: REGISTRY_USER: ${{ secrets.REGISTRY_USER || github.repository_owner }} REGISTRY_TOKEN: ${{ secrets.ACTION_PAT || vars.ACTION_PAT }} run: | set -e test -n "$REGISTRY_TOKEN" || { echo "не задан ACTION_PAT (Settings → Actions → Secrets)"; exit 1; } echo "$REGISTRY_TOKEN" | docker login "${{ steps.meta.outputs.registry }}" -u "$REGISTRY_USER" --password-stdin for t in ${{ steps.meta.outputs.tags }}; do docker push "$t"; done