client-go示例

访问kubernetes集群有几下几种方式:

方式

特点

支持者

Kubernetes dashboard

直接通过Web UI进行操作,简单直接,可定制化程度低

官方支持

kubectl

命令行操作,功能最全,但是比较复杂,适合对其进行进一步的分装,定制功能,版本适配最好

官方支持

从kubernetes的代码中抽离出来的客户端包,简单易用,但需要小心区分kubernetes的API版本

官方支持

python客户端,kubernetes-incubator

官方支持

fabric8中的一部分,kubernetes的java客户端

redhat

下面,我们基于client-go,对Deployment升级镜像的步骤进行了定制,通过命令行传递一个Deployment的名字、应用容器名和新image名字的方式来升级。

kubernetes-client-go-sample

代码如下:

package main

import (
    "flag"
    "fmt"
    "os"
    "path/filepath"

    "k8s.io/apimachinery/pkg/api/errors"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/tools/clientcmd"
)

func main() {
    var kubeconfig *string
    if home := homeDir(); home != "" {
        kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
    } else {
        kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
    }
    deploymentName := flag.String("deployment", "", "deployment name")
    imageName := flag.String("image", "", "new image name")
    appName := flag.String("app", "app", "application name")

    flag.Parse()
    if *deploymentName == "" {
        fmt.Println("You must specify the deployment name.")
        os.Exit(0)
    }
    if *imageName == "" {
        fmt.Println("You must specify the new image name.")
        os.Exit(0)
    }
    // use the current context in kubeconfig
    config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
    if err != nil {
        panic(err.Error())
    }

    // create the clientset
    clientset, err := kubernetes.NewForConfig(config)
    if err != nil {
        panic(err.Error())
    }
    deployment, err := clientset.AppsV1beta1().Deployments("default").Get(*deploymentName, metav1.GetOptions{})
    if err != nil {
        panic(err.Error())
    }
    if errors.IsNotFound(err) {
        fmt.Printf("Deployment not found\n")
    } else if statusError, isStatus := err.(*errors.StatusError); isStatus {
        fmt.Printf("Error getting deployment%v\n", statusError.ErrStatus.Message)
    } else if err != nil {
        panic(err.Error())
    } else {
        fmt.Printf("Found deployment\n")
        name := deployment.GetName()
        fmt.Println("name ->", name)
        containers := &deployment.Spec.Template.Spec.Containers
        found := false
        for i := range *containers {
            c := *containers
            if c[i].Name == *appName {
                found = true
                fmt.Println("Old image ->", c[i].Image)
                fmt.Println("New image ->", *imageName)
                c[i].Image = *imageName
            }
        }
        if found == false {
            fmt.Println("The application container not exist in the deployment pods.")
            os.Exit(0)
        }
        _, err := clientset.AppsV1beta1().Deployments("default").Update(deployment)
        if err != nil {
            panic(err.Error())
        }
    }
}

func homeDir() string {
    if h := os.Getenv("HOME"); h != "" {
        return h
    }
    return os.Getenv("USERPROFILE") // windows
}

我们使用kubeconfig文件认证连接kubernetes集群,该文件默认的位置是$HOME/.kube/config

该代码编译后可以直接在kubernetes集群之外,任何一个可以连接到API server的机器上运行。

编译运行

使用不存在的image更新

查看Deployment的event。

可以看到老的ReplicaSet从3个replica减少到了2个,有2个使用新配置的replica不可用,目前可用的replica是2个。

这是因为我们指定的镜像不存在,查看Deployment的pod的状态。

我们可以看到有两个pod正在拉取image。

还原为原先的镜像

将image设置为原来的镜像。

现在再查看Deployment的状态。

可以看到available的replica个数恢复成3了。

其实在使用该命令的过程中,通过kubernetes dashboard的页面上查看Deployment的状态更直观,更加方便故障排查。

使用kubernetes dashboard进行故障排查

这也是dashboard最大的优势,简单、直接、高效。

Last updated

Was this helpful?