CDN для git
git-cdn — это зеркало git, которое можно размещать рядом с вашими машинами CI и разработчиками. Оно действует как прокси git+http(s), снижая использование WAN и ускоряя доступ к большим репозиториям git.
git-cdn — это зеркало по запросу, и он обновляет свой локальный кэш только при запросе клиентом. Это значит, что зеркало всегда гарантировано вернет последнюю версию из центрального репозитория. Другие решения для зеркалирования git (гео-репликация GitLab, зеркало Gerrit) основаны на cron или событиях, и всегда есть различие между центральным репозиторием и его зеркалами, что затрудняет использование этих зеркал работниками непрерывной интеграции.
git-cdn очень легко установить:
Полностью бессостоятельный для горизонтальной масштабируемости
Поддерживает аутентификацию BasicAuth через HTTPS (проверка аутентификации выполняется за счет принудительного вызова к центральному репозиторию).以下是翻译后的结果:
CDN для Git
Git-CDN — это зеркало Git, которое можно размещать рядом с вашими машинами CI и разработчиками. Оно действует как прокси Git+HTTP(S), снижая использование WAN и ускоряя доступ к большим репозиториям Git.
Git-CDN — это зеркало по запросу, и он обновляет свой локальный кэш только при запросе клиентом. Это значит, что зеркало всегда гарантировано вернет последнюю версию из центрального репозитория. Другие решения для зеркалирования Git (гео-репликация GitLab, зеркало Gerrit) основаны на cron или событиях, и всегда есть различие между центральным репозиторием и его зеркалами, что затрудняет использование этих зеркал работниками непрерывной интеграции.
Git-CDN очень легко установить:
Полностью бесостоятельный для горизонтальной масштабируемости- Поддерживает аутентификацию BasicAuth через HTTPS (проверка аутентификации выполняется за счет принудительного вызова к upstream, используя учетные данные BasicAuth)
Объекты Git-LFS кэшируются.
Кэшируются результаты пакетов (когда 20 рабочих процессов запрашивают одно и то же обновление git, вычисления будут выполнены только один раз).
Операции push (alias receive-pack
) реализованы как простой прокси, они просто передаются на сервер upstream, без использования каких-либо умных решений.
Это упрощает конфигурацию git, позволяя избежать настройки pushInsteadOf
и http_proxy
.
Быстрое создание огромных репозиториев Android с помощью clone.bundle
в Google Storage.
Тестировано с GitLab, но должно работать со всеми BasicAuth git+http(s) серверами.
Готово к использованию в производстве. Уже обслужил петабайты данных git для Renault SW Labs CI.
Изображение Docker доступно на GitLab Registry:
mkdir ~/gitCDN
docker run -it -p 8000:8000 -v $HOME/gitCDN:/git-data -e GITSERVER_UPSTREAM=https://gitlab.example.com/ -e WORKING_DIRECTORY=/git-data registry.gitlab.com/grouperenault/git_cdn
Редактирование конфигурации git
[url "http://localhost:8000/"]
вместо = https://gitlab.example.com/
Затем просто используйте git как обычно:
git clone https://gitlab.example.com/org/project.git
Мы считаем, что systemd + Docker + Nginx — это самый простой способ запустить git_cdn в среде продакшн. На самом деле мы используем Ansible для развёртывания всего этого, но это выходит за рамки цели данной документации.
curl -O /etc/systemd/system/gitcdn.service https://gitlab.com/grouperenault/git_cdn/-/raw/master/deploy/gitcdn.service
# редактируйте шаблон файла для настройки сервера источника
vi /etc/systemd/system/gitcdn.service
systemctl daemon-reload
systemctl enable gitcdn
systemctl start gitcdn
curl -O /etc/nginx/conf.d/git-cdn.conf https://gitlab.com/grouperenault/git_cdn/-/raw/master/deploy/git-cdn.conf
# редактируйте и настройте этот конфиг (необходима настройка сертификата SSL)
vi /etc/nginx/conf.d/git-cdn.conf
systemctl restart nginx
Если git_cdn.intra.example.com является DNS-сервером для вашего git_cdn, то пользователям потребуется добавить следующий фрагмент в свой ~/.gitconfig
:
[url "https://git_cdn.intra.example.com/"]
вместо = https://gitlab.example.com/
Как он предназначен для выполнения через Docker, git-cdn конфигурируется с помощью переменных окружения.
Вот список и значения по умолчанию.
# базовая обязательная конфигурация
GITSERVER_UPSTREAM= # централизованный Git-сервер (URL HTTP)
WORKING_DIRECTORY= # директория для хранения кеш-файлов
# конфигурация Gunicorn
GUNICORN_WORKERS=8 # число асинхронных циклов управления Gunicorn
GUNICORN_WORKER_CLASS= # указывает другой класс работников
```# Конфигурация логгирования
LOGGING_SERVER= # Сервер логгирования (JSON через UDP), отлично работает с vector.dev. Если не указан, логгирование осуществляется в консоль
SENTRY_DSN= # DSN Sentry для отправки отчетов об ошибках
```# Конфигурация кэша сборки
PACK_CACHE_SIZE_GB=20 # Размер кэша для git packs
# Следующие два параметра увеличат размер кэша и снизят коэффициент попаданий в кэш
PACK_CACHE_MULTI=false # Установите значение true для кэширования нескольких паков ref
PACK_CACHE_DEPTH=false # Установите значение true для кэширования при использовании глубины клонирования
# Конфигурация прокси
https_proxy= # Прокси для связи с сервером git
BUNDLE_PROXY= # Прокси для получения git bundles с AOSP CDN
# Обходные пути для устойчивости сети
# Иногда сложность наших сетей создаёт потерю соединения.
# Git-cdn автоматически повторяет запросы прозрачно от текущего клиента (при возможности).
REQUEST_MAX_RETRIES=10 # Количество повторных попыток для HTTP-запросов, проксифицированных непосредственно к источнику.
BACKOFF_START=0.5 # Экспоненциальный таймер повторной попытки между повторными попытками получения данных из git (вдвое увеличивается для каждого последующего запроса)
BACKOFF_COUNT=5 # Количество повторных попыток для повторных попыток получения данных из git```MAX_CONNECTIONS=10 # Максимальное количество соединений, которое git_cdn будет создавать с сервером источника
# Это число будет распределено между процессами gunicorn
MAX_GIT_UPLOAD_PACK=cpu_count() # Максимальное количество пакетов загрузки, которое git_cdn будет обрабатывать
# Это число будет распределено между процессами gunicorn
GIT_SSL_NO_VERIFY= # Может быть использовано для среды тестирования при использовании самоподписанных SSL-сертификатов (не для продакшена!)# Защита от зависаний git
GIT_PROCESS_WAIT_TIMEOUT=2 # время ожидания перед завершением работы процесса git (после отправки сигнала SIGTERM)
# Конфигурация метрик
PROMETHEUS_ENABLED=true # если установлено значение true, метрики Prometheus будут доступны по адресу /metrics
PROMETHEUS_MULTIPROC_DIR= # общая директория для хранения метрик Prometheus между несколькими рабочими процессами.
# Как это работает
Протокол HTTP Git разделён на две фазы.
Во время первой фазы (GET) клиент проверяет, что сервер реализует RPC, и запрашивает список ref, которыми располагает сервер для данного репозитория. На этой фазе git-cdn действует как простой прокси, не вмешиваясь в результаты и не используя кэшированные данные. Это позволяет гарантировать, что клиент всегда имеет самые свежие коммиты. Затем, во второй фазе, клиент отправляет POST-запрос со списком объектов, которые он имеет, и списком объектов, которые хочет получить. Сервер должен отправить ему минимальное количество объектов для восстановления необходимой ветки. На этой фазе git-CDN действует как умный прокси-кэш, передает список HAVE и WANTS локальному процессу Git и пытается удовлетворить запрос клиента локально. Если это не срабатывает, он попробует получить новые данные с сервера верхнего уровня и затем повторно попытается удовлетворить запрос клиента. Git-cdn всегда использует локальный Git для получения новых данных, чтобы оптимистично получать все новые данные с сервера.## Состояния повторной попытки
Если локальное хранилище не может удовлетворить запрос upload-pack, выполняются несколько повторных попыток, и
- если директория не существует, сразу переходим в состояние 3
- состояние 1: Повторная попытка после захвата записи. Захват записи означает, что параллельный запрос мог обновить базу данных параллельно. Мы повторяем попытку без обращения к верхнему уровню
- состояние 2: Повторная попытка после получения всех веток верхнего уровня
- состояние 3: Предполагаем, что хранилище повреждено, удаляем директорию и клонируем заново
- состояние 4: Невозможно ответить на запрос, отказываемся и передаем ошибку
# Клонирование-пакетов
git-cdn поддерживает клонирование пакетов как способ быстрого запуска больших окружений Android AOSP.
Это особенно полезно, когда git-cdn находится далеко от сервера верхнего уровня.
Эта функция работает только при использовании вместе с repo:- По умолчанию, repo скачивает файл `_clone.bundle` и использует его вместо полного клонирования.
- git-cdn проверяет в "https://storage.googleapis.com/gerritcodereview/android_{}_clone.bundle" (настраивается через переменную окружения CDN_BUNDLE_URL).
- git-cdn сначала выполняет команду HTTP HEAD и анализирует заголовки, чтобы выяснить наличие пакета, а также получить актуальную контрольную сумму MD5 и размер файла.
- git-cdn проксирует и кэширует этот файл в директорию \$WORKING_DIRECTORY/bundles.
- git-cdn гарантирует, что пакет имеет тот же размер и контрольную сумму, что и объявлено в bundle_url (контрольная сумма MD5 должна быть объявлена как `x-goog-hash: md5=$(md5hash_base64)`).
- repo инициализирует свой собственный локальный копию с помощью пакета, затем выполняет git fetch к git-cdn.
- git-cdn проверяет, есть ли пакет для этого модуля в кешевой директории, затем инициализирует свою локальную копию с помощью пакета.
- git-cdn синхронизирует оставшиеся объекты с сервера верхнего уровня, а затем обслуживает upload-pack как обычно # кэш для pack-файлов upload-pack.При выполнении команды `git clone`, Git вычисляет специальный 'pack'-файл, предназначенный для клиента.
Клиент предоставляет список имеющихся и желаемых номеров коммитов, а Git вычисляет точный список объектов, необходимых для восстановления базы данных Git, связанной с этими коммитами (включая историю).
В случае полного клонирования Git по умолчанию действительно отправляет всю базу данных Git.
Детали реализации делают так, что Git распаковывает и заново сжимает всю базу данных, поскольку формат, используемый для сетевых передач, немного отличается от формата, используемого для хранения на диске.
В общем рабочем процессе разработчика это достаточно эффективно, поскольку основным ограничивающим фактором является сеть, а разработчики всегда выполняют частые запросы на получение данных (`pull`), поэтому Git гарантирует, что мы отправляем минимальное количество данных клиенту.
В контексте CI на основе Docker, где работа непосредственно с данными всегда отбрасывается по причинам безопасности и/или воспроизводимости, это очень неэффективно, поскольку сервер Git постоянно генерирует полные данные для клонирования Git.Поэтому `git_cdn` реализует кэширование pack-файлов для `git clone`.
По умолчанию `git_cdn` кэширует только одно brunch-клонирование. Рекомендуется настроить CI-задания таким образом, чтобы они использовали метод клонирования ``--single-branch`` и скачивали только нужный branch. В результате это уменьшит количество объектов, требуемых для передачи, и также несколько увеличит коэффициент попаданий в кэш.Вы можете настроить характеристики кэша с помощью переменных окружения PACK_CACHE_*.
## Производительность и безопасность
Git-cdn принимает ряд дизайнерских решений, чтобы обеспечить производительность и безопасность без необходимости конфигурации.
- пакет клонирования всегда запрашивается по одному и тому же URL CDN, и всегда используется имя файла репозитория как базовое имя для поиска имени пакета.
Это означает, что репозитории Android должны всегда храниться в репозитории Git с каноническим URL пути AOSP, с заменой '/' на '_'.
Например, `platform/external/javapoet.git` хранится в upstream как `platform_external_javapoet.git` (каталог игнорируется).
- пакеты клонирования используются по каноническому имени, то есть вы можете иметь несколько деревьев Android в вашем сервере Git upstream, и все они будут использовать одинаковый пакет.- пакет клонирования может быть скачан без учета учетных данных. Эти пакеты предназначены для AOSP и доступны бесплатно. Это означает, что любой человек может использовать ваш git-cdn для скачивания и использования пространства хранилища, ограниченного размером того, что публикует Google. Вы можете установить пустую переменную окружения CDN_BUNDLE_URL, чтобы отключить эту возможность.
- клонирование пакетов очень объемно, и репозиторий загружает их параллельно. Чтобы ограничить влияние на память и процессор, файлы передаются от клиента к серверу потоково, а также вычисляется контрольная сумма MD5 во время передачи. В случае, если в конце передачи git-cdn обнаруживает, что контрольная сумма неверна, кэш-файл удаляется (вытесняется, поэтому следующая загрузка будет происходить с Google), но клиент всё равно завершает свою передачу (в этот момент HTTP-протокол уже не может прервать загрузку). Клиент репозитория всегда проверяет целостность пакета (пакеты Git содержат контрольную сумму SHA1 в заголовке и для всех своих объектов).- git-cdn использует имя репозитория для неявной выборки нужного файла clone.bundle при инициализации. Это значит, что если кто-то создаст проект с названием platform_external_javapoet, и git-cdn уже имеет пакет platform_external_javapoet в своём каталоге пакетов, то git-cdn будет инициализирован с лишними объектами из этого пакета. Это не влияет на функциональность, но может влиять на производительность команды `git gc` и занимаемое пространство хранения.
## Чувствительность к версии Git
Несколько раз проблемы возникали из-за изменения версии Git. Для исследования с различными версиями Git можно выполнить:
```bash
$ git clone https://github.com/git/git
$ git checkout v2.19.1
$ make all install DESTDIR=/tmp/git_2.19.1
$ git checkout v2.17.1
$ make all install DESTDIR=/tmp/git_2.17.1
```
Затем попробуйте тестирование с конкретной версией Git, пример:
```bash
$ V=19 GIT_EXEC_PATH=/tmp/git_2.$V.1/home/renault/libexec/git-core PATH=/tmp/git_2.$V.1/home/renault/bin:$PATH pipenv run pytest -v git_cdn/tests/test_upload_pack.py::test_shallow_trunc2[pyloop]
$ V=17 GIT_EXEC_PATH=/tmp/git_2.$V.1/home/renault/libexec/git-core PATH=/tmp/git_2.$V.1/home/renault/bin:$PATH pipenv run pytest -v git_cdn/tests/test_upload_pack.py::test_shallow_trunc2[pyloop]
```
# Журнал и Отслеживание
Git-cdn использует методологию структурированного журналирования для получения контекстного структурированного журналирования. Как git-cdn масштабируется параллельно с использованием asyncio, это необходимо для отслеживания проблемных запросов.На данный момент только основной логический модуль **upload_pack.py** использует контекстное журналирование.
Для включения структурированного журналирования вам потребуется настроить сервер, слушающий JSON через UDP. Например:
ОБОРОТНЫЙ_СЕРВЕР=vector.dev.example.com:12201
[Vector](https://vector.dev) использует источник данных udp и преобразование в формат json легко настраивается. Он будет обрабатывать и фильтровать эти логи, а также поддерживать множество "потоков" для хранения ваших логов.
# Метрики Prometheus
Если включено, метрики в стиле Prometheus доступны по стандартному пути `/metrics` верхнего уровня на порту по умолчанию (по умолчанию bcmode 8000).
Включение экспорта метрик можно осуществить путём установки переменной окружения `PROMETHEUS_ENABLED`, как описано выше в разделе Конфигурация. Метрики включены по умолчанию при запуске образа контейнера **registry.gitlab.com/grouperenault/git_cdn**.Представленные ниже метрики:
| Название | [Тип](https://prometheus.io/docs/concepts/metric_types/) | Описание |
| --- | --- | --- |
| `git_cdn_workdir_filesystem_avail_bytes` | Gauge | Текущее свободное место на файловой системе, где находится `WORKING_DIRECTORY`, в байтах |
| `git_cdn_workdir_filesystem_size_bytes` | Gauge | Общая размерность файловой системы, где находится `WORKING_DIRECTORY`, в байтах |
| `git_cdn_requests_total` | Counter | Общее количество HTTP-запросов, обслуженных с момента запуска сервера |
| `git_cdn_response_status_total` | Counter | Общее количество запросов, обслуженных с момента запуска сервера, помеченное статусом ответа |
| `git_cdn_upstream_responses_total` | Counter | Общее количество запросов, делегированных к верхнему уровню без кэширования с момента запуска сервера. Включает незакэшируемые запросы и пропуски кэша |
| `git_cdn_pack_sent_bytes_total` | Counter | Общий объем данных, переданных напрямую из кэша пакетов с момента запуска сервера, в байтах |
| `git_cdn_pack_cache_used_bytes` | Gauge | Общий объём используемого места на диске для файлов, находящихся в кэше пакетов, в байтах |
| `git_cdn_request_time_seconds` | Summary | Обзор времени, затраченного на обслуживание всех запросов, в секундах |
| `git_cdn_total_bytes_sent` | Counter | Общий объем данных, переданных через все запросы с момента запуска сервера, в байтах |
| `git_cdn_cache_hit_bytes_sent` | Summary | Обзор общего объема данных, переданных из кэша пакетов, в байтах |
| `git_cdn_cache_miss_bytes_sent` | Summary | Обзор общего объема данных, переданных, которые не были найдены в кэше пакетов, в байтах || `git_cdn_nocache_bytes_sent` | Summary | Обзор общего объема данных, переданных через все запросы, кроме закэшированных `/git-upload-pack` запросов, в байтах |
| `git_cdn_stats_write_seconds` | Summary | Обзор времени, затраченного на запись метрик, в секундах |
| `git_cdn_pack_cache_evicted_bytes` | Summary | Обзор вытеснений из кэша пакетов, в байтах |
| `git_cdn_repo_cache_received_bytes` | Summary | Обзор общего объема данных, полученных от верхнего уровня для пополнения кэша репозитория, в байтах |
При запуске `git_cdn` с помощью `gunicorn` или любого другого многопоточного сервера веб-приложений на Python, переменная окружения `PROMETHEUS_MULTIPROC_DIR` должна быть установлена в допустимую директорию. Метрики передаются между отдельными рабочими процессами через эту файловую систему, что позволяет обеспечивать последовательное представление метрик среди нескольких потоков рабочих процессов. Содержимое этой директории будет удаляться каждый раз при запуске сервера `git_cdn`.## Дашборд Grafana
Наиболее простым способом визуализировать вышеупомянутые метрики Prometheus является использование [Grafana — открытой платформы для визуализации данных и создания дашбордов](https://grafana.com/oss/).
- Чтобы создать временные ряды метрик, необходимо настроить экземпляр Prometheus для периодического сбора метрик с деплоя git_cdn. Для получения более подробной информации о настройке Prometheus обратитесь к [документации по началу работы с Prometheus](https://prometheus.io/docs/prometheus/latest/installation/).
- Следуйте документации по началу работы, чтобы настроить локальный экземпляр Grafana или хостинговый дашборд в облачном сервисе Grafana: https://grafana.com/docs/grafana/latest/getting-started/
- [Настройте источник данных Prometheus в вашем экземпляре Grafana](https://grafana.com/docs/grafana/latest/datasources/prometheus/configure-prometheus-data-source/), чтобы сделать метрики Prometheus доступными для использования в дашбордах.
- Используйте кнопку "+" в Grafana для импорта дашборда. Выберите опцию "Загрузить файл JSON дашборда", чтобы импортировать [пример дашборда, содержащийся в этом репозитории](./doc/grafana/dashboards/GitCDN-Cache-Performance.json) или просто скопируйте содержимое файла JSON дашборда в поле "Импорт через модель JSON дашборда". Укажите имя и ID для дашборда, а также выберите свой источник данных Prometheus.
# Настройка для разработки:
Среда разработки с использованием Nix```bash
$ nix develop
$ make nixdev
или legacy среда разработки:
$ make dev
Устранение проблем с оформлением кода:
$ make style
Проверки (оформление кода, проверка на ошибки, pep8...):
$ make check
Тестирование:
$ make test
Запуск приложения локально:
$ make run
Добавление пакета в Pipfile:
$ pipenv install --dev mydevdependency
$ pipenv install myproddependency
MIT
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Комментарии ( 0 )