最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

kubernetes - Why does ClientSet in client-go fail to deploy a Deployment? - Stack Overflow

programmeradmin2浏览0评论

When I attempt to use the client-go client to apply a Deployment, I encounter the error "invalid object type: /, Kind=". Interestingly, if I use the create method instead, the Deployment is created successfully without any issues, and the code compiles perfectly fine. This discrepancy suggests that there might be a problem with how the Apply method is being used or how the object is being configured for Apply.

I’ve thoroughly reviewed the official Kubernetes and client-go documentation but haven’t found any specific guidance or examples that address this particular issue. It’s unclear why the Apply method fails while create works as expected. I suspect it might be related to how the ApplyConfiguration object is structured or how the FieldManager is being set, but I’m unable to pinpoint the exact cause.

If anyone has encountered a similar issue or has insights into why this might be happening, I would greatly appreciate your help. Any suggestions or solutions would be incredibly valuable. Thank you so much in advance for your assistance!

main.go

package main

import (
    "context"
    "flag"
    "fmt"
    "log"
    "path/filepath"
    "time"

    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    applyappsv1 "k8s.io/client-go/applyconfigurations/apps/v1"
    applycorev1 "k8s.io/client-go/applyconfigurations/core/v1"
    applymetav1 "k8s.io/client-go/applyconfigurations/meta/v1"
    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/tools/clientcmd"
    "k8s.io/client-go/util/homedir"
    "k8s.io/utils/pointer"
)

func main() {
    var kubeconfig *string
    if home := homedir.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")
    }
    flag.Parse()

    config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
    if err != nil {
        panic(err.Error())
    }

    clientset, err := kubernetes.NewForConfig(config)
    if err != nil {
        panic(err.Error())
    }

    deploymentName := "test-deployment"
    namespace := "default"

    deploymentApplyConfig := applyappsv1.DeploymentApplyConfiguration{
        ObjectMetaApplyConfiguration: &applymetav1.ObjectMetaApplyConfiguration{
            Name:      &deploymentName,
            Namespace: &namespace,
        },
        Spec: &applyappsv1.DeploymentSpecApplyConfiguration{
            Replicas: pointer.Int32(3),
            Selector: &applymetav1.LabelSelectorApplyConfiguration{
                MatchLabels: map[string]string{
                    "app": "test-app",
                },
            },
            Template: &applycorev1.PodTemplateSpecApplyConfiguration{
                ObjectMetaApplyConfiguration: &applymetav1.ObjectMetaApplyConfiguration{
                    Labels: map[string]string{
                        "app": "test-app",
                    },
                },
                Spec: &applycorev1.PodSpecApplyConfiguration{
                    Containers: []applycorev1.ContainerApplyConfiguration{
                        {
                            Name:  pointer.String("nginx"),
                            Image: pointer.String("nginx:1.14.2"),
                            Ports: []applycorev1.ContainerPortApplyConfiguration{
                                {
                                    ContainerPort: pointer.Int32(80),
                                },
                            },
                        },
                    },
                },
            },
        },
    }

    fmt.Println("Applying Deployment...")
    appliedDeployment, err := clientset.AppsV1().Deployments(namespace).Apply(
        context.TODO(),
        &deploymentApplyConfig,
        metav1.ApplyOptions{FieldManager: "test-client"},
    )
    if err != nil {
        log.Fatalf("Error applying Deployment: %s", err)
    }
    fmt.Printf("Applied Deployment %q\n", appliedDeployment.Name)
}

Output:

Applying Deployment...
2025/03/15 12:48:06 Error applying Deployment: invalid object type: /, Kind=
exit status 1

Versions:

go version: 1.23.0
client-go version: 0.32.0
k8s-version: 1.32.0

When I attempt to use the client-go client to apply a Deployment, I encounter the error "invalid object type: /, Kind=". Interestingly, if I use the create method instead, the Deployment is created successfully without any issues, and the code compiles perfectly fine. This discrepancy suggests that there might be a problem with how the Apply method is being used or how the object is being configured for Apply.

I’ve thoroughly reviewed the official Kubernetes and client-go documentation but haven’t found any specific guidance or examples that address this particular issue. It’s unclear why the Apply method fails while create works as expected. I suspect it might be related to how the ApplyConfiguration object is structured or how the FieldManager is being set, but I’m unable to pinpoint the exact cause.

If anyone has encountered a similar issue or has insights into why this might be happening, I would greatly appreciate your help. Any suggestions or solutions would be incredibly valuable. Thank you so much in advance for your assistance!

main.go

package main

import (
    "context"
    "flag"
    "fmt"
    "log"
    "path/filepath"
    "time"

    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    applyappsv1 "k8s.io/client-go/applyconfigurations/apps/v1"
    applycorev1 "k8s.io/client-go/applyconfigurations/core/v1"
    applymetav1 "k8s.io/client-go/applyconfigurations/meta/v1"
    "k8s.io/client-go/kubernetes"
    "k8s.io/client-go/tools/clientcmd"
    "k8s.io/client-go/util/homedir"
    "k8s.io/utils/pointer"
)

func main() {
    var kubeconfig *string
    if home := homedir.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")
    }
    flag.Parse()

    config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
    if err != nil {
        panic(err.Error())
    }

    clientset, err := kubernetes.NewForConfig(config)
    if err != nil {
        panic(err.Error())
    }

    deploymentName := "test-deployment"
    namespace := "default"

    deploymentApplyConfig := applyappsv1.DeploymentApplyConfiguration{
        ObjectMetaApplyConfiguration: &applymetav1.ObjectMetaApplyConfiguration{
            Name:      &deploymentName,
            Namespace: &namespace,
        },
        Spec: &applyappsv1.DeploymentSpecApplyConfiguration{
            Replicas: pointer.Int32(3),
            Selector: &applymetav1.LabelSelectorApplyConfiguration{
                MatchLabels: map[string]string{
                    "app": "test-app",
                },
            },
            Template: &applycorev1.PodTemplateSpecApplyConfiguration{
                ObjectMetaApplyConfiguration: &applymetav1.ObjectMetaApplyConfiguration{
                    Labels: map[string]string{
                        "app": "test-app",
                    },
                },
                Spec: &applycorev1.PodSpecApplyConfiguration{
                    Containers: []applycorev1.ContainerApplyConfiguration{
                        {
                            Name:  pointer.String("nginx"),
                            Image: pointer.String("nginx:1.14.2"),
                            Ports: []applycorev1.ContainerPortApplyConfiguration{
                                {
                                    ContainerPort: pointer.Int32(80),
                                },
                            },
                        },
                    },
                },
            },
        },
    }

    fmt.Println("Applying Deployment...")
    appliedDeployment, err := clientset.AppsV1().Deployments(namespace).Apply(
        context.TODO(),
        &deploymentApplyConfig,
        metav1.ApplyOptions{FieldManager: "test-client"},
    )
    if err != nil {
        log.Fatalf("Error applying Deployment: %s", err)
    }
    fmt.Printf("Applied Deployment %q\n", appliedDeployment.Name)
}

Output:

Applying Deployment...
2025/03/15 12:48:06 Error applying Deployment: invalid object type: /, Kind=
exit status 1

Versions:

go version: 1.23.0
client-go version: 0.32.0
k8s-version: 1.32.0
Share Improve this question asked Mar 15 at 5:11 groobygrooby 234 bronze badges 3
  • If you were to use the Deployment function, it sets the kind and apiVersion (see Deployment). Your code does not do this. – DazWilkin Commented Mar 15 at 18:38
  • Deployment returns an DeploymentApplyConfigurationl which also includes a bunch of methods (e.g. WithSpec) that will ensure that you're mutating the structs with the correct fields being set. Perhaps use that approach? – DazWilkin Commented Mar 15 at 18:40
  • Thanks, DazWilkin. I'm new to client-go programming. Could you please show me how to fix this issue, like how to ​set the kind and apiVersion? I can't ​find where to set them. – grooby Commented Mar 21 at 5:55
Add a comment  | 

1 Answer 1

Reset to default 1

The simplest way to correct your code is to add TypeMetaApplyConfiguration to your struct:

deploymentApplyConfig := applyappsv1.DeploymentApplyConfiguration{
    TypeMetaApplyConfiguration: applymetav1.TypeMetaApplyConfiguration{
        Kind:       pointer.String("Deployment"),
        APIVersion: pointer.String("apps/v1"),
    },
    ObjectMetaApplyConfiguration: &applymetav1.ObjectMetaApplyConfiguration{
        Name:      &deploymentName,
        Namespace: &namespace,
    },
    ...

But, per my comment, there are methods to help with the construction and it may be preferable to use these:

deploymentName := "test-deployment"
namespace := "default"

labels := map[string]string{
    "app": "test-app",
}

containerName := "nginx"
image := "docker.io/nginx:1.14.2"
port := int32(8080)

deploymentApplyConfig := applyappsv1.Deployment(
    deploymentName,
    namespace,
).WithSpec(
    applyappsv1.DeploymentSpec().WithReplicas(3).WithSelector(
        applymetav1.LabelSelector().WithMatchLabels(labels),
    ).WithTemplate(
        applycorev1.PodTemplateSpec().WithLabels(labels).WithSpec(
            applycorev1.PodSpec().WithContainers(
                applycorev1.Container().WithName(containerName).WithImage(image).WithPorts(applycorev1.ContainerPort().WithContainerPort(port)),
            ),
        ),
    ),
)
发布评论

评论列表(0)

  1. 暂无评论