Сбой при загрузке образа с unexpected end of JSON input
Содержание
Описание проблемыПричинаУстранение неполадкиШаг 1 — Проверьте конфигурацию слушателей LBШаг 2 — Повторите проверку с явным указанием протоколаШаг 3 — Проверьте отладочный журнал среды выполненияРешениеОбходной путь — явно укажите HTTP-порт в адресе доступа к HarborДолгосрочное решение — опубликовать Harbor по HTTPSПримечанияОписание проблемы
При загрузке образов из экземпляра Harbor, доступного через Ingress только по HTTP, среды выполнения контейнеров завершают работу с ошибками вроде:
Пайплайны, использующие тот же Harbor, могут выдавать вариант той же первопричины:
Проблема воспроизводится из кластера Kubernetes при использовании containerd / CRI-O / Podman в качестве среды выполнения контейнеров, даже если:
- адрес Harbor доступен;
- учетные данные верны, и
loginвыполняется успешно; - веб-интерфейс Harbor полностью работает в браузере.
Причина
Проблема возникает, когда одновременно выполняются все перечисленные ниже условия:
- Harbor опубликован через Ingress только по HTTP (на Ingress не настроен TLS).
- Балансировщик нагрузки кластера (LB) прослушивает и порт 80, и порт 443, а на слушателе 443 настроен действующий сертификат по умолчанию.
- Клиент, загружающий образ, использует среду выполнения контейнеров, которая следует распространенной схеме «сначала HTTPS, затем HTTP» (containerd, CRI-O, Podman).
При этих условиях:
- Среда выполнения сначала пытается использовать HTTPS, так как в ссылке на образ не указан явный протокол или порт.
- Балансировщик нагрузки принимает TLS-рукопожатие, поскольку на порту 443 доступен сертификат по умолчанию.
- Но в Ingress нет правила маршрутизации HTTPS для хоста Harbor, поэтому LB возвращает
404для HTTPS-запроса. - Поскольку TLS-рукопожатие прошло успешно, среда выполнения не переключается на HTTP. Она считает
404окончательным ответом и не может разобрать его как ответ реестра, из-за чего возникаетunexpected end of JSON input.
Устранение неполадки
Шаг 1 — Проверьте конфигурацию слушателей LB
Убедитесь, что LB, через который публикуется Harbor, прослушивает и 80, и 443, а на 443 настроен рабочий сертификат по умолчанию. Если порт 443 не прослушивается или TLS-рукопожатие завершается с ошибкой (нет сертификата по умолчанию), эта проблема к вам не относится, и причину следует искать в другом месте.
Шаг 2 — Повторите проверку с явным указанием протокола
На узле, где проявляется сбой, попробуйте загрузить образ по HTTP с явным указанием порта. Если этот вариант работает, а вариант по умолчанию без указания схемы — нет, диагноз подтвержден:
Шаг 3 — Проверьте отладочный журнал среды выполнения
На затронутом узле включите отладочное логирование в среде выполнения контейнеров и найдите сообщения, указывающие на то, что среда выполнения пропустила HTTP-эндпоинт после успешного TLS-рукопожатия, например:
Если вы видите это сообщение (или если среда выполнения переключается на HTTPS после успешного TLS-рукопожатия), это подтверждает первопричину.
Решение
Обходной путь — явно укажите HTTP-порт в адресе доступа к Harbor
Явное указание HTTP-порта в адресе доступа к Harbor заставляет клиентов использовать HTTP и обходить эту проблему. Используйте http://<HARBOR_HOST>:80 везде, где настраивается адрес Harbor, чтобы каждая ссылка на образ разрешалась в <HARBOR_HOST>:80/<PROJECT>/<IMAGE>:<TAG>.
В некоторых случаях, чтобы новое значение адреса вступило в силу, требуется перезапуск клиента — например, рабочие нагрузки, у которых загрузка уже завершилась неудачей, необходимо перезапустить, чтобы они повторили попытку с адресом, в котором явно указан порт.
Долгосрочное решение — опубликовать Harbor по HTTPS
Для производственных сред рекомендуемое решение — публиковать Harbor по HTTPS. Полная процедура описана в разделе Configuring HTTPS.
После правильной настройки HTTPS на Ingress ответ 404 от LB на 443 больше не возвращается, и среда выполнения корректно достигает Harbor без явного указания порта. После того как HTTPS начнет работать, удалите указание порта из адреса интеграции.
Примечания
- Одна и та же причина, разные ошибки. Пайплайны, загружающие манифесты, могут сообщать
invalid character '<' looking for beginning of valueвместоunexpected end of JSON input. В обоих случаях первопричиной является один и тот же HTML-пустой ответ404. - Почему это не исправить в среде выполнения? Поведение «сначала HTTPS, без перехода на HTTP после успешного рукопожатия» является документированной схемой для большинства сред выполнения контейнеров, и Harbor или этот оператор не могут его изменить.