I want to apply the following yaml multiple times with the fabric8 kubernetes-client
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
storageClassName: my-storage-class
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
I apply the yaml using createOrReplace()
Config config = new ConfigBuilder()
.withMasterUrl("https://my-kubernetes-root:6443")
.withNamespace("my-namespace")
.withOauthToken(token)
.withTrustCerts(true)
.build();
KubernetesClient client = new DefaultKubernetesClient(config);
ClasspathResource resource = new ClasspathResource("my-pvc.yaml");
client.load(resource.getInputStream()).createOrReplace(); // this works
TimeUnit.MINUTES.sleep(1); // volumeName is dynamically assigned during this period
client.load(resource.getInputStream()).createOrReplace(); // this fails
This works the first time (when the PVC does not exist in the namespace) but fails the second time that createOrReplace()
is called for the same yaml with the following error
io.fabric8.kubernetes.client.KubernetesClientException: Failure executing: PUT at: https://my-kubernetes-root:6443/api/v1/namespaces/my-namespace/persistentvolumeclaims/my-pvc. Message: PersistentVolumeClaim "my-pvc" is invalid: spec: Forbidden: spec is immutable after creation except resources.requests for bound claims
core.PersistentVolumeClaimSpec{
AccessModes: []core.PersistentVolumeAccessMode{"ReadWriteMany"},
Selector: nil,
Resources: core.ResourceRequirements{Requests: core.ResourceList{s"storage": {i: resource.int64Amount{value: 1073741824}, s: "1Gi", Format: "BinarySI"}}},
- VolumeName: "",
+ VolumeName: "pvc-b79ebfcb-d5cb-4450-9f17-d69ec10b8712",
StorageClassName: &"my-storage-class",
VolumeMode: &"Filesystem",
DataSource: nil,
}
Notice how "volumeName" is not present in the yaml (nil) but in the error message "volumeName" is changing from empty string to the dynamically assigned volumeName.
I can reproduce this exact same behavior using kubectl and empty string for volumeName
I can kubectl apply
the following yaml as many times as I like
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
storageClassName: my-storage-class
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
But if I kubectl apply
a yaml with volumeName of empty string it works the first time and fails the second time (The error message is the same as above)
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: my-pvc
spec:
storageClassName: my-storage-class
volumeName: ""
accessModes:
- ReadWriteMany
resources:
requests:
storage: 1Gi
How can I get KubernetesClient
to behave the same as kubectl apply
? Is there any way that I can apply the same PersistentVolumeClaim yaml multiple times with KubernetesClient
?
As a workaround, I have switched to using a StatefulSet
to manage my Pod
which allows me to specify volumeClaimTemplates
eg the following yaml can be applied multiple times:
apiVersion: apps/v1
kind: StatefulSet
metadata:
name: web
spec:
selector:
matchLabels:
app: nginx
serviceName: "nginx"
replicas: 1
template:
metadata:
labels:
app: nginx
spec:
terminationGracePeriodSeconds: 10
containers:
- name: nginx
image: k8s.gcr.io/nginx-slim:0.8
ports:
- containerPort: 80
name: web
volumeMounts:
- name: www
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: www
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: "my-storage-class"
resources:
requests:
storage: 1Gi