GKE - извлечение ErrImagePull из реестра контейнеров Google

У меня есть кластер Google Kubernetes Engine, который до недавнего времени с удовольствием извлекал частные образы контейнеров из корзины Google Container Registry. Я ничего не менял, но теперь, когда я обновляю свои развертывания Kubernetes, он не может запускать новые поды, и я получаю следующие события:

Normal   Pulling  14s                kubelet, <node-id>  pulling image "gcr.io/cloudsql-docker/gce-proxy:latest"
Normal   Pulling  14s                kubelet, <node-id>  pulling image "gcr.io/<project-id>/backend:62d634e"
Warning  Failed   14s                kubelet, <node-id>  Failed to pull image "gcr.io/<project-id>/backend:62d634e": rpc error: code = Unknown desc = unauthorized: authentication required
Warning  Failed   14s                kubelet, <node-id>  Error: ErrImagePull
Normal   Pulled   13s                kubelet, <node-id>  Successfully pulled image "gcr.io/cloudsql-docker/gce-proxy:latest"
Normal   Created  13s                kubelet, <node-id>  Created container
Normal   Started  13s                kubelet, <node-id>  Started container
Normal   BackOff  11s (x2 over 12s)  kubelet, <node-id>  Back-off pulling image "gcr.io/<project-id>/backend:62d634e"
Warning  Failed   11s (x2 over 12s)  kubelet, <node-id>  Error: ImagePullBackOff

Я проверил следующие вещи, которые кажутся правильными:

  • Контейнеры и их теги действительно существуют и верны.
  • Пул узлов / экземпляры виртуальных машин для кластера GKE имеют разрешение storage-ro
  • Сегмент реестра контейнеров Google и кластер GKE находятся в одном проекте.

Я также пробовал отключить и снова включить службы container.googleapis.com и containerregistry.googleapis.com, но это не помогло.

Документация Google для реестра контейнеров гласит:

Кластеры Kubernetes Engine автоматически настраиваются с доступом для извлечения частных образов из реестра контейнеров в том же проекте. Вам не нужно выполнять дополнительные шаги для настройки аутентификации, если реестр и кластер находятся в одном облачном проекте.

Но похоже, что это не так.

Может ли кто-нибудь пролить дополнительный свет на то, что может происходить? Или дополнительные шаги, чтобы попробовать?


person Jason Langenauer    schedule 29.09.2018    source источник
comment
Привет, Джейсон, я столкнулся с той же проблемой. У тебя есть какое-нибудь решение?   -  person Shrashti    schedule 21.03.2019


Ответы (5)


В моем случае проблема оказалась в том, что в пулах узлов, сгенерированных минимальным файлом спецификации, отсутствуют области oauth2, которые предоставляют доступ к реестру. Добавление

nodePools:
  config:
    oauthScopes:
    - https://www.googleapis.com/auth/devstorage.read_only
    - https://www.googleapis.com/auth/servicecontrol
    - https://www.googleapis.com/auth/service.management.readonly
    - https://www.googleapis.com/auth/trace.append

в соответствии с моей спецификацией исправленные вещи. Я думаю, что важна devstorage область видимости, но я не уверен, так как я просто скопировал весь список областей из спецификации, создаваемой веб-консолью.

person Andy Jones    schedule 10.02.2019
comment
Я думаю, что это тоже https://www.googleapis.com/auth/devstorage.read_only нужно. По крайней мере, это все, что я добавил в учетную запись службы, которую использовал. - person James Hiew; 06.05.2019
comment
Я просто скопировал весь список областей из спецификации, которую генерирует веб-консоль. Как вы это сделали? - person Paweł Szczur; 18.09.2019
comment
Перейдите к мастеру создания кластера, затем найдите кнопку «Эквивалентный REST» внизу экрана. - person Andy Jones; 19.09.2019

Хорошо, это оказалось непросто, но причина была в следующем:

Я использовал Terraform для установки учетной записи службы для узлов в кластере GKE, но вместо использования вывода email ресурса google_service_account для указания учетной записи службы я использовал вместо этого вывод unique_id. Это было хорошо принято как Terraform, так и Google Cloud API.

Когда Kubernetes (и другие вещи) пытался получить доступ к внутреннему API метаданных на каждом узле, чтобы получить токен, который он мог бы использовать, он получал ответ Service account is invalid/disabled и статус 403.

Повторное создание пула узлов с правильно указанной учетной записью службы устранило проблему.

person Jason Langenauer    schedule 29.09.2018
comment
Для меня оказалось, что мой шаблон terraform google_bcuket_acl на самом деле УДАЛЯЕТ ACL для учетной записи службы, хотя нигде в шаблоне не было ссылки на него. Бросить сюда на случай, если кто-нибудь попадется в ту же ловушку. - person Jean-Bernard Jansen; 07.03.2019

У меня возникла та же проблема, когда я создал кластер с помощью terraform. Во-первых, я указал только service_account в node_config, поэтому пул узлов был создан со слишком маленькими областями действия OAuth. Явно напишите как service_account, так и oauth_scope, как показано ниже, узлы могут извлекать изображения из частных репозиториев GCR.

resource "google_container_node_pool" "primary_preemptible_nodes" {
  node_config {
    service_account = "${google_service_account.gke_nodes.email}"

    oauth_scopes = [
      "storage-ro",
      "logging-write",
      "monitoring"
    ]
  }
}
person translucens    schedule 13.04.2019
comment
Спасибо @translucens, мы столкнулись с этой проблемой, и ваш ответ решил ее! - person Hans Kristian; 06.03.2020
comment
Как вы указали сервисный аккаунт? У меня такая же проблема, но это не помогло. Я использую сервисный аккаунт project_no-compute. - person Mike; 02.05.2020
comment
@Mike Если service_account = "${google_service_account.gke_nodes.email}" удален, будет использоваться ваша учетная запись службы (учетная запись службы вычислений по умолчанию). - person translucens; 02.05.2020

В моем случае установка правильных областей oAuth не сработала. Поэтому я просто настроил его для любого другого частного репозитория, добавив imagePullSecrets в свою спецификацию Pod.

Документы Kubernetes | Получение изображения из частного реестра

Пример сценария для создания учетных данных реестра в конвейере

Вы также можете сделать это вручную, если сейчас не управляете своей инфраструктурой как кодом.

# Setup registry credentials so we can pull images from gcr
gcloud auth print-access-token | docker login -u oauth2accesstoken --password-stdin https://gcr.io

kubectl create secret generic regcred \
    --namespace=development \
    --from-file=.dockerconfigjson="${HOME}/.docker/config.json" \
    --type=kubernetes.io/dockerconfigjson \
    --output yaml --dry-run | kubectl apply -f - # create or update if already created

Образец файла развертывания

(Не обращайте внимания на все замены). Это не имеет значения. Просто проверьте последнюю строку файла yaml.

apiVersion: apps/v1
kind: Deployment
metadata:
  namespace: ${NAMESPACE}
  name: ${PROJECT_PREFIX}-${PROJECT_TYPE}-${PROJECT_NAME}
  labels:
    name: ${PROJECT_PREFIX}-${PROJECT_TYPE}-${PROJECT_NAME}
spec:
  replicas: ${REPLICA_COUNT}
  selector:
    matchLabels:
      name: ${PROJECT_PREFIX}-${PROJECT_TYPE}-${PROJECT_NAME}
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
  template:
    metadata:
      labels:
        name: ${PROJECT_PREFIX}-${PROJECT_TYPE}-${PROJECT_NAME}
    spec:
      containers:
        - name: ${PROJECT_PREFIX}-${PROJECT_TYPE}-${PROJECT_NAME}
          image: gcr.io/${GOOGLE_PROJECT_ID}/${PROJECT_TYPE}-${PROJECT_NAME}:${GITHUB_SHA}
          imagePullPolicy: IfNotPresent
          ports:
            - name: http
              containerPort: ${PORT}
              protocol: TCP
          readinessProbe:
            httpGet:
              path: /${PROJECT_NAME}/v1/health
              port: ${PORT}
            initialDelaySeconds: 0
            timeoutSeconds: 10
            periodSeconds: 10
          resources:
            requests:
              cpu: ${RESOURCES_CPU_REQUEST}
              memory: ${RESOURCES_MEMORY_REQUEST}
            limits:
              cpu: ${RESOURCES_CPU_LIMIT}
              memory: ${RESOURCES_MEMORY_LIMIT}
          env:
            - name: NODE_ENV
              value: ${NODE_ENV}
            - name: PORT
              value: '${PORT}'
      imagePullSecrets:
        - name: regcred
person Clement    schedule 11.08.2020

Проверьте события узла на предмет фактической ошибки. Для меня он сказал:

Failed to pull image "gcr.io/project/image@sha256:c8e91af54fc17faa1c49d2a05def5cbabf8f0a67fc558eb6cbca138061b8400a":
 rpc error: code = Unknown desc = error pulling image configuration: unknown blob

Оказалось, что изображение пропало или испорчено. После повторного нажатия изображения все заработало.

person Vincent Gerris    schedule 10.07.2020