Repository: VictoriaMetrics/VictoriaMetrics
Pull request #7324 (2024-10-22 11:29:08)

lib/promscrape/discovery/kubernetes: support kubernetes native sidecars
### Describe Your Changes

Added Kubernetes Native Sidecar support
fixes https://github.com/VictoriaMetrics/VictoriaMetrics/issues/7287

### Checklist

The following checks are **mandatory**:

- [ ] My change adheres [VictoriaMetrics contributing guidelines](https://docs.victoriametrics.com/contributing/).



Patch:
diff --git a/docs/changelog/CHANGELOG.md b/docs/changelog/CHANGELOG.md
index 09641f4da..0f5cabafb 100644
--- a/docs/changelog/CHANGELOG.md
+++ b/docs/changelog/CHANGELOG.md
@@ -19,6 +19,7 @@ See also [LTS releases](https://docs.victoriametrics.com/lts-releases/).
 ## tip
 
 * FEATURE: [vmalert](https://docs.victoriametrics.com/vmalert/): `-rule` cmd-line flag now supports multi-document YAML files. This could be useful when rules are retrieved via HTTP URL where multiple rule files were merged together in one response. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/6753). Thanks to @Irene-123 for [the pull request](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/6995).
+* FEATURE: [vmagent](https://docs.victoriametrics.com/vmagent/): support scraping from Kubernetes Native Sidecars. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/7287).
 * FEATURE: [Single-node VictoriaMetrics](https://docs.victoriametrics.com/) and `vmstorage` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/cluster-victoriametrics/): add a separate cache type for storing sparse entries when performing large index scans. This significantly reduces memory usage when applying [downsampling filters](https://docs.victoriametrics.com/#downsampling) and [retention filters](https://docs.victoriametrics.com/#retention-filters) during background merge. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/7182) for the details.
 
 * BUGFIX: [vmalert](https://docs.victoriametrics.com/vmalert): properly set `group_name` and `file` fields for recording rules in `/api/v1/rules`.
diff --git a/lib/promscrape/discovery/kubernetes/endpoints.go b/lib/promscrape/discovery/kubernetes/endpoints.go
index 4b6ca982b..0fde96237 100644
--- a/lib/promscrape/discovery/kubernetes/endpoints.go
+++ b/lib/promscrape/discovery/kubernetes/endpoints.go
@@ -37,7 +37,7 @@ func parseEndpoints(data []byte) (object, error) {
 
 // EndpointsList implements k8s endpoints list.
 //
-// See https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.17/#endpointslist-v1-core
+// See https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#endpointslist-v1-core
 type EndpointsList struct {
 	Metadata ListMeta
 	Items    []*Endpoints
@@ -45,7 +45,7 @@ type EndpointsList struct {
 
 // Endpoints implements k8s endpoints.
 //
-// See https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.17/#endpoints-v1-core
+// See https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#endpoints-v1-core
 type Endpoints struct {
 	Metadata ObjectMeta
 	Subsets  []EndpointSubset
@@ -53,7 +53,7 @@ type Endpoints struct {
 
 // EndpointSubset implements k8s endpoint subset.
 //
-// See https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.17/#endpointsubset-v1-core
+// See https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#endpointsubset-v1-core
 type EndpointSubset struct {
 	Addresses         []EndpointAddress
 	NotReadyAddresses []EndpointAddress
@@ -62,7 +62,7 @@ type EndpointSubset struct {
 
 // EndpointAddress implements k8s endpoint address.
 //
-// See https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.17/#endpointaddress-v1-core
+// See https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#endpointaddress-v1-core
 type EndpointAddress struct {
 	Hostname  string
 	IP        string
@@ -72,7 +72,7 @@ type EndpointAddress struct {
 
 // ObjectReference implements k8s object reference.
 //
-// See https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.17/#objectreference-v1-core
+// See https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#objectreference-v1-core
 type ObjectReference struct {
 	Kind      string
 	Name      string
@@ -81,7 +81,7 @@ type ObjectReference struct {
 
 // EndpointPort implements k8s endpoint port.
 //
-// See https://v1-21.docs.kubernetes.io/docs/reference/generated/kubernetes-api/v1.21/#endpointport-v1-discovery-k8s-io
+// See https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#endpointport-v1-discovery-k8s-io
 type EndpointPort struct {
 	AppProtocol string
 	Name        string
@@ -123,29 +123,39 @@ func (eps *Endpoints) getTargetLabels(gw *groupWatcher) []*promutils.Labels {
 		}
 		return false
 	}
+	appendPodMetadata := func(p *Pod, c *Container, seen []int, isInit bool) {
+		for _, cp := range c.Ports {
+			if portSeen(cp.ContainerPort, seen) {
+				continue
+			}
+			addr := discoveryutils.JoinHostPort(p.Status.PodIP, cp.ContainerPort)
+			m := promutils.GetLabels()
+			m.Add("__address__", addr)
+			p.appendCommonLabels(m, gw)
+			p.appendContainerLabels(m, c, &cp, isInit)
+
+			// Prometheus sets endpoints_name and namespace labels for all endpoints
+			// Even if port is not matching service port.
+			// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4154
+			p.appendEndpointLabels(m, eps)
+			if svc != nil {
+				svc.appendCommonLabels(m)
+			}
+			// Remove possible duplicate labels, which can appear after appendCommonLabels() call
+			m.RemoveDuplicates()
+			ms = append(ms, m)
+		}
+	}
 	for p, ports := range podPortsSeen {
 		for _, c := range p.Spec.Containers {
-			for _, cp := range c.Ports {
-				if portSeen(cp.ContainerPort, ports) {
-					continue
-				}
-				addr := discoveryutils.JoinHostPort(p.Status.PodIP, cp.ContainerPort)
-				m := promutils.GetLabels()
-				m.Add("__address__", addr)
-				p.appendCommonLabels(m, gw)
-				p.appendContainerLabels(m, &c, &cp)
-
-				// Prometheus sets endpoints_name and namespace labels for all endpoints
-				// Even if port is not matching service port.
-				// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4154
-				p.appendEndpointLabels(m, eps)
-				if svc != nil {
-					svc.appendCommonLabels(m)
-				}
-				// Remove possible duplicate labels, which can appear after appendCommonLabels() call
-				m.RemoveDuplicates()
-				ms = append(ms, m)
+			appendPodMetadata(p, &c, ports, false)
+		}
+		for _, c := range p.Spec.InitContainers {
+			// Defines native sidecar https://kubernetes.io/blog/2023/08/25/native-sidecar-containers/#what-are-sidecar-containers-in-1-28
+			if c.RestartPolicy != "Always" {
+				continue
 			}
+			appendPodMetadata(p, &c, ports, true)
 		}
 	}
 	return ms
@@ -189,7 +199,20 @@ func getEndpointLabelsForAddressAndPort(gw *groupWatcher, podPortsSeen map[*Pod]
 		for _, cp := range c.Ports {
 			if cp.ContainerPort == epp.Port {
 				podPortsSeen[p] = append(podPortsSeen[p], cp.ContainerPort)
-				p.appendContainerLabels(m, &c, &cp)
+				p.appendContainerLabels(m, &c, &cp, false)
+				break
+			}
+		}
+	}
+	for _, c := range p.Spec.InitContainers {
+		// Defines native sidecar https://kubernetes.io/blog/2023/08/25/native-sidecar-containers/#what-are-sidecar-containers-in-1-28
+		if c.RestartPolicy != "Always" {
+			continue
+		}
+		for _, cp := range c.Ports {
+			if cp.ContainerPort == epp.Port {
+				podPortsSeen[p] = append(podPortsSeen[p], cp.ContainerPort)
+				p.appendContainerLabels(m, &c, &cp, true)
 				break
 			}
 		}
diff --git a/lib/promscrape/discovery/kubernetes/endpointslice.go b/lib/promscrape/discovery/kubernetes/endpointslice.go
index e0e969afe..5cddb4ee4 100644
--- a/lib/promscrape/discovery/kubernetes/endpointslice.go
+++ b/lib/promscrape/discovery/kubernetes/endpointslice.go
@@ -73,30 +73,41 @@ func (eps *EndpointSlice) getTargetLabels(gw *groupWatcher) []*promutils.Labels
 		}
 		return false
 	}
+	appendPodMetadata := func(p *Pod, c *Container, seen []int, isInit bool) {
+		for _, cp := range c.Ports {
+			if portSeen(cp.ContainerPort, seen) {
+				continue
+			}
+			addr := discoveryutils.JoinHostPort(p.Status.PodIP, cp.ContainerPort)
+			m := promutils.GetLabels()
+			m.Add("__address__", addr)
+			p.appendCommonLabels(m, gw)
+			p.appendContainerLabels(m, c, &cp, isInit)
+
+			// Prometheus sets endpoints_name and namespace labels for all endpoints
+			// Even if port is not matching service port.
+			// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4154
+			p.appendEndpointSliceLabels(m, eps)
+			if svc != nil {
+				svc.appendCommonLabels(m)
+			}
+			// Remove possible duplicate labels, which can appear after appendCommonLabels() call
+			m.RemoveDuplicates()
+			ms = append(ms, m)
+		}
+	}
 	for p, ports := range podPortsSeen {
 		for _, c := range p.Spec.Containers {
-			for _, cp := range c.Ports {
-				if portSeen(cp.ContainerPort, ports) {
-					continue
-				}
-				addr := discoveryutils.JoinHostPort(p.Status.PodIP, cp.ContainerPort)
-				m := promutils.GetLabels()
-				m.Add("__address__", addr)
-				p.appendCommonLabels(m, gw)
-				p.appendContainerLabels(m, &c, &cp)
-
-				// Prometheus sets endpoints_name and namespace labels for all endpoints
-				// Even if port is not matching service port.
-				// See https://github.com/VictoriaMetrics/VictoriaMetrics/issues/4154
-				p.appendEndpointSliceLabels(m, eps)
-				if svc != nil {
-					svc.appendCommonLabels(m)
-				}
-				// Remove possible duplicate labels, which can appear after appendCommonLabels() calls
-				m.RemoveDuplicates()
-				ms = append(ms, m)
+			appendPodMetadata(p, &c, ports, false)
+		}
+		for _, c := range p.Spec.InitContainers {
+			// Defines native sidecar https://kubernetes.io/blog/2023/08/25/native-sidecar-containers/#what-are-sidecar-containers-in-1-28
+			if c.RestartPolicy != "Always" {
+				continue
 			}
+			appendPodMetadata(p, &c, ports, true)
 		}
+
 	}
 	return ms
 }
@@ -127,7 +138,16 @@ func getEndpointSliceLabelsForAddressAndPort(gw *groupWatcher, podPortsSeen map[
 		for _, cp := range c.Ports {
 			if cp.ContainerPort == epp.Port {
 				podPortsSeen[p] = append(podPortsSeen[p], cp.ContainerPort)
-				p.appendContainerLabels(m, &c, &cp)
+				p.appendContainerLabels(m, &c, &cp, false)
+				break
+			}
+		}
+	}
+	for _, c := range p.Spec.InitContainers {
+		for _, cp := range c.Ports {
+			if cp.ContainerPort == epp.Port {
+				podPortsSeen[p] = append(podPortsSeen[p], cp.ContainerPort)
+				p.appendContainerLabels(m, &c, &cp, true)
 				break
 			}
 		}
@@ -167,7 +187,7 @@ func getEndpointSliceLabels(eps *EndpointSlice, addr string, ea Endpoint, epp En
 
 // EndpointSliceList - implements kubernetes endpoint slice list object, that groups service endpoints slices.
 //
-// See https://v1-21.docs.kubernetes.io/docs/reference/generated/kubernetes-api/v1.21/#endpointslicelist-v1-discovery-k8s-io
+// See https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#endpointslicelist-v1-discovery-k8s-io
 type EndpointSliceList struct {
 	Metadata ListMeta
 	Items    []*EndpointSlice
@@ -175,7 +195,7 @@ type EndpointSliceList struct {
 
 // EndpointSlice - implements kubernetes endpoint slice.
 //
-// See https://v1-21.docs.kubernetes.io/docs/reference/generated/kubernetes-api/v1.21/#endpointslice-v1-discovery-k8s-io
+// See https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#endpointslice-v1-discovery-k8s-io
 type EndpointSlice struct {
 	Metadata    ObjectMeta
 	Endpoints   []Endpoint
@@ -185,7 +205,7 @@ type EndpointSlice struct {
 
 // Endpoint implements kubernetes object endpoint for endpoint slice.
 //
-// See https://v1-21.docs.kubernetes.io/docs/reference/generated/kubernetes-api/v1.21/#endpoint-v1-discovery-k8s-io
+// See https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#endpoint-v1-discovery-k8s-io
 type Endpoint struct {
 	Addresses  []string
 	Conditions EndpointConditions
@@ -196,7 +216,7 @@ type Endpoint struct {
 
 // EndpointConditions implements kubernetes endpoint condition.
 //
-// See https://v1-21.docs.kubernetes.io/docs/reference/generated/kubernetes-api/v1.21/#endpointconditions-v1-discovery-k8s-io
+// See https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#endpointconditions-v1-discovery-k8s-io
 type EndpointConditions struct {
 	Ready bool
 }
diff --git a/lib/promscrape/discovery/kubernetes/pod.go b/lib/promscrape/discovery/kubernetes/pod.go
index 4ea474e5e..4b5e6111c 100644
--- a/lib/promscrape/discovery/kubernetes/pod.go
+++ b/lib/promscrape/discovery/kubernetes/pod.go
@@ -38,7 +38,7 @@ func parsePod(data []byte) (object, error) {
 
 // PodList implements k8s pod list.
 //
-// See https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.17/#podlist-v1-core
+// See https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#podlist-v1-core
 type PodList struct {
 	Metadata ListMeta
 	Items    []*Pod
@@ -46,7 +46,7 @@ type PodList struct {
 
 // Pod implements k8s pod.
 //
-// See https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.17/#pod-v1-core
+// See https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#pod-v1-core
 type Pod struct {
 	Metadata ObjectMeta
 	Spec     PodSpec
@@ -55,7 +55,7 @@ type Pod struct {
 
 // PodSpec implements k8s pod spec.
 //
-// See https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.17/#podspec-v1-core
+// See https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#podspec-v1-core
 type PodSpec struct {
 	NodeName       string
 	Containers     []Container
@@ -64,11 +64,12 @@ type PodSpec struct {
 
 // Container implements k8s container.
 //
-// See https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.17/#container-v1-core
+// See https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#container-v1-core
 type Container struct {
-	Name  string
-	Image string
-	Ports []ContainerPort
+	Name          string
+	Image         string
+	Ports         []ContainerPort
+	RestartPolicy string
 }
 
 // ContainerPort implements k8s container port.
@@ -80,7 +81,7 @@ type ContainerPort struct {
 
 // PodStatus implements k8s pod status.
 //
-// See https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.17/#podstatus-v1-core
+// See https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#podstatus-v1-core
 type PodStatus struct {
 	Phase                 string
 	PodIP                 string
@@ -92,7 +93,7 @@ type PodStatus struct {
 
 // PodCondition implements k8s pod condition.
 //
-// See https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.17/#podcondition-v1-core
+// See https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/#podcondition-v1-core
 type PodCondition struct {
 	Type   string
 	Status string
@@ -198,11 +199,6 @@ func appendPodLabelsInternal(ms []*promutils.Labels, gw *groupWatcher, p *Pod, c
 	}
 	m := promutils.GetLabels()
 	m.Add("__address__", addr)
-	isInitStr := "false"
-	if isInit {
-		isInitStr = "true"
-	}
-	m.Add("__meta_kubernetes_pod_container_init", isInitStr)
 
 	containerID := getContainerID(p, c.Name, isInit)
 	if containerID != "" {
@@ -210,13 +206,18 @@ func appendPodLabelsInternal(ms []*promutils.Labels, gw *groupWatcher, p *Pod, c
 	}
 
 	p.appendCommonLabels(m, gw)
-	p.appendContainerLabels(m, c, cp)
+	p.appendContainerLabels(m, c, cp, isInit)
 	return append(ms, m)
 }
 
-func (p *Pod) appendContainerLabels(m *promutils.Labels, c *Container, cp *ContainerPort) {
+func (p *Pod) appendContainerLabels(m *promutils.Labels, c *Container, cp *ContainerPort, isInit bool) {
 	m.Add("__meta_kubernetes_pod_container_image", c.Image)
 	m.Add("__meta_kubernetes_pod_container_name", c.Name)
+	isInitStr := "false"
+	if isInit {
+		isInitStr = "true"
+	}
+	m.Add("__meta_kubernetes_pod_container_init", isInitStr)
 	if cp != nil {
 		m.Add("__meta_kubernetes_pod_container_port_name", cp.Name)
 		m.Add("__meta_kubernetes_pod_container_port_number", bytesutil.Itoa(cp.ContainerPort))


Test patch:
diff --git a/lib/promscrape/discovery/kubernetes/endpoints_test.go b/lib/promscrape/discovery/kubernetes/endpoints_test.go
index 36b4c5745..2288cc633 100644
--- a/lib/promscrape/discovery/kubernetes/endpoints_test.go
+++ b/lib/promscrape/discovery/kubernetes/endpoints_test.go
@@ -115,8 +115,9 @@ func TestParseEndpointsListSuccess(t *testing.T) {
 
 func TestGetEndpointsLabels(t *testing.T) {
 	type testArgs struct {
-		containerPorts map[string][]ContainerPort
-		endpointPorts  []EndpointPort
+		containerPorts     map[string][]ContainerPort
+		initContainerPorts map[string][]ContainerPort
+		endpointPorts      []EndpointPort
 	}
 	f := func(t *testing.T, args testArgs, wantLabels []*promutils.Labels) {
 		t.Helper()
@@ -177,6 +178,14 @@ func TestGetEndpointsLabels(t *testing.T) {
 				Labels: promutils.NewLabelsFromMap(map[string]string{"node-label": "xyz"}),
 			},
 		}
+		for cn, ports := range args.initContainerPorts {
+			pod.Spec.InitContainers = append(pod.Spec.InitContainers, Container{
+				Name:          cn,
+				Image:         "test-init-image",
+				Ports:         ports,
+				RestartPolicy: "Always",
+			})
+		}
 		for cn, ports := range args.containerPorts {
 			pod.Spec.Containers = append(pod.Spec.Containers, Container{
 				Name:  cn,
@@ -301,6 +310,7 @@ func TestGetEndpointsLabels(t *testing.T) {
 				"__meta_kubernetes_node_labelpresent_node_label": "true",
 				"__meta_kubernetes_node_name":                    "test-node",
 				"__meta_kubernetes_pod_container_image":          "test-image",
+				"__meta_kubernetes_pod_container_init":           "false",
 				"__meta_kubernetes_pod_container_name":           "metrics",
 				"__meta_kubernetes_pod_container_port_name":      "http-metrics",
 				"__meta_kubernetes_pod_container_port_number":    "8428",
@@ -347,6 +357,54 @@ func TestGetEndpointsLabels(t *testing.T) {
 				"__meta_kubernetes_node_labelpresent_node_label": "true",
 				"__meta_kubernetes_node_name":                    "test-node",
 				"__meta_kubernetes_pod_container_image":          "test-image",
+				"__meta_kubernetes_pod_container_init":           "false",
+				"__meta_kubernetes_pod_container_name":           "metrics",
+				"__meta_kubernetes_pod_container_port_name":      "web",
+				"__meta_kubernetes_pod_container_port_number":    "8428",
+				"__meta_kubernetes_pod_container_port_protocol":  "sdc",
+				"__meta_kubernetes_pod_host_ip":                  "4.5.6.7",
+				"__meta_kubernetes_pod_ip":                       "192.168.15.1",
+				"__meta_kubernetes_pod_name":                     "test-pod",
+				"__meta_kubernetes_pod_node_name":                "test-node",
+				"__meta_kubernetes_pod_phase":                    "abc",
+				"__meta_kubernetes_pod_ready":                    "unknown",
+				"__meta_kubernetes_pod_uid":                      "pod-uid",
+				"__meta_kubernetes_service_cluster_ip":           "1.2.3.4",
+				"__meta_kubernetes_service_name":                 "test-eps",
+				"__meta_kubernetes_service_type":                 "service-type",
+			}),
+		})
+	})
+
+	t.Run("1 init container port from endpoint", func(t *testing.T) {
+		f(t, testArgs{
+			initContainerPorts: map[string][]ContainerPort{"metrics": {{
+				Name:          "web",
+				ContainerPort: 8428,
+				Protocol:      "sdc",
+			}}},
+			endpointPorts: []EndpointPort{
+				{
+					Name:     "web",
+					Port:     8428,
+					Protocol: "xabc",
+				},
+			},
+		}, []*promutils.Labels{
+			promutils.NewLabelsFromMap(map[string]string{
+				"__address__": "10.13.15.15:8428",
+				"__meta_kubernetes_endpoint_address_target_kind": "Pod",
+				"__meta_kubernetes_endpoint_address_target_name": "test-pod",
+				"__meta_kubernetes_endpoint_port_name":           "web",
+				"__meta_kubernetes_endpoint_port_protocol":       "xabc",
+				"__meta_kubernetes_endpoint_ready":               "true",
+				"__meta_kubernetes_endpoints_name":               "test-eps",
+				"__meta_kubernetes_namespace":                    "default",
+				"__meta_kubernetes_node_label_node_label":        "xyz",
+				"__meta_kubernetes_node_labelpresent_node_label": "true",
+				"__meta_kubernetes_node_name":                    "test-node",
+				"__meta_kubernetes_pod_container_image":          "test-init-image",
+				"__meta_kubernetes_pod_container_init":           "true",
 				"__meta_kubernetes_pod_container_name":           "metrics",
 				"__meta_kubernetes_pod_container_port_name":      "web",
 				"__meta_kubernetes_pod_container_port_number":    "8428",
diff --git a/lib/promscrape/discovery/kubernetes/endpointslice_test.go b/lib/promscrape/discovery/kubernetes/endpointslice_test.go
index 1d8d10a70..988019fbf 100644
--- a/lib/promscrape/discovery/kubernetes/endpointslice_test.go
+++ b/lib/promscrape/discovery/kubernetes/endpointslice_test.go
@@ -225,8 +225,9 @@ func TestParseEndpointSliceListSuccess(t *testing.T) {
 
 func TestGetEndpointsliceLabels(t *testing.T) {
 	type testArgs struct {
-		containerPorts map[string][]ContainerPort
-		endpointPorts  []EndpointPort
+		initContainerPorts map[string][]ContainerPort
+		containerPorts     map[string][]ContainerPort
+		endpointPorts      []EndpointPort
 	}
 	f := func(t *testing.T, args testArgs, wantLabels []*promutils.Labels) {
 		t.Helper()
@@ -296,6 +297,14 @@ func TestGetEndpointsliceLabels(t *testing.T) {
 				Labels: promutils.NewLabelsFromMap(map[string]string{"node-label": "xyz"}),
 			},
 		}
+		for cn, ports := range args.initContainerPorts {
+			pod.Spec.InitContainers = append(pod.Spec.InitContainers, Container{
+				Name:          cn,
+				Image:         "test-init-image",
+				Ports:         ports,
+				RestartPolicy: "Always",
+			})
+		}
 		for cn, ports := range args.containerPorts {
 			pod.Spec.Containers = append(pod.Spec.Containers, Container{
 				Name:  cn,
@@ -437,6 +446,7 @@ func TestGetEndpointsliceLabels(t *testing.T) {
 				"__meta_kubernetes_node_labelpresent_node_label":                          "true",
 				"__meta_kubernetes_node_name":                                             "test-node",
 				"__meta_kubernetes_pod_container_image":                                   "test-image",
+				"__meta_kubernetes_pod_container_init":                                    "false",
 				"__meta_kubernetes_pod_container_name":                                    "metrics",
 				"__meta_kubernetes_pod_container_port_name":                               "http-metrics",
 				"__meta_kubernetes_pod_container_port_number":                             "8428",
@@ -490,6 +500,61 @@ func TestGetEndpointsliceLabels(t *testing.T) {
 				"__meta_kubernetes_node_labelpresent_node_label":                          "true",
 				"__meta_kubernetes_node_name":                                             "test-node",
 				"__meta_kubernetes_pod_container_image":                                   "test-image",
+				"__meta_kubernetes_pod_container_init":                                    "false",
+				"__meta_kubernetes_pod_container_name":                                    "metrics",
+				"__meta_kubernetes_pod_container_port_name":                               "web",
+				"__meta_kubernetes_pod_container_port_number":                             "8428",
+				"__meta_kubernetes_pod_container_port_protocol":                           "sdc",
+				"__meta_kubernetes_pod_host_ip":                                           "4.5.6.7",
+				"__meta_kubernetes_pod_ip":                                                "192.168.15.1",
+				"__meta_kubernetes_pod_name":                                              "test-pod",
+				"__meta_kubernetes_pod_node_name":                                         "test-node",
+				"__meta_kubernetes_pod_phase":                                             "abc",
+				"__meta_kubernetes_pod_ready":                                             "unknown",
+				"__meta_kubernetes_pod_uid":                                               "pod-uid",
+				"__meta_kubernetes_service_cluster_ip":                                    "1.2.3.4",
+				"__meta_kubernetes_service_name":                                          "test-svc",
+				"__meta_kubernetes_service_type":                                          "service-type",
+			}),
+		})
+	})
+
+	t.Run("1 init container port from endpoint", func(t *testing.T) {
+		f(t, testArgs{
+			initContainerPorts: map[string][]ContainerPort{"metrics": {{
+				Name:          "web",
+				ContainerPort: 8428,
+				Protocol:      "sdc",
+			}}},
+			endpointPorts: []EndpointPort{
+				{
+					Name:     "web",
+					Port:     8428,
+					Protocol: "xabc",
+				},
+			},
+		}, []*promutils.Labels{
+			promutils.NewLabelsFromMap(map[string]string{
+				"__address__": "10.13.15.15:8428",
+				"__meta_kubernetes_endpointslice_address_target_kind":                     "Pod",
+				"__meta_kubernetes_endpointslice_address_target_name":                     "test-pod",
+				"__meta_kubernetes_endpointslice_address_type":                            "foobar",
+				"__meta_kubernetes_endpointslice_endpoint_conditions_ready":               "true",
+				"__meta_kubernetes_endpointslice_endpoint_hostname":                       "foo.bar",
+				"__meta_kubernetes_endpointslice_endpoint_topology_present_x":             "true",
+				"__meta_kubernetes_endpointslice_endpoint_topology_x":                     "y",
+				"__meta_kubernetes_endpointslice_label_kubernetes_io_service_name":        "test-svc",
+				"__meta_kubernetes_endpointslice_labelpresent_kubernetes_io_service_name": "true",
+				"__meta_kubernetes_endpointslice_name":                                    "test-eps",
+				"__meta_kubernetes_endpointslice_port":                                    "8428",
+				"__meta_kubernetes_endpointslice_port_name":                               "web",
+				"__meta_kubernetes_endpointslice_port_protocol":                           "xabc",
+				"__meta_kubernetes_namespace":                                             "default",
+				"__meta_kubernetes_node_label_node_label":                                 "xyz",
+				"__meta_kubernetes_node_labelpresent_node_label":                          "true",
+				"__meta_kubernetes_node_name":                                             "test-node",
+				"__meta_kubernetes_pod_container_image":                                   "test-init-image",
+				"__meta_kubernetes_pod_container_init":                                    "true",
 				"__meta_kubernetes_pod_container_name":                                    "metrics",
 				"__meta_kubernetes_pod_container_port_name":                               "web",
 				"__meta_kubernetes_pod_container_port_number":                             "8428",