{"id":2952,"date":"2024-08-24T15:43:09","date_gmt":"2024-08-24T14:43:09","guid":{"rendered":"https:\/\/contentlabstudy.com\/soft\/?p=2952"},"modified":"2026-09-24T21:16:12","modified_gmt":"2026-09-24T20:16:12","slug":"local-kubernetes-with-load-balancer","status":"publish","type":"post","link":"https:\/\/contentlabstudy.com\/soft\/local-kubernetes-with-load-balancer\/","title":{"rendered":"Local Kubernetes with Load Balancer"},"content":{"rendered":"<p>On a real cloud, <code>Service type: LoadBalancer<\/code> provisions an external address. <strong>On a local cluster it often does nothing useful<\/strong> unless you add a path: MetalLB (VMs), kind\u2019s extra port mappings, minikube tunnel, or an ingress controller bound to localhost. Know which fake you are using.<\/p>\n<h2>Practical local options<\/h2>\n<ul>\n<li><strong>kubectl port-forward:<\/strong> always works; good enough for one API. Not how you test \u201cthe Ingress path.\u201d<\/li>\n<li><strong>kind extraPortMappings:<\/strong> map 80\/443 on the host to the ingress node. Then <code>\/etc\/hosts<\/code> for a fake name.<\/li>\n<li><strong>minikube tunnel \/ k3d port mapping:<\/strong> similar idea. Read the tool\u2019s current docs; they change.<\/li>\n<li><strong>Ingress (nginx, Traefik) + localhost:<\/strong> the usual local \u201cload balancer\u201d for HTTP. Gateway API if that is what you run in prod \u2014 match the family, not the brand.<\/li>\n<\/ul>\n<h2>What you are not testing<\/h2>\n<p>Cloud LB idle timeouts, PROXY protocol, security groups, cross-zone behavior. If the bug lives there, you need a cloud environment, not a more clever kind config.<\/p>\n<h2>Example<\/h2>\n<p>This is a kind cluster config, not a manifest you <code>kubectl apply<\/code>. Host port 8080 reaches container port 80 on the node, where the ingress controller is listening.<\/p>\n<pre><code>kind: Cluster\napiVersion: kind.x-k8s.io\/v1alpha4\nnodes:\n  - role: control-plane\n    extraPortMappings:\n      - containerPort: 80\n        hostPort: 8080<\/code><\/pre>\n<h2>What breaks it<\/h2>\n<p>A cloud <code>LoadBalancer<\/code> Service copied onto the laptop stays <code>&lt;pending&gt;<\/code>. Use the port mapping above, or <code>kubectl port-forward<\/code>, for local HTTP.<\/p>\n<pre><code>apiVersion: v1\nkind: Service\nmetadata:\n  name: api\nspec:\n  type: LoadBalancer\n  selector:\n    app: api\n  ports:\n    - port: 80\n      targetPort: 8080<\/code><\/pre>\n<h2>Pitfalls<\/h2>\n<ul>\n<li>Copy-pasting a cloud LoadBalancer YAML locally and wondering why EXTERNAL-IP is pending forever.<\/li>\n<li>Binding 80 as root on the laptop when 8080 would do.<\/li>\n<li>TLS with a public CA on localhost \u2014 use mkcert or skip TLS locally and test TLS in staging.<\/li>\n<\/ul>\n<p>Cluster objects: <a href=\"\/soft\/kubernetes-deployment\/\">Kubernetes Deployment<\/a>. Local cluster: <a href=\"\/soft\/local-kubernetes\/\">Local Kubernetes<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>On a real cloud, Service type: LoadBalancer provisions an external address. On a local cluster it often does nothing useful [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"site-sidebar-layout":"default","site-content-layout":"","ast-site-content-layout":"default","site-content-style":"default","site-sidebar-style":"default","ast-global-header-display":"","ast-banner-title-visibility":"","ast-main-header-display":"","ast-hfb-above-header-display":"","ast-hfb-below-header-display":"","ast-hfb-mobile-header-display":"","site-post-title":"","ast-breadcrumbs-content":"","ast-featured-img":"","footer-sml-layout":"","ast-disable-related-posts":"","theme-transparent-header-meta":"","adv-header-id-meta":"","stick-header-meta":"","header-above-stick-meta":"","header-main-stick-meta":"","header-below-stick-meta":"","astra-migrate-meta-layouts":"default","ast-page-background-enabled":"default","ast-page-background-meta":{"desktop":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"ast-content-background-meta":{"desktop":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"tablet":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""},"mobile":{"background-color":"var(--ast-global-color-5)","background-image":"","background-repeat":"repeat","background-position":"center center","background-size":"auto","background-attachment":"scroll","background-type":"","background-media":"","overlay-type":"","overlay-color":"","overlay-opacity":"","overlay-gradient":""}},"footnotes":""},"categories":[13],"tags":[],"class_list":["post-2952","post","type-post","status-publish","format-standard","hentry","category-software-deployment"],"_links":{"self":[{"href":"https:\/\/contentlabstudy.com\/soft\/wp-json\/wp\/v2\/posts\/2952","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/contentlabstudy.com\/soft\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/contentlabstudy.com\/soft\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/contentlabstudy.com\/soft\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/contentlabstudy.com\/soft\/wp-json\/wp\/v2\/comments?post=2952"}],"version-history":[{"count":4,"href":"https:\/\/contentlabstudy.com\/soft\/wp-json\/wp\/v2\/posts\/2952\/revisions"}],"predecessor-version":[{"id":3243,"href":"https:\/\/contentlabstudy.com\/soft\/wp-json\/wp\/v2\/posts\/2952\/revisions\/3243"}],"wp:attachment":[{"href":"https:\/\/contentlabstudy.com\/soft\/wp-json\/wp\/v2\/media?parent=2952"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/contentlabstudy.com\/soft\/wp-json\/wp\/v2\/categories?post=2952"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/contentlabstudy.com\/soft\/wp-json\/wp\/v2\/tags?post=2952"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}