copart-uk-api

api: checking… 0 lots loaded
loading…
Diagnostic tests
— click a button above to run a test —
Ручной парсинг лота Запрашивает свежие данные с Copart UK, обновляет БД и (при необходимости) докачивает картинки.
Без force и при выставленном images_downloaded_at картинки не перекачиваются (защита от лишнего расхода прокси-квоты). Сами байты в любом случае не дублируются — Storage.Exists() проверяется перед каждым download'ом.
Сводка за 24 часа обновляется автоматически
Последние запуски crawler / sweeper фильтр:
start kind status duration pages lots seen new / upd lost images ok / fail error
loading…
Картинки: окно
Распределение по типу события
kindokfailedsuccess rate
Топ ошибок
errorcount
HTTP-статусы
Последние события
occurredlotkindoutcome httpbytesdurationerror
loading…
Аналитика API: окно
Запросы по времени
Топ маршрутов
methodrouterequestserrors avg, msp95, msbytes out
Топ клиентов (за окно)
client / api_keyrequestserrorslast seen
Распределение по статусам
Текущая конфигурация живёт в памяти процесса
Деплой в Google Cloud

Краткий план

Сервис состоит из трёх процессов: api (HTTP), crawler (обходит каталог), sweeper (рефрешит лоты в горизонте 48ч). Все три собираются из одного Dockerfile. Картинки складываются в S3-совместимое хранилище. Postgres лучше всего держать в Cloud SQL, чтобы не управлять persistence руками.

  1. Подготовьте GCP-проект и API.
    gcloud projects create copart-uk --name "copart-uk"
    gcloud config set project copart-uk
    gcloud services enable run.googleapis.com artifactregistry.googleapis.com \
                           sqladmin.googleapis.com secretmanager.googleapis.com \
                           compute.googleapis.com storage.googleapis.com
  2. Создайте Artifact Registry и загрузите образ.
    gcloud artifacts repositories create copart-uk \
       --repository-format=docker --location=europe-west2
    
    REGION=europe-west2
    IMG="$REGION-docker.pkg.dev/$(gcloud config get-value project)/copart-uk/api:$(git rev-parse --short HEAD)"
    docker build --platform=linux/amd64 -t "$IMG" .
    docker push "$IMG"
  3. Cloud SQL Postgres.
    gcloud sql instances create copart-uk-pg --database-version=POSTGRES_16 \
       --region=europe-west2 --tier=db-custom-2-7680 --storage-type=SSD --storage-size=50
    gcloud sql databases create copart    --instance=copart-uk-pg
    gcloud sql users create     copart    --instance=copart-uk-pg --password=...
    # Используйте Cloud SQL Auth Proxy или приватный VPC connector — open INET не нужен.
  4. Бакет для картинок. Можно AWS S3 (рекомендуется для меньшей задержки до cs.copart.com), либо GCS в S3-совместимом режиме.
    # Вариант 1: GCS в S3-режиме
    gcloud storage buckets create gs://copart-uk-images --location=europe-west2 \
           --uniform-bucket-level-access
    # HMAC-ключ:
    gsutil hmac create copart-uk-images-sa@$(gcloud config get-value project).iam.gserviceaccount.com
    # → выдаст S3_ACCESS_KEY и S3_SECRET_KEY
    # В env:
    #   S3_ENDPOINT=storage.googleapis.com
    #   S3_USE_SSL=true
    #   S3_REGION=auto
    #   S3_BUCKET=copart-uk-images
    
    # Вариант 2: AWS S3 (eu-west-2)
    aws s3api create-bucket --bucket copart-uk-images --region eu-west-2 \
        --create-bucket-configuration LocationConstraint=eu-west-2
  5. Секреты в Secret Manager.
    for k in JWT_SECRET DATABASE_URL S3_ACCESS_KEY S3_SECRET_KEY PROXY_LIST AUCTIONSAPI_COMPAT_KEY; do
      echo -n "..." | gcloud secrets create $k --data-file=-
    done
  6. Деплой api на Cloud Run. Stateless, авто-скейл, hooks на /healthz. Не подойдёт для crawler/sweeper — Run останавливает контейнер без активных запросов.
    gcloud run deploy copart-uk-api \
       --image="$IMG" --region=$REGION --port=8080 \
       --memory=1Gi --cpu=2 --min-instances=1 --max-instances=5 \
       --add-cloudsql-instances=$(gcloud config get-value project):$REGION:copart-uk-pg \
       --set-env-vars=STORAGE_BACKEND=s3,S3_BUCKET=copart-uk-images,S3_ENDPOINT=s3.eu-west-2.amazonaws.com,S3_REGION=eu-west-2,S3_USE_SSL=true,CHROMEDP_ENABLED=false,PROXY_QUOTA_GB=500 \
       --set-secrets=JWT_SECRET=JWT_SECRET:latest,DATABASE_URL=DATABASE_URL:latest,S3_ACCESS_KEY=S3_ACCESS_KEY:latest,S3_SECRET_KEY=S3_SECRET_KEY:latest,AUCTIONSAPI_COMPAT_KEY=AUCTIONSAPI_COMPAT_KEY:latest \
       --allow-unauthenticated

    Внимание: для api Chromedp не нужен (его использует только bootstrap-flow в crawler/sweeper). Cloud Run не позволяет монтировать /dev/shm в нужном размере — отключайте chromedp на API.

  7. Crawler / sweeper — Compute Engine или GKE. Это долгоживущие процессы с Chrome (нужно shm_size=1g). Простейший способ — Compute Engine VM e2-standard-2, на которой через docker compose подняты crawler + sweeper.
    gcloud compute instances create copart-uk-workers \
       --zone=europe-west2-a --machine-type=e2-standard-2 \
       --image-family=cos-stable --image-project=cos-cloud \
       --tags=copart-workers --service-account=copart-uk-sa@...
    # на машине запустить docker compose --profile crawler,sweeper up -d

    Если уже есть GKE — Deployment с emptyDir { medium: Memory, sizeLimit: 1Gi } на /dev/shm.

  8. Миграции. Один shot-job до деплоя api.
    gcloud run jobs deploy copart-uk-migrate \
       --image="$IMG" --command=/usr/local/bin/goose \
       --args="-dir,/app/migrations,postgres,${DATABASE_URL},up" \
       --set-secrets=DATABASE_URL=DATABASE_URL:latest \
       --region=$REGION
    gcloud run jobs execute copart-uk-migrate --region=$REGION --wait
  9. Cloud Logging / Monitoring. Запросы пишутся в stdout (chi middleware.Logger) и автоматически индексируются. Используйте лог-фильтр resource.type="cloud_run_revision" severity>=WARNING для алертов.
Локальный запуск
cp .env.example .env
# для локалки переопределите STORAGE_BACKEND=fs или поднимите MinIO из docker-compose
docker compose up -d postgres redis minio
docker compose run --rm migrate
docker compose up -d api
docker compose --profile crawler run --rm crawler   # одноразовый прогон
docker compose up -d sweeper                         # фон
Токены и доступы

Какие тут есть тачки авторизации?

  • JWT (Bearer) — для /v1/* (lots, search). Конфиг: JWT_SECRET. Алгоритм — HMAC (HS256/HS384/HS512).
  • API-ключ (?api_key=… или заголовок X-Api-Key) — для /api/cars (auctionsapi.com-совместимый эндпоинт). Конфиг: AUCTIONSAPI_COMPAT_KEY. Если переменная пустая — middleware пропускает всех (dev-режим).
  • Без авторизации/img/{lot}/{file}, /healthz, и сам админ-UI (предполагается, что он закрыт IAP/VPN на уровне сети).

Генерация JWT

Самый быстрый путь — однострочник на Python (никаких сторонних утилит ставить не нужно):

python3 - <<'PY'
import hmac, hashlib, json, base64, time, os
secret = os.environ["JWT_SECRET"].encode()
header  = base64.urlsafe_b64encode(json.dumps({"alg":"HS256","typ":"JWT"}).encode()).rstrip(b'=')
payload = base64.urlsafe_b64encode(json.dumps({
    "sub": "client-acme",          # client identifier — попадает в request log
    "iat": int(time.time()),
    "exp": int(time.time()) + 365*24*3600,
}).encode()).rstrip(b'=')
signing = header + b'.' + payload
sig     = base64.urlsafe_b64encode(hmac.new(secret, signing, hashlib.sha256).digest()).rstrip(b'=')
print((signing + b'.' + sig).decode())
PY

Используется так:

curl -H "Authorization: Bearer $TOKEN" \
     https://api.copart-uk.example.com/v1/lots/12345678

Использование API-ключа для /api/cars

# через query
curl "https://api.copart-uk.example.com/api/cars?limit=50&api_key=$AUCTIONSAPI_COMPAT_KEY"

# или через заголовок
curl -H "X-Api-Key: $AUCTIONSAPI_COMPAT_KEY" \
     https://api.copart-uk.example.com/api/cars?limit=50

Ротация

  • JWT: поменяйте JWT_SECRET в Secret Manager → перезапустите api. Все ранее выписанные токены инвалидируются. Перед ротацией выдайте клиентам новые токены, чтобы избежать простоя.
  • API-ключ: аналогично, поменяйте AUCTIONSAPI_COMPAT_KEY. Сейчас поддерживается один активный ключ; для постепенной ротации запустите две версии сервиса с разными ключами и распределите трафик через Cloud Run revisions.
  • Все запросы пишутся в api_request_log с last4 ключа и client_id из JWT — следите за аномалиями во вкладке Аналитика API.

Безопасность

  • Админ-UI не имеет встроенной авторизации — закройте его IAP (Cloud Run → Identity-Aware Proxy) или ограничьте по IP через Cloud Load Balancer.
  • Никогда не коммитьте .env с реальными секретами. Используйте Secret Manager + --set-secrets.
  • Прокси-листы (PROXY_LIST, IMAGE_PROXY_LIST) тоже секреты — там логины IPRoyal.
×

Images

Raw JSON