You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
<
10000
script type="application/json" data-target="react-app.embeddedData">{"payload":{"allShortcutsEnabled":false,"fileTree":{"docs":{"items":[{"name":"design","path":"docs/design","contentType":"directory"},{"name":"devel","path":"docs/devel","contentType":"directory"},{"name":"getting-started-guides","path":"docs/getting-started-guides","contentType":"directory"},{"name":"man","path":"docs/man","contentType":"directory"},{"name":"proposals","path":"docs/proposals","contentType":"directory"},{"name":"README.md","path":"docs/README.md","contentType":"file"},{"name":"accessing-the-cluster.md","path":"docs/accessing-the-cluster.md","contentType":"file"},{"name":"accessing_the_api.md","path":"docs/accessing_the_api.md","contentType":"file"},{"name":"annotations.md","path":"docs/annotations.md","contentType":"file"},{"name":"api-conventions.md","path":"docs/api-conventions.md","contentType":"file"},{"name":"architecture.dia","path":"docs/architecture.dia","contentType":"file"},{"name":"architecture.png","path":"docs/architecture.png","contentType":"file"},{"name":"architecture.svg","path":"docs/architecture.svg","contentType":"file"},{"name":"authentication.md","path":"docs/authentication.md","contentType":"file"},{"name":"authorization.md","path":"docs/authorization.md","contentType":"file"},{"name":"availability.md","path":"docs/availability.md","contentType":"file"},{"name":"cli-roadmap.md","path":"docs/cli-roadmap.md","contentType":"file"},{"name":"client-libraries.md","path":"docs/client-libraries.md","contentType":"file"},{"name":"cluster-admin-guide.md","path":"docs/cluster-admin-guide.md","contentType":"file"},{"name":"cluster_management.md","path":"docs/cluster_management.md","contentType":"file"},{"name":"container-environment.md","path":"docs/container-environment.md","contentType":"file"},{"name":"containers.md","path":"docs/containers.md","contentType":"file"},{"name":"developer-guide.md","path":"docs/developer-guide.md","contentType":"file"},{"name":"dns.md","path":"docs/dns.md","contentType":"file"},{"name":"glossary.md","path":"docs/glossary.md","contentType":"file"},{"name":"identifiers.md","path":"docs/identifiers.md","contentType":"file"},{"name":"images.md","path":"docs/images.md","contentType":"file"},{"name":"kibana.png","path":"docs/kibana.png","contentType":"file"},{"name":"kubeconfig-file.md","path":"docs/kubeconfig-file.md","contentType":"file"},{"name":"kubectl-apiversions.md","path":"docs/kubectl-apiversions.md","contentType":"file"},{"name":"kubectl-clusterinfo.md","path":"docs/kubectl-clusterinfo.md","contentType":"file"},{"name":"kubectl-config-set-cluster.md","path":"docs/kubectl-config-set-cluster.md","contentType":"file"},{"name":"kubectl-config-set-context.md","path":"docs/kubectl-config-set-context.md","contentType":"file"},{"name":"kubectl-config-set-credentials.md","path":"docs/kubectl-config-set-credentials.md","contentType":"file"},{"name":"kubectl-config-set.md","path":"docs/kubectl-config-set.md","contentType":"file"},{"name":"kubectl-config-unset.md","path":"docs/kubectl-config-unset.md","contentType":"file"},{"name":"kubectl-config-use-context.md","path":"docs/kubectl-config-use-context.md","contentType":"file"},{"name":"kubectl-config-view.md","path":"docs/kubectl-config-view.md","contentType":"file"},{"name":"kubectl-config.md","path":"docs/kubectl-config.md","contentType":"file"},{"name":"kubectl-create.md","path":"docs/kubectl-create.md","contentType":"file"},{"name":"kubectl-delete.md","path":"docs/kubectl-delete.md","contentType":"file"},{"name":"kubectl-describe.md","path":"docs/kubectl-describe.md","contentType":"file"},{"name":"kubectl-exec.md","path":"docs/kubectl-exec.md","contentType":"file"},{"name":"kubectl-expose.md","path":"docs/kubectl-expose.md","contentType":"file"},{"name":"kubectl-get.md","path":"docs/kubectl-get.md","contentType":"file"},{"name":"kubectl-label.md","path":"docs/kubectl-label.md","contentType":"file"},{"name":"kubectl-log.md","path":"docs/kubectl-log.md","contentType":"file"},{"name":"kubectl-namespace.md","path":"docs/kubectl-namespace.md","contentType":"file"},{"name":"kubectl-port-forward.md","path":"docs/kubectl-port-forward.md","contentType":"file"},{"name":"kubectl-proxy.md","path":"docs/kubectl-proxy.md","contentType":"file"},{"name":"kubectl-resize.md","path":"docs/kubectl-resize.md","contentType":"file"},{"name":"kubectl-rollingupdate.md","path":"docs/kubectl-rollingupdate.md","contentType":"file"},{"name":"kubectl-run-container.md","path":"docs/kubectl-run-container.md","contentType":"file"},{"name":"kubectl-stop.md","path":"docs/kubectl-stop.md","contentType":"file"},{"name":"kubectl-update.md","path":"docs/kubectl-update.md","contentType":"file"},{"name":"kubectl-version.md","path":"docs/kubectl-version.md","contentType":"file"},{"name":"kubectl.md","path":"docs/kubectl.md","contentType":"file"},{"name":"labels.md","path":"docs/labels.md","contentType":"file"},{"name":"logging.md","path":"docs/logging.md","contentType":"file"},{"name":"namespaces.md","path":"docs/namespaces.md","contentType":"file"},{"name":"networking.md","path":"docs/networking.md","contentType":"file"},{"name":"node.md","path":"docs/node.md","contentType":"file"},{"name":"overview.md","path":"docs/overview.md","contentType":"file"},{"name":"ovs-networking.md","path":"docs/ovs-networking.md","contentType":"file"},{"name":"ovs-networking.png","path":"docs/ovs-networking.png","contentType":"file"},{"name":"pod-states.md","path":"docs/pod-states.md","contentType":"file"},{"name":"pods.md","path":"docs/pods.md","contentType":"file"},{"name":"replication-controller.md","path":"docs/replication-controller.md","contentType":"file"},{"name":"resource_quota_admin.md","path":"docs/resource_quota_admin.md","contentType":"file"},{"name":"resources.md","path":"docs/resources.md","contentType":"file"},{"name":"roadmap.md","path":"docs/roadmap.md","contentType":"file"},{"name":"salt.md","path":"docs/salt.md","contentType":"file"},{"name":"services.md","path":"docs/services.md","contentType":"file"},{"name":"services_detail.png","path":"docs/services_detail.png","contentType":"file"},{"name":"services_detail.svg","path":"docs/services_detail.svg","contentType":"file"},{"name":"services_overview.png","path":"docs/services_overview.png","contentType":"file"},{"name":"services_overview.svg","path":"docs/services_overview.svg","contentType":"file"},{"name":"sharing-clusters.md","path":"docs/sharing-clusters.md","contentType":"file"},{"name":"ui.md","path":"docs/ui.md","contentType":"file"},{"name":"user-guide.md","path":"docs/user-guide.md","contentType":"file"},{"name":"versioning.md","path":"docs/versioning.md","contentType":"file"},{"name":"volumes.md","path":"docs/volumes.md","contentType":"file"}],"totalCount":82},"":{"items":[{"name":"Godeps","path":"Godeps","contentType":"directory"},{"name":"api","path":"api","contentType":"directory"},{"name":"build","path":"build","contentType":"directory"},{"name":"cluster","path":"cluster","contentType":"directory"},{"name":"cmd","path":"cmd","contentType":"directory"},{"name":"contrib","path":"contrib","contentType":"directory"},{"name":"docs","path":"docs","contentType":"directory"},{"name":"examples","path":"examples","contentType":"directory"},{"name":"hack","path":"hack","contentType":"directory"},{"name":"hooks","path":"hooks","contentType":"directory"},{"name":"pkg","path":"pkg","contentType":"directory"},{"name":"plugin","path":"plugin","contentType":"directory"},{"name":"test","path":"test","contentType":"directory"},{"name":"third_party","path":"third_party","contentType":"directory"},{"name":"www","path":"www","contentType":"directory"},{"name":".gitignore","path":".gitignore","contentType":"file"},{"name":".travis.yml","path":".travis.yml","contentType":"file"},{"name":"CHANGELOG.md","path":"CHANGELOG.md","contentType":"file"},{"name":"CONTRIB.md","path":"CONTRIB.md","contentType":"file"},{"name":"CONTRIBUTING.md","path":"CONTRIBUTING.md","contentType":"file"},{"name":"DESIGN.md","path":"DESIGN.md","contentType":"file"},{"name":"LICENSE","path":"LICENSE","contentType":"file"},{"name":"MAINTAINERS.md","path":"MAINTAINERS.md","contentType":"file"},{"name":"Makefile","path":"Makefile","contentType":"file"},{"name":"README.md","path":"README.md","contentType":"file"},{"name":"Vagrantfile","path":"Vagrantfile","contentType":"file"},{"name":"logo.pdf","path":"logo.pdf","contentType":"file"},{"name":"logo.png","path":"logo.png","contentType":"file"},{"name":"logo.svg","path":"logo.svg","contentType":"file"},{"name":"logo_usage_guidelines.md","path":"logo_usage_guidelines.md","contentType":"file"},{"name":"shippable.yml","path":"shippable.yml","contentType":"file"}],"totalCount":31}},"fileTreeProcessingTime":19.066713999999997,"foldersToFetch":[],"incompleteFileTree":false,"repo":{"id":32922847,"defaultBranch":"master","name":"kubernetes","ownerLogin":"lyda","currentUserCanPush":false,"isFork":true,"isEmpty":false,"createdAt":"2015-03-26T11:13:46.000Z","ownerAvatar":"https://avatars.githubusercontent.com/u/714124?v=4","public":true,"private":false,"isOrgOwned":false},"codeLineWrapEnabled":false,"symbolsExpanded":false,"treeExpanded":true,"refInfo":{"name":"master","listCacheKey":"v0:1427879426.0","canEdit":false,"refType":"branch","currentOid":"151b2efa20a95fa9193ba055f01f747a25a4dda9"},"path":"docs/services.md","currentUser":null,"blob":{"rawLines":null,"stylingDirectives":null,"colorizedLines":null,"csv":null,"csvError":null,"dependabotInfo":{"showConfigurationBanner":false,"configFilePath":null,"networkDependabotPath":"/lyda/kubernetes/network/updates","dismissConfigurationNoticePath":"/settings/dismiss-notice/dependabot_configuration_notice","configurationNoticeDismissed":null},"displayName":"services.md","displayUrl":"https://github.com/lyda/kubernetes/blob/master/docs/services.md?raw=true","headerInfo":{"blobSize":"13 KB","deleteTooltip":"You must be signed in to make or propose changes","editTooltip":"You must be signed in to make or propose changes","ghDesktopPath":"https://desktop.github.com","isGitLfs":false,"onBranch":true,"shortPath":"1829c52","siteNavLoginPath":"/login?return_to=https%3A%2F%2Fgithub.com%2Flyda%2Fkubernetes%2Fblob%2Fmaster%2Fdocs%2Fservices.md","isCSV":false,"isRichtext":true,"toc":[{"level":1,"text":"Services in Kubernetes","anchor":"services-in-kubernetes","htmlText":"Services in Kubernetes"},{"level":2,"text":"Overview","anchor":"overview","htmlText":"Overview"},{"level":2,"text":"Defining a Service","anchor":"defining-a-service","htmlText":"Defining a Service"},{"level":3,"text":"Services without selectors","anchor":"services-without-selectors","htmlText":"Services without selectors"},{"level":2,"text":"Portals and service proxies","anchor":"portals-and-service-proxies","htmlText":"Portals and service proxies"},{"level":3,"text":"Why not use round-robin DNS?","anchor":"why-not-use-round-robin-dns","htmlText":"Why not use round-robin DNS?"},{"level":2,"text":"Discovering services","anchor":"discovering-services","htmlText":"Discovering services"},{"level":3,"text":"Environment variables","anchor":"environment-variables","htmlText":"Environment variables"},{"level":3,"text":"DNS","anchor":"dns","htmlText":"DNS"},{"level":2,"text":"Headless Services","anchor":"headless-services","htmlText":"Headless Services"},{"level":2,"text":"External Services","anchor":"external-services","htmlText":"External Services"},{"level":2,"text":"Choosing your own PortalIP address","anchor":"choosing-your-own-portalip-address","htmlText":"Choosing your own PortalIP address"},{"level":2,"text":"Shortcomings","anchor":"shortcomings","htmlText":"Shortcomings"},{"level":2,"text":"Future work","anchor":"future-work","htmlText":"Future work"},{"level":2,"text":"The gory details of portals","anchor":"the-gory-details-of-portals","htmlText":"The gory details of portals"},{"level":3,"text":"Avoiding collisions","anchor":"avoiding-collisions","htmlText":"Avoiding collisions"},{"level":3,"text":"IPs and Portals","anchor":"ips-and-portals","htmlText":"IPs and Portals"}],"lineInfo":{"truncatedLoc":"294","truncatedSloc":"230"},"mode":"file"},"image":false,"isCodeownersFile":null,"isPlain":false,"isValidLegacyIssueTemplate":false,"issueTemplate":null,"discussionTemplate":null,"language":"Markdown","languageID":222,"large":false,"planSupportInfo":{"repoIsFork":null,"repoOwnedByCurrentUser":null,"requestFullPath":"/lyda/kubernetes/blob/master/docs/services.md","showFreeOrgGatedFeatureMessage":null,"showPlanSupportBanner":null,"upgradeDataAttributes":null,"upgradePath":null},"publishBannersInfo":{"dismissActionNoticePath":"/settings/dismiss-notice/publish_action_from_dockerfile","releasePath":"/lyda/kubernetes/releases/new?marketplace=true","showPublishActionBanner":false},"rawBlobUrl":"https://github.com/lyda/kubernetes/raw/refs/heads/master/docs/services.md","renderImageOrRaw":false,"richText":"\u003carticle class=\"markdown-body entry-content container-lg\" itemprop=\"text\"\u003e\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch1 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eServices in Kubernetes\u003c/h1\u003e\u003ca id=\"user-content-services-in-kubernetes\" class=\"anchor\" aria-label=\"Permalink: Services in Kubernetes\" href=\"#services-in-kubernetes\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eOverview\u003c/h2\u003e\u003ca id=\"user-content-overview\" class=\"anchor\" aria-label=\"Permalink: Overview\" href=\"#overview\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eKubernetes \u003ca href=\"/lyda/kubernetes/blob/master/docs/Pods.md\"\u003e\u003ccode\u003ePods\u003c/code\u003e\u003c/a\u003e are mortal. They are born and they die, and they\nare not resurrected. \u003ca href=\"/lyda/kubernetes/blob/master/docs/replication-controller.md\"\u003e\u003ccode\u003eReplicationControllers\u003c/code\u003e\u003c/a\u003e in\nparticular create and destroy \u003ccode\u003ePods\u003c/code\u003e dynamically (e.g. when scaling up or down\nor when doing rolling updates). While each \u003ccode\u003ePod\u003c/code\u003e gets its own IP address, even\nthose IP addresses can not be relied upon to be stable over time. This leads to\na problem: if some set of \u003ccode\u003ePods\u003c/code\u003e (let's call them backends) provides\nfunctionality to other \u003ccode\u003ePods\u003c/code\u003e (let's call them frontends) inside the Kubernetes\ncluster, how do those frontends find out and keep track of which backends are\nin that set?\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eEnter \u003ccode\u003eServices\u003c/code\u003e.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eA Kubernetes \u003ccode\u003eService\u003c/code\u003e is an abstraction which defines a logical set of \u003ccode\u003ePods\u003c/code\u003e\nand a policy by which to access them - sometimes called a micro-service. The\nset of \u003ccode\u003ePods\u003c/code\u003e targetted by a \u003ccode\u003eService\u003c/code\u003e is determined by a \u003ca href=\"/lyda/kubernetes/blob/master/docs/labels.md\"\u003e\u003ccode\u003eLabel Selector\u003c/code\u003e\u003c/a\u003e.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eAs an example, consider an image-processing backend which is running with 3\nreplicas. Those replicas are fungible - frontends do not care which backend\nthey use. While the actual \u003ccode\u003ePods\u003c/code\u003e that compose the backend set may change, the\nfrontend clients should not need to manage that themselves. The \u003ccode\u003eService\u003c/code\u003e\nabstraction enables this decoupling.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eFor Kubernetes-native applications, Kubernetes offers a simple \u003ccode\u003eEndpoints\u003c/code\u003e API\nthat is updated whenever the set of \u003ccode\u003ePods\u003c/code\u003e in a \u003ccode\u003eService\u003c/code\u003e changes. For\nnon-native applications, Kubernetes offers a virtual-IP-based bridge to Services\nwhich redirects to the backend \u003ccode\u003ePods\u003c/code\u003e.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eDefining a Service\u003c/h2\u003e\u003ca id=\"user-content-defining-a-service\" class=\"anchor\" aria-label=\"Permalink: Defining a Service\" href=\"#defining-a-service\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eA \u003ccode\u003eService\u003c/code\u003e in Kubernetes is a REST object, similar to a \u003ccode\u003ePod\u003c/code\u003e. Like all of the\nREST objects, a \u003ccode\u003eService\u003c/code\u003e definition can be POSTed to the apiserver to create a\nnew instance. For example, suppose you have a set of \u003ccode\u003ePods\u003c/code\u003e that each expose\nport 9376 and carry a label \"app=MyApp\".\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-json notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\"{\n \u0026quot;kind\u0026quot;: \u0026quot;Service\u0026quot;,\n \u0026quot;apiVersion\u0026quot;: \u0026quot;v1beta1\u0026quot;,\n \u0026quot;id\u0026quot;: \u0026quot;myapp\u0026quot;,\n \u0026quot;selector\u0026quot;: {\n \u0026quot;app\u0026quot;: \u0026quot;MyApp\u0026quot;\n },\n \u0026quot;containerPort\u0026quot;: 9376,\n \u0026quot;protocol\u0026quot;: \u0026quot;TCP\u0026quot;,\n \u0026quot;port\u0026quot;: 80\n}\"\u003e\u003cpre\u003e{\n \u003cspan class=\"pl-ent\"\u003e\"kind\"\u003c/span\u003e: \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003eService\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e,\n \u003cspan class=\"pl-ent\"\u003e\"apiVersion\"\u003c/span\u003e: \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003ev1beta1\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e,\n \u003cspan class=\"pl-ent\"\u003e\"id\"\u003c/span\u003e: \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003emyapp\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e,\n \u003cspan class=\"pl-ent\"\u003e\"selector\"\u003c/span\u003e: {\n \u003cspan class=\"pl-ent\"\u003e\"app\"\u003c/span\u003e: \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003eMyApp\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e\n },\n \u003cspan class=\"pl-ent\"\u003e\"containerPort\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e9376\u003c/span\u003e,\n \u003cspan class=\"pl-ent\"\u003e\"protocol\"\u003c/span\u003e: \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003eTCP\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e,\n \u003cspan class=\"pl-ent\"\u003e\"port\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e80\u003c/span\u003e\n}\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThis specification will create a new \u003ccode\u003eService\u003c/code\u003e object named \"myapp\" which\ntargets TCP port 9376 on any \u003ccode\u003ePod\u003c/code\u003e with the \"app=MyApp\" label. Every \u003ccode\u003eService\u003c/code\u003e\nis also assigned a virtual IP address (called the \"portal IP\"), which is used by\nthe service proxies (see below). The \u003ccode\u003eService\u003c/code\u003e's selector will be evaluated\ncontinuously and the results will be posted in an \u003ccode\u003eEndpoints\u003c/code\u003e object also named\n\"myapp\".\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eServices without selectors\u003c/h3\u003e\u003ca id=\"user-content-services-without-selectors\" class=\"anchor\" aria-label=\"Permalink: Services without selectors\" href=\"#services-without-selectors\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eServices, in addition to providing abstractions to access \u003ccode\u003ePods\u003c/code\u003e, can also\nabstract any kind of backend. For example:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eyou want to have an external database cluster in production, but in test\nyou use your own databases.\u003c/li\u003e\n\u003cli\u003eyou want to point your service to a service in another\n\u003ca href=\"/lyda/kubernetes/blob/master/docs/namespaces.md\"\u003e\u003ccode\u003eNamespace\u003c/code\u003e\u003c/a\u003e or on another cluster.\u003c/li\u003e\n\u003cli\u003eyou are migrating your workload to Kubernetes and some of your backends run\noutside of Kubernetes.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003eIn any of these scenarios you can define a service without a selector:\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-json notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\" \u0026quot;kind\u0026quot;: \u0026quot;Service\u0026quot;,\n \u0026quot;apiVersion\u0026quot;: \u0026quot;v1beta1\u0026quot;,\n \u0026quot;id\u0026quot;: \u0026quot;myapp\u0026quot;,\n \u0026quot;port\u0026quot;: 80\"\u003e\u003cpre\u003e \u003cspan class=\"pl-ent\"\u003e\"kind\"\u003c/span\u003e: \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003eService\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e,\n \u003cspan class=\"pl-ent\"\u003e\"apiVersion\"\u003c/span\u003e: \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003ev1beta1\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e,\n \u003cspan class=\"pl-ent\"\u003e\"id\"\u003c/span\u003e: \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003emyapp\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e,\n \u003cspan class=\"pl-ent\"\u003e\"port\"\u003c/span\u003e: \u003cspan class=\"pl-c1\"\u003e80\u003c/span\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThen you can explicitly map the service to a specific endpoint(s):\u003c/p\u003e\n\u003cdiv class=\"highlight highlight-source-json notranslate position-relative overflow-auto\" dir=\"auto\" data-snippet-clipboard-copy-content=\" \u0026quot;kind\u0026quot;: \u0026quot;Endpoints\u0026quot;,\n \u0026quot;apiVersion\u0026quot;: \u0026quot;v1beta1\u0026quot;,\n \u0026quot;id\u0026quot;: \u0026quot;myapp\u0026quot;,\n \u0026quot;endpoints\u0026quot;: [\u0026quot;173.194.112.206:80\u0026quot;]\"\u003e\u003cpre\u003e \u003cspan class=\"pl-ent\"\u003e\"kind\"\u003c/span\u003e: \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003eEndpoints\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e,\n \u003cspan class=\"pl-ent\"\u003e\"apiVersion\"\u003c/span\u003e: \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003ev1beta1\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e,\n \u003cspan class=\"pl-ent\"\u003e\"id\"\u003c/span\u003e: \u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003emyapp\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e,\n \u003cspan class=\"pl-ent\"\u003e\"endpoints\"\u003c/span\u003e: [\u003cspan class=\"pl-s\"\u003e\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e173.194.112.206:80\u003cspan class=\"pl-pds\"\u003e\"\u003c/span\u003e\u003c/span\u003e]\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eAccessing a \u003ccode\u003eService\u003c/code\u003e without a selector works the same as if it had selector. The\ntraffic will be routed to endpoints defined by the user (\u003ccode\u003e173.194.112.206:80\u003c/code\u003e in\nthis example).\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003ePortals and service proxies\u003c/h2\u003e\u003ca id=\"user-content-portals-and-service-proxies\" class=\"anchor\" aria-label=\"Permalink: Portals and service proxies\" href=\"#portals-and-service-proxies\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eEvery node in a Kubernetes cluster runs a \u003ccode\u003ekube-proxy\u003c/code\u003e. This application\nwatches the Kubernetes master for the addition and removal of \u003ccode\u003eService\u003c/code\u003e\nand \u003ccode\u003eEndpoints\u003c/code\u003e objects. For each \u003ccode\u003eService\u003c/code\u003e it opens a port (random) on the\nlocal node. Any connections made to that port will be proxied to one of the\ncorresponding backend \u003ccode\u003ePods\u003c/code\u003e. Which backend to use is decided based on the\nAffinityPolicy of the \u003ccode\u003eService\u003c/code\u003e. Lastly, it installs iptables rules which\ncapture traffic to the \u003ccode\u003eService\u003c/code\u003e's \u003ccode\u003ePort\u003c/code\u003e on the \u003ccode\u003eService\u003c/code\u003e's portal IP and\nredirects that traffic to the previously described port.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe net result is that any traffic bound for the \u003ccode\u003eService\u003c/code\u003e is proxied to an\nappropriate backend without the clients knowing anything about Kubernetes or\n\u003ccode\u003eServices\u003c/code\u003e or \u003ccode\u003ePods\u003c/code\u003e.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003ca target=\"_blank\" rel=\"noopener noreferrer\" href=\"/lyda/kubernetes/blob/master/docs/services_overview.png\"\u003e\u003cimg src=\"/lyda/kubernetes/raw/master/docs/services_overview.png\" alt=\"Services overview diagram\" style=\"max-width: 100%;\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eWhy not use round-robin DNS?\u003c/h3\u003e\u003ca id=\"user-content-why-not-use-round-robin-dns\" class=\"anchor\" aria-label=\"Permalink: Why not use round-robin DNS?\" href=\"#why-not-use-round-robin-dns\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eA question that pops up every now and then is why we do all this stuff with\nportals rather than just use standard round-robin DNS. There are a few reasons:\u003c/p\u003e\n\u003cul dir=\"auto\"\u003e\n\u003cli\u003eThere is a long history of DNS libraries not respecting DNS TTLs and\ncaching the results of name lookups.\u003c/li\u003e\n\u003cli\u003eMany apps do DNS lookups once and cache the results.\u003c/li\u003e\n\u003cli\u003eEven if apps and libraries did proper re-resolution, the load of every\nclient re-resolving DNS over and over would be difficult to manage.\u003c/li\u003e\n\u003c/ul\u003e\n\u003cp dir=\"auto\"\u003eWe try to discourage users from doing things that hurt themselves. That said,\nif enough people ask for this, we may implement it as an alternative to portals.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eDiscovering services\u003c/h2\u003e\u003ca id=\"user-content-discovering-services\" class=\"anchor\" aria-label=\"Permalink: Discovering services\" href=\"#discovering-services\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eKubernetes supports 2 primary modes of finding a \u003ccode\u003eService\u003c/code\u003e - environment\nvariables and DNS.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eEnvironment variables\u003c/h3\u003e\u003ca id=\"user-content-environment-variables\" class=\"anchor\" aria-label=\"Permalink: Environment variables\" href=\"#environment-variables\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eWhen a \u003ccode\u003ePod\u003c/code\u003e is run on a \u003ccode\u003eNode\u003c/code\u003e, the kubelet adds a set of environment variables\nfor each active \u003ccode\u003eService\u003c/code\u003e. It supports both \u003ca href=\"https://docs.docker.com/userguide/dockerlinks/\" rel=\"nofollow\"\u003eDocker links\ncompatible\u003c/a\u003e variables (see\n\u003ca href=\"https://github.com/GoogleCloudPlatform/kubernetes/blob/master/pkg/kubelet/envvars/envvars.go#L49\"\u003emakeLinkVariables\u003c/a\u003e)\nand simpler \u003ccode\u003e{SVCNAME}_SERVICE_HOST\u003c/code\u003e and \u003ccode\u003e{SVCNAME}_SERVICE_PORT\u003c/code\u003e variables,\nwhere the Service name is upper-cased and dashes are converted to underscores.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eFor example, the Service \"redis-master\" which exposes TCP port 6379 and has been\nallocated portal IP address 10.0.0.11 produces the following environment\nvariables:\u003c/p\u003e\n\u003cdiv class=\"snippet-clipboard-content notranslate position-relative overflow-auto\" data-snippet-clipboard-copy-content=\"REDIS_MASTER_SERVICE_HOST=10.0.0.11\nREDIS_MASTER_SERVICE_PORT=6379\nREDIS_MASTER_PORT=tcp://10.0.0.11:6379\nREDIS_MASTER_PORT_6379_TCP=tcp://10.0.0.11:6379\nREDIS_MASTER_PORT_6379_TCP_PROTO=tcp\nREDIS_MASTER_PORT_6379_TCP_PORT=6379\nREDIS_MASTER_PORT_6379_TCP_ADDR=10.0.0.11\"\u003e\u003cpre class=\"notranslate\"\u003e\u003ccode\u003eREDIS_MASTER_SERVICE_HOST=10.0.0.11\nREDIS_MASTER_SERVICE_PORT=6379\nREDIS_MASTER_PORT=tcp://10.0.0.11:6379\nREDIS_MASTER_PORT_6379_TCP=tcp://10.0.0.11:6379\nREDIS_MASTER_PORT_6379_TCP_PROTO=tcp\nREDIS_MASTER_PORT_6379_TCP_PORT=6379\nREDIS_MASTER_PORT_6379_TCP_ADDR=10.0.0.11\n\u003c/code\u003e\u003c/pre\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003e\u003cem\u003eThis does imply an ordering requirement\u003c/em\u003e - any \u003ccode\u003eService\u003c/code\u003e that a \u003ccode\u003ePod\u003c/code\u003e wants to\naccess must be created before the \u003ccode\u003ePod\u003c/code\u003e itself, or else the environment\nvariables will not be populated. DNS does not have this restriction.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eDNS\u003c/h3\u003e\u003ca id=\"user-content-dns\" class=\"anchor\" aria-label=\"Permalink: DNS\" href=\"#dns\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eAn optional (though strongly recommended) cluster add-on is a DNS server. The\nDNS server watches the Kubernetes API for new \u003ccode\u003eServices\u003c/code\u003e and creates a set of\nDNS records for each. If DNS has been enabled throughout the cluster then all\n\u003ccode\u003ePods\u003c/code\u003e should be able to do name resolution of \u003ccode\u003eServices\u003c/code\u003e automatically.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eFor example, if you have a \u003ccode\u003eService\u003c/code\u003e called \"my-service\" in Kubernetes\n\u003ccode\u003eNamespace\u003c/code\u003e \"my-ns\" a DNS record for \"my-service.my-ns\" is created. \u003ccode\u003ePods\u003c/code\u003e\nwhich exist in the \"my-ns\" \u003ccode\u003eNamespace\u003c/code\u003e should be able to find it by simply doing\na name lookup for \"my-service\". \u003ccode\u003ePods\u003c/code\u003e which exist in other \u003ccode\u003eNamespaces\u003c/code\u003e must\nqualify the name as \"my-service.my-ns\". The result of these name lookups is the\nvirtual portal IP.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eHeadless Services\u003c/h2\u003e\u003ca id=\"user-content-headless-services\" class=\"anchor\" aria-label=\"Permalink: Headless Services\" href=\"#headless-services\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eUsers can create headless services by specifying \"None\" for the PortalIP.\nFor such services, an IP or DNS is not created and neither are service-specific\nenvironment variables for the pods created. Additionally, the kube proxy does not\nhandle these services and there is no load balancing or proxying being done by the\nplatform for them. The endpoints_controller would still create endpoint records in\netcd for such services, which are also made available via the API. These services\nalso take advantage of any UI, readiness probes, etc. that are applicable for\nservices in general.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThe tradeoff for a developer would be whether to couple to the Kubernetes API or to\na particular discovery system. This API would not preclude the self-registration\napproach, however, and adapters for other discovery systems could be built upon this\nAPI, as well.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eExternal Services\u003c/h2\u003e\u003ca id=\"user-content-external-services\" class=\"anchor\" aria-label=\"Permalink: External Services\" href=\"#external-services\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eFor some parts of your application (e.g. frontends) you may want to expose a\nService onto an external (outside of your cluster, maybe public internet) IP\naddress.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eOn cloud providers which support external load balancers, this should be as\nsimple as setting the \u003ccode\u003ecreateExternalLoadBalancer\u003c/code\u003e flag of the \u003ccode\u003eService\u003c/code\u003e to\n\u003ccode\u003etrue\u003c/code\u003e. This sets up a cloud-specific load balancer and populates the\n\u003ccode\u003epublicIPs\u003c/code\u003e field (see below). Traffic from the external load balancer will be\ndirected at the backend \u003ccode\u003ePods\u003c/code\u003e, though exactly how that works depends on the\ncloud provider.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eFor cloud providers which do not support external load balancers, there is\nanother approach that is a bit more \"do-it-yourself\" - the \u003ccode\u003epublicIPs\u003c/code\u003e field.\nAny address you put into the \u003ccode\u003epublicIPs\u003c/code\u003e array will be handled the same as the\nportal IP - the kube-proxy will install iptables rules which proxy traffic\nthrough to the backends. You are then responsible for ensuring that traffic to\nthose IPs gets sent to one or more Kubernetes \u003ccode\u003eNodes\u003c/code\u003e. As long as the traffic\narrives at a Node, it will be be subject to the iptables rules.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eAn example situation might be when a \u003ccode\u003eNode\u003c/code\u003e has both internal and an external\nnetwork interfaces. If you assign that \u003ccode\u003eNode\u003c/code\u003e's external IP as a \u003ccode\u003epublicIP\u003c/code\u003e, you\ncan then aim traffic at the \u003ccode\u003eService\u003c/code\u003e port on that \u003ccode\u003eNode\u003c/code\u003e and it will be proxied\nto the backends.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eChoosing your own PortalIP address\u003c/h2\u003e\u003ca id=\"user-content-choosing-your-own-portalip-address\" class=\"anchor\" aria-label=\"Permalink: Choosing your own PortalIP address\" href=\"#choosing-your-own-portalip-address\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eA user can specify their own \u003ccode\u003ePortalIP\u003c/code\u003e address as part of a service creation\nrequest. For example, if they already have an existing DNS entry that they wish\nto replace, or legacy systems that are configured for a specific IP address and difficult\nto re-configure. The \u003ccode\u003ePortalIP\u003c/code\u003e address that a user chooses must be a valid IP address\nand within the portal net CIDR range that is specified by flag to the API server. If\nthe PortalIP value is invalid, the apiserver returns a \u003ccode\u003e422\u003c/code\u003e HTTP status code to\nindicate that the value is invalid.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eShortcomings\u003c/h2\u003e\u003ca id=\"user-content-shortcomings\" class=\"anchor\" aria-label=\"Permalink: Shortcomings\" href=\"#shortcomings\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eWe expect that using iptables and userspace proxies for portals will work at\nsmall to medium scale, but may not scale to very large clusters with thousands\nof Services. See \u003ca href=\"https://github.com/GoogleCloudPlatform/kubernetes/issues/1107\" data-hovercard-type=\"issue\" data-hovercard-url=\"/kubernetes/kubernetes/issues/1107/hovercard\"\u003ethe original design proposal for\nportals\u003c/a\u003e for more\ndetails.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eUsing the kube-proxy obscures the source-IP of a packet accessing a \u003ccode\u003eService\u003c/code\u003e.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eFuture work\u003c/h2\u003e\u003ca id=\"user-content-future-work\" class=\"anchor\" aria-label=\"Permalink: Future work\" href=\"#future-work\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eIn the future we envision that the proxy policy can become more nuanced than\nsimple round robin balancing, for example master elected or sharded. We also\nenvision that some \u003ccode\u003eServices\u003c/code\u003e will have \"real\" load balancers, in which case the\nportal will simply transport the packets there.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThere's a\n\u003ca href=\"https://github.com/GoogleCloudPlatform/kubernetes/issues/3760\" data-hovercard-type=\"issue\" data-hovercard-url=\"/kubernetes/kubernetes/issues/3760/hovercard\"\u003eproposal\u003c/a\u003e to\neliminate userspace proxying in favor of doing it all in iptables. This should\nperform better, though is less flexible than arbitrary userspace code.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eWe hope to make the situation around external load balancers and public IPs\nsimpler and easier to comprehend.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch2 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eThe gory details of portals\u003c/h2\u003e\u003ca id=\"user-content-the-gory-details-of-portals\" class=\"anchor\" aria-label=\"Permalink: The gory details of portals\" href=\"#the-gory-details-of-portals\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eThe previous information should be sufficient for many people who just want to\nuse \u003ccode\u003eServices\u003c/code\u003e. However, there is a lot going on behind the scenes that may be\nworth understanding.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eAvoiding collisions\u003c/h3\u003e\u003ca id=\"user-content-avoiding-collisions\" class=\"anchor\" aria-label=\"Permalink: Avoiding collisions\" href=\"#avoiding-collisions\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eOne of the primary philosophies of Kubernetes is that users should not be\nexposed to situations that could cause their actions to fail through no fault\nof their own. In this situation, we are looking at network ports - users\nshould not have to choose a port number if that choice might collide with\nanother user. That is an isolation failure.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eIn order to allow users to choose a port number for their \u003ccode\u003eServices\u003c/code\u003e, we must\nensure that no two \u003ccode\u003eServices\u003c/code\u003e can collide. We do that by allocating each\n\u003ccode\u003eService\u003c/code\u003e its own IP address.\u003c/p\u003e\n\u003cdiv class=\"markdown-heading\" dir=\"auto\"\u003e\u003ch3 tabindex=\"-1\" class=\"heading-element\" dir=\"auto\"\u003eIPs and Portals\u003c/h3\u003e\u003ca id=\"user-content-ips-and-portals\" class=\"anchor\" aria-label=\"Permalink: IPs and Portals\" href=\"#ips-and-portals\"\u003e\u003csvg class=\"octicon octicon-link\" viewBox=\"0 0 16 16\" version=\"1.1\" width=\"16\" height=\"16\" aria-hidden=\"true\"\u003e\u003cpath d=\"m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z\"\u003e\u003c/path\u003e\u003c/svg\u003e\u003c/a\u003e\u003c/div\u003e\n\u003cp dir=\"auto\"\u003eUnlike \u003ccode\u003ePod\u003c/code\u003e IP addresses, which actually route to a fixed destination,\n\u003ccode\u003eService\u003c/code\u003e IPs are not actually answered by a single host. Instead, we use\n\u003ccode\u003eiptables\u003c/code\u003e (packet processing logic in Linux) to define \"virtual\" IP addresses\nwhich are transparently redirected as needed. We call the tuple of the\n\u003ccode\u003eService\u003c/code\u003e IP and the \u003ccode\u003eService\u003c/code\u003e port the \u003ccode\u003eportal\u003c/code\u003e. When clients connect to the\n\u003ccode\u003eportal\u003c/code\u003e, their traffic is automatically transported to an appropriate\nendpoint. The environment variables and DNS for \u003ccode\u003eServices\u003c/code\u003e are actually\npopulated in terms of the portal IP and port.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eAs an example, consider the image processing application described above.\nWhen the backend \u003ccode\u003eService\u003c/code\u003e is created, the Kubernetes master assigns a portal\nIP address, for example 10.0.0.1. Assuming the \u003ccode\u003eService\u003c/code\u003e port is 1234, the\nportal is 10.0.0.1:1234. The master stores that information, which is then\nobserved by all of the \u003ccode\u003ekube-proxy\u003c/code\u003e instances in the cluster. When a proxy\nsees a new portal, it opens a new random port, establishes an iptables redirect\nfrom the portal to this new port, and starts accepting connections on it.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eWhen a client connects to the portal the iptables rule kicks in, and redirects\nthe packets to the \u003ccode\u003eService proxy\u003c/code\u003e's own port. The \u003ccode\u003eService proxy\u003c/code\u003e chooses a\nbackend, and starts proxying traffic from the client to the backend.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003eThis means that \u003ccode\u003eService\u003c/code\u003e owners can choose any \u003ccode\u003eService\u003c/code\u003e port they want without\nrisk of collision. Clients can simply connect to an IP and port, without\nbeing aware of which \u003ccode\u003ePods\u003c/code\u003e they are actually accessing.\u003c/p\u003e\n\u003cp dir=\"auto\"\u003e\u003ca target=\"_blank\" rel=\"noopener noreferrer\" href=\"/lyda/kubernetes/blob/master/docs/services_detail.png\"\u003e\u003cimg src=\"/lyda/kubernetes/raw/master/docs/services_detail.png\" alt=\"Services detailed diagram\" style=\"max-width: 100%;\"\u003e\u003c/a\u003e\u003c/p\u003e\n\u003c/article\u003e","renderedFileInfo":null,"shortPath":null,"symbolsEnabled":true,"tabSize":8,"topBannersInfo":{"overridingGlobalFundingFile":false,"globalPreferredFundingPath":null,"showInvalidCitationWarning":false,"citationHelpUrl":"https://docs.github.com/github/creating-cloning-and-archiving-repositories/creating-a-repository-on-github/about-citation-files","actionsOnboardingTip":null},"truncated":false,"viewable":true,"workflowRedirectUrl":null,"symbols":null},"copilotInfo":null,"copilotAccessAllowed":false,"modelsAccessAllowed":false,"modelsRepoIntegrationEnabled":false,"csrf_tokens":{"/lyda/kubernetes/branches":{"post":"xpPqLU09868cQ1sRP-Tvbfbxli2mE14MtiRuoDDP9BfMFEzsIMY0CdKA7taWxewbBuHn5FplXYfXd9YwLUXwOQ"},"/repos/preferences":{"post":"gLDQ0p8QrxlwXkpBOBbfQLLHesuOXZAmTRLenoG_JN2vAzZfv-67i0ZoolZPT49cM7M08tFzgAKb02DH0hwG0Q"}}},"title":"kubernetes/docs/services.md at master · lyda/kubernetes","appPayload":{"helpUrl":"https://docs.github.com","findFileWorkerPath":"/assets-cdn/worker/find-file-worker-263cab1760dd.js","findInFileWorkerPath":"/assets-cdn/worker/find-in-file-worker-1b17b3e7786a.js","githubDevUrl":null,"enabled_features":{"code_nav_ui_events":false,"react_blob_overlay":false,"accessible_code_button":true}}}