1. Фон и проблема
В процессе недавней эксплуатации проекта возникла ситуация, когда в среде Kubernetes конкретный Pod не может нормально запуститься и повторно вызывает ошибку ImagePullBackOff.
Поскольку ранее запущенные Pod работали без проблем, изначально было решено, что это не сбой самого реестра.
Однако после развертывания нового деплоймента только вновь создаваемые Pod постоянно сталкивались с ошибками при извлечении изображений, и в конечном итоге новые Pod не смогли нормально запуститься.
В результате анализа логов kubelet и логов контейнерного рантайма для выявления причины проблемы было установлено, что в процессе TLS-соединения с Private Registry произошла ошибка проверки SSL-сертификата.
В частности, при непосредственном вызове конечной точки Registry с помощью команды “curl -v https://repo.example.com:11000/v2/” было обнаружено следующее сообщение об ошибке.
SSL certificate problem: unable to get local issuer certificate
Это сообщение означает не только то, что сертификат истек, но и то, что узел не доверяет CA (Центр сертификации), выдавшему этот SSL сертификат.
То есть, сервер реестра использовал обычный сертификат, но информация об этом центре сертификации отсутствовала в хранилище доверия (Trust Store) узла Kubernetes, поэтому проверка TLS не прошла.
Особенно в средах Private Registry часто используются сертификаты, предназначенные только для внутренней сети, или сертификаты на основе частных удостоверяющих центров.
В этом случае администратору необходимо не только создать Registry, но и зарегистрировать информацию об удостоверяющем центре в среде Kubernetes Worker Node и Container Runtime.
Однако на стадии начального развертывания этот аспект часто упускается, и возникают проблемы в случаях добавления новых узлов или перераспределения.
Кроме того, причина, по которой существующие Pod работали нормально, а новые Pod терпели неудачу, заключается в кэшировании изображений.
Контейнерный рантайм может повторно использовать образы, уже загруженные на локальном уровне, поэтому существующие Pod могли работать без доступа к реестру.
С другой стороны, новосоздаваемые Pod должны были напрямую обращаться к реестру, чтобы загрузить образы, и в этом процессе возникла ошибка проверки SSL.
Эти проблемы могут возникать не только в среде Kubernetes, но и в большинстве сред Container Runtime, таких как Docker, containerd, CRI-O, k3s и т. д.
Поэтому понимание структуры системы SSL-сертификатов и доверенного хранилища CA крайне важно для стабильности эксплуатационной среды.
2. Решение проблемы
(1) Проверка SSL сертификата
Первый шаг к решению проблемы заключается в проверке того, какой сертификат использует настоящий сервер реестра.
В производственной среде цепочка сертификатов часто состоит из нескольких уровней, и такая же проблема может возникнуть, если промежуточный сертификат (Intermediate CA) отсутствует.
Сначала используйте команду openssl для проверки информации о Subject и Issuer сертификата.
openssl s_client -connect repo.example.com:11000 /dev/null | openssl x509 -noout -subject –issuer
Пример вывода следующий:
subject=CN=*.example.com
issuer=C=GB; O=Sectigo Limited; CN=Sectigo Public Server Authentication CA DV R36
По результатам можно подтвердить, что организацией, выдавшей фактический сертификат, является CA группы Sectigo.
Этот процесс является ключевым этапом для определения, каким центрам сертификации можно доверять, а не просто для проверки срока действия сертификата.
На следующем шаге мы извлечем реальный сертификат в файл.
openssl s_client -connect repo.example.com:11000 -showcerts /dev/null | sed -n
'/-----BEGIN CERTIFICATE-----/,/-----END CERTIFICATE-----/p' >
SectigoPublicServerAuthenticationCA.crt
Эта команда сохраняет всю цепочку сертификатов, предоставляемую сервером реестра, в файл.
В зависимости от окружения корневой сертификат и промежуточный сертификат могут быть включены вместе, и в некоторых окружениях может быть извлечено несколько сертификатов одновременно.
Количество извлеченных сертификатов можно проверить с помощью следующей команды.
grep -c 'BEGIN CERTIFICATE' SectigoPublicServerAuthenticationCA.crt
Если цепочка сертификатов состоит из нескольких элементов, необходимо обязательно убедиться, что все сертификаты корректно включены.
Особенно, если отсутствует промежуточный сертификат, браузер может работать нормально, но в Container Runtime может произойти ошибка проверки.
(2) Регистрация CA сертификатов в системе (Ubuntu / Debian)
Наиболее рекомендуемое решение - зарегистрировать CA сертификаты в хранилище доверия системы узла.
Этот метод является самым безопасным способом в рабочей среде, поскольку он позволяет надежно взаимодействовать с реестром, сохраняя проверку TLS.
Сначала скопируйте извлеченный сертификат в путь к хранилищу CA системы.
sudo cp SectigoPublicServerAuthenticationCA.crt /usr/local/share/ca-certificates/
Затем обновите хранилище доверенных сертификатов системы с помощью команды update-ca-certificates.
sudo update-ca-certificates
После завершения этой задачи системы на базе Ubuntu или Debian автоматически создадут символическую ссылку внутри /etc/ssl/certs и пересоберут весь набор CA.
Статус регистрации можно проверить с помощью команды ниже.
openssl verify -CAfile /etc/ssl/certs/ca-certificates.crt SectigoPublicServerAuthenticationCA.crt
Если регистрация прошла успешно, будет выведено сообщение “OK”.
После перезапуска containerd или Docker Runtime проблема с загрузкой образов в большинстве сред будет решена.
Использование этого метода в производственной среде имеет решающее значение.
Настройка insecure обходит саму проверку безопасности, поэтому при длительном использовании это может сделать уязвимым к атакам MITM (Man-In-The-Middle).
Кроме того, в средах Auto Scaling или новых средах Provisioning Node рекомендуется создать систему автоматического распространения CA сертификатов через скрипты cloud-init, Ansible, Terraform, Kubernetes bootstrap.
(3) настройка Insecure containerd
В некоторых средах доступ к узлу по SSH может быть невозможен, или в экстренных ситуациях приоритетом является быстрая восстановление.
В этом случае вы можете временно отключить проверку SSL в настройках containerd.
Сначала создайте каталог certs.d, посвященный реестру.
mkdir -p /etc/containerd/certs.d/repo.example.com:11000
Затем создайте файл hosts.toml.
server = https://repo.example.com:11000
[host."https://repo.example.com:11000"]
capabilities = ["pull", "resolve"]
skip_verify = true
Здесь ключевым является параметр skip_verify = true. Эта настройка заставляет не проверять сертификат реестра. После применения настроек обязательно перезапустите containerd.
sudo systemctl restart containerd
Этот метод полезен для быстрого восстановления после сбоев, но не рекомендуется использовать его в производственной среде на длительный срок.
Особенно в средах с безопасностью, такими как финансовые или государственные, несанкционированные настройки могут быть нарушением политики. Кроме того, даже если сертификаты реестра будут подделаны, может быть разрешено подключение без проверки, что создает риск безопасности. Поэтому этот метод следует использовать только в качестве временной меры или ограниченно в средах разработки.
(4) настройка Insecure в k3s registries.yaml
В среде k3s управление настройками containerd автоматически осуществляется внутри, в отличие от обычного Kubernetes. Поэтому, даже если вы вручную измените настройки containerd, они могут быть перезаписаны при перезапуске k3s.
В этом случае необходимо использовать файл /etc/rancher/k3s/registries.yaml.
mirrors:
"repo.example.com:11000":
endpoint:
- "https://repo.example.com:11000"
configs:
"repo.example.com:11000":
auth:
username: "your-username"
password: "your-password"
tls:
insecure_skip_verify: true
Эта настройка автоматически применится, когда k3s будет внутренне создавать настройки containerd.
После применения настроек нужно перезапустить службу k3s.
sudo systemctl restart k3s
Особенно в средах Edge или легковесных Kubernetes важно понимать структуру registries.yaml, так как случаи использования k3s распространены.
Также рекомендуется рассмотреть использование Kubernetes Secret или Vault для интеграции аутентификационной информации (имя пользователя/пароль) вместо хранения их в открытом виде в рабочей среде.
3. Итоги
В ходе этого процесса реагирования на сбои мы проанализировали и испытали решение типичных проблем с SSL-сертификатами, которые могут возникнуть в среде Private Registry.
Основной причиной проблемы является отсутствие CA, выдавшего сертификат сервера Registry, в хранилище доверенных сертификатов узла Kubernetes.
Существующий Pod функционировал нормально благодаря кэшу изображений, но новый Pod сталкивается с ошибкой проверки SSL при доступе к реестру.
Для решения этой проблемы сначала с помощью openssl я проверил удостоверяющий орган и цепочку сертификатов, а затем применил метод извлечения фактического сертификата и регистрации его в доверенном хранилище системы.
Также был проверен способ настройки insecure на основе containerd hosts.toml и insecure_skip_verify на основе k3s registries.yaml для реагирования на экстренные ситуации.
Однако в производственной среде крайне важно зарегистрировать сертификат CA, чтобы поддерживать систему проверки TLS.
Настройки insecure следует использовать только как временную меру для устранения сбоев, так как их длительное использование может привести к уязвимостям в безопасности.
В конечном итоге мы смогли подтвердить, что для стабильной работы Kubernetes крайне важно понимать не только простую развертку приложений, но и систему SSL-сертификатов, структуру доверия к центрам сертификации и способ работы контейнерного времени выполнения.
Jsia