Commit 89d3d9d
[processor/k8s_attributes] Fix memory leak in k8s_attributes map (open-telemetry#48987)
[processor/k8s_attributes] Fix memory leak in k8s_attributes map due to
missing IP or other dynamic attributes from Pod deletion event object.
#### Component(s)
[processor/k8s_attributes]
#### Description
In environments with high pod churn or rapid scale-down, the
`k8sattributes` processor can leak pod IP-based cache entries
(`connection: <IP>` and `resource_attribute: k8s.pod.ip`) in the
internal `c.Pods` map. This leads to unbounded memory growth and a
stable baseline of leaked keys even after the actual pods have been
scaled down to zero.
#### Root Cause
When a pod is deleted, the `WatchClient`'s
[`forgetPod`](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/processor/k8sattributesprocessor/internal/kube/client.go#L1635)
method is called to purge the cached entries:
```go
func (c *WatchClient) forgetPod(pod *api_v1.Pod) {
podToRemove := c.podFromAPI(pod)
identifiers := c.getIdentifiersFromAssoc(podToRemove)
for i := range identifiers {
id := identifiers[i]
p, ok := c.GetPod(id)
if ok && p.PodUID == string(pod.UID) {
c.appendDeleteQueue(id, p.PodUID)
}
}
}
```
1. `forgetPod` builds `podToRemove` from the incoming delete event
payload `pod`.
2. It then calls `getIdentifiersFromAssoc(podToRemove)` to determine
which keys to add to the delete queue.
3. If the CNI has already reclaimed/cleared the Pod's IP address by the
time the final `DELETE` event is dispatched (or if the status payload is
incomplete), `pod.Status.PodIP` will be empty (`""`).
4. As a result, `getIdentifiersFromAssoc` **only** generates the
UID-based identifier (`resource_attribute: k8s.pod.uid`). The IP-based
identifiers (`connection: <IP>` and `resource_attribute: k8s.pod.ip`)
are skipped.
5. Consequently, only the UID-based key is queued for deletion, while
the IP-based keys are never cleared and are permanently leaked in the
`c.Pods` map.
#### Proposed Solution
Instead of relying on the incoming delete event status to determine the
keys to delete, `forgetPod` should look up the cached pod from `c.Pods`
using the pod's UID (which is always present in the event). The cached
pod object is guaranteed to contain the IP address and all attributes as
they were stored during the pod's lifecycle.
<!-- Issue number (e.g. open-telemetry#1234) or full URL to issue, if applicable. -->
#### Link to tracking issue
Fixes
open-telemetry#48986
<!--Describe what testing was performed and which tests were added.-->
#### Testing
Added a unit test case that catches the issue of a Pod object from a
deletion event that is missing IP fields.
<!--Describe the documentation added.-->
#### Documentation
Added a changelog entry for a bug fix.
<!--Authorship attestation. See AGENTS.md for details. AI agents must
not check this box on behalf
of the user; the human author must check it themselves before the PR is
ready for review.-->
#### Authorship
- [ X ] I, a human, wrote this pull request description myself.
<!--Please delete paragraphs that you did not use before submitting.-->1 parent f52800a commit 89d3d9d
3 files changed
Lines changed: 85 additions & 2 deletions
File tree
- .chloggen
- processor/k8sattributesprocessor/internal/kube
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1655 | 1655 | | |
1656 | 1656 | | |
1657 | 1657 | | |
1658 | | - | |
1659 | | - | |
| 1658 | + | |
| 1659 | + | |
| 1660 | + | |
| 1661 | + | |
| 1662 | + | |
| 1663 | + | |
| 1664 | + | |
| 1665 | + | |
| 1666 | + | |
| 1667 | + | |
| 1668 | + | |
| 1669 | + | |
| 1670 | + | |
| 1671 | + | |
| 1672 | + | |
| 1673 | + | |
| 1674 | + | |
| 1675 | + | |
| 1676 | + | |
| 1677 | + | |
| 1678 | + | |
1660 | 1679 | | |
1661 | 1680 | | |
1662 | 1681 | | |
| |||
Lines changed: 45 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4874 | 4874 | | |
4875 | 4875 | | |
4876 | 4876 | | |
| 4877 | + | |
| 4878 | + | |
| 4879 | + | |
| 4880 | + | |
| 4881 | + | |
| 4882 | + | |
| 4883 | + | |
| 4884 | + | |
| 4885 | + | |
| 4886 | + | |
| 4887 | + | |
| 4888 | + | |
| 4889 | + | |
| 4890 | + | |
| 4891 | + | |
| 4892 | + | |
| 4893 | + | |
| 4894 | + | |
| 4895 | + | |
| 4896 | + | |
| 4897 | + | |
| 4898 | + | |
| 4899 | + | |
| 4900 | + | |
| 4901 | + | |
| 4902 | + | |
| 4903 | + | |
| 4904 | + | |
| 4905 | + | |
| 4906 | + | |
| 4907 | + | |
| 4908 | + | |
| 4909 | + | |
| 4910 | + | |
| 4911 | + | |
| 4912 | + | |
| 4913 | + | |
| 4914 | + | |
| 4915 | + | |
| 4916 | + | |
| 4917 | + | |
| 4918 | + | |
| 4919 | + | |
| 4920 | + | |
| 4921 | + | |
0 commit comments