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
|
1 Answer
Reset to default 1The 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)),
),
),
),
)
Deployment
function, it sets thekind
andapiVersion
(seeDeployment
). Your code does not do this. – DazWilkin Commented Mar 15 at 18:38Deployment
returns anDeploymentApplyConfigurationl
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