[{"data":1,"prerenderedAt":1212},["ShallowReactive",2],{"print-topic-\u002Flearn\u002Fen\u002Fcourses\u002Fnetworking":3,"lessons-\u002Flearn\u002Fen\u002Fcourses\u002Fnetworking":51,"i-lucide:printer":1209},{"id":4,"title":5,"access":6,"body":7,"description":14,"draft":15,"estimatedMinutes":16,"extension":17,"featured":18,"icon":19,"lang":20,"level":21,"meta":22,"navigation":18,"order":23,"path":24,"prerequisites":25,"resources":27,"seo":38,"sku":39,"stem":40,"subjects":41,"summary":43,"tags":44,"updated":49,"__hash__":50},"courses\u002Flearn\u002Fen\u002Fcourses\u002Fnetworking\u002Findex.md","Kubernetes Networking","free",{"type":8,"value":9,"toc":10},"minimark",[],{"title":11,"searchDepth":12,"depth":12,"links":13},"",3,[],"Services, Ingress and network policy — how a packet actually reaches a pod.",false,45,"md",true,"lucide:network","en","intermediate",{},2,"\u002Flearn\u002Fen\u002Fcourses\u002Fnetworking",[26],"\u002Flearn\u002Fen\u002Fkubernetes\u002Fpods",[28,32],{"label":29,"file":30,"access":6,"size":31},"Service types cheat sheet","k8s-service-types.pdf","180 KB",{"label":33,"file":34,"access":35,"sku":36,"size":37},"NetworkPolicy recipe pack","k8s-network-policies.pdf","premium","res-k8s-netpol","640 KB",{"title":5,"description":14},null,"learn\u002Fen\u002Fcourses\u002Fnetworking\u002Findex",[42],"kubernetes","Kubernetes networking rests on one rule: every pod gets its own IP and can\nreach every other pod without NAT. Everything above that — Services, Ingress,\nNetworkPolicy — exists because pod IPs are not stable and not exposed.\nServices give you a stable virtual IP and load balancing. Ingress puts an\nHTTP router in front of Services so many hostnames share one entry point.\nNetworkPolicy takes the default-allow flat network and narrows it down. Get\nthose three roles clear and the failure modes stop being mysterious.\n",[45,46,47,48],"networking","services","ingress","cni","2026-08-06","GumIppvDWYP1scgT_rOvScFGIQ-Wqs-Uax-NJtxnUbU",[52,402,834],{"id":53,"title":54,"access":6,"body":55,"description":396,"extension":17,"lang":20,"meta":397,"navigation":18,"order":97,"partial":15,"path":398,"seo":399,"stem":400,"__hash__":401},"lessons\u002Flearn\u002Fen\u002Fcourses\u002Fnetworking\u002F01.services.md","Services",{"type":8,"value":56,"toc":389},[57,60,64,72,77,85,199,206,212,216,285,291,295,302,305,319,323,332,335,339,346,382,385],[58,59,54],"h1",{"id":46},[61,62,63],"p",{},"A pod IP is an unstable identifier. Pods are rescheduled, replaced on deploy, and\nscaled in and out. Anything that hard-codes a pod IP breaks on the first restart.",[61,65,66,67,71],{},"A ",[68,69,70],"strong",{},"Service"," is a stable name and virtual IP in front of a changing set of pods.",[73,74,76],"h2",{"id":75},"how-the-selector-works","How the selector works",[61,78,79,80,84],{},"A Service does not reference pods directly. It declares a label selector, and a\ncontroller keeps a matching ",[81,82,83],"code",{},"EndpointSlice"," up to date:",[86,87,91],"pre",{"className":88,"code":89,"language":90,"meta":11,"style":11},"language-yaml shiki shiki-themes github-dark-dimmed github-dark-dimmed","apiVersion: v1\nkind: Service\nmetadata:\n  name: payments\nspec:\n  selector:\n    app: payments\n  ports:\n    - port: 80\n      targetPort: 8080\n","yaml",[81,92,93,110,120,128,139,147,155,165,173,188],{"__ignoreMap":11},[94,95,98,102,106],"span",{"class":96,"line":97},"line",1,[94,99,101],{"class":100},"sza-u","apiVersion",[94,103,105],{"class":104},"sM9_K",": ",[94,107,109],{"class":108},"szYpP","v1\n",[94,111,112,115,117],{"class":96,"line":23},[94,113,114],{"class":100},"kind",[94,116,105],{"class":104},[94,118,119],{"class":108},"Service\n",[94,121,122,125],{"class":96,"line":12},[94,123,124],{"class":100},"metadata",[94,126,127],{"class":104},":\n",[94,129,131,134,136],{"class":96,"line":130},4,[94,132,133],{"class":100},"  name",[94,135,105],{"class":104},[94,137,138],{"class":108},"payments\n",[94,140,142,145],{"class":96,"line":141},5,[94,143,144],{"class":100},"spec",[94,146,127],{"class":104},[94,148,150,153],{"class":96,"line":149},6,[94,151,152],{"class":100},"  selector",[94,154,127],{"class":104},[94,156,158,161,163],{"class":96,"line":157},7,[94,159,160],{"class":100},"    app",[94,162,105],{"class":104},[94,164,138],{"class":108},[94,166,168,171],{"class":96,"line":167},8,[94,169,170],{"class":100},"  ports",[94,172,127],{"class":104},[94,174,176,179,182,184],{"class":96,"line":175},9,[94,177,178],{"class":104},"    - ",[94,180,181],{"class":100},"port",[94,183,105],{"class":104},[94,185,187],{"class":186},"sQdni","80\n",[94,189,191,194,196],{"class":96,"line":190},10,[94,192,193],{"class":100},"      targetPort",[94,195,105],{"class":104},[94,197,198],{"class":186},"8080\n",[61,200,201,202,205],{},"Any pod carrying ",[81,203,204],{},"app: payments"," and passing its readiness probe is added to the\nendpoint list. Any pod that fails readiness is removed. This is the reconciliation\nmodel again: the Service is a declaration, the endpoint list is reality, and a\ncontroller closes the gap.",[207,208,209],"note",{},[61,210,211],{},"A Service with a selector that matches nothing is not an error. It is an empty\nendpoint list, and connections to it fail with connection refused rather than a\nclear message. This is the single most common \"my Service is broken\" cause.",[73,213,215],{"id":214},"the-three-types","The three types",[217,218,219,235],"table",{},[220,221,222],"thead",{},[223,224,225,229,232],"tr",{},[226,227,228],"th",{},"Type",[226,230,231],{},"Allocates",[226,233,234],{},"Reachable from",[236,237,238,252,269],"tbody",{},[223,239,240,246,249],{},[241,242,243],"td",{},[81,244,245],{},"ClusterIP",[241,247,248],{},"A virtual IP inside the cluster",[241,250,251],{},"Inside the cluster only",[223,253,254,259,266],{},[241,255,256],{},[81,257,258],{},"NodePort",[241,260,261,262,265],{},"A ClusterIP ",[68,263,264],{},"plus"," the same port on every node",[241,267,268],{},"Anything that can reach a node",[223,270,271,276,282],{},[241,272,273],{},[81,274,275],{},"LoadBalancer",[241,277,278,279,281],{},"A NodePort ",[68,280,264],{}," an external load balancer",[241,283,284],{},"The internet, via the cloud provider",[61,286,287,288,290],{},"The types are cumulative, not alternatives. A ",[81,289,275],{}," Service still has a\nClusterIP and still has a node port — the cloud controller simply provisions an\nexternal balancer that points at those node ports.",[73,292,294],{"id":293},"what-clusterip-really-is","What ClusterIP really is",[61,296,297,298,301],{},"The ClusterIP is not assigned to any interface. Nothing answers ARP for it. It\nexists only as a set of rules in each node's kernel — iptables or IPVS entries\ninstalled by ",[81,299,300],{},"kube-proxy"," — that rewrite the destination address to a real pod IP\nas the packet leaves.",[61,303,304],{},"That has a practical consequence worth internalising:",[306,307,308],"warning",{},[61,309,310,311,314,315,318],{},"You cannot ",[81,312,313],{},"ping"," a ClusterIP. There is no host to answer ICMP — only DNAT rules\nfor the ports the Service declares. A failed ping proves nothing about whether\nthe Service works. Test with ",[81,316,317],{},"curl"," against a declared port instead.",[73,320,322],{"id":321},"load-balancing-granularity","Load balancing granularity",[61,324,325,327,328,331],{},[81,326,300],{}," picks an endpoint per ",[68,329,330],{},"connection",", not per request. For HTTP\u002F1.1\nwith connection reuse, and especially for HTTP\u002F2 and gRPC where a single long-lived\nconnection carries every request, this means traffic pins to one pod.",[61,333,334],{},"This is why gRPC services behind a plain ClusterIP often show badly skewed load.\nThe fix is client-side load balancing, a proxy that understands HTTP\u002F2, or a\nservice mesh — not a different Service type.",[73,336,338],{"id":337},"headless-services","Headless Services",[61,340,341,342,345],{},"Setting ",[81,343,344],{},"clusterIP: None"," disables the virtual IP entirely. DNS then returns the\npod IPs directly, one A record per ready endpoint:",[86,347,349],{"className":88,"code":348,"language":90,"meta":11,"style":11},"spec:\n  clusterIP: None\n  selector:\n    app: cassandra\n",[81,350,351,357,367,373],{"__ignoreMap":11},[94,352,353,355],{"class":96,"line":97},[94,354,144],{"class":100},[94,356,127],{"class":104},[94,358,359,362,364],{"class":96,"line":23},[94,360,361],{"class":100},"  clusterIP",[94,363,105],{"class":104},[94,365,366],{"class":108},"None\n",[94,368,369,371],{"class":96,"line":12},[94,370,152],{"class":100},[94,372,127],{"class":104},[94,374,375,377,379],{"class":96,"line":130},[94,376,160],{"class":100},[94,378,105],{"class":104},[94,380,381],{"class":108},"cassandra\n",[61,383,384],{},"This is what StatefulSets use. When each replica is individually addressable and\nidentity matters — database members, brokers, anything with a quorum — you want\nthe caller to see the real topology rather than a single virtual IP hiding it.",[386,387,388],"style",{},"html pre.shiki code .sza-u, html code.shiki .sza-u{--shiki-default:#8DDB8C;--shiki-dark:#8DDB8C}html pre.shiki code .sM9_K, html code.shiki .sM9_K{--shiki-default:#ADBAC7;--shiki-dark:#ADBAC7}html pre.shiki code .szYpP, html code.shiki .szYpP{--shiki-default:#96D0FF;--shiki-dark:#96D0FF}html pre.shiki code .sQdni, html code.shiki .sQdni{--shiki-default:#6CB6FF;--shiki-dark:#6CB6FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":11,"searchDepth":12,"depth":12,"links":390},[391,392,393,394,395],{"id":75,"depth":23,"text":76},{"id":214,"depth":23,"text":215},{"id":293,"depth":23,"text":294},{"id":321,"depth":23,"text":322},{"id":337,"depth":23,"text":338},"ClusterIP, NodePort and LoadBalancer, and what each one actually allocates.",{},"\u002Flearn\u002Fen\u002Fcourses\u002Fnetworking\u002Fservices",{"title":54,"description":396},"learn\u002Fen\u002Fcourses\u002Fnetworking\u002F01.services","6w0dHzL6jKSzV2gpGWIKGGQgiq8FUOgmMB__4BLHel8",{"id":403,"title":404,"access":6,"body":405,"description":828,"extension":17,"lang":20,"meta":829,"navigation":18,"order":23,"partial":15,"path":830,"seo":831,"stem":832,"__hash__":833},"lessons\u002Flearn\u002Fen\u002Fcourses\u002Fnetworking\u002F02.ingress.md","Ingress",{"type":8,"value":406,"toc":821},[407,409,414,418,425,438,442,660,666,670,718,743,748,752,796,803,809,813,816,819],[58,408,404],{"id":47},[61,410,66,411,413],{},[81,412,275],{}," Service gives you one external IP per Service. Thirty services\nmeans thirty load balancers and thirty bills. Ingress exists to collapse that into\none entry point that routes by hostname and path.",[73,415,417],{"id":416},"the-resource-is-only-a-declaration","The resource is only a declaration",[61,419,420,421,424],{},"This is the part that catches people out. An Ingress object is inert. It describes\nrouting rules; it does not implement them. Without an ",[68,422,423],{},"ingress controller"," running\nin the cluster — ingress-nginx, Traefik, HAProxy, a cloud-native one — creating an\nIngress does exactly nothing.",[306,426,427],{},[61,428,429,430,433,434,437],{},"An Ingress with no controller stays in a permanent pending state with no address,\nand produces no events explaining why. If ",[81,431,432],{},"kubectl get ingress"," shows an empty\n",[81,435,436],{},"ADDRESS"," column and nothing is logged, check whether a controller is installed\nbefore debugging the rules.",[73,439,441],{"id":440},"a-minimal-rule-set","A minimal rule set",[86,443,445],{"className":88,"code":444,"language":90,"meta":11,"style":11},"apiVersion: networking.k8s.io\u002Fv1\nkind: Ingress\nmetadata:\n  name: storefront\nspec:\n  ingressClassName: nginx\n  rules:\n    - host: shop.example.com\n      http:\n        paths:\n          - path: \u002Fapi\n            pathType: Prefix\n            backend:\n              service:\n                name: api\n                port:\n                  number: 80\n          - path: \u002F\n            pathType: Prefix\n            backend:\n              service:\n                name: web\n                port:\n                  number: 80\n",[81,446,447,456,465,471,480,486,496,503,515,522,529,543,554,562,570,581,589,599,611,620,627,634,644,651],{"__ignoreMap":11},[94,448,449,451,453],{"class":96,"line":97},[94,450,101],{"class":100},[94,452,105],{"class":104},[94,454,455],{"class":108},"networking.k8s.io\u002Fv1\n",[94,457,458,460,462],{"class":96,"line":23},[94,459,114],{"class":100},[94,461,105],{"class":104},[94,463,464],{"class":108},"Ingress\n",[94,466,467,469],{"class":96,"line":12},[94,468,124],{"class":100},[94,470,127],{"class":104},[94,472,473,475,477],{"class":96,"line":130},[94,474,133],{"class":100},[94,476,105],{"class":104},[94,478,479],{"class":108},"storefront\n",[94,481,482,484],{"class":96,"line":141},[94,483,144],{"class":100},[94,485,127],{"class":104},[94,487,488,491,493],{"class":96,"line":149},[94,489,490],{"class":100},"  ingressClassName",[94,492,105],{"class":104},[94,494,495],{"class":108},"nginx\n",[94,497,498,501],{"class":96,"line":157},[94,499,500],{"class":100},"  rules",[94,502,127],{"class":104},[94,504,505,507,510,512],{"class":96,"line":167},[94,506,178],{"class":104},[94,508,509],{"class":100},"host",[94,511,105],{"class":104},[94,513,514],{"class":108},"shop.example.com\n",[94,516,517,520],{"class":96,"line":175},[94,518,519],{"class":100},"      http",[94,521,127],{"class":104},[94,523,524,527],{"class":96,"line":190},[94,525,526],{"class":100},"        paths",[94,528,127],{"class":104},[94,530,532,535,538,540],{"class":96,"line":531},11,[94,533,534],{"class":104},"          - ",[94,536,537],{"class":100},"path",[94,539,105],{"class":104},[94,541,542],{"class":108},"\u002Fapi\n",[94,544,546,549,551],{"class":96,"line":545},12,[94,547,548],{"class":100},"            pathType",[94,550,105],{"class":104},[94,552,553],{"class":108},"Prefix\n",[94,555,557,560],{"class":96,"line":556},13,[94,558,559],{"class":100},"            backend",[94,561,127],{"class":104},[94,563,565,568],{"class":96,"line":564},14,[94,566,567],{"class":100},"              service",[94,569,127],{"class":104},[94,571,573,576,578],{"class":96,"line":572},15,[94,574,575],{"class":100},"                name",[94,577,105],{"class":104},[94,579,580],{"class":108},"api\n",[94,582,584,587],{"class":96,"line":583},16,[94,585,586],{"class":100},"                port",[94,588,127],{"class":104},[94,590,592,595,597],{"class":96,"line":591},17,[94,593,594],{"class":100},"                  number",[94,596,105],{"class":104},[94,598,187],{"class":186},[94,600,602,604,606,608],{"class":96,"line":601},18,[94,603,534],{"class":104},[94,605,537],{"class":100},[94,607,105],{"class":104},[94,609,610],{"class":108},"\u002F\n",[94,612,614,616,618],{"class":96,"line":613},19,[94,615,548],{"class":100},[94,617,105],{"class":104},[94,619,553],{"class":108},[94,621,623,625],{"class":96,"line":622},20,[94,624,559],{"class":100},[94,626,127],{"class":104},[94,628,630,632],{"class":96,"line":629},21,[94,631,567],{"class":100},[94,633,127],{"class":104},[94,635,637,639,641],{"class":96,"line":636},22,[94,638,575],{"class":100},[94,640,105],{"class":104},[94,642,643],{"class":108},"web\n",[94,645,647,649],{"class":96,"line":646},23,[94,648,586],{"class":100},[94,650,127],{"class":104},[94,652,654,656,658],{"class":96,"line":653},24,[94,655,594],{"class":100},[94,657,105],{"class":104},[94,659,187],{"class":186},[61,661,662,665],{},[81,663,664],{},"ingressClassName"," decides which controller claims this object. With two controllers\ninstalled and no class set, either both claim it or neither does — both outcomes are\nconfusing to debug.",[73,667,669],{"id":668},"pathtype-matters-more-than-it-looks","pathType matters more than it looks",[217,671,672,682],{},[220,673,674],{},[223,675,676,679],{},[226,677,678],{},"Value",[226,680,681],{},"Matches",[236,683,684,694,708],{},[223,685,686,691],{},[241,687,688],{},[81,689,690],{},"Exact",[241,692,693],{},"The path string exactly, case-sensitive",[223,695,696,701],{},[241,697,698],{},[81,699,700],{},"Prefix",[241,702,703,704,707],{},"Split on ",[81,705,706],{},"\u002F",", element by element",[223,709,710,715],{},[241,711,712],{},[81,713,714],{},"ImplementationSpecific",[241,716,717],{},"Whatever the controller decides",[61,719,720,722,723,727,728,731,732,734,735,738,739,742],{},[81,721,700],{}," compares path ",[724,725,726],"em",{},"elements",", not characters. ",[81,729,730],{},"\u002Fapi"," matches ",[81,733,730],{}," and\n",[81,736,737],{},"\u002Fapi\u002Forders",", but not ",[81,740,741],{},"\u002Fapiary",". That distinction surprises people expecting a\nplain string prefix.",[61,744,745,747],{},[81,746,714],{}," is where portability quietly dies — an ingress-nginx regex\npath will not survive a move to a different controller.",[73,749,751],{"id":750},"tls","TLS",[86,753,755],{"className":88,"code":754,"language":90,"meta":11,"style":11},"spec:\n  tls:\n    - hosts:\n        - shop.example.com\n      secretName: shop-tls\n",[81,756,757,763,770,779,786],{"__ignoreMap":11},[94,758,759,761],{"class":96,"line":97},[94,760,144],{"class":100},[94,762,127],{"class":104},[94,764,765,768],{"class":96,"line":23},[94,766,767],{"class":100},"  tls",[94,769,127],{"class":104},[94,771,772,774,777],{"class":96,"line":12},[94,773,178],{"class":104},[94,775,776],{"class":100},"hosts",[94,778,127],{"class":104},[94,780,781,784],{"class":96,"line":130},[94,782,783],{"class":104},"        - ",[94,785,514],{"class":108},[94,787,788,791,793],{"class":96,"line":141},[94,789,790],{"class":100},"      secretName",[94,792,105],{"class":104},[94,794,795],{"class":108},"shop-tls\n",[61,797,798,799,802],{},"The Secret must be type ",[81,800,801],{},"kubernetes.io\u002Ftls",", must live in the same namespace as the\nIngress, and must already exist. A missing Secret does not block the Ingress from\nbeing created — it just serves the controller's default self-signed certificate,\nwhich looks like a certificate problem rather than a missing-object problem.",[804,805,806],"tip",{},[61,807,808],{},"In practice you rarely create these by hand. cert-manager watches Ingress objects\nand issues certificates automatically from an ACME issuer such as Let's Encrypt.",[73,810,812],{"id":811},"when-ingress-is-not-enough","When Ingress is not enough",[61,814,815],{},"Ingress only models HTTP and HTTPS. Raw TCP, UDP, gRPC routing rules and weighted\ntraffic splits all sit outside the spec, which is why every controller grew its own\nannotations — and why those annotations do not port between controllers.",[61,817,818],{},"The Gateway API is the successor that models these properly, with separate resources\nfor infrastructure and routing. New clusters should look at it before committing to\ncontroller-specific annotations.",[386,820,388],{},{"title":11,"searchDepth":12,"depth":12,"links":822},[823,824,825,826,827],{"id":416,"depth":23,"text":417},{"id":440,"depth":23,"text":441},{"id":668,"depth":23,"text":669},{"id":750,"depth":23,"text":751},{"id":811,"depth":23,"text":812},"HTTP routing in front of Services, and why the resource does nothing on its own.",{},"\u002Flearn\u002Fen\u002Fcourses\u002Fnetworking\u002Fingress",{"title":404,"description":828},"learn\u002Fen\u002Fcourses\u002Fnetworking\u002F02.ingress","ijcTN78jYH-ktpYMTtKJTvnbYvlGui3oJDXv_cjRfNA",{"id":835,"title":836,"access":6,"body":837,"description":1203,"extension":17,"lang":20,"meta":1204,"navigation":18,"order":12,"partial":15,"path":1205,"seo":1206,"stem":1207,"__hash__":1208},"lessons\u002Flearn\u002Fen\u002Fcourses\u002Fnetworking\u002F03.network-policies.md","Network policies",{"type":8,"value":838,"toc":1197},[839,842,845,851,855,862,1000,1007,1031,1035,1045,1091,1103,1107,1110,1120,1124,1127,1186,1195],[58,840,836],{"id":841},"network-policies",[61,843,844],{},"By default, every pod in a cluster can reach every other pod, in any namespace.\nThe flat network is a deliberate simplification — and a poor security posture the\nmoment you run more than one team's workloads.",[61,846,847,850],{},[81,848,849],{},"NetworkPolicy"," narrows it.",[73,852,854],{"id":853},"selecting-turns-on-default-deny","Selecting turns on default-deny",[61,856,857,858,861],{},"A NetworkPolicy does not add rules to a permissive baseline. The moment any policy\nselects a pod, that pod switches to default-deny ",[68,859,860],{},"for the directions the policy\nmentions",", and only the listed rules are permitted.",[86,863,865],{"className":88,"code":864,"language":90,"meta":11,"style":11},"apiVersion: networking.k8s.io\u002Fv1\nkind: NetworkPolicy\nmetadata:\n  name: payments-ingress\nspec:\n  podSelector:\n    matchLabels:\n      app: payments\n  policyTypes: [Ingress]\n  ingress:\n    - from:\n        - podSelector:\n            matchLabels:\n              app: checkout\n      ports:\n        - port: 8080\n",[81,866,867,875,884,890,899,905,912,919,928,941,948,957,966,973,983,990],{"__ignoreMap":11},[94,868,869,871,873],{"class":96,"line":97},[94,870,101],{"class":100},[94,872,105],{"class":104},[94,874,455],{"class":108},[94,876,877,879,881],{"class":96,"line":23},[94,878,114],{"class":100},[94,880,105],{"class":104},[94,882,883],{"class":108},"NetworkPolicy\n",[94,885,886,888],{"class":96,"line":12},[94,887,124],{"class":100},[94,889,127],{"class":104},[94,891,892,894,896],{"class":96,"line":130},[94,893,133],{"class":100},[94,895,105],{"class":104},[94,897,898],{"class":108},"payments-ingress\n",[94,900,901,903],{"class":96,"line":141},[94,902,144],{"class":100},[94,904,127],{"class":104},[94,906,907,910],{"class":96,"line":149},[94,908,909],{"class":100},"  podSelector",[94,911,127],{"class":104},[94,913,914,917],{"class":96,"line":157},[94,915,916],{"class":100},"    matchLabels",[94,918,127],{"class":104},[94,920,921,924,926],{"class":96,"line":167},[94,922,923],{"class":100},"      app",[94,925,105],{"class":104},[94,927,138],{"class":108},[94,929,930,933,936,938],{"class":96,"line":175},[94,931,932],{"class":100},"  policyTypes",[94,934,935],{"class":104},": [",[94,937,404],{"class":108},[94,939,940],{"class":104},"]\n",[94,942,943,946],{"class":96,"line":190},[94,944,945],{"class":100},"  ingress",[94,947,127],{"class":104},[94,949,950,952,955],{"class":96,"line":531},[94,951,178],{"class":104},[94,953,954],{"class":100},"from",[94,956,127],{"class":104},[94,958,959,961,964],{"class":96,"line":545},[94,960,783],{"class":104},[94,962,963],{"class":100},"podSelector",[94,965,127],{"class":104},[94,967,968,971],{"class":96,"line":556},[94,969,970],{"class":100},"            matchLabels",[94,972,127],{"class":104},[94,974,975,978,980],{"class":96,"line":564},[94,976,977],{"class":100},"              app",[94,979,105],{"class":104},[94,981,982],{"class":108},"checkout\n",[94,984,985,988],{"class":96,"line":572},[94,986,987],{"class":100},"      ports",[94,989,127],{"class":104},[94,991,992,994,996,998],{"class":96,"line":583},[94,993,783],{"class":104},[94,995,181],{"class":100},[94,997,105],{"class":104},[94,999,198],{"class":186},[61,1001,1002,1003,1006],{},"Payments now accepts traffic from checkout on 8080 and nothing else. Egress is\nuntouched, because ",[81,1004,1005],{},"policyTypes"," does not list it.",[306,1008,1009],{},[61,1010,1011,1012,1015,1016,1018,1019,1022,1023,1026,1027,1030],{},"Listing ",[81,1013,1014],{},"Egress"," in ",[81,1017,1005],{}," with an empty ",[81,1020,1021],{},"egress"," block denies ",[724,1024,1025],{},"all","\noutbound traffic — including DNS to ",[81,1028,1029],{},"kube-dns",". Name resolution stops, so every\noutbound connection fails with a resolution error rather than a connection error,\nand the policy looks unrelated to the symptom. Always allow UDP and TCP 53 to the\nDNS namespace when you start restricting egress.",[73,1032,1034],{"id":1033},"namespace-selectors-need-labels","Namespace selectors need labels",[61,1036,1037,1040,1041,1044],{},[81,1038,1039],{},"namespaceSelector"," matches on namespace labels, not names. Namespaces have no\nuseful labels by default beyond ",[81,1042,1043],{},"kubernetes.io\u002Fmetadata.name",", which the control\nplane sets automatically:",[86,1046,1048],{"className":88,"code":1047,"language":90,"meta":11,"style":11},"ingress:\n  - from:\n      - namespaceSelector:\n          matchLabels:\n            kubernetes.io\u002Fmetadata.name: monitoring\n",[81,1049,1050,1056,1065,1074,1081],{"__ignoreMap":11},[94,1051,1052,1054],{"class":96,"line":97},[94,1053,47],{"class":100},[94,1055,127],{"class":104},[94,1057,1058,1061,1063],{"class":96,"line":23},[94,1059,1060],{"class":104},"  - ",[94,1062,954],{"class":100},[94,1064,127],{"class":104},[94,1066,1067,1070,1072],{"class":96,"line":12},[94,1068,1069],{"class":104},"      - ",[94,1071,1039],{"class":100},[94,1073,127],{"class":104},[94,1075,1076,1079],{"class":96,"line":130},[94,1077,1078],{"class":100},"          matchLabels",[94,1080,127],{"class":104},[94,1082,1083,1086,1088],{"class":96,"line":141},[94,1084,1085],{"class":100},"            kubernetes.io\u002Fmetadata.name",[94,1087,105],{"class":104},[94,1089,1090],{"class":108},"monitoring\n",[61,1092,1093,1094,1096,1097,1099,1100,1102],{},"Combining ",[81,1095,1039],{}," and ",[81,1098,963],{}," in a single ",[81,1101,954],{}," entry is an AND.\nListing them as two entries is an OR. One character of YAML indentation separates\n\"Prometheus pods in the monitoring namespace\" from \"anything in monitoring, plus\nPrometheus pods anywhere\".",[73,1104,1106],{"id":1105},"the-cni-has-to-implement-it","The CNI has to implement it",[61,1108,1109],{},"Like Ingress, the object is only a declaration. Calico, Cilium and Antrea enforce\npolicies. Flannel, on its own, does not.",[1111,1112,1113],"danger",{},[61,1114,1115,1116,1119],{},"Applying NetworkPolicy on a CNI that ignores it produces no error and no warning.\n",[81,1117,1118],{},"kubectl get networkpolicy"," lists the object, the API accepted it, and traffic\nflows exactly as before. A policy you believe is enforced but is not is worse than\nno policy — verify by actually attempting a connection that should be denied.",[73,1121,1123],{"id":1122},"a-sensible-starting-point","A sensible starting point",[61,1125,1126],{},"Deny everything inbound in a namespace, then open specific paths:",[86,1128,1130],{"className":88,"code":1129,"language":90,"meta":11,"style":11},"apiVersion: networking.k8s.io\u002Fv1\nkind: NetworkPolicy\nmetadata:\n  name: default-deny-ingress\nspec:\n  podSelector: {}\n  policyTypes: [Ingress]\n",[81,1131,1132,1140,1148,1154,1163,1169,1176],{"__ignoreMap":11},[94,1133,1134,1136,1138],{"class":96,"line":97},[94,1135,101],{"class":100},[94,1137,105],{"class":104},[94,1139,455],{"class":108},[94,1141,1142,1144,1146],{"class":96,"line":23},[94,1143,114],{"class":100},[94,1145,105],{"class":104},[94,1147,883],{"class":108},[94,1149,1150,1152],{"class":96,"line":12},[94,1151,124],{"class":100},[94,1153,127],{"class":104},[94,1155,1156,1158,1160],{"class":96,"line":130},[94,1157,133],{"class":100},[94,1159,105],{"class":104},[94,1161,1162],{"class":108},"default-deny-ingress\n",[94,1164,1165,1167],{"class":96,"line":141},[94,1166,144],{"class":100},[94,1168,127],{"class":104},[94,1170,1171,1173],{"class":96,"line":149},[94,1172,909],{"class":100},[94,1174,1175],{"class":104},": {}\n",[94,1177,1178,1180,1182,1184],{"class":96,"line":157},[94,1179,932],{"class":100},[94,1181,935],{"class":104},[94,1183,404],{"class":108},[94,1185,940],{"class":104},[61,1187,1188,1189,1191,1192,1194],{},"An empty ",[81,1190,963],{}," selects every pod in the namespace. With no ",[81,1193,47],{}," rules,\nnothing is allowed in. Layer permissive policies on top per service — policies are\nadditive, so any rule that allows traffic wins over the baseline denial.",[386,1196,388],{},{"title":11,"searchDepth":12,"depth":12,"links":1198},[1199,1200,1201,1202],{"id":853,"depth":23,"text":854},{"id":1033,"depth":23,"text":1034},{"id":1105,"depth":23,"text":1106},{"id":1122,"depth":23,"text":1123},"Narrowing a default-allow flat network, and the traps in doing it.",{},"\u002Flearn\u002Fen\u002Fcourses\u002Fnetworking\u002Fnetwork-policies",{"title":836,"description":1203},"learn\u002Fen\u002Fcourses\u002Fnetworking\u002F03.network-policies","6JfTFK0E4FUQ3up_YPMrK33esdPME_tZFDmROIyTNDw",{"left":1210,"top":1210,"width":653,"height":653,"rotate":1210,"vFlip":15,"hFlip":15,"body":1211},0,"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2M6 9V3a1 1 0 0 1 1-1h10a1 1 0 0 1 1 1v6\"\u002F>\u003Crect width=\"12\" height=\"8\" x=\"6\" y=\"14\" rx=\"1\"\u002F>\u003C\u002Fg>",1787597905129]