Change:
is not normalized in in the status manager: This does not seem to cause any user facing problem because is sorted before passed to the status manager and timestamps are normalized at marshaling to create a patch: However, an unexpected behavior is caused internally because timestamps are not normalized. If the log verbosity is 3 or larger, the following messages are logged periodically in kubelet when an ephemeral container exists: This message is emitted here: After returns , is called. This does not look so harmful because gets eventually: API is called once unnecessarily in , though: It might be better to normalize ephemeral container statuses, at least timestamps, in the status manager to avoid this unexpected behavior. Set the log verbosity of kubelet to 3 or larger. Then, create an ephemeral container like . No response <details</details<detailsNone </details<details</details<details</details<details</details<details</details
/sig node
This is a bug. Can you submit a PR to fix it? If not, I'd be happy to work on it
If you are interested, please feel free to assign yourself.
thx
/assign
/triage accepted /priority important-longterm

Discussion:
// Related issue #15262/PR #15263 to move apiserver to RFC339NANO is closed. func normalizeStatus(pod *v1.Pod, status *v1.PodStatus) *v1.PodStatus { bytesPerStatus := kubecontainer.MaxPodTerminationMessageLogLength <del> if containers := len(pod.Spec.Containers) + len(pod.Spec.InitContainers); containers > 0 { </del> <ins> if containers := len(pod.Spec.Containers) + len(pod.Spec.InitContainers) + len(pod.Spec.EphemeralContainers); containers > 0 { </ins> bytesPerStatus = bytesPerStatus / containers } normalizeTimeStamp := func(t *metav1.Time) {

normalizeTimeStamp(&condition.LastTransitionTime) } <del> // update container statuses for i := range status.ContainerStatuses { cstatus := &status.ContainerStatuses[i] normalizeContainerState(&cstatus.State) normalizeContainerState(&cstatus.LastTerminationState) </del> <ins> normalizeContainerStatuses := func(containerStatuses []v1.ContainerStatus) { for i := range containerStatuses { cstatus := &containerStatuses[i] normalizeContainerState(&cstatus.State) normalizeContainerState(&cstatus.LastTerminationState) } </ins> } <del> // Sort the container statuses, so that the order won't affect the result of comparison </del> <ins> normalizeContainerStatuses(status.ContainerStatuses) </ins> sort.Sort(kubetypes.SortedContainerStatuses(status.ContainerStatuses)) <del> // update init container statuses for i := range status.InitContainerStatuses { cstatus := &status.InitContainerStatuses[i] normalizeContainerState(&cstatus.State) normalizeContainerState(&cstatus.LastTerminationState) } // Sort the container statuses, so that the order won't affect the result of comparison </del> <ins> normalizeContainerStatuses(status.InitContainerStatuses) </ins> kubetypes.SortInitContainerStatuses(pod, status.InitContainerStatuses) <ins> normalizeContainerStatuses(status.EphemeralContainerStatuses) sort.Sort(kubetypes.SortedContainerStatuses(status.EphemeralContainerStatuses)) </ins> return status }

} func TestStatusEquality(t *testing.T) { <del> pod := v1.Pod{ Spec: v1.PodSpec{}, } containerStatus := []v1.ContainerStatus{} for i := 0; i < 10; i++ { s := v1.ContainerStatus{ Name: fmt.Sprintf("container%d", i), </del> <ins> getContainersAndStatuses := func() ([]v1.Container, []v1.ContainerStatus) { var containers []v1.Container var containerStatuses []v1.ContainerStatus for i := 0; i < 10; i++ { containerName := fmt.Sprintf("container%d", i) containers = append(containers, v1.Container{Name: containerName}) containerStatuses = append(containerStatuses, v1.ContainerStatus{Name: containerName}) </ins> } <del> containerStatus = append(containerStatus, s) </del> <ins> return containers, containerStatuses } containers, containerStatuses := getContainersAndStatuses() pod := v1.Pod{ Spec: v1.PodSpec{ InitContainers: containers, }, </ins> } podStatus := v1.PodStatus{ <del> ContainerStatuses: containerStatus, </del> <ins> ContainerStatuses:          containerStatuses, InitContainerStatuses:      containerStatuses, EphemeralContainerStatuses: containerStatuses, </ins> } for i := 0; i < 10; i++ { oldPodStatus := v1.PodStatus{ <del> ContainerStatuses: shuffle(podStatus.ContainerStatuses), </del> <ins> ContainerStatuses:          shuffle(podStatus.ContainerStatuses), InitContainerStatuses:      shuffle(podStatus.InitContainerStatuses), EphemeralContainerStatuses: shuffle(podStatus.EphemeralContainerStatuses), </ins> } normalizeStatus(&pod, &oldPodStatus) normalizeStatus(&pod, &podStatus)

containerStatus = append(containerStatus, s) } podStatus := v1.PodStatus{ <del> InitContainerStatuses: containerStatus[:24], ContainerStatuses:     containerStatus[24:], </del> <ins> InitContainerStatuses:      containerStatus[:16], ContainerStatuses:          containerStatus[16:32], EphemeralContainerStatuses: containerStatus[32:], </ins> } result := normalizeStatus(&pod, &podStatus) count := 0

} } <ins> func TestStatusNormalizeTimeStamp(t *testing.T) { pod := v1.Pod{ Spec: v1.PodSpec{}, } now := metav1.Now() podStatus := v1.PodStatus{ ContainerStatuses: []v1.ContainerStatus{ {State: v1.ContainerState{Running: &v1.ContainerStateRunning{StartedAt: now}}}, {State: v1.ContainerState{Terminated: &v1.ContainerStateTerminated{StartedAt: now, FinishedAt: now}}}, }, InitContainerStatuses: []v1.ContainerStatus{ {State: v1.ContainerState{Running: &v1.ContainerStateRunning{StartedAt: now}}}, {State: v1.ContainerState{Terminated: &v1.ContainerStateTerminated{StartedAt: now, FinishedAt: now}}}, }, EphemeralContainerStatuses: []v1.ContainerStatus{ {State: v1.ContainerState{Running: &v1.ContainerStateRunning{StartedAt: now}}}, {State: v1.ContainerState{Terminated: &v1.ContainerStateTerminated{StartedAt: now, FinishedAt: now}}}, }, } expectedTime := now.DeepCopy().Rfc3339Copy() expectedPodStatus := v1.PodStatus{ ContainerStatuses: []v1.ContainerStatus{ {State: v1.ContainerState{Running: &v1.ContainerStateRunning{StartedAt: expectedTime}}}, {State: v1.ContainerState{Terminated: &v1.ContainerStateTerminated{StartedAt: expectedTime, FinishedAt: expectedTime}}}, }, InitContainerStatuses: []v1.ContainerStatus{ {State: v1.ContainerState{Running: &v1.ContainerStateRunning{StartedAt: expectedTime}}}, {State: v1.ContainerState{Terminated: &v1.ContainerStateTerminated{StartedAt: expectedTime, FinishedAt: expectedTime}}}, }, EphemeralContainerStatuses: []v1.ContainerStatus{ {State: v1.ContainerState{Running: &v1.ContainerStateRunning{StartedAt: expectedTime}}}, {State: v1.ContainerState{Terminated: &v1.ContainerStateTerminated{StartedAt: expectedTime, FinishedAt: expectedTime}}}, }, } normalizedStatus := normalizeStatus(&pod, &podStatus) if !isPodStatusByKubeletEqual(&expectedPodStatus, normalizedStatus) { t.Fatalf("The timestamp is not correctly converted to RFC3339 format.") } } </ins> func TestStaticPod(t *testing.T) { staticPod := getTestPod() staticPod.Annotations = map[string]string{kubetypes.ConfigSourceAnnotationKey: "file"}