From baf8559173ebe386c7b42af90a36324c2ac60fab Mon Sep 17 00:00:00 2001 From: DrAuYueng Date: Fri, 6 Jun 2025 11:45:13 +0800 Subject: [PATCH] expose status.PodIPs as ipv4 and ipv6 if dualstack enabled Signed-off-by: acm1204 <15663718+acm1204@user.noreply.gitee.com> --- discovery/kubernetes/pod.go | 42 +- discovery/kubernetes/pod_test.go | 590 ++++++++++++++++++++++++++++ docs/configuration/configuration.md | 4 +- 3 files changed, 634 insertions(+), 2 deletions(-) diff --git a/discovery/kubernetes/pod.go b/discovery/kubernetes/pod.go index 1fed78b3a7..3017024797 100644 --- a/discovery/kubernetes/pod.go +++ b/discovery/kubernetes/pod.go @@ -221,6 +221,8 @@ const ( podUID = metaLabelPrefix + "pod_uid" podControllerKind = metaLabelPrefix + "pod_controller_kind" podControllerName = metaLabelPrefix + "pod_controller_name" + podIPv4Label = metaLabelPrefix + "pod_ipv4" + podIPv6Label = metaLabelPrefix + "pod_ipv6" ) // GetControllerOf returns a pointer to a copy of the controllerRef if controllee has a controller @@ -244,6 +246,36 @@ func podLabels(pod *apiv1.Pod) model.LabelSet { podUID: lv(string(pod.UID)), } + // PodIPs contains all the IP addresses of the eth0 network interface in the Pod container. + // The specific number of IP addresses depends on the specific cni plugin response, which means there may be more than two IP addresses. + // However, in most cases, there is one IP address (single-stack; IPv4 or IPv6) or two IP addresses (dual-stack; IPv4 and IPv6 co-existing simultaneously). + // If there are multiple IP addresses, use the first IPv4 and IPv6 respectively, this way, it can be consistent with the primary IP address (pod.Status.PodIP behavior) and avoid exposing redundant IP information. + // Reference1: https://github.com/kubernetes/kubernetes/blob/c8fb7c9174b03ebc9a072913ca12c08ef3ed83c6/pkg/kubelet/kuberuntime/kuberuntime_sandbox.go#L317 + // Reference2: https://github.com/containerd/containerd/blob/b99b82db7d05dfd257edcdb50bc72769e782d6c2/internal/cri/server/sandbox_run.go#L572 + var ipv4Exists, ipv6Exists bool + for _, podIP := range pod.Status.PodIPs { + if podIP.IP == "" { + continue + } + _, ipv4Exists = ls[podIPv4Label] + _, ipv6Exists = ls[podIPv6Label] + if ipv4Exists && ipv6Exists { + break + } + ip := net.ParseIP(podIP.IP) + if ip != nil { + if ip.To4() != nil { + if !ipv4Exists { + ls[podIPv4Label] = lv(podIP.IP) + } + } else if ip.To16() != nil { + if !ipv6Exists { + ls[podIPv6Label] = lv(podIP.IP) + } + } + } + } + addObjectMetaLabels(ls, pod.ObjectMeta, RolePod) createdBy := GetControllerOf(pod) @@ -310,8 +342,16 @@ func (p *Pod) buildPod(pod *apiv1.Pod) *targetgroup.Group { if len(c.Ports) == 0 { // We don't have a port so we just set the address label to the pod IP. // The user has to add a port manually. + addr := pod.Status.PodIP + ip := net.ParseIP(addr) + if ip != nil && ip.To4() == nil { + // If pod.Status.PodIP is a IPv6 address, addr should be "[pod.Status.PodIP]". + // Contrary to what net.JoinHostPort does when the port is empty, RFC3986 forbids a ":" delimiter as the last character in such cases, leaving us with the following implementation. + // Refer https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.3 + addr = "[" + ip.String() + "]" + } tg.Targets = append(tg.Targets, model.LabelSet{ - model.AddressLabel: lv(pod.Status.PodIP), + model.AddressLabel: lv(addr), podContainerNameLabel: lv(c.Name), podContainerIDLabel: lv(cID), podContainerImageLabel: lv(c.Image), diff --git a/discovery/kubernetes/pod_test.go b/discovery/kubernetes/pod_test.go index db5db546d0..07040108fb 100644 --- a/discovery/kubernetes/pod_test.go +++ b/discovery/kubernetes/pod_test.go @@ -627,3 +627,593 @@ func TestPodDiscoveryWithUpdatedNamespaceMetadata(t *testing.T) { }, }.Run(t) } + +func TestPodDiscoveryAddWithDualStackIPv4First(t *testing.T) { + t.Parallel() + n, c := makeDiscovery(RolePod, NamespaceDiscovery{}) + + ns := "default" + key := fmt.Sprintf("pod/%s/testpod", ns) + k8sDiscoveryTest{ + discovery: n, + afterStart: func() { + obj := &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "testpod", + Namespace: "default", + UID: types.UID("abc123"), + }, + Spec: v1.PodSpec{ + NodeName: "testnode", + Containers: []v1.Container{ + { + Name: "testcontainer", + Image: "testcontainer:latest", + Ports: []v1.ContainerPort{ + { + Name: "testport", + Protocol: v1.ProtocolTCP, + ContainerPort: int32(9000), + }, + }, + }, + }, + }, + Status: v1.PodStatus{ + PodIP: "100.117.147.144", + PodIPs: []v1.PodIP{ + {IP: "100.117.147.144"}, + {IP: "2001::3238:634c:2ed4:ed01"}, + }, + HostIP: "2.3.4.5", + Phase: "Running", + Conditions: []v1.PodCondition{ + { + Type: v1.PodReady, + Status: v1.ConditionTrue, + }, + }, + ContainerStatuses: []v1.ContainerStatus{ + { + Name: "testcontainer", + ContainerID: "docker://a1b2c3d4e5f6", + }, + }, + }, + } + c.CoreV1().Pods(obj.Namespace).Create(context.Background(), obj, metav1.CreateOptions{}) + }, + expectedMaxItems: 1, + expectedRes: map[string]*targetgroup.Group{ + key: { + Targets: []model.LabelSet{ + { + "__address__": "100.117.147.144:9000", + "__meta_kubernetes_pod_container_name": "testcontainer", + "__meta_kubernetes_pod_container_image": "testcontainer:latest", + "__meta_kubernetes_pod_container_port_name": "testport", + "__meta_kubernetes_pod_container_port_number": "9000", + "__meta_kubernetes_pod_container_port_protocol": "TCP", + "__meta_kubernetes_pod_container_init": "false", + "__meta_kubernetes_pod_container_id": "docker://a1b2c3d4e5f6", + }, + }, + Labels: model.LabelSet{ + "__meta_kubernetes_pod_name": "testpod", + "__meta_kubernetes_namespace": lv(ns), + "__meta_kubernetes_pod_node_name": "testnode", + "__meta_kubernetes_pod_ip": "100.117.147.144", + "__meta_kubernetes_pod_host_ip": "2.3.4.5", + "__meta_kubernetes_pod_ready": "true", + "__meta_kubernetes_pod_phase": "Running", + "__meta_kubernetes_pod_uid": "abc123", + "__meta_kubernetes_pod_ipv4": "100.117.147.144", + "__meta_kubernetes_pod_ipv6": "2001::3238:634c:2ed4:ed01", + }, + Source: key, + }, + }, + }.Run(t) +} + +func TestPodDiscoveryAddWithDualStackIPv6First(t *testing.T) { + t.Parallel() + n, c := makeDiscovery(RolePod, NamespaceDiscovery{}) + + ns := "default" + key := fmt.Sprintf("pod/%s/testpod", ns) + k8sDiscoveryTest{ + discovery: n, + afterStart: func() { + obj := &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "testpod", + Namespace: "default", + UID: types.UID("abc123"), + }, + Spec: v1.PodSpec{ + NodeName: "testnode", + Containers: []v1.Container{ + { + Name: "testcontainer", + Image: "testcontainer:latest", + Ports: []v1.ContainerPort{ + { + Name: "testport", + Protocol: v1.ProtocolTCP, + ContainerPort: int32(9000), + }, + }, + }, + }, + }, + Status: v1.PodStatus{ + PodIP: "2001::3238:634c:2ed4:ed01", + PodIPs: []v1.PodIP{ + {IP: "2001::3238:634c:2ed4:ed01"}, + {IP: "100.117.147.144"}, + }, + HostIP: "2.3.4.5", + Phase: "Running", + Conditions: []v1.PodCondition{ + { + Type: v1.PodReady, + Status: v1.ConditionTrue, + }, + }, + ContainerStatuses: []v1.ContainerStatus{ + { + Name: "testcontainer", + ContainerID: "docker://a1b2c3d4e5f6", + }, + }, + }, + } + c.CoreV1().Pods(obj.Namespace).Create(context.Background(), obj, metav1.CreateOptions{}) + }, + expectedMaxItems: 1, + expectedRes: map[string]*targetgroup.Group{ + key: { + Targets: []model.LabelSet{ + { + "__address__": "[2001::3238:634c:2ed4:ed01]:9000", + "__meta_kubernetes_pod_container_name": "testcontainer", + "__meta_kubernetes_pod_container_image": "testcontainer:latest", + "__meta_kubernetes_pod_container_port_name": "testport", + "__meta_kubernetes_pod_container_port_number": "9000", + "__meta_kubernetes_pod_container_port_protocol": "TCP", + "__meta_kubernetes_pod_container_init": "false", + "__meta_kubernetes_pod_container_id": "docker://a1b2c3d4e5f6", + }, + }, + Labels: model.LabelSet{ + "__meta_kubernetes_pod_name": "testpod", + "__meta_kubernetes_namespace": lv(ns), + "__meta_kubernetes_pod_node_name": "testnode", + "__meta_kubernetes_pod_ip": "2001::3238:634c:2ed4:ed01", + "__meta_kubernetes_pod_host_ip": "2.3.4.5", + "__meta_kubernetes_pod_ready": "true", + "__meta_kubernetes_pod_phase": "Running", + "__meta_kubernetes_pod_uid": "abc123", + "__meta_kubernetes_pod_ipv4": "100.117.147.144", + "__meta_kubernetes_pod_ipv6": "2001::3238:634c:2ed4:ed01", + }, + Source: key, + }, + }, + }.Run(t) +} + +func TestPodDiscoveryAddWithSingleStackIPv4(t *testing.T) { + t.Parallel() + n, c := makeDiscovery(RolePod, NamespaceDiscovery{}) + + ns := "default" + key := fmt.Sprintf("pod/%s/testpod", ns) + k8sDiscoveryTest{ + discovery: n, + afterStart: func() { + obj := &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "testpod", + Namespace: "default", + UID: types.UID("abc123"), + }, + Spec: v1.PodSpec{ + NodeName: "testnode", + Containers: []v1.Container{ + { + Name: "testcontainer", + Image: "testcontainer:latest", + Ports: []v1.ContainerPort{ + { + Name: "testport", + Protocol: v1.ProtocolTCP, + ContainerPort: int32(9000), + }, + }, + }, + }, + }, + Status: v1.PodStatus{ + PodIP: "100.117.147.144", + PodIPs: []v1.PodIP{ + {IP: "100.117.147.144"}, + }, + HostIP: "2.3.4.5", + Phase: "Running", + Conditions: []v1.PodCondition{ + { + Type: v1.PodReady, + Status: v1.ConditionTrue, + }, + }, + ContainerStatuses: []v1.ContainerStatus{ + { + Name: "testcontainer", + ContainerID: "docker://a1b2c3d4e5f6", + }, + }, + }, + } + c.CoreV1().Pods(obj.Namespace).Create(context.Background(), obj, metav1.CreateOptions{}) + }, + expectedMaxItems: 1, + expectedRes: map[string]*targetgroup.Group{ + key: { + Targets: []model.LabelSet{ + { + "__address__": "100.117.147.144:9000", + "__meta_kubernetes_pod_container_name": "testcontainer", + "__meta_kubernetes_pod_container_image": "testcontainer:latest", + "__meta_kubernetes_pod_container_port_name": "testport", + "__meta_kubernetes_pod_container_port_number": "9000", + "__meta_kubernetes_pod_container_port_protocol": "TCP", + "__meta_kubernetes_pod_container_init": "false", + "__meta_kubernetes_pod_container_id": "docker://a1b2c3d4e5f6", + }, + }, + Labels: model.LabelSet{ + "__meta_kubernetes_pod_name": "testpod", + "__meta_kubernetes_namespace": lv(ns), + "__meta_kubernetes_pod_node_name": "testnode", + "__meta_kubernetes_pod_ip": "100.117.147.144", + "__meta_kubernetes_pod_host_ip": "2.3.4.5", + "__meta_kubernetes_pod_ready": "true", + "__meta_kubernetes_pod_phase": "Running", + "__meta_kubernetes_pod_uid": "abc123", + "__meta_kubernetes_pod_ipv4": "100.117.147.144", + }, + Source: key, + }, + }, + }.Run(t) +} + +func TestPodDiscoveryAddWithSingleStackIPv6(t *testing.T) { + t.Parallel() + n, c := makeDiscovery(RolePod, NamespaceDiscovery{}) + + ns := "default" + key := fmt.Sprintf("pod/%s/testpod", ns) + k8sDiscoveryTest{ + discovery: n, + afterStart: func() { + obj := &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "testpod", + Namespace: "default", + UID: types.UID("abc123"), + }, + Spec: v1.PodSpec{ + NodeName: "testnode", + Containers: []v1.Container{ + { + Name: "testcontainer", + Image: "testcontainer:latest", + Ports: []v1.ContainerPort{ + { + Name: "testport", + Protocol: v1.ProtocolTCP, + ContainerPort: int32(9000), + }, + }, + }, + }, + }, + Status: v1.PodStatus{ + PodIP: "2001::3238:634c:2ed4:ed01", + PodIPs: []v1.PodIP{ + {IP: "2001::3238:634c:2ed4:ed01"}, + }, + HostIP: "2.3.4.5", + Phase: "Running", + Conditions: []v1.PodCondition{ + { + Type: v1.PodReady, + Status: v1.ConditionTrue, + }, + }, + ContainerStatuses: []v1.ContainerStatus{ + { + Name: "testcontainer", + ContainerID: "docker://a1b2c3d4e5f6", + }, + }, + }, + } + c.CoreV1().Pods(obj.Namespace).Create(context.Background(), obj, metav1.CreateOptions{}) + }, + expectedMaxItems: 1, + expectedRes: map[string]*targetgroup.Group{ + key: { + Targets: []model.LabelSet{ + { + "__address__": "[2001::3238:634c:2ed4:ed01]:9000", + "__meta_kubernetes_pod_container_name": "testcontainer", + "__meta_kubernetes_pod_container_image": "testcontainer:latest", + "__meta_kubernetes_pod_container_port_name": "testport", + "__meta_kubernetes_pod_container_port_number": "9000", + "__meta_kubernetes_pod_container_port_protocol": "TCP", + "__meta_kubernetes_pod_container_init": "false", + "__meta_kubernetes_pod_container_id": "docker://a1b2c3d4e5f6", + }, + }, + Labels: model.LabelSet{ + "__meta_kubernetes_pod_name": "testpod", + "__meta_kubernetes_namespace": lv(ns), + "__meta_kubernetes_pod_node_name": "testnode", + "__meta_kubernetes_pod_ip": "2001::3238:634c:2ed4:ed01", + "__meta_kubernetes_pod_host_ip": "2.3.4.5", + "__meta_kubernetes_pod_ready": "true", + "__meta_kubernetes_pod_phase": "Running", + "__meta_kubernetes_pod_uid": "abc123", + "__meta_kubernetes_pod_ipv6": "2001::3238:634c:2ed4:ed01", + }, + Source: key, + }, + }, + }.Run(t) +} + +func TestPodDiscoveryAddWithSingleStackIPv6WithoutPorts(t *testing.T) { + t.Parallel() + n, c := makeDiscovery(RolePod, NamespaceDiscovery{}) + + ns := "default" + key := fmt.Sprintf("pod/%s/testpod", ns) + k8sDiscoveryTest{ + discovery: n, + afterStart: func() { + obj := &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "testpod", + Namespace: "default", + UID: types.UID("abc123"), + }, + Spec: v1.PodSpec{ + NodeName: "testnode", + Containers: []v1.Container{ + { + Name: "testcontainer", + Image: "testcontainer:latest", + }, + }, + }, + Status: v1.PodStatus{ + PodIP: "2001::3238:634c:2ed4:ed01", + PodIPs: []v1.PodIP{ + {IP: "2001::3238:634c:2ed4:ed01"}, + }, + HostIP: "2.3.4.5", + Phase: "Running", + Conditions: []v1.PodCondition{ + { + Type: v1.PodReady, + Status: v1.ConditionTrue, + }, + }, + ContainerStatuses: []v1.ContainerStatus{ + { + Name: "testcontainer", + ContainerID: "docker://a1b2c3d4e5f6", + }, + }, + }, + } + c.CoreV1().Pods(obj.Namespace).Create(context.Background(), obj, metav1.CreateOptions{}) + }, + expectedMaxItems: 1, + expectedRes: map[string]*targetgroup.Group{ + key: { + Targets: []model.LabelSet{ + { + "__address__": "[2001::3238:634c:2ed4:ed01]", + "__meta_kubernetes_pod_container_name": "testcontainer", + "__meta_kubernetes_pod_container_image": "testcontainer:latest", + "__meta_kubernetes_pod_container_init": "false", + "__meta_kubernetes_pod_container_id": "docker://a1b2c3d4e5f6", + }, + }, + Labels: model.LabelSet{ + "__meta_kubernetes_pod_name": "testpod", + "__meta_kubernetes_namespace": lv(ns), + "__meta_kubernetes_pod_node_name": "testnode", + "__meta_kubernetes_pod_ip": "2001::3238:634c:2ed4:ed01", + "__meta_kubernetes_pod_host_ip": "2.3.4.5", + "__meta_kubernetes_pod_ready": "true", + "__meta_kubernetes_pod_phase": "Running", + "__meta_kubernetes_pod_uid": "abc123", + "__meta_kubernetes_pod_ipv6": "2001::3238:634c:2ed4:ed01", + }, + Source: key, + }, + }, + }.Run(t) +} + +func TestPodDiscoveryAddWithSingleStackIPv4WithoutPorts(t *testing.T) { + t.Parallel() + n, c := makeDiscovery(RolePod, NamespaceDiscovery{}) + + ns := "default" + key := fmt.Sprintf("pod/%s/testpod", ns) + k8sDiscoveryTest{ + discovery: n, + afterStart: func() { + obj := &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "testpod", + Namespace: "default", + UID: types.UID("abc123"), + }, + Spec: v1.PodSpec{ + NodeName: "testnode", + Containers: []v1.Container{ + { + Name: "testcontainer", + Image: "testcontainer:latest", + }, + }, + }, + Status: v1.PodStatus{ + PodIP: "100.117.147.144", + PodIPs: []v1.PodIP{ + {IP: "100.117.147.144"}, + }, + HostIP: "2.3.4.5", + Phase: "Running", + Conditions: []v1.PodCondition{ + { + Type: v1.PodReady, + Status: v1.ConditionTrue, + }, + }, + ContainerStatuses: []v1.ContainerStatus{ + { + Name: "testcontainer", + ContainerID: "docker://a1b2c3d4e5f6", + }, + }, + }, + } + c.CoreV1().Pods(obj.Namespace).Create(context.Background(), obj, metav1.CreateOptions{}) + }, + expectedMaxItems: 1, + expectedRes: map[string]*targetgroup.Group{ + key: { + Targets: []model.LabelSet{ + { + "__address__": "100.117.147.144", + "__meta_kubernetes_pod_container_name": "testcontainer", + "__meta_kubernetes_pod_container_image": "testcontainer:latest", + "__meta_kubernetes_pod_container_init": "false", + "__meta_kubernetes_pod_container_id": "docker://a1b2c3d4e5f6", + }, + }, + Labels: model.LabelSet{ + "__meta_kubernetes_pod_name": "testpod", + "__meta_kubernetes_namespace": lv(ns), + "__meta_kubernetes_pod_node_name": "testnode", + "__meta_kubernetes_pod_ip": "100.117.147.144", + "__meta_kubernetes_pod_host_ip": "2.3.4.5", + "__meta_kubernetes_pod_ready": "true", + "__meta_kubernetes_pod_phase": "Running", + "__meta_kubernetes_pod_uid": "abc123", + "__meta_kubernetes_pod_ipv4": "100.117.147.144", + }, + Source: key, + }, + }, + }.Run(t) +} + +func TestPodDiscoveryAddWithDualStackAndMultiIPs(t *testing.T) { + t.Parallel() + n, c := makeDiscovery(RolePod, NamespaceDiscovery{}) + + ns := "default" + key := fmt.Sprintf("pod/%s/testpod", ns) + k8sDiscoveryTest{ + discovery: n, + afterStart: func() { + obj := &v1.Pod{ + ObjectMeta: metav1.ObjectMeta{ + Name: "testpod", + Namespace: "default", + UID: types.UID("abc123"), + }, + Spec: v1.PodSpec{ + NodeName: "testnode", + Containers: []v1.Container{ + { + Name: "testcontainer", + Image: "testcontainer:latest", + Ports: []v1.ContainerPort{ + { + Name: "testport", + Protocol: v1.ProtocolTCP, + ContainerPort: int32(9000), + }, + }, + }, + }, + }, + Status: v1.PodStatus{ + PodIP: "100.117.147.144", + PodIPs: []v1.PodIP{ + {IP: "100.117.147.144"}, + {IP: "110.117.147.144"}, + {IP: "2001::3238:634c:2ed4:ed01"}, + {IP: "2002::3238:634c:2ed4:ed01"}, + }, + HostIP: "2.3.4.5", + Phase: "Running", + Conditions: []v1.PodCondition{ + { + Type: v1.PodReady, + Status: v1.ConditionTrue, + }, + }, + ContainerStatuses: []v1.ContainerStatus{ + { + Name: "testcontainer", + ContainerID: "docker://a1b2c3d4e5f6", + }, + }, + }, + } + c.CoreV1().Pods(obj.Namespace).Create(context.Background(), obj, metav1.CreateOptions{}) + }, + expectedMaxItems: 1, + expectedRes: map[string]*targetgroup.Group{ + key: { + Targets: []model.LabelSet{ + { + "__address__": "100.117.147.144:9000", + "__meta_kubernetes_pod_container_name": "testcontainer", + "__meta_kubernetes_pod_container_image": "testcontainer:latest", + "__meta_kubernetes_pod_container_port_name": "testport", + "__meta_kubernetes_pod_container_port_number": "9000", + "__meta_kubernetes_pod_container_port_protocol": "TCP", + "__meta_kubernetes_pod_container_init": "false", + "__meta_kubernetes_pod_container_id": "docker://a1b2c3d4e5f6", + }, + }, + Labels: model.LabelSet{ + "__meta_kubernetes_pod_name": "testpod", + "__meta_kubernetes_namespace": lv(ns), + "__meta_kubernetes_pod_node_name": "testnode", + "__meta_kubernetes_pod_ip": "100.117.147.144", + "__meta_kubernetes_pod_host_ip": "2.3.4.5", + "__meta_kubernetes_pod_ready": "true", + "__meta_kubernetes_pod_phase": "Running", + "__meta_kubernetes_pod_uid": "abc123", + "__meta_kubernetes_pod_ipv4": "100.117.147.144", + "__meta_kubernetes_pod_ipv6": "2001::3238:634c:2ed4:ed01", + }, + Source: key, + }, + }, + }.Run(t) +} diff --git a/docs/configuration/configuration.md b/docs/configuration/configuration.md index 1f2f9931e8..de857846fa 100644 --- a/docs/configuration/configuration.md +++ b/docs/configuration/configuration.md @@ -2112,7 +2112,7 @@ Available meta labels: * `__meta_kubernetes_namespace`: The namespace of the pod object. * `__meta_kubernetes_pod_name`: The name of the pod object. -* `__meta_kubernetes_pod_ip`: The pod IP of the pod object. +* `__meta_kubernetes_pod_ip`: The pod IP of the pod object, corresponds to `pod.Status.PodIP`. * `__meta_kubernetes_pod_label_`: Each label from the pod object, with any unsupported characters converted to an underscore. * `__meta_kubernetes_pod_labelpresent_`: `true` for each label from the pod object, with any unsupported characters converted to an underscore. * `__meta_kubernetes_pod_annotation_`: Each annotation from the pod object. @@ -2132,6 +2132,8 @@ Available meta labels: * `__meta_kubernetes_pod_uid`: The UID of the pod object. * `__meta_kubernetes_pod_controller_kind`: Object kind of the pod controller. * `__meta_kubernetes_pod_controller_name`: Name of the pod controller. +* `__meta_kubernetes_pod_ipv4`: The pod IPv4 of the pod object, corresponds to `pod.Status.PodIPs`. +* `__meta_kubernetes_pod_ipv6`: The pod IPv6 of the pod object, corresponds to `pod.Status.PodIPs`. #### `endpoints`