diff --git a/CHANGELOG.md b/CHANGELOG.md index 34630f581d6d..06b45869c134 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -94,6 +94,8 @@ Main (unreleased) - Added support for replaying not sent data for `loki.write` when WAL is enabled. (@thepalbi) +- Make the result of 'discovery.kubelet' support pods that without ports, such as k8s control plane static pods. (@masonmei) + - Added support for unicode strings in `pyroscope.ebpf` python profiles. (@korniltsev) - Improved resilience of graph evaluation in presence of slow components. (@thampiotr) diff --git a/component/discovery/kubelet/kubelet.go b/component/discovery/kubelet/kubelet.go index 53032c424968..ff952e2ada6e 100644 --- a/component/discovery/kubelet/kubelet.go +++ b/component/discovery/kubelet/kubelet.go @@ -34,6 +34,7 @@ const ( podNameLabel = metaLabelPrefix + "pod_name" podIPLabel = metaLabelPrefix + "pod_ip" podContainerNameLabel = metaLabelPrefix + "pod_container_name" + podContainerIDLabel = metaLabelPrefix + "pod_container_id" podContainerImageLabel = metaLabelPrefix + "pod_container_image" podContainerPortNameLabel = metaLabelPrefix + "pod_container_port_name" podContainerPortNumberLabel = metaLabelPrefix + "pod_container_port_number" @@ -214,6 +215,27 @@ func (d *Discovery) buildPodTargetGroup(pod v1.Pod) *targetgroup.Group { containers := append(pod.Spec.Containers, pod.Spec.InitContainers...) for i, c := range containers { isInit := i >= len(pod.Spec.Containers) + cStatuses := &pod.Status.ContainerStatuses + if isInit { + cStatuses = &pod.Status.InitContainerStatuses + } + cID := d.findPodContainerID(cStatuses, c.Name) + + // If no ports are defined for the container, create an anonymous + // target per container. + 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. + tg.Targets = append(tg.Targets, model.LabelSet{ + model.AddressLabel: lv(pod.Status.PodIP), + podContainerNameLabel: lv(c.Name), + podContainerIDLabel: lv(cID), + podContainerImageLabel: lv(c.Image), + podContainerIsInit: lv(strconv.FormatBool(isInit)), + }) + continue + } + for _, port := range c.Ports { ports := strconv.FormatUint(uint64(port.ContainerPort), 10) addr := net.JoinHostPort(pod.Status.PodIP, ports) @@ -221,6 +243,7 @@ func (d *Discovery) buildPodTargetGroup(pod v1.Pod) *targetgroup.Group { tg.Targets = append(tg.Targets, model.LabelSet{ model.AddressLabel: lv(addr), podContainerNameLabel: lv(c.Name), + podContainerIDLabel: lv(cID), podContainerImageLabel: lv(c.Image), podContainerPortNumberLabel: lv(ports), podContainerPortNameLabel: lv(port.Name), @@ -233,6 +256,23 @@ func (d *Discovery) buildPodTargetGroup(pod v1.Pod) *targetgroup.Group { return tg } +func (p *Discovery) findPodContainerStatus(statuses *[]v1.ContainerStatus, containerName string) (*v1.ContainerStatus, error) { + for _, s := range *statuses { + if s.Name == containerName { + return &s, nil + } + } + return nil, fmt.Errorf("cannot find container with name %v", containerName) +} + +func (p *Discovery) findPodContainerID(statuses *[]v1.ContainerStatus, containerName string) string { + cStatus, err := p.findPodContainerStatus(statuses, containerName) + if err != nil { + return "" + } + return cStatus.ContainerID +} + func (d *Discovery) podInTargetNamespaces(pod v1.Pod) bool { for _, ns := range d.targetNamespaces { if pod.Namespace == ns { diff --git a/component/discovery/kubelet/kubelet_test.go b/component/discovery/kubelet/kubelet_test.go index dd73a42d1b3d..b7d2c750d9d2 100644 --- a/component/discovery/kubelet/kubelet_test.go +++ b/component/discovery/kubelet/kubelet_test.go @@ -88,3 +88,20 @@ func newPod(name, namespace string) v1.Pod { }, } } + +func TestDiscoveryPodWithoutPod(t *testing.T) { + pod1 := newPod("pod-1", "namespace-1") + pod2 := newPod("pod-2", "namespace-2") + pod1.Spec.Containers[0].Ports = []v1.ContainerPort{} + + podList1 := v1.PodList{ + Items: []v1.Pod{pod1, pod2}, + } + + kubeletDiscovery, err := NewKubeletDiscovery(DefaultConfig) + require.NoError(t, err) + + _, err = kubeletDiscovery.refresh(podList1) + require.NoError(t, err) + require.Len(t, kubeletDiscovery.discoveredPodSources, 2) +}