การใช้ไคลเอนต์ไปที่ 'kubectl ใช้' กับ Kubernetes API โดยตรงกับหลายประเภทในไฟล์ YAML เดียว


10

ฉันใช้https://github.com/kubernetes/client-goและใช้งานได้ดี

ฉันมีรายการ (YAML) สำหรับแผงควบคุม Kubernetes อย่างเป็นทางการ: https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-beta4/aio/deploy/recommended.yaml

ฉันต้องการเลียนแบบkubectl applyรายการนี้ในโค้ด Go โดยใช้ client-go

ฉันเข้าใจว่าฉันจำเป็นต้องทำ marshalling (ไม่) จำนวนหนึ่งของ YAML เป็นประเภท API ที่ถูกต้องที่กำหนดไว้ในแพ็คเกจ: https://github.com/kubernetes/api

ฉันประสบความสำเร็จในการสร้างCreateAPI ชนิดเดียวให้กับคลัสเตอร์ของฉันแต่ฉันจะทำสิ่งนี้เพื่อรายการที่มีรายการประเภทที่ไม่เหมือนกันได้อย่างไร มีทรัพยากรkind: List*ที่สนับสนุนประเภทต่าง ๆ เหล่านี้หรือไม่?

วิธีแก้ปัญหาปัจจุบันของฉันคือการแยกไฟล์ YAML ที่ใช้csplitด้วย --- เป็นตัวคั่น

csplit /path/to/recommended.yaml /---/ '{*}' --prefix='dashboard.' --suffix-format='%03d.yaml'

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

ฉันต้องการทำสิ่งนี้โดยทางโปรแกรมเพื่อทำการอัพเดตแดชบอร์ดเวอร์ชันใหม่ใด ๆ ลงในคลัสเตอร์ของฉัน ฉันจะต้องทำสิ่งนี้เพื่อเซิร์ฟเวอร์ Metrics และทรัพยากรอื่น ๆ อีกมากมาย ทางเลือกที่ (อาจจะง่าย) วิธีการคือการจัดส่งรหัสของฉันกับ kubectl ติดตั้งให้ภาพภาชนะและโทรโดยตรงkubectl apply -f -; แต่นั่นหมายความว่าฉันต้องเขียนการตั้งค่า kube ไปยังดิสก์หรืออาจส่งผ่านอินไลน์เพื่อให้ kubectl สามารถใช้งานได้

ฉันพบว่าปัญหานี้มีประโยชน์: https://github.com/kubernetes/client-go/issues/193 ตัวถอดรหัสอาศัยอยู่ที่นี่: https://github.com/kubernetes/apimachinery/tree/master/pkg/runtime/ serializer

มันปรากฏในไคลเอนต์ไปที่นี่: https://github.com/kubernetes/client-go/blob/master/kubernetes/scheme/register.go#L69

ฉันได้ดูที่วิธี RunConvert ที่ใช้โดย kubectl: https://github.com/kubernetes/kubernetes/blob/master/pkg/kubectl/cmd/convert/convert.go#L139และคิดว่าฉัน สามารถให้ตัวเลือกทั่วไปของฉันเองiOSได้รับผลลัพธ์หรือไม่

ดูเหมือนว่า RunConvert อยู่บนเส้นทางที่เลิกใช้แล้ว

ฉันได้ดูคำถามอื่น ๆ ที่ติดแท็ก [client-go] แต่ส่วนใหญ่ใช้ตัวอย่างเก่าหรือใช้ไฟล์ YAML ที่มีการkindกำหนดเดียวและ API ก็เปลี่ยนไป

แก้ไข: เนื่องจากฉันต้องทำสิ่งนี้มากกว่าหนึ่งคลัสเตอร์และกำลังสร้างกลุ่มโดยทางโปรแกรม (AWS EKS API + CloudFormation / eksctl ) ฉันต้องการลดค่าใช้จ่ายในการสร้างเนื้อหาServiceAccountในหลายบริบทคลัสเตอร์ในบัญชี AWS จำนวนมาก ตามหลักแล้วขั้นตอนการพิสูจน์ตัวตนเท่านั้นที่เกี่ยวข้องกับการสร้างชุดไคลเอ็นต์ของฉันคือการใช้aws-iam-authenticatorเพื่อรับโทเค็นโดยใช้ข้อมูลคลัสเตอร์ (ชื่อภูมิภาคภูมิภาคใบรับรอง CA ฯลฯ ) ยังไม่มีการเผยแพร่ aws-iam-authenticator มาระยะหนึ่งแล้ว แต่เนื้อหาของการmasterอนุญาตให้ใช้บทบาทข้ามบัญชีบทบาทบุคคลที่สามและรหัสภายนอกที่จะส่งผ่าน IMO นี้สะอาดกว่าการใช้ServiceAccount(และIRSA) เนื่องจากมีบริการ AWS อื่น ๆ แอปพลิเคชัน (API ส่วนหลังที่สร้างและใช้งานส่วนเสริมกับกลุ่มเหล่านี้) จำเป็นต้องโต้ตอบกับ

แก้ไข: ฉันได้พบเมื่อเร็ว ๆ นี้https://github.com/ericchiang/k8s มันใช้งานง่ายกว่าการใช้งานของลูกค้าในระดับสูง แต่ไม่รองรับพฤติกรรมนี้


1
แทนที่จะเขียน kube config ลงในดิสก์ของคอนเทนเนอร์ให้ลองใช้บัญชีบริการkubernetes.io/docs/tasks/configure-pod-container/ …
KFC_

1
ทำไมคุณไม่อ่านเนื้อหาของไฟล์ YAML และแยกด้วย^---$รหัสของคุณ?
Shawyeok

@Shawyeok เพราะนั่นยังทำให้ฉันต้องรู้ว่าไฟล์ประเภทไหน ไม่มีวิธีรับชนิดแบบไดนามิกโดยไม่ต้องทดสอบกับชนิดที่คาดไว้หลายอย่าง (วัตถุ Kubernetes) และหากชนิดที่คาดหวังไม่ปรากฏจากนั้นวัตถุจะไม่ถูกนำไปใช้กับคลัสเตอร์ (ซึ่งนำไปสู่ปัญหาที่มากยิ่งขึ้น) สิ่งนี้จะส่งผลให้ต้องเขียนโค้ดจำนวนมากสำหรับองค์ประกอบเดียวซึ่งไม่ได้ปรับขนาดสำหรับองค์ประกอบหลายอย่าง นอกเหนือจากการถอดรหัสกำลังเรียกใช้วิธีการ API ที่ถูกต้องเพื่อนำวัตถุไปใช้กับคลัสเตอร์
Simon

คำตอบ:


3

ดูเหมือนว่าคุณจะรู้วิธีการยกเลิกการจัดทำไฟล์ YAML ใน Kubernetes runtime.Objectแต่ปัญหาคือการปรับใช้แบบไดนามิกruntime.Objectโดยไม่ต้องเขียนรหัสพิเศษสำหรับแต่ละชนิด

kubectlประสบความสำเร็จในเรื่องนี้โดยการโต้ตอบกับREST APIโดยตรง โดยเฉพาะผ่านทางทรัพยากรผู้ช่วย

ในรหัสของฉันฉันมีสิ่งที่ชอบ:

import (
    meta "k8s.io/apimachinery/pkg/api/meta"
    "k8s.io/cli-runtime/pkg/resource"
    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/rest"
    "k8s.io/client-go/restmapper"
    "k8s.io/apimachinery/pkg/runtime"
)

func createObject(kubeClientset kubernetes.Interface, restConfig rest.Config, obj runtime.Object) error {
    // Create a REST mapper that tracks information about the available resources in the cluster.
    groupResources, err := restmapper.GetAPIGroupResources(kubeClientset.Discovery())
    if err != nil {
        return err
    }
    rm := restmapper.NewDiscoveryRESTMapper(groupResources)

    // Get some metadata needed to make the REST request.
    gvk := obj.GetObjectKind().GroupVersionKind()
    gk := schema.GroupKind{Group: gvk.Group, Kind: gvk.Kind}
    mapping, err := rm.RESTMapping(gk, gvk.Version)
    if err != nil {
        return err
    }

    name, err := meta.NewAccessor().Name(obj)
    if err != nil {
        return err
    }

    // Create a client specifically for creating the object.
    restClient, err := newRestClient(restConfig, mapping.GroupVersionKind.GroupVersion())
    if err != nil {
        return err
    }

    // Use the REST helper to create the object in the "default" namespace.
    restHelper := resource.NewHelper(restClient, mapping)
    return restHelper.Create("default", false, obj, &metav1.CreateOptions{})
}

func newRestClient(restConfig rest.Config, gv schema.GroupVersion) (rest.Interface, error) {
    restConfig.ContentConfig = resource.UnstructuredPlusDefaultContentConfig()
    restConfig.GroupVersion = &gv
    if len(gv.Group) == 0 {
        restConfig.APIPath = "/api"
    } else {
        restConfig.APIPath = "/apis"
    }

    return rest.RESTClientFor(&restConfig)
}

สวัสดีเควินขอบคุณสำหรับคำตอบของคุณ! ฉันไม่ได้มีโอกาสได้ลองทำสิ่งนี้ แต่ฉันไม่รู้package restmapperและสิ่งนี้ดูดีมาก ยอมรับคำตอบในตอนนี้ แต่จะกลับมาใหม่ในไม่ช้า
Simon

1
หวังว่ามันจะเหมาะกับคุณ!
Kevin Lin
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.