[轉(zhuǎn)發(fā)]--使用client-go在K8S集群發(fā)布項(xiàng)目

https://www.voidking.com/dev-k8s-client-go-deploy/
https://github.com/voidking/k8s-client-go/

一,感興趣的章節(jié)

client-go

《使用client-go操作K8S》一文中,配置好了k8s-client-go項(xiàng)目国葬,可以使用這個(gè)項(xiàng)目對(duì)k8s集群進(jìn)行一些基本操作于颖。在此基礎(chǔ)上古今,本節(jié)會(huì)實(shí)現(xiàn)一些更高階的操作货邓。

判斷發(fā)布狀態(tài)

根據(jù)deployment和pod的狀態(tài)馏艾,怎樣判斷一次發(fā)布成功還是失斁俟濉捣辆?首先,要知道deployment和pod都有哪些狀態(tài)此迅。

1汽畴、通過(guò)kubectl命令獲取發(fā)布數(shù)據(jù)

kubectl get deployments hello-node -o json
kubectl get deployments nginx -o json
kubectl get pods -l app=hello-node -o json
kubectl get pods -l app=nginx -o json

2旧巾、獲取到的發(fā)布數(shù)據(jù)
發(fā)布成功的json數(shù)據(jù):hello-node.json
發(fā)布失敗的json數(shù)據(jù):nginx.json

3、具體可用狀態(tài)有哪些


deployment.generation
deployment.spec.replicas
deployment.status.observedGeneration
deployment.status.replicas
deployment.status.readyReplicas/unavailableReplicas
deployment.status.updatedReplicas
deployment.status.conditions[*].type{Available,Progressing} && deployment.status.conditions[*].status{True,False}


pod.status.phase{Pending,Running}
pod.status.conditions[*].type{Initialized,Ready,ContainersReady,PodScheduled} && pod.status.conditions[*].status{True,False}
pod.status.containerStatuses[*].state.{waiting,running}

4忍些、判斷條件組合
參考k8s-client-go/common/deployment.go文件的GetDeploymentStatus函數(shù)鲁猩。

二,感興趣的代碼

package common

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    apps_v1beta1 "k8s.io/api/apps/v1beta1"
    core_v1 "k8s.io/api/core/v1"
    "k8s.io/apimachinery/pkg/api/errors"
    meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/apimachinery/pkg/util/yaml"
    "k8s.io/client-go/kubernetes"
    "strings"
    "time"
)


// 讀取deployment yaml文件
func ReadDeploymentYaml(filename string) (apps_v1beta1.Deployment) {
    // 讀取YAML
    deployYaml, err := ioutil.ReadFile(filename)
    if err != nil {
        fmt.Println(err)
        return apps_v1beta1.Deployment{}
    }

    // YAML轉(zhuǎn)JSON
    deployJson, err := yaml.ToJSON(deployYaml)
    if err != nil {
        fmt.Println(err)
        return apps_v1beta1.Deployment{}
    }

    // JSON轉(zhuǎn)struct
    var deployment apps_v1beta1.Deployment
    err = json.Unmarshal(deployJson, &deployment)
    if err != nil {
        fmt.Println(err)
        return apps_v1beta1.Deployment{}
    }
    return deployment
}

func ApplyDeployment(clientset kubernetes.Clientset, deployment apps_v1beta1.Deployment) {
    var namespace string
    if deployment.Namespace != "" {
        namespace = deployment.Namespace
    }else {
        namespace = "default"
    }

    // 查詢k8s是否有該deployment
    _, err := clientset.AppsV1beta1().Deployments(namespace).Get(deployment.Name, meta_v1.GetOptions{});
    if err != nil {
        if !errors.IsNotFound(err) {
            fmt.Println(err)
            return
        }
        // 不存在則創(chuàng)建
        _, err = clientset.AppsV1beta1().Deployments(namespace).Create(&deployment)
        if err != nil {
            fmt.Println(err)
            return
        }
    } else { // 已存在則更新
        _, err = clientset.AppsV1beta1().Deployments(namespace).Update(&deployment)
        if err != nil {
            fmt.Println(err)
            return
        }
    }

    fmt.Printf("apply deployment %s success!\n", deployment.Name)
}

func DeleteDeployment(clientset kubernetes.Clientset, deployment apps_v1beta1.Deployment){
    var namespace string
    if deployment.Namespace != "" {
        namespace = deployment.Namespace
    }else {
        namespace = "default"
    }
    err := clientset.AppsV1beta1().Deployments(namespace).Delete(deployment.Name, &meta_v1.DeleteOptions{})
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Printf("delete deployment %s success!\n", deployment.Name)
}

func GetDeploymentStatus(clientset kubernetes.Clientset, deployment apps_v1beta1.Deployment) (success bool,reasons []string, err error) {

    // 獲取deployment狀態(tài)
    k8sDeployment, err := clientset.AppsV1beta1().Deployments("default").Get(deployment.Name, meta_v1.GetOptions{})
    if err != nil {
        return false,[]string{"get deployments status error"}, err
    }

    // 獲取pod的狀態(tài)
    labelSelector := ""
    for key, value := range deployment.Spec.Selector.MatchLabels {
        labelSelector = labelSelector + key + "=" + value + ","
    }
    labelSelector = strings.TrimRight(labelSelector, ",")

    podList, err := clientset.CoreV1().Pods("default").List(meta_v1.ListOptions{LabelSelector: labelSelector})
    if err != nil {
        return false, []string{"get pods status error"}, err
    }

    readyPod := 0
    unavailablePod := 0
    waitingReasons := []string{}
    for _, pod := range podList.Items {
        // 記錄等待原因
        for _, containerStatus := range pod.Status.ContainerStatuses{
            if containerStatus.State.Waiting != nil {
                reason := "pod " + pod.Name + ", container " + containerStatus.Name + ", waiting reason: " + containerStatus.State.Waiting.Reason
                waitingReasons = append(waitingReasons, reason)
            }
        }

        podScheduledCondition := GetPodCondition(pod.Status, core_v1.PodScheduled)
        initializedCondition := GetPodCondition(pod.Status, core_v1.PodInitialized)
        readyCondition := GetPodCondition(pod.Status, core_v1.PodReady)
        containersReadyCondition := GetPodCondition(pod.Status, core_v1.ContainersReady)

        if pod.Status.Phase == "Running" &&
            podScheduledCondition.Status == "True" &&
            initializedCondition.Status == "True" &&
            readyCondition.Status == "True" &&
            containersReadyCondition.Status == "True" {
            readyPod++
        }else {
            unavailablePod++
        }
    }

    // 根據(jù)container狀態(tài)判定
    if len(waitingReasons) != 0 {
        return false, waitingReasons, nil
    }

    // 根據(jù)pod狀態(tài)判定
    if int32(readyPod) < *(k8sDeployment.Spec.Replicas) ||
        int32(unavailablePod) != 0{
        return false, []string{"pods not ready!"}, nil
    }

    // deployment進(jìn)行狀態(tài)判定
    availableCondition := GetDeploymentCondition(k8sDeployment.Status, apps_v1beta1.DeploymentAvailable)
    progressingCondition := GetDeploymentCondition(k8sDeployment.Status, apps_v1beta1.DeploymentProgressing)

    if k8sDeployment.Status.UpdatedReplicas != *(k8sDeployment.Spec.Replicas) ||
        k8sDeployment.Status.Replicas != *(k8sDeployment.Spec.Replicas) ||
        k8sDeployment.Status.AvailableReplicas != *(k8sDeployment.Spec.Replicas) ||
        availableCondition.Status != "True" ||
        progressingCondition.Status != "True" {
        return false, []string{"deployments not ready!"}, nil
    }

    if k8sDeployment.Status.ObservedGeneration < k8sDeployment.Generation {
        return false, []string{"observed generation less than generation!"}, nil
    }

    // 發(fā)布成功
    return true, []string{}, nil
}

func PrintDeploymentStatus(clientset kubernetes.Clientset, deployment apps_v1beta1.Deployment) {

    // 拼接selector
    labelSelector := ""
    for key, value := range deployment.Spec.Selector.MatchLabels {
        labelSelector = labelSelector + key + "=" + value + ","
    }
    labelSelector = strings.TrimRight(labelSelector, ",")

    for {
        // 獲取k8s中deployment的狀態(tài)
        k8sDeployment, err := clientset.AppsV1beta1().Deployments("default").Get(deployment.Name, meta_v1.GetOptions{})
        if err != nil {
            fmt.Println(err)
        }

        // 打印deployment狀態(tài)
        fmt.Printf("-------------deployment status------------\n")
        fmt.Printf("deployment.name: %s\n", k8sDeployment.Name)
        fmt.Printf("deployment.generation: %d\n", k8sDeployment.Generation)
        fmt.Printf("deployment.status.observedGeneration: %d\n", k8sDeployment.Status.ObservedGeneration)
        fmt.Printf("deployment.spec.replicas: %d\n", *(k8sDeployment.Spec.Replicas))
        fmt.Printf("deployment.status.replicas: %d\n", k8sDeployment.Status.Replicas)
        fmt.Printf("deployment.status.updatedReplicas: %d\n", k8sDeployment.Status.UpdatedReplicas)
        fmt.Printf("deployment.status.readyReplicas: %d\n", k8sDeployment.Status.ReadyReplicas)
        fmt.Printf("deployment.status.unavailableReplicas: %d\n", k8sDeployment.Status.UnavailableReplicas)
        for _, condition := range k8sDeployment.Status.Conditions {
            fmt.Printf("condition.type: %s, condition.status: %s, condition.reason: %s\n", condition.Type, condition.Status, condition.Reason)
        }

        // 獲取pod狀態(tài)
        podList, err := clientset.CoreV1().Pods("default").List(meta_v1.ListOptions{LabelSelector: labelSelector})
        if err != nil {
            fmt.Println(err)
            return
        }

        for index, pod := range podList.Items {
            // 打印pod的狀態(tài)
            fmt.Printf("-------------pod %d status------------\n", index)
            fmt.Printf("pod.name: %s\n", pod.Name)
            fmt.Printf("pod.status.phase: %s\n", pod.Status.Phase)
            for _, condition := range pod.Status.Conditions {
                fmt.Printf("condition.type: %s, condition.status: %s, conditon.reason: %s\n", condition.Type, condition.Status, condition.Reason)
            }

            for _, containerStatus := range pod.Status.ContainerStatuses {
                if containerStatus.State.Waiting != nil {
                    fmt.Printf("containerStatus.state.waiting.reason: %s\n", containerStatus.State.Waiting.Reason)
                }
                if containerStatus.State.Running != nil {
                    fmt.Printf("containerStatus.state.running.startedAt: %s\n", containerStatus.State.Running.StartedAt)
                }
            }
        }

        availableCondition := GetDeploymentCondition(k8sDeployment.Status, apps_v1beta1.DeploymentAvailable)
        progressingCondition := GetDeploymentCondition(k8sDeployment.Status, apps_v1beta1.DeploymentProgressing)
        if k8sDeployment.Status.UpdatedReplicas == *(k8sDeployment.Spec.Replicas) &&
            k8sDeployment.Status.Replicas == *(k8sDeployment.Spec.Replicas) &&
            k8sDeployment.Status.AvailableReplicas == *(k8sDeployment.Spec.Replicas) &&
            k8sDeployment.Status.ObservedGeneration >= k8sDeployment.Generation &&
            availableCondition.Status == "True" &&
            progressingCondition.Status == "True" {
            fmt.Printf("-------------deploy status------------\n")
            fmt.Println("success!")
        }else{
            fmt.Printf("-------------deploy status------------\n")
            fmt.Println("waiting...")
        }

        time.Sleep(3 * time.Second)
    }
}

// GetDeploymentCondition returns the condition with the provided type.
func GetDeploymentCondition(status apps_v1beta1.DeploymentStatus, condType apps_v1beta1.DeploymentConditionType) *apps_v1beta1.DeploymentCondition {
    for i := range status.Conditions {
        c := status.Conditions[i]
        if c.Type == condType {
            return &c
        }
    }
    return nil
}

func GetPodCondition(status core_v1.PodStatus, condType core_v1.PodConditionType) *core_v1.PodCondition {
    for i := range status.Conditions {
        c := status.Conditions[i]
        if c.Type == condType {
            return &c
        }
    }
    return nil
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末罢坝,一起剝皮案震驚了整個(gè)濱河市廓握,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌嘁酿,老刑警劉巖隙券,帶你破解...
    沈念sama閱讀 211,817評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異闹司,居然都是意外死亡娱仔,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)游桩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)牲迫,“玉大人,你說(shuō)我怎么就攤上這事借卧№镌鳎” “怎么了廉油?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,354評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)实柠。 經(jīng)常有香客問(wèn)我捏膨,道長(zhǎng),這世上最難降的妖魔是什么蛛蒙? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,498評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上捡遍,老公的妹妹穿的比我還像新娘。我一直安慰自己竹握,他們只是感情好画株,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著啦辐,像睡著了一般谓传。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上芹关,一...
    開(kāi)封第一講書(shū)人閱讀 49,829評(píng)論 1 290
  • 那天续挟,我揣著相機(jī)與錄音,去河邊找鬼侥衬。 笑死诗祸,一個(gè)胖子當(dāng)著我的面吹牛跑芳,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播直颅,決...
    沈念sama閱讀 38,979評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼博个,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了功偿?” 一聲冷哼從身側(cè)響起盆佣,我...
    開(kāi)封第一講書(shū)人閱讀 37,722評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎械荷,沒(méi)想到半個(gè)月后罪塔,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,189評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡养葵,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評(píng)論 2 327
  • 正文 我和宋清朗相戀三年征堪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片关拒。...
    茶點(diǎn)故事閱讀 38,654評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡佃蚜,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出着绊,到底是詐尸還是另有隱情谐算,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布归露,位于F島的核電站洲脂,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏剧包。R本人自食惡果不足惜恐锦,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評(píng)論 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望疆液。 院中可真熱鬧一铅,春花似錦、人聲如沸堕油。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,762評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)掉缺。三九已至卜录,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間眶明,已是汗流浹背艰毒。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,993評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留赘来,地道東北人现喳。 一個(gè)月前我還...
    沈念sama閱讀 46,382評(píng)論 2 360
  • 正文 我出身青樓凯傲,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親嗦篱。 傳聞我的和親對(duì)象是個(gè)殘疾皇子冰单,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評(píng)論 2 349