создание службы через кластер с одним узлом kubernetes не дает мне внешнего IP-адреса, но механизм контейнеров Google делает (?)

Я пытаюсь настроить кластер Kubernetes с одним узлом для демонстрации и тестирования, и я хочу, чтобы он вел себя как «полномасштабный» кластер k8s (например, движок контейнеров Google). У моего клиента есть собственная установка k8s, которая для этого обсуждения, как мы можем предположить, действует во многом как установка k8s движка контейнеров Google.

Получение Ingress IP на полноразмерных K8

Я создаю модуль wordpress и представляю его как службу, как описано в этом руководстве: https://cloud.google.com/container-engine/docs/tutorials/hello-wordpress

Если вы хотите воспроизвести проблему, просто скопируйте и вставьте приведенные ниже команды, которые я извлек из учебника: (Предполагается, что у вас есть проект под названием 'stellar-access-117903'. Если нет, укажите имя вашего Google Проект Container Engine.)

# set up the cluster  (this will take a while to provision)
#
 gcloud config set project stellar-access-117903
 gcloud config set compute/zone us-central1-b
 gcloud container clusters create hello-world \
     --num-nodes 1 \
     --machine-type g1-small

# Create the pod, and expose it as a service
#
kubectl run wordpress --image=tutum/wordpress --port=80
kubectl expose rc wordpress --type=LoadBalancer

# Describe the service
kubectl describe services wordpress

Выходные данные команды описать содержат строку «LoadBalancer Ingress: {some-ip-address}», чего я и ожидал. Теперь, когда я делаю то же самое с настройкой кластера с одним узлом, я не получаю эту строку. Я могу подключиться к службе wordpress по IP-адресу, который отображается в выходных данных команды «описать службу». Но в режиме «одного узла» распечатанный IP-адрес является> IP-адресом кластера ‹службы, который обычно (насколько я понимаю) публично недоступен. По какой-то причине он общедоступен в режиме одного узла. Мы можем воспроизвести это, выполнив следующие шаги.

НЕ ПОЛУЧЕНИЕ IP-адреса Ingress на одноузловых K8s

Сначала настройте одиночный узел k8s, как описано в этом руководстве: https://github.com/kubernetes/kubernetes/blob/master/docs/getting-started-guides/docker.md

Для облегчения воспроизведения я включил все приведенные ниже команды, поэтому вы можете просто скопировать / вставить:

K8S_VERSION=1.1.1

sudo docker run --net=host -d gcr.io/google_containers/etcd:2.0.12 /usr/local/bin/etcd --addr=127.0.0.1:4001 --bind-addr=0.0.0.0:4001 --data-dir=/var/etcd/data


sudo docker run \
    --volume=/:/rootfs:ro \
    --volume=/sys:/sys:ro \
    --volume=/dev:/dev \
    --volume=/var/lib/docker/:/var/lib/docker:ro \
    --volume=/var/lib/kubelet/:/var/lib/kubelet:rw \
    --volume=/var/run:/var/run:rw \
    --net=host \
    --pid=host \
    --privileged=true \
    -d \
    gcr.io/google_containers/hyperkube:v${K8S_VERSION} \
    /hyperkube kubelet --containerized --hostname-override="127.0.0.1" --address="0.0.0.0" --api-servers=http://localhost:8080 --config=/etc/kubernetes/manifests

sudo docker run -d --net=host --privileged gcr.io/google_containers/hyperkube:v${K8S_VERSION} /hyperkube proxy --master=http://127.0.0.1:8080 --v=2


# set your context to use the locally running k8s API server 
#
kubectl config set-cluster dev --server=http://localhost:8080
kubectl config set-context dev --cluster=dev  --namespace=$NS
kubectl config use-context dev

Теперь выполните те же команды, что и для k8s Google Container Engine.

# Create the pod, and expose it as a service
#
kubectl run wordpress --image=tutum/wordpress --port=80
kubectl expose rc wordpress --type=LoadBalancer

# Describe the service
kubectl describe services wordpress

Результат последней команды (которая, как вы увидите, не содержит информации о входящем входе):

Name:           wordpress
Namespace:      default
Labels:         run=wordpress
Selector:       run=wordpress
Type:           LoadBalancer
IP:         10.0.0.61
Port:           <unnamed>   80/TCP
NodePort:       <unnamed>   31795/TCP
Endpoints:      172.17.0.30:80
Session Affinity:   None
No events.

В k8s движка контейнеров Google я вижу такие события, как «Создание балансировщика нагрузки», «Балансировщик нагрузки создан». Но ничего подобного в экземпляре с одним узлом не происходит.

Мне интересно ... есть ли какая-то конфигурация, которую мне нужно сделать, чтобы заставить их работать одинаково? Очень важно, чтобы они работали одинаково ... отличаясь только масштабируемостью, потому что мы хотим запустить тесты против версии с одним узлом, и будет очень запутанно, если она будет вести себя по-другому.

Заранее благодарим за помощь-крис


person Chris Bedford    schedule 03.01.2016    source источник


Ответы (2)


Вот решение, которое мы придумали. Когда мы работаем с одноузловым Kubernetes, мы методом проб и ошибок поняли, что когда вы открываете сервис, внешний IP-адрес не возвращается через IngressIP; скорее, он возвращается через clusterIP, который, как упоминалось выше, является общедоступным. Итак, мы просто изменили наш код для работы с этим. Мы используем clusterIP в случае с одним узлом. Вот код, который мы используем, чтобы установить наблюдение за сервисом, чтобы выяснить, когда k8s выделил наш видимый извне IP:

Сначала мы используем API-интерфейс fabric8 для создания конфигурации службы:

            case "Service" =>
              val serviceConf = mapper.readValue(f, classOf[Service])
              val service = kube.services().inNamespace(namespaceId).create(serviceConf)
              watchService(service)

Метод watchService определен ниже:

  private def watchService(service: Service) = {
    val namespace = service.getMetadata.getNamespace
    val name = service.getMetadata.getName
    logger.debug("start -> watching service -> namespace: " + namespace + " name: " + name)
    val kube = createClient()
    try {
      @volatile var complete = false
      val socket = kube.services().inNamespace(namespace).withName(name).watch(new Watcher[Service]() {
        def eventReceived(action: Action, resource: Service) {
          logger.info(action + ":" + resource)
          action match {
            case Action.MODIFIED =>
              if (resource.getMetadata.getName == name) {
                complete = isServiceComplete(resource)
              }
            //            case Action.DELETED =>
            //              complete = true
            case _ =>
          }
        }
      })
      while (!complete) {
        Thread.sleep(5000)
        complete = isServiceComplete(kube.services().inNamespace(namespace).withName(name).get)
      }
      logger.info("Closing socket connection")
      socket.close()
    } finally {
      logger.info("Closing client connection")
      kube.close()
    }

    logger.debug("complete -> watching services , namespace: " + namespace + " name: " + name)
  }

Ключевой прием, который мы представили, заключался в методе isServiceComplete ... при использовании одиночного узла k8s значение isUsingMock истинно. так что это заставляет нас использовать clusterIP, чтобы определить, завершена ли конфигурация службы или нет.

  private def isServiceComplete(service: Service) = {
    !service.getStatus.getLoadBalancer.getIngress.isEmpty  || mockServiceComplete(service)
  }

  def mockServiceComplete(service: Service): Boolean = {
    val clusterIP  = service.getSpec.getClusterIP
    logger.trace(s"mockServiceComplete:   $isUsingMock /  $clusterIP / $KUBE_SERVER" )
    isUsingMock && ! clusterIP.isEmpty
  }

Извините, если здесь не так много лишнего контекста. В конце концов, у нашего проекта должен быть открытый исходный код, и мы сможем опубликовать полное решение.

-Крис

person Chris Bedford    schedule 13.01.2016

LoadBalancer - это функция, которая реализована поставщиком внутреннего облачного сервиса, поэтому вы не видите ни одного, созданного в вашей локальной настройке.

(см. облачных провайдеров: https://github.com/kubernetes/kubernetes/tree/master/pkg/cloudprovider/providers)

person uvgroovy    schedule 03.01.2016
comment
Спасибо .. да, я читал об этом. Я надеюсь на какую-то настройку конфигурации, плагин, скрипт, взлом любого вида, который позволит единственному узлу имитировать поведение облачного провайдера, который предлагает балансировку нагрузки. Если я смогу выяснить, как подключиться к кубернетам и сделать это, я опубликую здесь решение .. Но, надеюсь, кто-то уже сделал это. В любом случае еще раз спасибо за ваш ответ. - person Chris Bedford; 04.01.2016
comment
вы можете настроить службу с помощью NodePort и использовать nginx для балансировки нагрузки через другой RC (вы потенциально можете обнаружить узлы через api и автоматически настроить nginx), хотя и не знаете, как порт узла работает в развертываниях на одной машине ... - person uvgroovy; 04.01.2016
comment
также, если вы просто хотите получить доступ к развернутой службе, вы можете попробовать использовать функцию прокси-сервера kubelet - person uvgroovy; 04.01.2016