1"use strict";(self.webpackChunkig_website=self.webpackChunkig_website||[]).push([[12460],{78361:(e,t,n)=>{n.r(t),n.d(t,{assets:()=>d,contentTitle:()=>c,default:()=>m,frontMatter:()=>i,metadata:()=>r,toc:()=>u});const r=JSON.parse('{"id":"gadgets/trace_oomkill","title":"trace_oomkill","description":"The trace_oomkill gadget is used to trace OOM kill events.","source":"@site/versioned_docs/version-v0.54.1/gadgets/trace_oomkill.mdx","sourceDirName":"gadgets","slug":"/gadgets/trace_oomkill","permalink":"/docs/v0.54.1/gadgets/trace_oomkill","draft":false,"unlisted":false,"editUrl":"https://github.com/inspektor-gadget/inspektor-gadget/edit/main/versioned_docs/version-v0.54.1/gadgets/trace_oomkill.mdx","tags":[],"version":"v0.54.1","sidebarPosition":0,"frontMatter":{"title":"trace_oomkill","sidebar_position":0},"sidebar":"mainSidebar","previous":{"title":"trace_mount","permalink":"/docs/v0.54.1/gadgets/trace_mount"},"next":{"title":"trace_open","permalink":"/docs/v0.54.1/gadgets/trace_open"}}');var l=n(74848),a=n(28453),o=n(49489),s=n(7227);const i={title:"trace_oomkill",sidebar_position:0},c="trace_oomkill",d={},u=[{value:"Requirements",id:"requirements",level:2},{value:"Getting started",id:"getting-started",level:2},{value:"Guide",id:"guide",level:2}];function h(e){const t={a:"a",admonition:"admonition",code:"code",em:"em",h1:"h1",h2:"h2",header:"header",li:"li",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,a.R)(),...e.components};return(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)(t.header,{children:(0,l.jsx)(t.h1,{id:"trace_oomkill",children:"trace_oomkill"})}),"\n",(0,l.jsx)(t.p,{children:"The trace_oomkill gadget is used to trace OOM kill events."}),"\n",(0,l.jsx)(t.h2,{id:"requirements",children:"Requirements"}),"\n",(0,l.jsxs)(t.ul,{children:["\n",(0,l.jsx)(t.li,{children:"Minimum Kernel Version : 5.4"}),"\n"]}),"\n",(0,l.jsx)(t.h2,{id:"getting-started",children:"Getting started"}),"\n",(0,l.jsx)(t.p,{children:"Running the gadget:"}),"\n",(0,l.jsxs)(o.A,{groupId:"env",children:[(0,l.jsx)(s.A,{value:"kubectl-gadget",label:"kubectl gadget",children:(0,l.jsx)(t.pre,{children:(0,l.jsx)(t.code,{className:"language-bash",children:"$ kubectl gadget run ghcr.io/inspektor-gadget/gadget/trace_oomkill:v0.54.1 [flags]\n"})})}),(0,l.jsx)(s.A,{value:"ig",label:"ig",children:(0,l.jsx)(t.pre,{children:(0,l.jsx)(t.code,{className:"language-bash",children:"$ sudo ig run ghcr.io/inspektor-gadget/gadget/trace_oomkill:v0.54.1 [flags]\n"})})})]}),"\n",(0,l.jsx)(t.h2,{id:"guide",children:"Guide"}),"\n",(0,l.jsxs)(o.A,{groupId:"env",children:[(0,l.jsxs)(s.A,{value:"kubectl-gadget",label:"kubectl gadget",children:[(0,l.jsxs)(t.p,{children:["Kubernetes allows you to set memory limits on containers. When a container exceeds its memory limit, the kernel's out-of-memory (OOM) killer is invoked, which kills the process requesting more memory than allowed in such a container.\nBefore Kubernetes version ",(0,l.jsx)(t.code,{children:"1.28.0"}),', the OOM kill events were only generated if the main container process (PID 1) was OOM killed. If any other process in the container was OOM killed, it would remain "invisible" to Kubernetes, meaning users wouldn\'t be notified.\nEven after version ',(0,l.jsx)(t.code,{children:"1.28.0"}),", OOM kill events will not be generated if ",(0,l.jsx)(t.a,{href:"https://kubernetes.io/docs/concepts/architecture/cgroups/#using-cgroupv2",children:"cgroup v2 isn't enabled"})," or if ",(0,l.jsx)(t.a,{href:"https://github.com/kubernetes/kubernetes/pull/126096",children:"singleProcessOOMKill"})," is being used."]}),(0,l.jsxs)(t.p,{children:["To ensure you are notified whenever any process within a container is OOM killed, regardless of whether it is PID 1 or not, you can use the ",(0,l.jsx)(t.code,{children:"trace_oomkill"})," gadget.\nTo demonstrate it, let's start by creating a deployment in a namespace:"]}),(0,l.jsx)(t.admonition,{type:"note",children:(0,l.jsxs)(t.p,{children:["This guide uses Kubernetes version ",(0,l.jsx)(t.code,{children:"1.27.0"})," to ensure that OOM kill events (other than main process) are not reported by Kubernetes."]})}),(0,l.jsx)(t.pre,{children:(0,l.jsx)(t.code,{className:"language-bash",children:"$ kubectl create namespace oomkill-demo\nnamespace/oomkill-demo created\n$ kubectl create deployment oomkill-demo --image=busybox --namespace oomkill-demo -- sleep inf\ndeployment.apps/oomkill-demo created\n"})}),(0,l.jsx)(t.p,{children:"Set the memory limit of the pod to a low value:"}),(0,l.jsx)(t.pre,{children:(0,l.jsx)(t.code,{className:"language-bash",children:"$ kubectl set resources deployment oomkill-demo --namespace oomkill-demo --limits=memory=128Mi\ndeployment.apps/oomkill-demo resource requirements updated\n$ kubectl wait --for=condition=Ready pod -l app=oomkill-demo --namespace oomkill-demo\npod/oomkill-demo-<...> condition met\n"})}),(0,l.jsx)(t.p,{children:"Run the gadget in a terminal:"}),(0,l.jsx)(t.pre,{children:(0,l.jsx)(t.code,{className:"language-bash",children:"$ kubectl gadget run trace_oomkill:v0.54.1 --namespace oomkill-demo\nK8S.NODE K8S.NAMESPACE K8S.PODNAME K8S.CONTAINERNAME MNTNS_ID FPID FUID FGID TPID PAGES FCOMM TCOMM\n"})}),(0,l.jsxs)(t.p,{children:["The gadget is waiting for the OOM killer to get triggered and kill a process in ",(0,l.jsx)(t.code,{children:"oomkill-demo"})," namespace (alternatively, we could use ",(0,l.jsx)(t.code,{children:"-A"})," and get out-of-memory killer events in all namespaces).\nTo trigger the OOM killer, in ",(0,l.jsx)(t.em,{children:"another terminal"}),", ",(0,l.jsx)(t.code,{children:"exec"})," a container and run this command to exhaust the memory:"]}),(0,l.jsx)(t.pre,{children:(0,l.jsx)(t.code,{className:"language-bash",children:"$ kubectl exec -n oomkill-demo -ti deployments/oomkill-demo -- tail /dev/zero\ncommand terminated with exit code 137\n"})}),(0,l.jsx)(t.p,{children:"First check if pod was restarted:"}),(0,l.jsx)(t.pre,{children:(0,l.jsx)(t.code,{className:"language-bash",children:"$ kubectl get pod -l app=oomkill-demo -n oomkill-demo\nNAME READY STATUS RESTARTS AGE\noomkill-demo-f5976f447-pr486 1/1 Running 0 70s\n\nNow, check if the OOM kill event was reported by Kubernetes:\n\n```bash\n$ kubectl get events --field-selector=reason=OOMKilled -n oomkill-demo\nNo resources found in oomkill-demo namespace.\n"})}),(0,l.jsxs)(t.p,{children:["or check the ",(0,l.jsx)(t.code,{children:"lastState"})," of the pod:"]}),(0,l.jsx)(t.pre,{children:(0,l.jsx)(t.code,{className:"language-bash",children:'$ kubectl get pod -l app=oomkill-demo -n oomkill-demo -o jsonpath="{.items[*].status.containerStatuses[*].lastState}"\n{}\n'})}),(0,l.jsxs)(t.p,{children:["Even if the OOM kill event is not reported by Kubernetes, the ",(0,l.jsx)(t.code,{children:"trace_oomkill"})," gadget will capture it. So, go back to ",(0,l.jsx)(t.em,{children:"the first terminal"})," and see:"]}),(0,l.jsx)(t.pre,{children:(0,l.jsx)(t.code,{className:"language-bash",children:"K8S.NODE K8S.NAMESPACE K8S.PODNAME K8S.CONTAINERNAME MNTNS_ID FPID FUID FGID TPID PAGES FCOMM TCOMM\nminikube-docker oomkill-demo oomkill-demo\u2026dbf85d-r9tls busybox 4026533320 728870 0 0 728870 4227071 tail tail\n"})})]}),(0,l.jsxs)(s.A,{value:"ig",label:"ig",children:[(0,l.jsx)(t.p,{children:"Start the gadget in a terminal:"}),(0,l.jsx)(t.pre,{children:(0,l.jsx)(t.code,{className:"language-bash",children:"$ sudo ig run trace_oomkill:v0.54.1 --containern
1ame test-trace-oomkill\nRUNTIME.CONTAINERNAME MNTNS_ID FPID FUID FGID TPID PAGES FCOMM TCOMM\n"})}),(0,l.jsx)(t.p,{children:"Run a container that will be killed by the OOM killer:"}),(0,l.jsx)(t.pre,{children:(0,l.jsx)(t.code,{className:"language-bash",children:"$ docker run --name test-trace-oomkill -m 512M -it busybox tail /dev/zero\n"})}),(0,l.jsx)(t.pre,{children:(0,l.jsx)(t.code,{className:"language-bash",children:"RUNTIME.CONTAINERNAME MNTNS_ID FPID FUID FGID TPID PAGES FCOMM TCOMM\ntest-trace-oomkill 4026532205 733494 0 0 733494 262144 tail tail\n"})})]})]}),"\n",(0,l.jsxs)(t.p,{children:["The printed lined corresponds to the killing of the ",(0,l.jsx)(t.code,{children:"tail"})," process by the OOM killer.\nNote that, in this case, the command which was killed by the OOM killer is the same which triggered it, ",(0,l.jsx)(t.strong,{children:"this is not always the case"}),"."]}),"\n",(0,l.jsx)(t.p,{children:"Congratulations! You reached the end of this guide!\nYou can now delete the resource we created:"}),"\n",(0,l.jsxs)(o.A,{groupId:"env",children:[(0,l.jsx)(s.A,{value:"kubectl-gadget",label:"kubectl gadget",children:(0,l.jsx)(t.pre,{children:(0,l.jsx)(t.code,{className:"language-bash",children:"$ kubectl delete namespace oomkill-demo\n"})})}),(0,l.jsx)(s.A,{value:"ig",label:"ig",children:(0,l.jsx)(t.pre,{children:(0,l.jsx)(t.code,{className:"language-bash",children:"$ docker rm -f test-trace-oomkill\n"})})})]})]})}function m(e={}){const{wrapper:t}={...(0,a.R)(),...e.components};return t?(0,l.jsx)(t,{...e,children:(0,l.jsx)(h,{...e})}):h(e)}},7227:(e,t,n)=>{n.d(t,{A:()=>o});n(96540);var r=n(34164);const l={tabItem:"tabItem_Ymn6"};var a=n(74848);function o(e){let{children:t,hidden:n,className:o}=e;return(0,a.jsx)("div",{role:"tabpanel",className:(0,r.A)(l.tabItem,o),hidden:n,children:t})}},49489:(e,t,n)=>{n.d(t,{A:()=>y});var r=n(96540),l=n(34164),a=n(24245),o=n(56347),s=n(36494),i=n(62814),c=n(45167),d=n(69900);function u(e){return r.Children.toArray(e).filter((e=>"\n"!==e)).map((e=>{if(!e||(0,r.isValidElement)(e)&&function(e){const{props:t}=e;return!!t&&"object"==typeof t&&"value"in t}(e))return e;throw new Error(`Docusaurus error: Bad <Tabs> child <${"string"==typeof e.type?e.type:e.type.name}>: all children of the <Tabs> component should be <TabItem>, and every <TabItem> should have a unique "value" prop.`)}))?.filter(Boolean)??[]}function h(e){const{values:t,children:n}=e;return(0,r.useMemo)((()=>{const e=t??function(e){return u(e).map((e=>{let{props:{value:t,label:n,attributes:r,default:l}}=e;return{value:t,label:n,attributes:r,default:l}}))}(n);return function(e){const t=(0,c.XI)(e,((e,t)=>e.value===t.value));if(t.length>0)throw new Error(`Docusaurus error: Duplicate values "${t.map((e=>e.value)).join(", ")}" found in <Tabs>. Every value needs to be unique.`)}(e),e}),[t,n])}function m(e){let{value:t,tabValues:n}=e;return n.some((e=>e.value===t))}function g(e){let{queryString:t=!1,groupId:n}=e;const l=(0,o.W6)(),a=function(e){let{queryString:t=!1,groupId:n}=e;if("string"==typeof t)return t;if(!1===t)return null;if(!0===t&&!n)throw new Error('Docusaurus error: The <Tabs> component groupId prop is required if queryString=true, because this value is used as the search param name. You can also provide an explicit value such as queryString="my-search-param".');return n??null}({queryString:t,groupId:n});return[(0,i.aZ)(a),(0,r.useCallback)((e=>{if(!a)return;const t=new URLSearchParams(l.location.search);t.set(a,e),l.replace({...l.location,search:t.toString()})}),[a,l])]}function p(e){const{defaultValue:t,queryString:n=!1,groupId:l}=e,a=h(e),[o,i]=(0,r.useState)((()=>function(e){let{defaultValue:t,tabValues:n}=e;if(0===n.length)throw new Error("Docusaurus error: the <Tabs> component requires at least one <TabItem> children component");if(t){if(!m({value:t,tabValues:n}))throw new Error(`Docusaurus error: The <Tabs> has a defaultValue "${t}" but none of its children has the corresponding value. Available values are: ${n.map((e=>e.value)).join(", ")}. If you intend to show no default tab, use defaultValue={null} instead.`);return t}const r=n.find((e=>e.default))??n[0];if(!r)throw new Error("Unexpected error: 0 tabValues");return r.value}({defaultValue:t,tabValues:a}))),[c,u]=g({queryString:n,groupId:l}),[p,b]=function(e){let{groupId:t}=e;const n=function(e){return e?`docusaurus.tab.${e}`:null}(t),[l,a]=(0,d.Dv)(n);return[l,(0,r.useCallback)((e=>{n&&a.set(e)}),[n,a])]}({groupId:l}),k=(()=>{const e=c??p;return m({value:e,tabValues:a})?e:null})();(0,s.A)((()=>{k&&i(k)}),[k]);return{selectedValue:o,selectValue:(0,r.useCallback)((e=>{if(!m({value:e,tabValues:a}))throw new Error(`Can't select invalid tab value=${e}`);i(e),u(e),b(e)}),[u,b,a]),tabValues:a}}var b=n(11062);const k={tabList:"tabList__CuJ",tabItem:"tabItem_LNqP"};var x=n(74848);function f(e){let{className:t,block:n,selectedValue:r,selectValue:o,tabValues:s}=e;const i=[],{blockElementScrollPositionUntilNextRender:c}=(0,a.a_)(),d=e=>{const t=e.currentTarget,n=i.indexOf(t),l=s[n].value;l!==r&&(c(t),o(l))},u=e=>{let t=null;switch(e.key){case"Enter":d(e);break;case"ArrowRight":{const n=i.indexOf(e.currentTarget)+1;t=i[n]??i[0];break}case"ArrowLeft":{const n=i.indexOf(e.currentTarget)-1;t=i[n]??i[i.length-1];break}}t?.focus()};return(0,x.jsx)("ul",{role:"tablist","aria-orientation":"horizontal",className:(0,l.A)("tabs",{"tabs--block":n},t),children:s.map((e=>{let{value:t,label:n,attributes:a}=e;return(0,x.jsx)("li",{role:"tab",tabIndex:r===t?0:-1,"aria-selected":r===t,ref:e=>i.push(e),onKeyDown:u,onClick:d,...a,className:(0,l.A)("tabs__item",k.tabItem,a?.className,{"tabs__item--active":r===t}),children:n??t},t)}))})}function v(e){let{lazy:t,children:n,selectedValue:a}=e;
1const o=(Array.isArray(n)?n:[n]).filter(Boolean);if(t){const e=o.find((e=>e.props.value===a));return e?(0,r.cloneElement)(e,{className:(0,l.A)("margin-top--md",e.props.className)}):null}return(0,x.jsx)("div",{className:"margin-top--md",children:o.map(((e,t)=>(0,r.cloneElement)(e,{key:t,hidden:e.props.value!==a})))})}function j(e){const t=p(e);return(0,x.jsxs)("div",{className:(0,l.A)("tabs-container",k.tabList),children:[(0,x.jsx)(f,{...t,...e}),(0,x.jsx)(v,{...t,...e})]})}function y(e){const t=(0,b.A)();return(0,x.jsx)(j,{...e,children:u(e.children)},String(t))}},28453:(e,t,n)=>{n.d(t,{R:()=>o,x:()=>s});var r=n(96540);const l={},a=r.createContext(l);function o(e){const t=r.useContext(a);return r.useMemo((function(){return"function"==typeof e?e(t):{...t,...e}}),[t,e])}function s(e){let t;return t=e.disableParentContext?"function"==typeof e.components?e.components(l):e.components||l:o(e.components),r.createElement(a.Provider,{value:t},e.children)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.