Repository: kubernetes/kubernetes (language: go)

Issue:
[FG:InPlacePodVerticalScaling] api server "INTERNAL_ERROR; received from peer" while executing kubectl  replace 
### What happened?

error on kubectl replace cmd : error: error when replacing "pod-updated-example.yaml": Put "https://localhost:6443/api/v1/namespaces/default/pods/high-priority?fieldManager=kubectl-replace&fieldValidation=Strict": stream error: stream ID 5; INTERNAL_ERROR; received from peer 

On api server logs : 
```
E0911 00:12:42.298940  214100 wrap.go:57] "apiserver panic'd" method="PUT" URI="/api/v1/namespaces/default/pods/high-priority?fieldManager=kubectl-replace&fieldValidation=Strict" auditID="d82cb6f9-3244-4002-8575-ffa99805d451"
http2: panic serving 127.0.0.1:44790: runtime error: index out of range [1] with length 1
goroutine 44578 [running]:
k8s.io/apiserver/pkg/endpoints/handlers/finisher.finishRequest.func1.1()
        k8s.io/apiserver/pkg/endpoints/handlers/finisher/finisher.go:105 +0xa5
panic({0x33a7b20?, 0xc00af7b950?})
        runtime/panic.go:770 +0x132
k8s.io/kubernetes/pkg/api/pod.MarkPodProposedForResize(0xc00a9c8488, 0xc00a9c8d88)
        k8s.io/kubernetes/pkg/api/pod/util.go:1238 +0x371
k8s.io/kubernetes/pkg/registry/core/pod.podStrategy.PrepareForUpdate({{0x7f6ce61f0518?, 0x5a45760?}, {0xc0077da860?, 0x145d6e5?}}, {0xa?, 0x35677e0?}, {0x3c62268?, 0xc00a9c8d88}, {0x3c62268, 0xc00a9c8488})
        k8s.io/kubernetes/pkg/registry/core/pod/strategy.go:110 +0xe9
k8s.io/apiserver/pkg/registry/rest.BeforeUpdate({0x3c9e980, 0xc000626520}, {0x3c88f40, 0xc007016b40}, {0x3c62268, 0xc00a9c8d88}, {0x3c62268, 0xc00a9c8488})
        k8s.io/apiserver/pkg/registry/rest/update.go:129 +0x243
k8s.io/apiserver/pkg/registry/generic/registry.(*Store).Update.func1({0x3c62268, 0xc00a9c8488}, {0xc00947d3b0?, 0x35f7afb?})
```



### What did you expect to happen?

api server return this error : The Pod "XXX" is invalid: spec.containers: Forbidden: pod updates may not add or remove containers 

### How can we reproduce it (as minimally and precisely as possible)?

1-start the cluster with FEATURE_GATE ENABLED (InPlacePodVerticalScaling)
2- create a pod with one container , for example : 

```yaml
apiVersion: v1
kind: Pod
metadata:
  name: high-priority
spec:
  containers:
  - name: high-priority
    image: ubuntu
    command: ["/bin/sh"]
    args: ["-c", "while true; do echo hello; sleep 10;done"]
    resources:
      requests:
        memory: "10Mi"
        cpu: "10m"
      limits:
        memory: "10Mi"
        cpu: "10m"
```

3- try  to replace (without force) with ( + container) : 

```yaml
apiVersion: v1
kind: Pod
metadata:
  name: high-priority
spec:
  containers:
  - name: high-priority
    image: ubuntu
    command: ["/bin/sh"]
    args: ["-c", "while true; do echo hello; sleep 10;done"]
    resources:
      requests:
        memory: "10Mi"
        cpu: "10m"
      limits:
        memory: "10Mi"
        cpu: "10m"
  - name: high-priority-1
    image: ubuntu
    command: ["/bin/sh"]
    args: ["-c", "while true; do echo hello; sleep 10;done"]
    resources:
      requests:
        memory: "10Mi"
        cpu: "10m"
      limits:
        memory: "10Mi"
        cpu: "10m"

```

kubectl  replace -f pod-updated-example.yaml  

**ERROR** : Put "https://localhost:6443/api/v1/namespaces/default/pods/high-priority?fieldManager=kubectl-replace&fieldValidation=Strict": stream error: stream ID 5; INTERNAL_ERROR; received from peer 

### Anything else we need to know?

based on the master branch (ref commit : 139cc3c659dd1624f7a4bbcc3b07fda79539677a )


### Kubernetes version

<details>

```console
$ kubectl version
Server Version: v1.31.0-beta.0.854+4cfdad0935cfb7-dirty
```

</details>


### Cloud provider

<details>
locally 
</details>


### OS version

<details>

```console
# On Linux:
$ cat /etc/os-release
PRETTY_NAME="Ubuntu 22.04.4 LTS"
NAME="Ubuntu"
VERSION_ID="22.04"
VERSION="22.04.4 LTS (Jammy Jellyfish)"
VERSION_CODENAME=jammy
ID=ubuntu
ID_LIKE=debian
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
UBUNTU_CODENAME=jammy
$ uname -a
Linux 20231797-MARBT 5.15.153.1-microsoft-standard-WSL2 #1 SMP Fri Mar 29 23:14:13 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux

</details>


### Install tools

<details>

</details>


### Container runtime (CRI) and version (if applicable)

<details>
containerD
</details>


### Related plugins (CNI, CSI, ...) and versions (if applicable)

<details>

</details>



Discussion / hints:
/area/apiserver  
Hi, I want to try solving this problem.

/assign
/sig api-machinery

Fix patch:
diff --git a/pkg/api/pod/util.go b/pkg/api/pod/util.go
index 1d1a211a28eb2..2e425c93cd5e0 100644
--- a/pkg/api/pod/util.go
+++ b/pkg/api/pod/util.go
@@ -1255,6 +1255,11 @@ func hasInvalidLabelValueInAffinitySelector(spec *api.PodSpec) bool {
 }
 
 func MarkPodProposedForResize(oldPod, newPod *api.Pod) {
+	if len(newPod.Spec.Containers) != len(oldPod.Spec.Containers) {
+		// Update is invalid: ignore changes and let validation handle it
+		return
+	}
+
 	for i, c := range newPod.Spec.Containers {
 		if c.Resources.Requests == nil {
 			continue


Test patch:
diff --git a/pkg/api/pod/util_test.go b/pkg/api/pod/util_test.go
index c94005283a4e7..a99deac1a4cb8 100644
--- a/pkg/api/pod/util_test.go
+++ b/pkg/api/pod/util_test.go
@@ -3036,6 +3036,189 @@ func TestMarkPodProposedForResize(t *testing.T) {
 				},
 			},
 		},
+		{
+			desc: "the number of containers in the pod has increased; no action should be taken.",
+			newPod: &api.Pod{
+				Spec: api.PodSpec{
+					Containers: []api.Container{
+						{
+							Name:  "c1",
+							Image: "image",
+							Resources: api.ResourceRequirements{
+								Requests: api.ResourceList{api.ResourceCPU: resource.MustParse("100m")},
+								Limits:   api.ResourceList{api.ResourceCPU: resource.MustParse("200m")},
+							},
+						},
+						{
+							Name:  "c2",
+							Image: "image",
+							Resources: api.ResourceRequirements{
+								Requests: api.ResourceList{api.ResourceCPU: resource.MustParse("300m")},
+								Limits:   api.ResourceList{api.ResourceCPU: resource.MustParse("400m")},
+							},
+						},
+					},
+				},
+				Status: api.PodStatus{
+					ContainerStatuses: []api.ContainerStatus{
+						{
+							Name:               "c1",
+							Image:              "image",
+							AllocatedResources: api.ResourceList{api.ResourceCPU: resource.MustParse("100m")},
+						},
+						{
+							Name:               "c2",
+							Image:              "image",
+							AllocatedResources: api.ResourceList{api.ResourceCPU: resource.MustParse("200m")},
+						},
+					},
+				},
+			},
+			oldPod: &api.Pod{
+				Spec: api.PodSpec{
+					Containers: []api.Container{
+						{
+							Name:  "c1",
+							Image: "image",
+							Resources: api.ResourceRequirements{
+								Requests: api.ResourceList{api.ResourceCPU: resource.MustParse("100m")},
+								Limits:   api.ResourceList{api.ResourceCPU: resource.MustParse("200m")},
+							},
+						},
+					},
+				},
+				Status: api.PodStatus{
+					ContainerStatuses: []api.ContainerStatus{
+						{
+							Name:               "c1",
+							Image:              "image",
+							AllocatedResources: api.ResourceList{api.ResourceCPU: resource.MustParse("100m")},
+						},
+					},
+				},
+			},
+			expectedPod: &api.Pod{
+				Spec: api.PodSpec{
+					Containers: []api.Container{
+						{
+							Name:  "c1",
+							Image: "image",
+							Resources: api.ResourceRequirements{
+								Requests: api.ResourceList{api.ResourceCPU: resource.MustParse("100m")},
+								Limits:   api.ResourceList{api.ResourceCPU: resource.MustParse("200m")},
+							},
+						},
+						{
+							Name:  "c2",
+							Image: "image",
+							Resources: api.ResourceRequirements{
+								Requests: api.ResourceList{api.ResourceCPU: resource.MustParse("300m")},
+								Limits:   api.ResourceList{api.ResourceCPU: resource.MustParse("400m")},
+							},
+						},
+					},
+				},
+				Status: api.PodStatus{
+					ContainerStatuses: []api.ContainerStatus{
+						{
+							Name:               "c1",
+							Image:              "image",
+							AllocatedResources: api.ResourceList{api.ResourceCPU: resource.MustParse("100m")},
+						},
+						{
+							Name:               "c2",
+							Image:              "image",
+							AllocatedResources: api.ResourceList{api.ResourceCPU: resource.MustParse("200m")},
+						},
+					},
+				},
+			},
+		},
+		{
+			desc: "the number of containers in the pod has decreased; no action should be taken.",
+			newPod: &api.Pod{
+				Spec: api.PodSpec{
+					Containers: []api.Container{
+						{
+							Name:  "c1",
+							Image: "image",
+							Resources: api.ResourceRequirements{
+								Requests: api.ResourceList{api.ResourceCPU: resource.MustParse("100m")},
+								Limits:   api.ResourceList{api.ResourceCPU: resource.MustParse("200m")},
+							},
+						},
+					},
+				},
+				Status: api.PodStatus{
+					ContainerStatuses: []api.ContainerStatus{
+						{
+							Name:               "c1",
+							Image:              "image",
+							AllocatedResources: api.ResourceList{api.ResourceCPU: resource.MustParse("100m")},
+						},
+					},
+				},
+			},
+			oldPod: &api.Pod{
+				Spec: api.PodSpec{
+					Containers: []api.Container{
+						{
+							Name:  "c1",
+							Image: "image",
+							Resources: api.ResourceRequirements{
+								Requests: api.ResourceList{api.ResourceCPU: resource.MustParse("100m")},
+								Limits:   api.ResourceList{api.ResourceCPU: resource.MustParse("200m")},
+							},
+						},
+						{
+							Name:  "c2",
+							Image: "image",
+							Resources: api.ResourceRequirements{
+								Requests: api.ResourceList{api.ResourceCPU: resource.MustParse("200m")},
+								Limits:   api.ResourceList{api.ResourceCPU: resource.MustParse("300m")},
+							},
+						},
+					},
+				},
+				Status: api.PodStatus{
+					ContainerStatuses: []api.ContainerStatus{
+						{
+							Name:               "c1",
+							Image:              "image",
+							AllocatedResources: api.ResourceList{api.ResourceCPU: resource.MustParse("100m")},
+						},
+						{
+							Name:               "c2",
+							Image:              "image",
+							AllocatedResources: api.ResourceList{api.ResourceCPU: resource.MustParse("200m")},
+						},
+					},
+				},
+			},
+			expectedPod: &api.Pod{
+				Spec: api.PodSpec{
+					Containers: []api.Container{
+						{
+							Name:  "c1",
+							Image: "image",
+							Resources: api.ResourceRequirements{
+								Requests: api.ResourceList{api.ResourceCPU: resource.MustParse("100m")},
+								Limits:   api.ResourceList{api.ResourceCPU: resource.MustParse("200m")},
+							},
+						},
+					},
+				},
+				Status: api.PodStatus{
+					ContainerStatuses: []api.ContainerStatus{
+						{
+							Name:               "c1",
+							Image:              "image",
+							AllocatedResources: api.ResourceList{api.ResourceCPU: resource.MustParse("100m")},
+						},
+					},
+				},
+			},
+		},
 	}
 	for _, tc := range testCases {
 		t.Run(tc.desc, func(t *testing.T) {