การสร้างบริการผ่านคลัสเตอร์โหนดเดียวของ kubernetes ทำให้ฉันไม่สามารถ 'เข้าถึง' IP ภายนอกได้ แต่เครื่องมือคอนเทนเนอร์ของ Google ทำ (?)

ฉันกำลังพยายามตั้งค่าคลัสเตอร์ kubernetes โหนดเดียวเพื่อการสาธิตและการทดสอบ และฉันต้องการให้ทำงานเหมือนคลัสเตอร์ k8s ที่ 'เต็มประสิทธิภาพ' (เช่น Google Container Engine) ลูกค้าของฉันมีการติดตั้ง k8s เป็นของตัวเอง ซึ่งสำหรับการสนทนานี้ เราถือว่าทำหน้าที่ได้ค่อนข้างเหมือนกับการติดตั้ง k8s ของ Google Container Engine

รับ IP Ingress บน K8 แบบ Full Blown

ฉันกำลังสร้างพ็อด WordPress และแสดงเป็นบริการ ตามที่อธิบายไว้ในบทช่วยสอนนี้: https://cloud.google.com/container-engine/docs/tutorials/hello-wordpress

หากคุณต้องการทำซ้ำปัญหา เพียงคัดลอกและวางคำสั่งด้านล่างซึ่งฉันยกมาจากบทช่วยสอน: (ซึ่งถือว่าคุณมีโปรเจ็กต์ชื่อ 'stellar-access-117903' .. หากไม่ใช่ โปรดตั้งชื่อ Google ของคุณ โครงการเครื่องยนต์คอนเทนเนอร์)

# 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 ที่พิมพ์ออกมาคือ >cluster IP‹ ของบริการ ซึ่ง โดยทั่วไป (ตามที่ฉันเข้าใจ) จะไม่สามารถเข้าถึงได้แบบสาธารณะ ด้วยเหตุผลบางประการ สาธารณะสามารถเข้าถึงได้ในโหมดโหนดเดียว เราสามารถทำซ้ำได้โดยทำตามขั้นตอนต่อไปนี้

ไม่ได้รับ IP ขาเข้าบนโหนด K8 เดี่ยว

ขั้นแรกให้ตั้งค่าโหนดเดียว 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

ตอนนี้ ให้รันคำสั่งเดียวกับที่คุณทำกับ k8 ของ 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

ผลลัพธ์ของคำสั่งสุดท้าย (ซึ่งคุณจะเห็นว่าไม่มีข้อมูล 'Ingress') คือ:

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 Container Engine ฉันเห็นเหตุการณ์เช่น ' กำลังสร้างตัวโหลดบาลานเซอร์ ', ' โหลดบาลานเซอร์ที่สร้างแล้ว ' แต่ไม่มีอะไรแบบนั้นเกิดขึ้นในอินสแตนซ์โหนดเดียว

ฉันสงสัยว่า ... มีการกำหนดค่าบางอย่างที่ฉันต้องทำเพื่อให้ทำงานเหมือนกันหรือไม่? มันสำคัญมากที่จะต้องทำงานเหมือนกัน... ต่างกันแค่ความสามารถในการขยายเท่านั้น เนื่องจากเราต้องการทำการทดสอบกับเวอร์ชันโหนดเดียว และมันจะทำให้เกิดความสับสนมากหากมันทำงานแตกต่างออกไป

ขอบคุณล่วงหน้าสำหรับความช่วยเหลือของคุณ-คริส


person Chris Bedford    schedule 03.01.2016    source แหล่งที่มา


คำตอบ (2)


นี่คือวิธีแก้ปัญหาที่เราคิดขึ้นมา เมื่อเราทำงานกับ Kubernetes โหนดเดียว เราตระหนักได้จากการลองผิดลองถูกว่าเมื่อคุณเปิดเผยบริการ IP ภายนอกจะไม่กลับมาผ่าน IngressIP แต่จะกลับมาผ่านคลัสเตอร์IP ซึ่งดังที่กล่าวข้างต้นสามารถดูได้แบบสาธารณะ ดังนั้นเราจึงเพิ่งแก้ไขโค้ดของเราให้ใช้งานได้ เราใช้คลัสเตอร์IP ในกรณีโหนดเดียว นี่คือโค้ดที่เราใช้เพื่อสร้างนาฬิกาบนบริการเพื่อดูว่า k8s จัดสรร IP ที่มองเห็นได้จากภายนอกเมื่อใด:

ขั้นแรกเราใช้ Fabric8 API เพื่อสร้างการกำหนดค่าบริการ:

            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' จะเป็นเรื่องจริง นั่นทำให้เราใช้คลัสเตอร์ IP เพื่อตรวจสอบว่าการกำหนดค่าบริการเสร็จสมบูรณ์หรือไม่

  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
ขอบคุณ .. ใช่ฉันได้อ่านเกี่ยวกับเรื่องนั้นแล้ว สิ่งที่ฉันหวังไว้คือการตั้งค่าบางอย่าง ปลั๊กอิน สคริปต์ การแฮ็กใดๆ ก็ตาม ที่จะอนุญาตให้โหนดเดียวตั้งค่าเพื่อจำลองพฤติกรรมของผู้ให้บริการคลาวด์ที่ให้โหลดบาลานซ์ หากฉันสามารถหาวิธีเชื่อมต่อกับ kubernetes และทำสิ่งนี้ได้ ฉันจะโพสต์วิธีแก้ปัญหาที่นี่ .. แต่หวังว่าจะมีคนทำสิ่งนี้ไปแล้ว ยังไงก็ขอบคุณอีกครั้งสำหรับคำตอบของคุณ - person Chris Bedford; 04.01.2016
comment
คุณสามารถตั้งค่าบริการด้วย NodePort และใช้ nginx เพื่อโหลดบาลานซ์ผ่าน RC อื่น (คุณอาจค้นพบโหนดผ่าน api และกำหนดค่า nginx โดยอัตโนมัติ) แฮ็คขนาดใหญ่และไม่แน่ใจว่าพอร์ตโหนดทำงานอย่างไรในการปรับใช้เครื่องเดียว... - person uvgroovy; 04.01.2016
comment
นอกจากนี้ หากคุณเพียงต้องการเข้าถึงบริการที่ใช้งาน คุณสามารถลองใช้คุณสมบัติพร็อกซี kubelet ได้ - person uvgroovy; 04.01.2016