Convert site to Hugo (#8316)
This commit converts content and layout to use Hugo.
This commit is contained in:
committed by
k8s-ci-robot
parent
7745f0e0c5
commit
7f3b633aa0
@@ -0,0 +1,5 @@
|
||||
---
|
||||
title: "Services, Load Balancing, and Networking"
|
||||
weight: 80
|
||||
---
|
||||
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
---
|
||||
reviewers:
|
||||
- rickypai
|
||||
- thockin
|
||||
title: Adding entries to Pod /etc/hosts with HostAliases
|
||||
---
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
Adding entries to a Pod's /etc/hosts file provides Pod-level override of hostname resolution when DNS and other options are not applicable. In 1.7, users can add these custom entries with the HostAliases field in PodSpec.
|
||||
|
||||
Modification not using HostAliases is not suggested because the file is managed by Kubelet and can be overwritten on during Pod creation/restart.
|
||||
|
||||
## Default Hosts File Content
|
||||
|
||||
Lets start an Nginx Pod which is assigned a Pod IP:
|
||||
|
||||
```shell
|
||||
$ kubectl run nginx --image nginx --generator=run-pod/v1
|
||||
pod "nginx" created
|
||||
|
||||
$ kubectl get pods --output=wide
|
||||
NAME READY STATUS RESTARTS AGE IP NODE
|
||||
nginx 1/1 Running 0 13s 10.200.0.4 worker0
|
||||
```
|
||||
|
||||
The hosts file content would look like this:
|
||||
|
||||
```shell
|
||||
$ kubectl exec nginx -- cat /etc/hosts
|
||||
# Kubernetes-managed hosts file.
|
||||
127.0.0.1 localhost
|
||||
::1 localhost ip6-localhost ip6-loopback
|
||||
fe00::0 ip6-localnet
|
||||
fe00::0 ip6-mcastprefix
|
||||
fe00::1 ip6-allnodes
|
||||
fe00::2 ip6-allrouters
|
||||
10.200.0.4 nginx
|
||||
```
|
||||
|
||||
by default, the hosts file only includes ipv4 and ipv6 boilerplates like `localhost` and its own hostname.
|
||||
|
||||
## Adding Additional Entries with HostAliases
|
||||
|
||||
In addition to the default boilerplate, we can add additional entries to the hosts file to resolve `foo.local`, `bar.local` to `127.0.0.1` and `foo.remote`, `bar.remote` to `10.1.2.3`, we can by adding HostAliases to the Pod under `.spec.hostAliases`:
|
||||
|
||||
{{< code file="hostaliases-pod.yaml" >}}
|
||||
|
||||
This Pod can be started with the following commands:
|
||||
|
||||
```shell
|
||||
$ kubectl apply -f hostaliases-pod.yaml
|
||||
pod "hostaliases-pod" created
|
||||
|
||||
$ kubectl get pod -o=wide
|
||||
NAME READY STATUS RESTARTS AGE IP NODE
|
||||
hostaliases-pod 0/1 Completed 0 6s 10.244.135.10 node3
|
||||
```
|
||||
|
||||
The hosts file content would look like this:
|
||||
|
||||
```shell
|
||||
$ kubectl logs hostaliases-pod
|
||||
# Kubernetes-managed hosts file.
|
||||
127.0.0.1 localhost
|
||||
::1 localhost ip6-localhost ip6-loopback
|
||||
fe00::0 ip6-localnet
|
||||
fe00::0 ip6-mcastprefix
|
||||
fe00::1 ip6-allnodes
|
||||
fe00::2 ip6-allrouters
|
||||
10.244.135.10 hostaliases-pod
|
||||
127.0.0.1 foo.local
|
||||
127.0.0.1 bar.local
|
||||
10.1.2.3 foo.remote
|
||||
10.1.2.3 bar.remote
|
||||
```
|
||||
|
||||
With the additional entries specified at the bottom.
|
||||
|
||||
## Limitations
|
||||
|
||||
HostAlias is only supported in 1.7+.
|
||||
|
||||
HostAlias support in 1.7 is limited to non-hostNetwork Pods because kubelet only manages the hosts file for non-hostNetwork Pods.
|
||||
|
||||
In 1.8, HostAlias is supported for all Pods regardless of network configuration.
|
||||
|
||||
## Why Does Kubelet Manage the Hosts File?
|
||||
|
||||
Kubelet [manages](https://github.com/kubernetes/kubernetes/issues/14633) the hosts file for each container of the Pod to prevent Docker from [modifying](https://github.com/moby/moby/issues/17190) the file after the containers have already been started.
|
||||
|
||||
Because of the managed-nature of the file, any user-written content will be overwritten whenever the hosts file is remounted by Kubelet in the event of a container restart or a Pod reschedule. Thus, it is not suggested to modify the contents of the file.
|
||||
@@ -0,0 +1,327 @@
|
||||
---
|
||||
reviewers:
|
||||
- caesarxuchao
|
||||
- lavalamp
|
||||
- thockin
|
||||
title: Connecting Applications with Services
|
||||
---
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## The Kubernetes model for connecting containers
|
||||
|
||||
Now that you have a continuously running, replicated application you can expose it on a network. Before discussing the Kubernetes approach to networking, it is worthwhile to contrast it with the "normal" way networking works with Docker.
|
||||
|
||||
By default, Docker uses host-private networking, so containers can talk to other containers only if they are on the same machine. In order for Docker containers to communicate across nodes, there must be allocated ports on the machine’s own IP address, which are then forwarded or proxied to the containers. This obviously means that containers must either coordinate which ports they use very carefully or ports must be allocated dynamically.
|
||||
|
||||
Coordinating ports across multiple developers is very difficult to do at scale and exposes users to cluster-level issues outside of their control. Kubernetes assumes that pods can communicate with other pods, regardless of which host they land on. We give every pod its own cluster-private-IP address so you do not need to explicitly create links between pods or mapping container ports to host ports. This means that containers within a Pod can all reach each other's ports on localhost, and all pods in a cluster can see each other without NAT. The rest of this document will elaborate on how you can run reliable services on such a networking model.
|
||||
|
||||
This guide uses a simple nginx server to demonstrate proof of concept. The same principles are embodied in a more complete [Jenkins CI application](http://blog.kubernetes.io/2015/07/strong-simple-ssl-for-kubernetes.html).
|
||||
|
||||
## Exposing pods to the cluster
|
||||
|
||||
We did this in a previous example, but let's do it once again and focus on the networking perspective. Create an nginx pod, and note that it has a container port specification:
|
||||
|
||||
{{< code file="run-my-nginx.yaml" >}}
|
||||
|
||||
This makes it accessible from any node in your cluster. Check the nodes the pod is running on:
|
||||
|
||||
```shell
|
||||
$ kubectl create -f ./run-my-nginx.yaml
|
||||
$ kubectl get pods -l run=my-nginx -o wide
|
||||
NAME READY STATUS RESTARTS AGE IP NODE
|
||||
my-nginx-3800858182-jr4a2 1/1 Running 0 13s 10.244.3.4 kubernetes-minion-905m
|
||||
my-nginx-3800858182-kna2y 1/1 Running 0 13s 10.244.2.5 kubernetes-minion-ljyd
|
||||
```
|
||||
|
||||
Check your pods' IPs:
|
||||
|
||||
```shell
|
||||
$ kubectl get pods -l run=my-nginx -o yaml | grep podIP
|
||||
podIP: 10.244.3.4
|
||||
podIP: 10.244.2.5
|
||||
```
|
||||
|
||||
You should be able to ssh into any node in your cluster and curl both IPs. Note that the containers are *not* using port 80 on the node, nor are there any special NAT rules to route traffic to the pod. This means you can run multiple nginx pods on the same node all using the same containerPort and access them from any other pod or node in your cluster using IP. Like Docker, ports can still be published to the host node's interfaces, but the need for this is radically diminished because of the networking model.
|
||||
|
||||
You can read more about [how we achieve this](/docs/concepts/cluster-administration/networking/#how-to-achieve-this) if you're curious.
|
||||
|
||||
## Creating a Service
|
||||
|
||||
So we have pods running nginx in a flat, cluster wide, address space. In theory, you could talk to these pods directly, but what happens when a node dies? The pods die with it, and the Deployment will create new ones, with different IPs. This is the problem a Service solves.
|
||||
|
||||
A Kubernetes Service is an abstraction which defines a logical set of Pods running somewhere in your cluster, that all provide the same functionality. When created, each Service is assigned a unique IP address (also called clusterIP). This address is tied to the lifespan of the Service, and will not change while the Service is alive. Pods can be configured to talk to the Service, and know that communication to the Service will be automatically load-balanced out to some pod that is a member of the Service.
|
||||
|
||||
You can create a Service for your 2 nginx replicas with `kubectl expose`:
|
||||
|
||||
```shell
|
||||
$ kubectl expose deployment/my-nginx
|
||||
service "my-nginx" exposed
|
||||
```
|
||||
|
||||
This is equivalent to `kubectl create -f` the following yaml:
|
||||
|
||||
{{< code file="nginx-svc.yaml" >}}
|
||||
|
||||
This specification will create a Service which targets TCP port 80 on any Pod with the `run: my-nginx` label, and expose it on an abstracted Service port (`targetPort`: is the port the container accepts traffic on, `port`: is the abstracted Service port, which can be any port other pods use to access the Service). View [service API object](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#service-v1-core) to see the list of supported fields in service definition.
|
||||
Check your Service:
|
||||
|
||||
```shell
|
||||
$ kubectl get svc my-nginx
|
||||
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
|
||||
my-nginx 10.0.162.149 <none> 80/TCP 21s
|
||||
```
|
||||
|
||||
As mentioned previously, a Service is backed by a group of pods. These pods are exposed through `endpoints`. The Service's selector will be evaluated continuously and the results will be POSTed to an Endpoints object also named `my-nginx`. When a pod dies, it is automatically removed from the endpoints, and new pods matching the Service's selector will automatically get added to the endpoints. Check the endpoints, and note that the IPs are the same as the pods created in the first step:
|
||||
|
||||
```shell
|
||||
$ kubectl describe svc my-nginx
|
||||
Name: my-nginx
|
||||
Namespace: default
|
||||
Labels: run=my-nginx
|
||||
Annotations: <none>
|
||||
Selector: run=my-nginx
|
||||
Type: ClusterIP
|
||||
IP: 10.0.162.149
|
||||
Port: <unset> 80/TCP
|
||||
Endpoints: 10.244.2.5:80,10.244.3.4:80
|
||||
Session Affinity: None
|
||||
Events: <none>
|
||||
|
||||
$ kubectl get ep my-nginx
|
||||
NAME ENDPOINTS AGE
|
||||
my-nginx 10.244.2.5:80,10.244.3.4:80 1m
|
||||
```
|
||||
|
||||
You should now be able to curl the nginx Service on `<CLUSTER-IP>:<PORT>` from any node in your cluster. Note that the Service IP is completely virtual, it never hits the wire, if you're curious about how this works you can read more about the [service proxy](/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies).
|
||||
|
||||
## Accessing the Service
|
||||
|
||||
Kubernetes supports 2 primary modes of finding a Service - environment variables and DNS. The former works out of the box while the latter requires the [kube-dns cluster addon](http://releases.k8s.io/{{< param "githubbranch" >}}/cluster/addons/dns/README.md).
|
||||
|
||||
### Environment Variables
|
||||
|
||||
When a Pod runs on a Node, the kubelet adds a set of environment variables for each active Service. This introduces an ordering problem. To see why, inspect the environment of your running nginx pods (your pod name will be different):
|
||||
|
||||
```shell
|
||||
$ kubectl exec my-nginx-3800858182-jr4a2 -- printenv | grep SERVICE
|
||||
KUBERNETES_SERVICE_HOST=10.0.0.1
|
||||
KUBERNETES_SERVICE_PORT=443
|
||||
KUBERNETES_SERVICE_PORT_HTTPS=443
|
||||
```
|
||||
|
||||
Note there's no mention of your Service. This is because you created the replicas before the Service. Another disadvantage of doing this is that the scheduler might put both pods on the same machine, which will take your entire Service down if it dies. We can do this the right way by killing the 2 pods and waiting for the Deployment to recreate them. This time around the Service exists *before* the replicas. This will give you scheduler-level Service spreading of your pods (provided all your nodes have equal capacity), as well as the right environment variables:
|
||||
|
||||
```shell
|
||||
$ kubectl scale deployment my-nginx --replicas=0; kubectl scale deployment my-nginx --replicas=2;
|
||||
|
||||
$ kubectl get pods -l run=my-nginx -o wide
|
||||
NAME READY STATUS RESTARTS AGE IP NODE
|
||||
my-nginx-3800858182-e9ihh 1/1 Running 0 5s 10.244.2.7 kubernetes-minion-ljyd
|
||||
my-nginx-3800858182-j4rm4 1/1 Running 0 5s 10.244.3.8 kubernetes-minion-905m
|
||||
```
|
||||
|
||||
You may notice that the pods have different names, since they are killed and recreated.
|
||||
|
||||
```shell
|
||||
$ kubectl exec my-nginx-3800858182-e9ihh -- printenv | grep SERVICE
|
||||
KUBERNETES_SERVICE_PORT=443
|
||||
MY_NGINX_SERVICE_HOST=10.0.162.149
|
||||
KUBERNETES_SERVICE_HOST=10.0.0.1
|
||||
MY_NGINX_SERVICE_PORT=80
|
||||
KUBERNETES_SERVICE_PORT_HTTPS=443
|
||||
```
|
||||
|
||||
### DNS
|
||||
|
||||
Kubernetes offers a DNS cluster addon Service that uses skydns to automatically assign dns names to other Services. You can check if it's running on your cluster:
|
||||
|
||||
```shell
|
||||
$ kubectl get services kube-dns --namespace=kube-system
|
||||
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
|
||||
kube-dns 10.0.0.10 <none> 53/UDP,53/TCP 8m
|
||||
```
|
||||
|
||||
If it isn't running, you can [enable it](http://releases.k8s.io/{{< param "githubbranch" >}}/cluster/addons/dns/README.md#how-do-i-configure-it). The rest of this section will assume you have a Service with a long lived IP (my-nginx), and a dns server that has assigned a name to that IP (the kube-dns cluster addon), so you can talk to the Service from any pod in your cluster using standard methods (e.g. gethostbyname). Let's run another curl application to test this:
|
||||
|
||||
```shell
|
||||
$ kubectl run curl --image=radial/busyboxplus:curl -i --tty
|
||||
Waiting for pod default/curl-131556218-9fnch to be running, status is Pending, pod ready: false
|
||||
Hit enter for command prompt
|
||||
```
|
||||
|
||||
Then, hit enter and run `nslookup my-nginx`:
|
||||
|
||||
```shell
|
||||
[ root@curl-131556218-9fnch:/ ]$ nslookup my-nginx
|
||||
Server: 10.0.0.10
|
||||
Address 1: 10.0.0.10
|
||||
|
||||
Name: my-nginx
|
||||
Address 1: 10.0.162.149
|
||||
```
|
||||
|
||||
## Securing the Service
|
||||
|
||||
Till now we have only accessed the nginx server from within the cluster. Before exposing the Service to the internet, you want to make sure the communication channel is secure. For this, you will need:
|
||||
|
||||
* Self signed certificates for https (unless you already have an identity certificate)
|
||||
* An nginx server configured to use the certificates
|
||||
* A [secret](/docs/concepts/configuration/secret/) that makes the certificates accessible to pods
|
||||
|
||||
You can acquire all these from the [nginx https example](https://github.com/kubernetes/examples/tree/{{< param "githubbranch" >}}/staging/https-nginx/). This requires having go and make tools installed. If you don't want to install those, then follow the manual steps later. In short:
|
||||
|
||||
```shell
|
||||
$ make keys secret KEY=/tmp/nginx.key CERT=/tmp/nginx.crt SECRET=/tmp/secret.json
|
||||
$ kubectl create -f /tmp/secret.json
|
||||
secret "nginxsecret" created
|
||||
$ kubectl get secrets
|
||||
NAME TYPE DATA AGE
|
||||
default-token-il9rc kubernetes.io/service-account-token 1 1d
|
||||
nginxsecret Opaque 2 1m
|
||||
```
|
||||
Following are the manual steps to follow in case you run into problems running make (on windows for example):
|
||||
|
||||
```shell
|
||||
#create a public private key pair
|
||||
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /d/tmp/nginx.key -out /d/tmp/nginx.crt -subj "/CN=my-nginx/O=my-nginx"
|
||||
#convert the keys to base64 encoding
|
||||
cat /d/tmp/nginx.crt | base64
|
||||
cat /d/tmp/nginx.key | base64
|
||||
```
|
||||
Use the output from the previous commands to create a yaml file as follows. The base64 encoded value should all be on a single line.
|
||||
|
||||
```yaml
|
||||
apiVersion: "v1"
|
||||
kind: "Secret"
|
||||
metadata:
|
||||
name: "nginxsecret"
|
||||
namespace: "default"
|
||||
data:
|
||||
nginx.crt: "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURIekNDQWdlZ0F3SUJBZ0lKQUp5M3lQK0pzMlpJTUEwR0NTcUdTSWIzRFFFQkJRVUFNQ1l4RVRBUEJnTlYKQkFNVENHNW5hVzU0YzNaak1SRXdEd1lEVlFRS0V3aHVaMmx1ZUhOMll6QWVGdzB4TnpFd01qWXdOekEzTVRKYQpGdzB4T0RFd01qWXdOekEzTVRKYU1DWXhFVEFQQmdOVkJBTVRDRzVuYVc1NGMzWmpNUkV3RHdZRFZRUUtFd2h1CloybHVlSE4yWXpDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBSjFxSU1SOVdWM0IKMlZIQlRMRmtobDRONXljMEJxYUhIQktMSnJMcy8vdzZhU3hRS29GbHlJSU94NGUrMlN5ajBFcndCLzlYTnBwbQppeW1CL3JkRldkOXg5UWhBQUxCZkVaTmNiV3NsTVFVcnhBZW50VWt1dk1vLzgvMHRpbGhjc3paenJEYVJ4NEo5Ci82UVRtVVI3a0ZTWUpOWTVQZkR3cGc3dlVvaDZmZ1Voam92VG42eHNVR0M2QURVODBpNXFlZWhNeVI1N2lmU2YKNHZpaXdIY3hnL3lZR1JBRS9mRTRqakxCdmdONjc2SU90S01rZXV3R0ljNDFhd05tNnNTSzRqYUNGeGpYSnZaZQp2by9kTlEybHhHWCtKT2l3SEhXbXNhdGp4WTRaNVk3R1ZoK0QrWnYvcW1mMFgvbVY0Rmo1NzV3ajFMWVBocWtsCmdhSXZYRyt4U1FVQ0F3RUFBYU5RTUU0d0hRWURWUjBPQkJZRUZPNG9OWkI3YXc1OUlsYkROMzhIYkduYnhFVjcKTUI4R0ExVWRJd1FZTUJhQUZPNG9OWkI3YXc1OUlsYkROMzhIYkduYnhFVjdNQXdHQTFVZEV3UUZNQU1CQWY4dwpEUVlKS29aSWh2Y05BUUVGQlFBRGdnRUJBRVhTMW9FU0lFaXdyMDhWcVA0K2NwTHI3TW5FMTducDBvMm14alFvCjRGb0RvRjdRZnZqeE04Tzd2TjB0clcxb2pGSW0vWDE4ZnZaL3k4ZzVaWG40Vm8zc3hKVmRBcStNZC9jTStzUGEKNmJjTkNUekZqeFpUV0UrKzE5NS9zb2dmOUZ3VDVDK3U2Q3B5N0M3MTZvUXRUakViV05VdEt4cXI0Nk1OZWNCMApwRFhWZmdWQTRadkR4NFo3S2RiZDY5eXM3OVFHYmg5ZW1PZ05NZFlsSUswSGt0ejF5WU4vbVpmK3FqTkJqbWZjCkNnMnlwbGQ0Wi8rUUNQZjl3SkoybFIrY2FnT0R4elBWcGxNSEcybzgvTHFDdnh6elZPUDUxeXdLZEtxaUMwSVEKQ0I5T2wwWW5scE9UNEh1b2hSUzBPOStlMm9KdFZsNUIyczRpbDlhZ3RTVXFxUlU9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K"
|
||||
nginx.key: "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRQ2RhaURFZlZsZHdkbFIKd1V5eFpJWmVEZWNuTkFhbWh4d1NpeWF5N1AvOE9ta3NVQ3FCWmNpQ0RzZUh2dGtzbzlCSzhBZi9WemFhWm9zcApnZjYzUlZuZmNmVUlRQUN3WHhHVFhHMXJKVEVGSzhRSHA3VkpMcnpLUC9QOUxZcFlYTE0yYzZ3MmtjZUNmZitrCkU1bEVlNUJVbUNUV09UM3c4S1lPNzFLSWVuNEZJWTZMMDUrc2JGQmd1Z0ExUE5JdWFubm9UTWtlZTRuMG4rTDQKb3NCM01ZUDhtQmtRQlAzeE9JNHl3YjREZXUraURyU2pKSHJzQmlIT05Xc0RadXJFaXVJMmdoY1kxeWIyWHI2UAozVFVOcGNSbC9pVG9zQngxcHJHclk4V09HZVdPeGxZZmcvbWIvNnBuOUYvNWxlQlkrZStjSTlTMkQ0YXBKWUdpCkwxeHZzVWtGQWdNQkFBRUNnZ0VBZFhCK0xkbk8ySElOTGo5bWRsb25IUGlHWWVzZ294RGQwci9hQ1Zkank4dlEKTjIwL3FQWkUxek1yall6Ry9kVGhTMmMwc0QxaTBXSjdwR1lGb0xtdXlWTjltY0FXUTM5SjM0VHZaU2FFSWZWNgo5TE1jUHhNTmFsNjRLMFRVbUFQZytGam9QSFlhUUxLOERLOUtnNXNrSE5pOWNzMlY5ckd6VWlVZWtBL0RBUlBTClI3L2ZjUFBacDRuRWVBZmI3WTk1R1llb1p5V21SU3VKdlNyblBESGtUdW1vVlVWdkxMRHRzaG9reUxiTWVtN3oKMmJzVmpwSW1GTHJqbGtmQXlpNHg0WjJrV3YyMFRrdWtsZU1jaVlMbjk4QWxiRi9DSmRLM3QraTRoMTVlR2ZQegpoTnh3bk9QdlVTaDR2Q0o3c2Q5TmtEUGJvS2JneVVHOXBYamZhRGR2UVFLQmdRRFFLM01nUkhkQ1pKNVFqZWFKClFGdXF4cHdnNzhZTjQyL1NwenlUYmtGcVFoQWtyczJxWGx1MDZBRzhrZzIzQkswaHkzaE9zSGgxcXRVK3NHZVAKOWRERHBsUWV0ODZsY2FlR3hoc0V0L1R6cEdtNGFKSm5oNzVVaTVGZk9QTDhPTm1FZ3MxMVRhUldhNzZxelRyMgphRlpjQ2pWV1g0YnRSTHVwSkgrMjZnY0FhUUtCZ1FEQmxVSUUzTnNVOFBBZEYvL25sQVB5VWs1T3lDdWc3dmVyClUycXlrdXFzYnBkSi9hODViT1JhM05IVmpVM25uRGpHVHBWaE9JeXg5TEFrc2RwZEFjVmxvcG9HODhXYk9lMTAKMUdqbnkySmdDK3JVWUZiRGtpUGx1K09IYnRnOXFYcGJMSHBzUVpsMGhucDBYSFNYVm9CMUliQndnMGEyOFVadApCbFBtWmc2d1BRS0JnRHVIUVV2SDZHYTNDVUsxNFdmOFhIcFFnMU16M2VvWTBPQm5iSDRvZUZKZmcraEppSXlnCm9RN3hqWldVR3BIc3AyblRtcHErQWlSNzdyRVhsdlhtOElVU2FsbkNiRGlKY01Pc29RdFBZNS9NczJMRm5LQTQKaENmL0pWb2FtZm1nZEN0ZGtFMXNINE9MR2lJVHdEbTRpb0dWZGIwMllnbzFyb2htNUpLMUI3MkpBb0dBUW01UQpHNDhXOTVhL0w1eSt5dCsyZ3YvUHM2VnBvMjZlTzRNQ3lJazJVem9ZWE9IYnNkODJkaC8xT2sybGdHZlI2K3VuCnc1YytZUXRSTHlhQmd3MUtpbGhFZDBKTWU3cGpUSVpnQWJ0LzVPbnlDak9OVXN2aDJjS2lrQ1Z2dTZsZlBjNkQKckliT2ZIaHhxV0RZK2Q1TGN1YSt2NzJ0RkxhenJsSlBsRzlOZHhrQ2dZRUF5elIzT3UyMDNRVVV6bUlCRkwzZAp4Wm5XZ0JLSEo3TnNxcGFWb2RjL0d5aGVycjFDZzE2MmJaSjJDV2RsZkI0VEdtUjZZdmxTZEFOOFRwUWhFbUtKCnFBLzVzdHdxNWd0WGVLOVJmMWxXK29xNThRNTBxMmk1NVdUTThoSDZhTjlaMTltZ0FGdE5VdGNqQUx2dFYxdEYKWSs4WFJkSHJaRnBIWll2NWkwVW1VbGc9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K"
|
||||
```
|
||||
Now create the secrets using the file:
|
||||
|
||||
```shell
|
||||
$ kubectl create -f nginxsecrets.yaml
|
||||
$ kubectl get secrets
|
||||
NAME TYPE DATA AGE
|
||||
default-token-il9rc kubernetes.io/service-account-token 1 1d
|
||||
nginxsecret Opaque 2 1m
|
||||
```
|
||||
|
||||
Now modify your nginx replicas to start an https server using the certificate in the secret, and the Service, to expose both ports (80 and 443):
|
||||
|
||||
{{< code file="nginx-secure-app.yaml" >}}
|
||||
|
||||
Noteworthy points about the nginx-secure-app manifest:
|
||||
|
||||
- It contains both Deployment and Service specification in the same file.
|
||||
- The [nginx server](https://github.com/kubernetes/examples/tree/{{< param "githubbranch" >}}/staging/https-nginx/default.conf) serves http traffic on port 80 and https traffic on 443, and nginx Service exposes both ports.
|
||||
- Each container has access to the keys through a volume mounted at /etc/nginx/ssl. This is setup *before* the nginx server is started.
|
||||
|
||||
```shell
|
||||
$ kubectl delete deployments,svc my-nginx; kubectl create -f ./nginx-secure-app.yaml
|
||||
```
|
||||
|
||||
At this point you can reach the nginx server from any node.
|
||||
|
||||
```shell
|
||||
$ kubectl get pods -o yaml | grep -i podip
|
||||
podIP: 10.244.3.5
|
||||
node $ curl -k https://10.244.3.5
|
||||
...
|
||||
<h1>Welcome to nginx!</h1>
|
||||
```
|
||||
|
||||
Note how we supplied the `-k` parameter to curl in the last step, this is because we don't know anything about the pods running nginx at certificate generation time,
|
||||
so we have to tell curl to ignore the CName mismatch. By creating a Service we linked the CName used in the certificate with the actual DNS name used by pods during Service lookup.
|
||||
Let's test this from a pod (the same secret is being reused for simplicity, the pod only needs nginx.crt to access the Service):
|
||||
|
||||
{{< code file="curlpod.yaml" >}}
|
||||
|
||||
```shell
|
||||
$ kubectl create -f ./curlpod.yaml
|
||||
$ kubectl get pods -l app=curlpod
|
||||
NAME READY STATUS RESTARTS AGE
|
||||
curl-deployment-1515033274-1410r 1/1 Running 0 1m
|
||||
$ kubectl exec curl-deployment-1515033274-1410r -- curl https://my-nginx --cacert /etc/nginx/ssl/nginx.crt
|
||||
...
|
||||
<title>Welcome to nginx!</title>
|
||||
...
|
||||
```
|
||||
|
||||
## Exposing the Service
|
||||
|
||||
For some parts of your applications you may want to expose a Service onto an external IP address. Kubernetes supports two ways of doing this: NodePorts and LoadBalancers. The Service created in the last section already used `NodePort`, so your nginx https replica is ready to serve traffic on the internet if your node has a public IP.
|
||||
|
||||
```shell
|
||||
$ kubectl get svc my-nginx -o yaml | grep nodePort -C 5
|
||||
uid: 07191fb3-f61a-11e5-8ae5-42010af00002
|
||||
spec:
|
||||
clusterIP: 10.0.162.149
|
||||
ports:
|
||||
- name: http
|
||||
nodePort: 31704
|
||||
port: 8080
|
||||
protocol: TCP
|
||||
targetPort: 80
|
||||
- name: https
|
||||
nodePort: 32453
|
||||
port: 443
|
||||
protocol: TCP
|
||||
targetPort: 443
|
||||
selector:
|
||||
run: my-nginx
|
||||
|
||||
$ kubectl get nodes -o yaml | grep ExternalIP -C 1
|
||||
- address: 104.197.41.11
|
||||
type: ExternalIP
|
||||
allocatable:
|
||||
--
|
||||
- address: 23.251.152.56
|
||||
type: ExternalIP
|
||||
allocatable:
|
||||
...
|
||||
|
||||
$ curl https://<EXTERNAL-IP>:<NODE-PORT> -k
|
||||
...
|
||||
<h1>Welcome to nginx!</h1>
|
||||
```
|
||||
|
||||
Let's now recreate the Service to use a cloud load balancer, just change the `Type` of `my-nginx` Service from `NodePort` to `LoadBalancer`:
|
||||
|
||||
```shell
|
||||
$ kubectl edit svc my-nginx
|
||||
$ kubectl get svc my-nginx
|
||||
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
|
||||
my-nginx 10.0.162.149 162.222.184.144 80/TCP,81/TCP,82/TCP 21s
|
||||
|
||||
$ curl https://<EXTERNAL-IP> -k
|
||||
...
|
||||
<title>Welcome to nginx!</title>
|
||||
```
|
||||
|
||||
The IP address in the `EXTERNAL-IP` column is the one that is available on the public internet. The `CLUSTER-IP` is only available inside your
|
||||
cluster/private cloud network.
|
||||
|
||||
Note that on AWS, type `LoadBalancer` creates an ELB, which uses a (long)
|
||||
hostname, not an IP. It's too long to fit in the standard `kubectl get svc`
|
||||
output, in fact, so you'll need to do `kubectl describe service my-nginx` to
|
||||
see it. You'll see something like this:
|
||||
|
||||
```shell
|
||||
$ kubectl describe service my-nginx
|
||||
...
|
||||
LoadBalancer Ingress: a320587ffd19711e5a37606cf4a74574-1142138393.us-east-1.elb.amazonaws.com
|
||||
...
|
||||
```
|
||||
|
||||
## Further reading
|
||||
|
||||
Kubernetes also supports Federated Services, which can span multiple
|
||||
clusters and cloud providers, to provide increased availability,
|
||||
better fault tolerance and greater scalability for your services. See
|
||||
the [Federated Services User Guide](/docs/concepts/cluster-administration/federation-service-discovery/)
|
||||
for further information.
|
||||
@@ -0,0 +1,28 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: curl-deployment
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
app: curlpod
|
||||
replicas: 1
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: curlpod
|
||||
spec:
|
||||
volumes:
|
||||
- name: secret-volume
|
||||
secret:
|
||||
secretName: nginxsecret
|
||||
containers:
|
||||
- name: curlpod
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- while true; do sleep 1; done
|
||||
image: radial/busyboxplus:curl
|
||||
volumeMounts:
|
||||
- mountPath: /etc/nginx/ssl
|
||||
name: secret-volume
|
||||
@@ -0,0 +1,20 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
namespace: default
|
||||
name: dns-example
|
||||
spec:
|
||||
containers:
|
||||
- name: test
|
||||
image: nginx
|
||||
dnsPolicy: "None"
|
||||
dnsConfig:
|
||||
nameservers:
|
||||
- 1.2.3.4
|
||||
searches:
|
||||
- ns1.svc.cluster.local
|
||||
- my.dns.search.suffix
|
||||
options:
|
||||
- name: ndots
|
||||
value: "2"
|
||||
- name: edns0
|
||||
@@ -0,0 +1,264 @@
|
||||
---
|
||||
reviewers:
|
||||
- davidopp
|
||||
- thockin
|
||||
title: DNS for Services and Pods
|
||||
content_template: templates/concept
|
||||
---
|
||||
{{% capture overview %}}
|
||||
This page provides an overview of DNS support by Kubernetes.
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture body %}}
|
||||
|
||||
## Introduction
|
||||
|
||||
Kubernetes DNS schedules a DNS Pod and Service on the cluster, and configures
|
||||
the kubelets to tell individual containers to use the DNS Service's IP to
|
||||
resolve DNS names.
|
||||
|
||||
### What things get DNS names?
|
||||
|
||||
Every Service defined in the cluster (including the DNS server itself) is
|
||||
assigned a DNS name. By default, a client Pod's DNS search list will
|
||||
include the Pod's own namespace and the cluster's default domain. This is best
|
||||
illustrated by example:
|
||||
|
||||
Assume a Service named `foo` in the Kubernetes namespace `bar`. A Pod running
|
||||
in namespace `bar` can look up this service by simply doing a DNS query for
|
||||
`foo`. A Pod running in namespace `quux` can look up this service by doing a
|
||||
DNS query for `foo.bar`.
|
||||
|
||||
The following sections detail the supported record types and layout that is
|
||||
supported. Any other layout or names or queries that happen to work are
|
||||
considered implementation details and are subject to change without warning.
|
||||
For more up-to-date specification, see
|
||||
[Kubernetes DNS-Based Service Discovery](https://github.com/kubernetes/dns/blob/master/docs/specification.md).
|
||||
|
||||
## Services
|
||||
|
||||
### A records
|
||||
|
||||
"Normal" (not headless) Services are assigned a DNS A record for a name of the
|
||||
form `my-svc.my-namespace.svc.cluster.local`. This resolves to the cluster IP
|
||||
of the Service.
|
||||
|
||||
"Headless" (without a cluster IP) Services are also assigned a DNS A record for
|
||||
a name of the form `my-svc.my-namespace.svc.cluster.local`. Unlike normal
|
||||
Services, this resolves to the set of IPs of the pods selected by the Service.
|
||||
Clients are expected to consume the set or else use standard round-robin
|
||||
selection from the set.
|
||||
|
||||
### SRV records
|
||||
|
||||
SRV Records are created for named ports that are part of normal or [Headless
|
||||
Services](/docs/concepts/services-networking/service/#headless-services).
|
||||
For each named port, the SRV record would have the form
|
||||
`_my-port-name._my-port-protocol.my-svc.my-namespace.svc.cluster.local`.
|
||||
For a regular service, this resolves to the port number and the CNAME:
|
||||
`my-svc.my-namespace.svc.cluster.local`.
|
||||
For a headless service, this resolves to multiple answers, one for each pod
|
||||
that is backing the service, and contains the port number and a CNAME of the pod
|
||||
of the form `auto-generated-name.my-svc.my-namespace.svc.cluster.local`.
|
||||
|
||||
## Pods
|
||||
|
||||
### A Records
|
||||
|
||||
When enabled, pods are assigned a DNS A record in the form of
|
||||
"`pod-ip-address.my-namespace.pod.cluster.local`".
|
||||
|
||||
For example, a pod with IP `1.2.3.4` in the namespace `default` with a DNS name
|
||||
of `cluster.local` would have an entry: `1-2-3-4.default.pod.cluster.local`.
|
||||
|
||||
### Pod's hostname and subdomain fields
|
||||
|
||||
Currently when a pod is created, its hostname is the Pod's `metadata.name` value.
|
||||
|
||||
The Pod spec has an optional `hostname` field, which can be used to specify the
|
||||
Pod's hostname. When specified, it takes precedence over the Pod's name to be
|
||||
the hostname of the pod. For example, given a Pod with `hostname` set to
|
||||
"`my-host`", the Pod will have its hostname set to "`my-host`".
|
||||
|
||||
The Pod spec also has an optional `subdomain` field which can be used to specify
|
||||
its subdomain. For example, a Pod with `hostname` set to "`foo`", and `subdomain`
|
||||
set to "`bar`", in namespace "`my-namespace`", will have the fully qualified
|
||||
domain name (FQDN) "`foo.bar.my-namespace.svc.cluster.local`".
|
||||
|
||||
Example:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: default-subdomain
|
||||
spec:
|
||||
selector:
|
||||
name: busybox
|
||||
clusterIP: None
|
||||
ports:
|
||||
- name: foo # Actually, no port is needed.
|
||||
port: 1234
|
||||
targetPort: 1234
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: busybox1
|
||||
labels:
|
||||
name: busybox
|
||||
spec:
|
||||
hostname: busybox-1
|
||||
subdomain: default-subdomain
|
||||
containers:
|
||||
- image: busybox
|
||||
command:
|
||||
- sleep
|
||||
- "3600"
|
||||
name: busybox
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: busybox2
|
||||
labels:
|
||||
name: busybox
|
||||
spec:
|
||||
hostname: busybox-2
|
||||
subdomain: default-subdomain
|
||||
containers:
|
||||
- image: busybox
|
||||
command:
|
||||
- sleep
|
||||
- "3600"
|
||||
name: busybox
|
||||
```
|
||||
|
||||
If there exists a headless service in the same namespace as the pod and with
|
||||
the same name as the subdomain, the cluster's KubeDNS Server also returns an A
|
||||
record for the Pod's fully qualified hostname.
|
||||
For example, given a Pod with the hostname set to "`busybox-1`" and the subdomain set to
|
||||
"`default-subdomain`", and a headless Service named "`default-subdomain`" in
|
||||
the same namespace, the pod will see its own FQDN as
|
||||
"`busybox-1.default-subdomain.my-namespace.svc.cluster.local`". DNS serves an
|
||||
A record at that name, pointing to the Pod's IP. Both pods "`busybox1`" and
|
||||
"`busybox2`" can have their distinct A records.
|
||||
|
||||
The Endpoints object can specify the `hostname` for any endpoint addresses,
|
||||
along with its IP.
|
||||
|
||||
### Pod's DNS Policy
|
||||
|
||||
DNS policies can be set on a per-pod basis. Currently Kubernetes supports the
|
||||
following pod-specific DNS policies. These policies are specified in the
|
||||
`dnsPolicy` field of a Pod Spec.
|
||||
|
||||
- "`Default`": The Pod inherits the name resolution configuration from the node
|
||||
that the pods run on.
|
||||
See [related discussion](/docs/tasks/administer-cluster/dns-custom-nameservers/#inheriting-dns-from-the-node)
|
||||
for more details.
|
||||
- "`ClusterFirst`": Any DNS query that does not match the configured cluster
|
||||
domain suffix, such as "`www.kubernetes.io`", is forwarded to the upstream
|
||||
nameserver inherited from the node. Cluster administrators may have extra
|
||||
stub-domain and upstream DNS servers configured.
|
||||
See [related discussion](/docs/tasks/administer-cluster/dns-custom-nameservers/#impacts-on-pods)
|
||||
for details on how DNS queries are handled in those cases.
|
||||
- "`ClusterFirstWithHostNet`": For Pods running with hostNetwork, you should
|
||||
explicitly set its DNS policy "`ClusterFirstWithHostNet`".
|
||||
- "`None`": A new option value introduced in Kubernetes v1.9 (Beta in v1.10). It
|
||||
allows a Pod to ignore DNS settings from the Kubernetes environment. All DNS
|
||||
settings are supposed to be provided using the `dnsConfig` field in the Pod Spec.
|
||||
See [DNS config](#dns-config) subsection below.
|
||||
|
||||
{{< note >}}
|
||||
**NOTE:** "Default" is not the default DNS policy. If `dnsPolicy` is not
|
||||
explicitly specified, then “ClusterFirst” is used.
|
||||
{{< /note >}}
|
||||
|
||||
|
||||
The example below shows a Pod with its DNS policy set to
|
||||
"`ClusterFirstWithHostNet`" because it has `hostNetwork` set to `true`.
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: busybox
|
||||
namespace: default
|
||||
spec:
|
||||
containers:
|
||||
- image: busybox
|
||||
command:
|
||||
- sleep
|
||||
- "3600"
|
||||
imagePullPolicy: IfNotPresent
|
||||
name: busybox
|
||||
restartPolicy: Always
|
||||
hostNetwork: true
|
||||
dnsPolicy: ClusterFirstWithHostNet
|
||||
```
|
||||
|
||||
### Pod's DNS Config
|
||||
|
||||
Kubernetes v1.9 introduces an Alpha feature (Beta in v1.10) that allows users more
|
||||
control on the DNS settings for a Pod. This feature is enabled by default in v1.10.
|
||||
To enable this feature in v1.9, the cluster administrator
|
||||
needs to enable the `CustomPodDNS` feature gate on the apiserver and the kubelet,
|
||||
for example, "`--feature-gates=CustomPodDNS=true,...`".
|
||||
When the feature gate is enabled, users can set the `dnsPolicy` field of a Pod
|
||||
to "`None`" and they can add a new field `dnsConfig` to a Pod Spec.
|
||||
|
||||
The `dnsConfig` field is optional and it can work with any `dnsPolicy` settings.
|
||||
However, when a Pod's `dnsPolicy` is set to "`None`", the `dnsConfig` field has
|
||||
to be specified.
|
||||
|
||||
Below are the properties a user can specify in the `dnsConfig` field:
|
||||
|
||||
- `nameservers`: a list of IP addresses that will be used as DNS servers for the
|
||||
Pod. There can be at most 3 IP addresses specified. When the Pod's `dnsPolicy`
|
||||
is set to "`None`", the list must contain at least one IP address, otherwise
|
||||
this property is optional.
|
||||
The servers listed will be combined to the base nameservers generated from the
|
||||
specified DNS policy with duplicate addresses removed.
|
||||
- `searches`: a list of DNS search domains for hostname lookup in the Pod.
|
||||
This property is optional. When specified, the provided list will be merged
|
||||
into the base search domain names generated from the chosen DNS policy.
|
||||
Duplicate domain names are removed.
|
||||
Kubernetes allows for at most 6 search domains.
|
||||
- `options`: an optional list of objects where each object may have a `name`
|
||||
property (required) and a `value` property (optional). The contents in this
|
||||
property will be merged to the options generated from the specified DNS policy.
|
||||
Duplicate entries are removed.
|
||||
|
||||
The following is an example Pod with custom DNS settings:
|
||||
|
||||
{{< code file="custom-dns.yaml" >}}
|
||||
|
||||
When the Pod above is created, the container `test` gets the following contents
|
||||
in its `/etc/resolv.conf` file:
|
||||
|
||||
```
|
||||
nameserver 1.2.3.4
|
||||
search ns1.svc.cluster.local my.dns.search.suffix
|
||||
options ndots:2 edns0
|
||||
```
|
||||
|
||||
For IPv6 setup, search path and name server should be setup like this:
|
||||
|
||||
```
|
||||
$ kubectl exec -it busybox -- cat /etc/resolv.conf
|
||||
nameserver fd00:79:30::a
|
||||
search default.svc.cluster.local svc.cluster.local cluster.local
|
||||
options ndots:5
|
||||
```
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture whatsnext %}}
|
||||
|
||||
For guidance on administering DNS configurations, check
|
||||
[Configure DNS Service](/docs/tasks/administer-cluster/dns-custom-nameservers/)
|
||||
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: hostaliases-pod
|
||||
spec:
|
||||
restartPolicy: Never
|
||||
hostAliases:
|
||||
- ip: "127.0.0.1"
|
||||
hostnames:
|
||||
- "foo.local"
|
||||
- "bar.local"
|
||||
- ip: "10.1.2.3"
|
||||
hostnames:
|
||||
- "foo.remote"
|
||||
- "bar.remote"
|
||||
containers:
|
||||
- name: cat-hosts
|
||||
image: busybox
|
||||
command:
|
||||
- cat
|
||||
args:
|
||||
- "/etc/hosts"
|
||||
@@ -0,0 +1,303 @@
|
||||
---
|
||||
reviewers:
|
||||
- bprashanth
|
||||
title: Ingress
|
||||
content_template: templates/concept
|
||||
---
|
||||
|
||||
{{% capture overview %}}
|
||||
{{< glossary_definition term_id="ingress" length="all" >}}
|
||||
{{% /capture %}}
|
||||
|
||||
{{% capture body %}}
|
||||
__Terminology__
|
||||
|
||||
Throughout this doc you will see a few terms that are sometimes used interchangeably elsewhere, that might cause confusion. This section attempts to clarify them.
|
||||
|
||||
* Node: A single virtual or physical machine in a Kubernetes cluster.
|
||||
* Cluster: A group of nodes firewalled from the internet, that are the primary compute resources managed by Kubernetes.
|
||||
* Edge router: A router that enforces the firewall policy for your cluster. This could be a gateway managed by a cloud provider or a physical piece of hardware.
|
||||
* Cluster network: A set of links, logical or physical, that facilitate communication within a cluster according to the [Kubernetes networking model](/docs/concepts/cluster-administration/networking/). Examples of a Cluster network include Overlays such as [flannel](https://github.com/coreos/flannel#flannel) or SDNs such as [OVS](https://www.openvswitch.org/).
|
||||
* Service: A Kubernetes [Service](/docs/concepts/services-networking/service/) that identifies a set of pods using label selectors. Unless mentioned otherwise, Services are assumed to have virtual IPs only routable within the cluster network.
|
||||
|
||||
## What is Ingress?
|
||||
|
||||
Typically, services and pods have IPs only routable by the cluster network. All traffic that ends up at an edge router is either dropped or forwarded elsewhere. Conceptually, this might look like:
|
||||
|
||||
```
|
||||
internet
|
||||
|
|
||||
------------
|
||||
[ Services ]
|
||||
```
|
||||
|
||||
An Ingress is a collection of rules that allow inbound connections to reach the cluster services.
|
||||
|
||||
```
|
||||
internet
|
||||
|
|
||||
[ Ingress ]
|
||||
--|-----|--
|
||||
[ Services ]
|
||||
```
|
||||
|
||||
It can be configured to give services externally-reachable URLs, load balance traffic, terminate SSL, offer name based virtual hosting, and more. Users request ingress by POSTing the Ingress resource to the API server. An [Ingress controller](#ingress-controllers) is responsible for fulfilling the Ingress, usually with a loadbalancer, though it may also configure your edge router or additional frontends to help handle the traffic in an HA manner.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before you start using the Ingress resource, there are a few things you should understand. The Ingress is a beta resource, not available in any Kubernetes release prior to 1.1. You need an Ingress controller to satisfy an Ingress, simply creating the resource will have no effect.
|
||||
|
||||
GCE/Google Kubernetes Engine deploys an ingress controller on the master. You can deploy any number of custom ingress controllers in a pod. You must annotate each ingress with the appropriate class, as indicated [here](https://git.k8s.io/ingress#running-multiple-ingress-controllers) and [here](https://git.k8s.io/ingress-gce/BETA_LIMITATIONS.md#disabling-glbc).
|
||||
|
||||
Make sure you review the [beta limitations](https://github.com/kubernetes/ingress-gce/blob/master/BETA_LIMITATIONS.md#glbc-beta-limitations) of this controller. In environments other than GCE/Google Kubernetes Engine, you need to [deploy a controller](https://git.k8s.io/ingress-nginx/README.md) as a pod.
|
||||
|
||||
## The Ingress Resource
|
||||
|
||||
A minimal Ingress might look like:
|
||||
|
||||
```yaml
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: test-ingress
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/rewrite-target: /
|
||||
spec:
|
||||
rules:
|
||||
- http:
|
||||
paths:
|
||||
- path: /testpath
|
||||
backend:
|
||||
serviceName: test
|
||||
servicePort: 80
|
||||
```
|
||||
|
||||
*POSTing this to the API server will have no effect if you have not configured an [Ingress controller](#ingress-controllers).*
|
||||
|
||||
__Lines 1-6__: As with all other Kubernetes config, an Ingress needs `apiVersion`, `kind`, and `metadata` fields. For general information about working with config files, see [deploying applications](/docs/tasks/run-application/run-stateless-application-deployment/), [configuring containers](/docs/tasks/configure-pod-container/configure-pod-configmap/), [managing resources](/docs/concepts/cluster-administration/manage-deployment/) and [ingress configuration rewrite](https://github.com/kubernetes/ingress-nginx/blob/master/docs/examples/rewrite/README.md).
|
||||
|
||||
__Lines 7-9__: Ingress [spec](https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status) has all the information needed to configure a loadbalancer or proxy server. Most importantly, it contains a list of rules matched against all incoming requests. Currently the Ingress resource only supports http rules.
|
||||
|
||||
__Lines 10-11__: Each http rule contains the following information: A host (e.g.: foo.bar.com, defaults to * in this example), a list of paths (e.g.: /testpath) each of which has an associated backend (test:80). Both the host and path must match the content of an incoming request before the loadbalancer directs traffic to the backend.
|
||||
|
||||
__Lines 12-14__: A backend is a service:port combination as described in the [services doc](/docs/concepts/services-networking/service/). Ingress traffic is typically sent directly to the endpoints matching a backend.
|
||||
|
||||
__Global Parameters__: For the sake of simplicity the example Ingress has no global parameters, see the [API reference](https://releases.k8s.io/{{< param "githubbranch" >}}/staging/src/k8s.io/api/extensions/v1beta1/types.go) for a full definition of the resource. One can specify a global default backend in the absence of which requests that don't match a path in the spec are sent to the default backend of the Ingress controller.
|
||||
|
||||
## Ingress controllers
|
||||
|
||||
In order for the Ingress resource to work, the cluster must have an Ingress controller running. This is unlike other types of controllers, which typically run as part of the `kube-controller-manager` binary, and which are typically started automatically as part of cluster creation. You need to choose the ingress controller implementation that is the best fit for your cluster, or implement one. We currently support and maintain [GCE](https://git.k8s.io/ingress-gce/README.md) and [nginx](https://git.k8s.io/ingress-nginx/README.md) controllers.
|
||||
|
||||
## Before you begin
|
||||
|
||||
The following document describes a set of cross platform features exposed through the Ingress resource. Ideally, all Ingress controllers should fulfill this specification, but we're not there yet. We currently support and maintain [GCE](https://git.k8s.io/ingress-gce/README.md) and [nginx](https://git.k8s.io/ingress-nginx/README.md) controllers. **Make sure you review controller specific docs so you understand the caveats of each one**.
|
||||
|
||||
## Types of Ingress
|
||||
|
||||
### Single Service Ingress
|
||||
|
||||
There are existing Kubernetes concepts that allow you to expose a single service (see [alternatives](#alternatives)), however you can do so through an Ingress as well, by specifying a *default backend* with no rules.
|
||||
|
||||
{{< code file="ingress.yaml" >}}
|
||||
|
||||
If you create it using `kubectl create -f` you should see:
|
||||
|
||||
```shell
|
||||
$ kubectl get ing
|
||||
NAME RULE BACKEND ADDRESS
|
||||
test-ingress - testsvc:80 107.178.254.228
|
||||
```
|
||||
|
||||
Where `107.178.254.228` is the IP allocated by the Ingress controller to satisfy this Ingress. The `RULE` column shows that all traffic sent to the IP is directed to the Kubernetes Service listed under `BACKEND`.
|
||||
|
||||
### Simple fanout
|
||||
|
||||
As described previously, pods within kubernetes have IPs only visible on the cluster network, so we need something at the edge accepting ingress traffic and proxying it to the right endpoints. This component is usually a highly available loadbalancer. An Ingress allows you to keep the number of loadbalancers down to a minimum, for example, a setup like:
|
||||
|
||||
```shell
|
||||
foo.bar.com -> 178.91.123.132 -> / foo s1:80
|
||||
/ bar s2:80
|
||||
```
|
||||
|
||||
would require an Ingress such as:
|
||||
|
||||
```yaml
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: test
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/rewrite-target: /
|
||||
spec:
|
||||
rules:
|
||||
- host: foo.bar.com
|
||||
http:
|
||||
paths:
|
||||
- path: /foo
|
||||
backend:
|
||||
serviceName: s1
|
||||
servicePort: 80
|
||||
- path: /bar
|
||||
backend:
|
||||
serviceName: s2
|
||||
servicePort: 80
|
||||
```
|
||||
|
||||
When you create the Ingress with `kubectl create -f`:
|
||||
|
||||
```shell
|
||||
$ kubectl get ing
|
||||
NAME RULE BACKEND ADDRESS
|
||||
test -
|
||||
foo.bar.com
|
||||
/foo s1:80
|
||||
/bar s2:80
|
||||
```
|
||||
The Ingress controller will provision an implementation specific loadbalancer that satisfies the Ingress, as long as the services (s1, s2) exist. When it has done so, you will see the address of the loadbalancer under the last column of the Ingress.
|
||||
|
||||
### Name based virtual hosting
|
||||
|
||||
Name-based virtual hosts use multiple host names for the same IP address.
|
||||
|
||||
```
|
||||
foo.bar.com --| |-> foo.bar.com s1:80
|
||||
| 178.91.123.132 |
|
||||
bar.foo.com --| |-> bar.foo.com s2:80
|
||||
```
|
||||
|
||||
The following Ingress tells the backing loadbalancer to route requests based on the [Host header](https://tools.ietf.org/html/rfc7230#section-5.4).
|
||||
|
||||
```yaml
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: test
|
||||
spec:
|
||||
rules:
|
||||
- host: foo.bar.com
|
||||
http:
|
||||
paths:
|
||||
- backend:
|
||||
serviceName: s1
|
||||
servicePort: 80
|
||||
- host: bar.foo.com
|
||||
http:
|
||||
paths:
|
||||
- backend:
|
||||
serviceName: s2
|
||||
servicePort: 80
|
||||
```
|
||||
|
||||
__Default Backends__: An Ingress with no rules, like the one shown in the previous section, sends all traffic to a single default backend. You can use the same technique to tell a loadbalancer where to find your website's 404 page, by specifying a set of rules *and* a default backend. Traffic is routed to your default backend if none of the Hosts in your Ingress match the Host in the request header, and/or none of the paths match the URL of the request.
|
||||
|
||||
### TLS
|
||||
|
||||
You can secure an Ingress by specifying a [secret](/docs/user-guide/secrets) that contains a TLS private key and certificate. Currently the Ingress only supports a single TLS port, 443, and assumes TLS termination. If the TLS configuration section in an Ingress specifies different hosts, they will be multiplexed on the same port according to the hostname specified through the SNI TLS extension (provided the Ingress controller supports SNI). The TLS secret must contain keys named `tls.crt` and `tls.key` that contain the certificate and private key to use for TLS, e.g.:
|
||||
|
||||
```yaml
|
||||
apiVersion: v1
|
||||
data:
|
||||
tls.crt: base64 encoded cert
|
||||
tls.key: base64 encoded key
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: testsecret
|
||||
namespace: default
|
||||
type: Opaque
|
||||
```
|
||||
|
||||
Referencing this secret in an Ingress will tell the Ingress controller to secure the channel from the client to the loadbalancer using TLS:
|
||||
|
||||
```yaml
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: no-rules-map
|
||||
spec:
|
||||
tls:
|
||||
- secretName: testsecret
|
||||
backend:
|
||||
serviceName: s1
|
||||
servicePort: 80
|
||||
```
|
||||
|
||||
Note that there is a gap between TLS features supported by various Ingress controllers. Please refer to documentation on [nginx](https://git.k8s.io/ingress-nginx/README.md#https), [GCE](https://git.k8s.io/ingress-gce/README.md#frontend-https), or any other platform specific Ingress controller to understand how TLS works in your environment.
|
||||
|
||||
### Loadbalancing
|
||||
|
||||
An Ingress controller is bootstrapped with some load balancing policy settings that it applies to all Ingress, such as the load balancing algorithm, backend weight scheme, and others. More advanced load balancing concepts (e.g.: persistent sessions, dynamic weights) are not yet exposed through the Ingress. You can still get these features through the [service loadbalancer](https://github.com/kubernetes/ingress-nginx/blob/master/docs/catalog.md). With time, we plan to distill load balancing patterns that are applicable cross platform into the Ingress resource.
|
||||
|
||||
It's also worth noting that even though health checks are not exposed directly through the Ingress, there exist parallel concepts in Kubernetes such as [readiness probes](/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/) which allow you to achieve the same end result. Please review the controller specific docs to see how they handle health checks ([nginx](https://git.k8s.io/ingress-nginx/README.md), [GCE](https://git.k8s.io/ingress-gce/README.md#health-checks)).
|
||||
|
||||
## Updating an Ingress
|
||||
|
||||
Say you'd like to add a new Host to an existing Ingress, you can update it by editing the resource:
|
||||
|
||||
```shell
|
||||
$ kubectl get ing
|
||||
NAME RULE BACKEND ADDRESS
|
||||
test - 178.91.123.132
|
||||
foo.bar.com
|
||||
/foo s1:80
|
||||
$ kubectl edit ing test
|
||||
```
|
||||
|
||||
This should pop up an editor with the existing yaml, modify it to include the new Host:
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
rules:
|
||||
- host: foo.bar.com
|
||||
http:
|
||||
paths:
|
||||
- backend:
|
||||
serviceName: s1
|
||||
servicePort: 80
|
||||
path: /foo
|
||||
- host: bar.baz.com
|
||||
http:
|
||||
paths:
|
||||
- backend:
|
||||
serviceName: s2
|
||||
servicePort: 80
|
||||
path: /foo
|
||||
..
|
||||
```
|
||||
|
||||
Saving the yaml will update the resource in the API server, which should tell the Ingress controller to reconfigure the loadbalancer.
|
||||
|
||||
```shell
|
||||
$ kubectl get ing
|
||||
NAME RULE BACKEND ADDRESS
|
||||
test - 178.91.123.132
|
||||
foo.bar.com
|
||||
/foo s1:80
|
||||
bar.baz.com
|
||||
/foo s2:80
|
||||
```
|
||||
|
||||
You can achieve the same by invoking `kubectl replace -f` on a modified Ingress yaml file.
|
||||
|
||||
## Failing across availability zones
|
||||
|
||||
Techniques for spreading traffic across failure domains differs between cloud providers. Please check the documentation of the relevant Ingress controller for details. Please refer to the federation [doc](/docs/concepts/cluster-administration/federation/) for details on deploying Ingress in a federated cluster.
|
||||
|
||||
## Future Work
|
||||
|
||||
* Various modes of HTTPS/TLS support (e.g.: SNI, re-encryption)
|
||||
* Requesting an IP or Hostname via claims
|
||||
* Combining L4 and L7 Ingress
|
||||
* More Ingress controllers
|
||||
|
||||
Please track the [L7 and Ingress proposal](https://github.com/kubernetes/kubernetes/pull/12827) for more details on the evolution of the resource, and the [Ingress repository](https://github.com/kubernetes/ingress/tree/master) for more details on the evolution of various Ingress controllers.
|
||||
|
||||
## Alternatives
|
||||
|
||||
You can expose a Service in multiple ways that don't directly involve the Ingress resource:
|
||||
|
||||
* Use [Service.Type=LoadBalancer](/docs/concepts/services-networking/service/#type-loadbalancer)
|
||||
* Use [Service.Type=NodePort](/docs/concepts/services-networking/service/#type-nodeport)
|
||||
* Use a [Port Proxy](https://git.k8s.io/contrib/for-demos/proxy-to-service)
|
||||
{{% /capture %}}
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
apiVersion: extensions/v1beta1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: test-ingress
|
||||
spec:
|
||||
backend:
|
||||
serviceName: testsvc
|
||||
servicePort: 80
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
---
|
||||
reviewers:
|
||||
- thockin
|
||||
- caseydavenport
|
||||
- danwinship
|
||||
title: Network Policies
|
||||
---
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
A network policy is a specification of how groups of pods are allowed to communicate with each other and other network endpoints.
|
||||
|
||||
`NetworkPolicy` resources use labels to select pods and define rules which specify what traffic is allowed to the selected pods.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Network policies are implemented by the network plugin, so you must be using a networking solution which supports `NetworkPolicy` - simply creating the resource without a controller to implement it will have no effect.
|
||||
|
||||
## Isolated and Non-isolated Pods
|
||||
|
||||
By default, pods are non-isolated; they accept traffic from any source.
|
||||
|
||||
Pods become isolated by having a NetworkPolicy that selects them. Once there is any NetworkPolicy in a namespace selecting a particular pod, that pod will reject any connections that are not allowed by any NetworkPolicy. (Other pods in the namespace that are not selected by any NetworkPolicy will continue to accept all traffic.)
|
||||
|
||||
## The `NetworkPolicy` Resource
|
||||
|
||||
See the [NetworkPolicy](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#networkpolicy-v1-networking) for a full definition of the resource.
|
||||
|
||||
An example `NetworkPolicy` might look like this:
|
||||
|
||||
```yaml
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: test-network-policy
|
||||
namespace: default
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
role: db
|
||||
policyTypes:
|
||||
- Ingress
|
||||
- Egress
|
||||
ingress:
|
||||
- from:
|
||||
- ipBlock:
|
||||
cidr: 172.17.0.0/16
|
||||
except:
|
||||
- 172.17.1.0/24
|
||||
- namespaceSelector:
|
||||
matchLabels:
|
||||
project: myproject
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
role: frontend
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 6379
|
||||
egress:
|
||||
- to:
|
||||
- ipBlock:
|
||||
cidr: 10.0.0.0/24
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 5978
|
||||
```
|
||||
|
||||
*POSTing this to the API server will have no effect unless your chosen networking solution supports network policy.*
|
||||
|
||||
__Mandatory Fields__: As with all other Kubernetes config, a `NetworkPolicy`
|
||||
needs `apiVersion`, `kind`, and `metadata` fields. For general information
|
||||
about working with config files, see
|
||||
[Configure Containers Using a ConfigMap](/docs/tasks/configure-pod-container/configure-pod-configmap/),
|
||||
and [Object Management](/docs/concepts/overview/object-management-kubectl/overview/).
|
||||
|
||||
__spec__: `NetworkPolicy` [spec](https://git.k8s.io/community/contributors/devel/api-conventions.md#spec-and-status) has all the information needed to define a particular network policy in the given namespace.
|
||||
|
||||
__podSelector__: Each `NetworkPolicy` includes a `podSelector` which selects the grouping of pods to which the policy applies. The example policy selects pods with the label "role=db". An empty `podSelector` selects all pods in the namespace.
|
||||
|
||||
__policyTypes__: Each `NetworkPolicy` includes a `policyTypes` list which may include either `Ingress`, `Egress`, or both. The `policyTypes` field indicates whether or not the given policy applies to ingress traffic to selected pod, egress traffic from selected pods, or both. If no `policyTypes` are specified on a NetworkPolicy then by default `Ingress` will always be set and `Egress` will be set if the NetworkPolicy has any egress rules.
|
||||
|
||||
__ingress__: Each `NetworkPolicy` may include a list of whitelist `ingress` rules. Each rule allows traffic which matches both the `from` and `ports` sections. The example policy contains a single rule, which matches traffic on a single port, from one of three sources, the first specified via an `ipBlock`, the second via a `namespaceSelector` and the third via a `podSelector`.
|
||||
|
||||
__egress__: Each `NetworkPolicy` may include a list of whitelist `egress` rules. Each rule allows traffic which matches both the `to` and `ports` sections. The example policy contains a single rule, which matches traffic on a single port to any destination in `10.0.0.0/24`.
|
||||
|
||||
So, the example NetworkPolicy:
|
||||
|
||||
1. isolates "role=db" pods in the "default" namespace for both ingress and egress traffic (if they weren't already isolated)
|
||||
2. allows connections to TCP port 6379 of "role=db" pods in the "default" namespace from any pod in the "default" namespace with the label "role=frontend"
|
||||
3. allows connections to TCP port 6379 of "role=db" pods in the "default" namespace from any pod in a namespace with the label "project=myproject"
|
||||
4. allows connections to TCP port 6379 of "role=db" pods in the "default" namespace from IP addresses that are in CIDR 172.17.0.0/16 and not in 172.17.1.0/24
|
||||
5. allows connections from any pod in the "default" namespace with the label "role=db" to CIDR 10.0.0.0/24 on TCP port 5978
|
||||
|
||||
See the [Declare Network Policy](/docs/tasks/administer-cluster/declare-network-policy/) walkthrough for further examples.
|
||||
|
||||
## Default policies
|
||||
|
||||
By default, if no policies exist in a namespace, then all ingress and egress traffic is allowed to and from pods in that namespace. The following examples let you change the default behavior
|
||||
in that namespace.
|
||||
|
||||
### Default deny all ingress traffic
|
||||
|
||||
You can create a "default" isolation policy for a namespace by creating a NetworkPolicy that selects all pods but does not allow any ingress traffic to those pods.
|
||||
|
||||
```yaml
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: default-deny
|
||||
spec:
|
||||
podSelector: {}
|
||||
policyTypes:
|
||||
- Ingress
|
||||
```
|
||||
|
||||
This ensures that even pods that aren't selected by any other NetworkPolicy will still be isolated. This policy does not change the default egress isolation behavior.
|
||||
|
||||
### Default allow all ingress traffic
|
||||
|
||||
If you want to allow all traffic to all pods in a namespace (even if policies are added that cause some pods to be treated as "isolated"), you can create a policy that explicitly allows all traffic in that namespace.
|
||||
|
||||
```yaml
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: allow-all
|
||||
spec:
|
||||
podSelector: {}
|
||||
ingress:
|
||||
- {}
|
||||
```
|
||||
|
||||
### Default deny all egress traffic
|
||||
|
||||
You can create a "default" egress isolation policy for a namespace by creating a NetworkPolicy that selects all pods but does not allow any egress traffic from those pods.
|
||||
|
||||
```yaml
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: default-deny
|
||||
spec:
|
||||
podSelector: {}
|
||||
policyTypes:
|
||||
- Egress
|
||||
```
|
||||
|
||||
This ensures that even pods that aren't selected by any other NetworkPolicy will not be allowed egress traffic. This policy does not
|
||||
change the default ingress isolation behavior.
|
||||
|
||||
### Default allow all egress traffic
|
||||
|
||||
If you want to allow all traffic from all pods in a namespace (even if policies are added that cause some pods to be treated as "isolated"), you can create a policy that explicitly allows all egress traffic in that namespace.
|
||||
|
||||
```yaml
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: allow-all
|
||||
spec:
|
||||
podSelector: {}
|
||||
egress:
|
||||
- {}
|
||||
policyTypes:
|
||||
- Egress
|
||||
```
|
||||
|
||||
### Default deny all ingress and all egress traffic
|
||||
|
||||
You can create a "default" policy for a namespace which prevents all ingress AND egress traffic by creating the following NetworkPolicy in that namespace.
|
||||
|
||||
```yaml
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: default-deny
|
||||
spec:
|
||||
podSelector: {}
|
||||
policyTypes:
|
||||
- Ingress
|
||||
- Egress
|
||||
```
|
||||
|
||||
This ensures that even pods that aren't selected by any other NetworkPolicy will not be allowed ingress or egress traffic.
|
||||
|
||||
## What's next?
|
||||
|
||||
- See the [Declare Network Policy](/docs/tasks/administer-cluster/declare-network-policy/)
|
||||
walkthrough for further examples.
|
||||
- See more [Recipes](https://github.com/ahmetb/kubernetes-network-policy-recipes) for common scenarios enabled by the NetworkPolicy resource.
|
||||
@@ -0,0 +1,46 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: my-nginx
|
||||
labels:
|
||||
run: my-nginx
|
||||
spec:
|
||||
type: NodePort
|
||||
ports:
|
||||
- port: 8080
|
||||
targetPort: 80
|
||||
protocol: TCP
|
||||
name: http
|
||||
- port: 443
|
||||
protocol: TCP
|
||||
name: https
|
||||
selector:
|
||||
run: my-nginx
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: my-nginx
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
run: my-nginx
|
||||
replicas: 1
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
run: my-nginx
|
||||
spec:
|
||||
volumes:
|
||||
- name: secret-volume
|
||||
secret:
|
||||
secretName: nginxsecret
|
||||
containers:
|
||||
- name: nginxhttps
|
||||
image: bprashanth/nginxhttps:1.0
|
||||
ports:
|
||||
- containerPort: 443
|
||||
- containerPort: 80
|
||||
volumeMounts:
|
||||
- mountPath: /etc/nginx/ssl
|
||||
name: secret-volume
|
||||
@@ -0,0 +1,12 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: my-nginx
|
||||
labels:
|
||||
run: my-nginx
|
||||
spec:
|
||||
ports:
|
||||
- port: 80
|
||||
protocol: TCP
|
||||
selector:
|
||||
run: my-nginx
|
||||
@@ -0,0 +1,20 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: my-nginx
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
run: my-nginx
|
||||
replicas: 2
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
run: my-nginx
|
||||
spec:
|
||||
containers:
|
||||
- name: my-nginx
|
||||
image: nginx
|
||||
ports:
|
||||
- containerPort: 80
|
||||
|
||||
@@ -0,0 +1,894 @@
|
||||
---
|
||||
reviewers:
|
||||
- bprashanth
|
||||
title: Services
|
||||
---
|
||||
|
||||
Kubernetes [`Pods`](/docs/concepts/workloads/pods/pod/) are mortal. They are born and when they die, they
|
||||
are not resurrected. [`ReplicaSets`](/docs/concepts/workloads/controllers/replicaset/) in
|
||||
particular create and destroy `Pods` dynamically (e.g. when scaling up or down). While each `Pod` gets its own IP address, even
|
||||
those IP addresses cannot be relied upon to be stable over time. This leads to
|
||||
a problem: if some set of `Pods` (let's call them backends) provides
|
||||
functionality to other `Pods` (let's call them frontends) inside the Kubernetes
|
||||
cluster, how do those frontends find out and keep track of which backends are
|
||||
in that set?
|
||||
|
||||
Enter `Services`.
|
||||
|
||||
A Kubernetes `Service` is an abstraction which defines a logical set of `Pods`
|
||||
and a policy by which to access them - sometimes called a micro-service. The
|
||||
set of `Pods` targeted by a `Service` is (usually) determined by a [`Label
|
||||
Selector`](/docs/concepts/overview/working-with-objects/labels/#label-selectors) (see below for why you might want a
|
||||
`Service` without a selector).
|
||||
|
||||
As an example, consider an image-processing backend which is running with 3
|
||||
replicas. Those replicas are fungible - frontends do not care which backend
|
||||
they use. While the actual `Pods` that compose the backend set may change, the
|
||||
frontend clients should not need to be aware of that or keep track of the list
|
||||
of backends themselves. The `Service` abstraction enables this decoupling.
|
||||
|
||||
For Kubernetes-native applications, Kubernetes offers a simple `Endpoints` API
|
||||
that is updated whenever the set of `Pods` in a `Service` changes. For
|
||||
non-native applications, Kubernetes offers a virtual-IP-based bridge to Services
|
||||
which redirects to the backend `Pods`.
|
||||
|
||||
{{< toc >}}
|
||||
|
||||
## Defining a service
|
||||
|
||||
A `Service` in Kubernetes is a REST object, similar to a `Pod`. Like all of the
|
||||
REST objects, a `Service` definition can be POSTed to the apiserver to create a
|
||||
new instance. For example, suppose you have a set of `Pods` that each expose
|
||||
port 9376 and carry a label `"app=MyApp"`.
|
||||
|
||||
```yaml
|
||||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: my-service
|
||||
spec:
|
||||
selector:
|
||||
app: MyApp
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 80
|
||||
targetPort: 9376
|
||||
```
|
||||
|
||||
This specification will create a new `Service` object named "my-service" which
|
||||
targets TCP port 9376 on any `Pod` with the `"app=MyApp"` label. This `Service`
|
||||
will also be assigned an IP address (sometimes called the "cluster IP"), which
|
||||
is used by the service proxies (see below). The `Service`'s selector will be
|
||||
evaluated continuously and the results will be POSTed to an `Endpoints` object
|
||||
also named "my-service".
|
||||
|
||||
Note that a `Service` can map an incoming port to any `targetPort`. By default
|
||||
the `targetPort` will be set to the same value as the `port` field. Perhaps
|
||||
more interesting is that `targetPort` can be a string, referring to the name of
|
||||
a port in the backend `Pods`. The actual port number assigned to that name can
|
||||
be different in each backend `Pod`. This offers a lot of flexibility for
|
||||
deploying and evolving your `Services`. For example, you can change the port
|
||||
number that pods expose in the next version of your backend software, without
|
||||
breaking clients.
|
||||
|
||||
Kubernetes `Services` support `TCP` and `UDP` for protocols. The default
|
||||
is `TCP`.
|
||||
|
||||
### Services without selectors
|
||||
|
||||
Services generally abstract access to Kubernetes `Pods`, but they can also
|
||||
abstract other kinds of backends. For example:
|
||||
|
||||
* You want to have an external database cluster in production, but in test
|
||||
you use your own databases.
|
||||
* You want to point your service to a service in another
|
||||
[`Namespace`](/docs/concepts/overview/working-with-objects/namespaces/) or on another cluster.
|
||||
* You are migrating your workload to Kubernetes and some of your backends run
|
||||
outside of Kubernetes.
|
||||
|
||||
In any of these scenarios you can define a service without a selector:
|
||||
|
||||
```yaml
|
||||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: my-service
|
||||
spec:
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 80
|
||||
targetPort: 9376
|
||||
```
|
||||
|
||||
Because this service has no selector, the corresponding `Endpoints` object will not be
|
||||
created. You can manually map the service to your own specific endpoints:
|
||||
|
||||
```yaml
|
||||
kind: Endpoints
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: my-service
|
||||
subsets:
|
||||
- addresses:
|
||||
- ip: 1.2.3.4
|
||||
ports:
|
||||
- port: 9376
|
||||
```
|
||||
|
||||
{{< note >}}
|
||||
**NOTE** The endpoint IPs may not be loopback (127.0.0.0/8), link-local
|
||||
(169.254.0.0/16), or link-local multicast (224.0.0.0/24). They cannot be the
|
||||
cluster IPs of other Kubernetes services either because the `kube-proxy`
|
||||
component doesn't support virtual IPs as destination yet.
|
||||
{{< /note >}}
|
||||
|
||||
Accessing a `Service` without a selector works the same as if it had a selector.
|
||||
The traffic will be routed to endpoints defined by the user (`1.2.3.4:9376` in
|
||||
this example).
|
||||
|
||||
An ExternalName service is a special case of service that does not have
|
||||
selectors. It does not define any ports or Endpoints. Rather, it serves as a
|
||||
way to return an alias to an external service residing outside the cluster.
|
||||
|
||||
```yaml
|
||||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: my-service
|
||||
namespace: prod
|
||||
spec:
|
||||
type: ExternalName
|
||||
externalName: my.database.example.com
|
||||
```
|
||||
|
||||
When looking up the host `my-service.prod.svc.CLUSTER`, the cluster DNS service
|
||||
will return a `CNAME` record with the value `my.database.example.com`. Accessing
|
||||
such a service works in the same way as others, with the only difference that
|
||||
the redirection happens at the DNS level and no proxying or forwarding occurs.
|
||||
Should you later decide to move your database into your cluster, you can start
|
||||
its pods, add appropriate selectors or endpoints and change the service `type`.
|
||||
|
||||
## Virtual IPs and service proxies
|
||||
|
||||
Every node in a Kubernetes cluster runs a `kube-proxy`. `kube-proxy` is
|
||||
responsible for implementing a form of virtual IP for `Services` of type other
|
||||
than `ExternalName`.
|
||||
In Kubernetes v1.0, `Services` are a "layer 4" (TCP/UDP over IP) construct, the
|
||||
proxy was purely in userspace. In Kubernetes v1.1, the `Ingress` API was added
|
||||
(beta) to represent "layer 7"(HTTP) services, iptables proxy was added too,
|
||||
and become the default operating mode since Kubernetes v1.2. In Kubernetes v1.8.0-beta.0,
|
||||
ipvs proxy was added.
|
||||
|
||||
### Proxy-mode: userspace
|
||||
|
||||
In this mode, kube-proxy watches the Kubernetes master for the addition and
|
||||
removal of `Service` and `Endpoints` objects. For each `Service` it opens a
|
||||
port (randomly chosen) on the local node. Any connections to this "proxy port"
|
||||
will be proxied to one of the `Service`'s backend `Pods` (as reported in
|
||||
`Endpoints`). Which backend `Pod` to use is decided based on the
|
||||
`SessionAffinity` of the `Service`. Lastly, it installs iptables rules which
|
||||
capture traffic to the `Service`'s `clusterIP` (which is virtual) and `Port`
|
||||
and redirects that traffic to the proxy port which proxies the backend `Pod`.
|
||||
By default, the choice of backend is round robin.
|
||||
|
||||

|
||||
|
||||
Note that in the above diagram, `clusterIP` is shown as `ServiceIP`.
|
||||
|
||||
### Proxy-mode: iptables
|
||||
|
||||
In this mode, kube-proxy watches the Kubernetes master for the addition and
|
||||
removal of `Service` and `Endpoints` objects. For each `Service`, it installs
|
||||
iptables rules which capture traffic to the `Service`'s `clusterIP` (which is
|
||||
virtual) and `Port` and redirects that traffic to one of the `Service`'s
|
||||
backend sets. For each `Endpoints` object, it installs iptables rules which
|
||||
select a backend `Pod`. By default, the choice of backend is random.
|
||||
|
||||
Obviously, iptables need not switch back between userspace and kernelspace, it should be
|
||||
faster and more reliable than the userspace proxy. However, unlike the
|
||||
userspace proxier, the iptables proxier cannot automatically retry another
|
||||
`Pod` if the one it initially selects does not respond, so it depends on
|
||||
having working [readiness probes](/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#defining-readiness-probes).
|
||||
|
||||

|
||||
|
||||
Note that in the above diagram, `clusterIP` is shown as `ServiceIP`.
|
||||
|
||||
### Proxy-mode: ipvs
|
||||
|
||||
{{< feature-state for_k8s_version="v1.9" state="beta" >}}
|
||||
|
||||
In this mode, kube-proxy watches Kubernetes Services and Endpoints,
|
||||
calls `netlink` interface to create ipvs rules accordingly and syncs ipvs rules with Kubernetes
|
||||
Services and Endpoints periodically, to make sure ipvs status is
|
||||
consistent with the expectation. When Service is accessed, traffic will
|
||||
be redirected to one of the backend Pods.
|
||||
|
||||
Similar to iptables, Ipvs is based on netfilter hook function, but uses hash
|
||||
table as the underlying data structure and works in the kernel space.
|
||||
That means ipvs redirects traffic much faster, and has much
|
||||
better performance when syncing proxy rules. Furthermore, ipvs provides more
|
||||
options for load balancing algorithm, such as:
|
||||
|
||||
- `rr`: round-robin
|
||||
- `lc`: least connection
|
||||
- `dh`: destination hashing
|
||||
- `sh`: source hashing
|
||||
- `sed`: shortest expected delay
|
||||
- `nq`: never queue
|
||||
|
||||
**Note:** ipvs mode assumes IPVS kernel modules are installed on the node
|
||||
before running kube-proxy. When kube-proxy starts with ipvs proxy mode,
|
||||
kube-proxy would validate if IPVS modules are installed on the node, if
|
||||
it's not installed kube-proxy will fall back to iptables proxy mode.
|
||||
|
||||

|
||||
|
||||
In any of these proxy model, any traffic bound for the Service’s IP:Port is
|
||||
proxied to an appropriate backend without the clients knowing anything
|
||||
about Kubernetes or Services or Pods. Client-IP based session affinity
|
||||
can be selected by setting `service.spec.sessionAffinity` to "ClientIP"
|
||||
(the default is "None"), and you can set the max session sticky time by
|
||||
setting the field `service.spec.sessionAffinityConfig.clientIP.timeoutSeconds`
|
||||
if you have already set `service.spec.sessionAffinity` to "ClientIP"
|
||||
(the default is “10800”).
|
||||
|
||||
## Multi-Port Services
|
||||
|
||||
Many `Services` need to expose more than one port. For this case, Kubernetes
|
||||
supports multiple port definitions on a `Service` object. When using multiple
|
||||
ports you must give all of your ports names, so that endpoints can be
|
||||
disambiguated. For example:
|
||||
|
||||
```yaml
|
||||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: my-service
|
||||
spec:
|
||||
selector:
|
||||
app: MyApp
|
||||
ports:
|
||||
- name: http
|
||||
protocol: TCP
|
||||
port: 80
|
||||
targetPort: 9376
|
||||
- name: https
|
||||
protocol: TCP
|
||||
port: 443
|
||||
targetPort: 9377
|
||||
```
|
||||
|
||||
## Choosing your own IP address
|
||||
|
||||
You can specify your own cluster IP address as part of a `Service` creation
|
||||
request. To do this, set the `spec.clusterIP` field. For example, if you
|
||||
already have an existing DNS entry that you wish to replace, or legacy systems
|
||||
that are configured for a specific IP address and difficult to re-configure.
|
||||
The IP address that a user chooses must be a valid IP address and within the
|
||||
`service-cluster-ip-range` CIDR range that is specified by flag to the API
|
||||
server. If the IP address value is invalid, the apiserver returns a 422 HTTP
|
||||
status code to indicate that the value is invalid.
|
||||
|
||||
### Why not use round-robin DNS?
|
||||
|
||||
A question that pops up every now and then is why we do all this stuff with
|
||||
virtual IPs rather than just use standard round-robin DNS. There are a few
|
||||
reasons:
|
||||
|
||||
* There is a long history of DNS libraries not respecting DNS TTLs and
|
||||
caching the results of name lookups.
|
||||
* Many apps do DNS lookups once and cache the results.
|
||||
* Even if apps and libraries did proper re-resolution, the load of every
|
||||
client re-resolving DNS over and over would be difficult to manage.
|
||||
|
||||
We try to discourage users from doing things that hurt themselves. That said,
|
||||
if enough people ask for this, we may implement it as an alternative.
|
||||
|
||||
## Discovering services
|
||||
|
||||
Kubernetes supports 2 primary modes of finding a `Service` - environment
|
||||
variables and DNS.
|
||||
|
||||
### Environment variables
|
||||
|
||||
When a `Pod` is run on a `Node`, the kubelet adds a set of environment variables
|
||||
for each active `Service`. It supports both [Docker links
|
||||
compatible](https://docs.docker.com/userguide/dockerlinks/) variables (see
|
||||
[makeLinkVariables](http://releases.k8s.io/{{< param "githubbranch" >}}/pkg/kubelet/envvars/envvars.go#L49))
|
||||
and simpler `{SVCNAME}_SERVICE_HOST` and `{SVCNAME}_SERVICE_PORT` variables,
|
||||
where the Service name is upper-cased and dashes are converted to underscores.
|
||||
|
||||
For example, the Service `"redis-master"` which exposes TCP port 6379 and has been
|
||||
allocated cluster IP address 10.0.0.11 produces the following environment
|
||||
variables:
|
||||
|
||||
```shell
|
||||
REDIS_MASTER_SERVICE_HOST=10.0.0.11
|
||||
REDIS_MASTER_SERVICE_PORT=6379
|
||||
REDIS_MASTER_PORT=tcp://10.0.0.11:6379
|
||||
REDIS_MASTER_PORT_6379_TCP=tcp://10.0.0.11:6379
|
||||
REDIS_MASTER_PORT_6379_TCP_PROTO=tcp
|
||||
REDIS_MASTER_PORT_6379_TCP_PORT=6379
|
||||
REDIS_MASTER_PORT_6379_TCP_ADDR=10.0.0.11
|
||||
```
|
||||
|
||||
*This does imply an ordering requirement* - any `Service` that a `Pod` wants to
|
||||
access must be created before the `Pod` itself, or else the environment
|
||||
variables will not be populated. DNS does not have this restriction.
|
||||
|
||||
### DNS
|
||||
|
||||
An optional (though strongly recommended) [cluster
|
||||
add-on](/docs/concepts/cluster-administration/addons/) is a DNS server. The
|
||||
DNS server watches the Kubernetes API for new `Services` and creates a set of
|
||||
DNS records for each. If DNS has been enabled throughout the cluster then all
|
||||
`Pods` should be able to do name resolution of `Services` automatically.
|
||||
|
||||
For example, if you have a `Service` called `"my-service"` in Kubernetes
|
||||
`Namespace` `"my-ns"` a DNS record for `"my-service.my-ns"` is created. `Pods`
|
||||
which exist in the `"my-ns"` `Namespace` should be able to find it by simply doing
|
||||
a name lookup for `"my-service"`. `Pods` which exist in other `Namespaces` must
|
||||
qualify the name as `"my-service.my-ns"`. The result of these name lookups is the
|
||||
cluster IP.
|
||||
|
||||
Kubernetes also supports DNS SRV (service) records for named ports. If the
|
||||
`"my-service.my-ns"` `Service` has a port named `"http"` with protocol `TCP`, you
|
||||
can do a DNS SRV query for `"_http._tcp.my-service.my-ns"` to discover the port
|
||||
number for `"http"`.
|
||||
|
||||
The Kubernetes DNS server is the only way to access services of type
|
||||
`ExternalName`. More information is available in the [DNS Pods and Services](/docs/concepts/services-networking/dns-pod-service/).
|
||||
|
||||
## Headless services
|
||||
|
||||
Sometimes you don't need or want load-balancing and a single service IP. In
|
||||
this case, you can create "headless" services by specifying `"None"` for the
|
||||
cluster IP (`spec.clusterIP`).
|
||||
|
||||
This option allows developers to reduce coupling to the Kubernetes system by
|
||||
allowing them freedom to do discovery their own way. Applications can still use
|
||||
a self-registration pattern and adapters for other discovery systems could easily
|
||||
be built upon this API.
|
||||
|
||||
For such `Services`, a cluster IP is not allocated, kube-proxy does not handle
|
||||
these services, and there is no load balancing or proxying done by the platform
|
||||
for them. How DNS is automatically configured depends on whether the service has
|
||||
selectors defined.
|
||||
|
||||
### With selectors
|
||||
|
||||
For headless services that define selectors, the endpoints controller creates
|
||||
`Endpoints` records in the API, and modifies the DNS configuration to return A
|
||||
records (addresses) that point directly to the `Pods` backing the `Service`.
|
||||
|
||||
### Without selectors
|
||||
|
||||
For headless services that do not define selectors, the endpoints controller does
|
||||
not create `Endpoints` records. However, the DNS system looks for and configures
|
||||
either:
|
||||
|
||||
* CNAME records for `ExternalName`-type services.
|
||||
* A records for any `Endpoints` that share a name with the service, for all
|
||||
other types.
|
||||
|
||||
## Publishing services - service types
|
||||
|
||||
For some parts of your application (e.g. frontends) you may want to expose a
|
||||
Service onto an external (outside of your cluster) IP address.
|
||||
|
||||
|
||||
Kubernetes `ServiceTypes` allow you to specify what kind of service you want.
|
||||
The default is `ClusterIP`.
|
||||
|
||||
`Type` values and their behaviors are:
|
||||
|
||||
* `ClusterIP`: Exposes the service on a cluster-internal IP. Choosing this value
|
||||
makes the service only reachable from within the cluster. This is the
|
||||
default `ServiceType`.
|
||||
* `NodePort`: Exposes the service on each Node's IP at a static port (the `NodePort`).
|
||||
A `ClusterIP` service, to which the `NodePort` service will route, is automatically
|
||||
created. You'll be able to contact the `NodePort` service, from outside the cluster,
|
||||
by requesting `<NodeIP>:<NodePort>`.
|
||||
* `LoadBalancer`: Exposes the service externally using a cloud provider's load balancer.
|
||||
`NodePort` and `ClusterIP` services, to which the external load balancer will route,
|
||||
are automatically created.
|
||||
* `ExternalName`: Maps the service to the contents of the `externalName` field
|
||||
(e.g. `foo.bar.example.com`), by returning a `CNAME` record with its value.
|
||||
No proxying of any kind is set up. This requires version 1.7 or higher of
|
||||
`kube-dns`.
|
||||
|
||||
### Type NodePort
|
||||
|
||||
If you set the `type` field to `"NodePort"`, the Kubernetes master will
|
||||
allocate a port from a flag-configured range (default: 30000-32767), and each
|
||||
Node will proxy that port (the same port number on every Node) into your `Service`.
|
||||
That port will be reported in your `Service`'s `spec.ports[*].nodePort` field.
|
||||
|
||||
If you want to specify particular IP(s) to proxy the port, you can set the `--nodeport-addresses` flag in kube-proxy to particular IP block(s) (which is supported since Kubernetes v1.10). A comma-delimited list of IP blocks (e.g. 10.0.0.0/8, 1.2.3.4/32) is used to filter addresses local to this node. For example, if you start kube-proxy with flag `--nodeport-addresses=127.0.0.0/8`, kube-proxy will select only the loopback interface for NodePort Services. The `--nodeport-addresses` is defaulted to empty (`[]`), which means select all available interfaces and is in compliance with current NodePort behaviors.
|
||||
|
||||
If you want a specific port number, you can specify a value in the `nodePort`
|
||||
field, and the system will allocate you that port or else the API transaction
|
||||
will fail (i.e. you need to take care about possible port collisions yourself).
|
||||
The value you specify must be in the configured range for node ports.
|
||||
|
||||
This gives developers the freedom to set up their own load balancers, to
|
||||
configure environments that are not fully supported by Kubernetes, or
|
||||
even to just expose one or more nodes' IPs directly.
|
||||
|
||||
Note that this Service will be visible as both `<NodeIP>:spec.ports[*].nodePort`
|
||||
and `spec.clusterIP:spec.ports[*].port`. (If the `--nodeport-addresses` flag in kube-proxy is set, <NodeIP> would be filtered NodeIP(s).)
|
||||
|
||||
### Type LoadBalancer
|
||||
|
||||
On cloud providers which support external load balancers, setting the `type`
|
||||
field to `"LoadBalancer"` will provision a load balancer for your `Service`.
|
||||
The actual creation of the load balancer happens asynchronously, and
|
||||
information about the provisioned balancer will be published in the `Service`'s
|
||||
`status.loadBalancer` field. For example:
|
||||
|
||||
```yaml
|
||||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: my-service
|
||||
spec:
|
||||
selector:
|
||||
app: MyApp
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 80
|
||||
targetPort: 9376
|
||||
clusterIP: 10.0.171.239
|
||||
loadBalancerIP: 78.11.24.19
|
||||
type: LoadBalancer
|
||||
status:
|
||||
loadBalancer:
|
||||
ingress:
|
||||
- ip: 146.148.47.155
|
||||
```
|
||||
|
||||
Traffic from the external load balancer will be directed at the backend `Pods`,
|
||||
though exactly how that works depends on the cloud provider. Some cloud providers allow
|
||||
the `loadBalancerIP` to be specified. In those cases, the load-balancer will be created
|
||||
with the user-specified `loadBalancerIP`. If the `loadBalancerIP` field is not specified,
|
||||
an ephemeral IP will be assigned to the loadBalancer. If the `loadBalancerIP` is specified, but the
|
||||
cloud provider does not support the feature, the field will be ignored.
|
||||
|
||||
**Special notes for Azure**: To use user-specified public type `loadBalancerIP`, a static type
|
||||
public IP address resource needs to be created first, and it should be in the same resource
|
||||
group of the cluster. Specify the assigned IP address as loadBalancerIP. Verify you have
|
||||
securityGroupName in the cloud provider configuration file.
|
||||
|
||||
#### Internal load balancer
|
||||
In a mixed environment it is sometimes necessary to route traffic from services inside the same VPC.
|
||||
|
||||
In a split-horizon DNS environment you would need two services to be able to route both external and internal traffic to your endpoints.
|
||||
|
||||
This can be achieved by adding the following annotations to the service based on cloud provider.
|
||||
|
||||
{{< tabs name="service_tabs" >}}
|
||||
{{% tab name="Decfault" %}}
|
||||
Select one of the tabs.
|
||||
{{% /tab %}}
|
||||
{{% tab name="GCP" %}}
|
||||
```yaml
|
||||
[...]
|
||||
metadata:
|
||||
name: my-service
|
||||
annotations:
|
||||
cloud.google.com/load-balancer-type: "Internal"
|
||||
[...]
|
||||
```
|
||||
Use `cloud.google.com/load-balancer-type: "internal"` for masters with version 1.7.0 to 1.7.3.
|
||||
For more information, see the [docs](https://cloud.google.com/kubernetes-engine/docs/internal-load-balancing).
|
||||
{{% /tab %}}
|
||||
{{% tab name="AWS" %}}
|
||||
```yaml
|
||||
[...]
|
||||
metadata:
|
||||
name: my-service
|
||||
annotations:
|
||||
service.beta.kubernetes.io/aws-load-balancer-internal: 0.0.0.0/0
|
||||
[...]
|
||||
```
|
||||
{{% /tab %}}
|
||||
{{% tab name="Azure" %}}
|
||||
```yaml
|
||||
[...]
|
||||
metadata:
|
||||
name: my-service
|
||||
annotations:
|
||||
service.beta.kubernetes.io/azure-load-balancer-internal: "true"
|
||||
[...]
|
||||
```
|
||||
{{% /tab %}}
|
||||
{{% tab name="OpenStack" %}}
|
||||
```yaml
|
||||
[...]
|
||||
metadata:
|
||||
name: my-service
|
||||
annotations:
|
||||
service.beta.kubernetes.io/openstack-internal-load-balancer: "true"
|
||||
[...]
|
||||
```
|
||||
{{% /tab %}}
|
||||
{{< /tabs >}}
|
||||
|
||||
|
||||
#### SSL support on AWS
|
||||
For partial SSL support on clusters running on AWS, starting with 1.3 three
|
||||
annotations can be added to a `LoadBalancer` service:
|
||||
|
||||
```yaml
|
||||
metadata:
|
||||
name: my-service
|
||||
annotations:
|
||||
service.beta.kubernetes.io/aws-load-balancer-ssl-cert: arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012
|
||||
```
|
||||
|
||||
The first specifies the ARN of the certificate to use. It can be either a
|
||||
certificate from a third party issuer that was uploaded to IAM or one created
|
||||
within AWS Certificate Manager.
|
||||
|
||||
```yaml
|
||||
metadata:
|
||||
name: my-service
|
||||
annotations:
|
||||
service.beta.kubernetes.io/aws-load-balancer-backend-protocol: (https|http|ssl|tcp)
|
||||
```
|
||||
|
||||
The second annotation specifies which protocol a pod speaks. For HTTPS and
|
||||
SSL, the ELB will expect the pod to authenticate itself over the encrypted
|
||||
connection.
|
||||
|
||||
HTTP and HTTPS will select layer 7 proxying: the ELB will terminate
|
||||
the connection with the user, parse headers and inject the `X-Forwarded-For`
|
||||
header with the user's IP address (pods will only see the IP address of the
|
||||
ELB at the other end of its connection) when forwarding requests.
|
||||
|
||||
TCP and SSL will select layer 4 proxying: the ELB will forward traffic without
|
||||
modifying the headers.
|
||||
|
||||
In a mixed-use environment where some ports are secured and others are left unencrypted,
|
||||
the following annotations may be used:
|
||||
|
||||
```yaml
|
||||
metadata:
|
||||
name: my-service
|
||||
annotations:
|
||||
service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http
|
||||
service.beta.kubernetes.io/aws-load-balancer-ssl-ports: "443,8443"
|
||||
```
|
||||
|
||||
In the above example, if the service contained three ports, `80`, `443`, and
|
||||
`8443`, then `443` and `8443` would use the SSL certificate, but `80` would just
|
||||
be proxied HTTP.
|
||||
|
||||
Beginning in 1.9, services can use [predefined AWS SSL policies](http://docs.aws.amazon.com/elasticloadbalancing/latest/classic/elb-security-policy-table.html)
|
||||
for any HTTPS or SSL listeners. To see which policies are available for use, run
|
||||
the awscli command:
|
||||
|
||||
```bash
|
||||
aws elb describe-load-balancer-policies --query 'PolicyDescriptions[].PolicyName'
|
||||
```
|
||||
|
||||
Any one of those policies can then be specified using the
|
||||
"`service.beta.kubernetes.io/aws-load-balancer-ssl-negotiation-policy`"
|
||||
annotation, for example:
|
||||
|
||||
```yaml
|
||||
metadata:
|
||||
name: my-service
|
||||
annotations:
|
||||
service.beta.kubernetes.io/aws-load-balancer-ssl-negotiation-policy: "ELBSecurityPolicy-TLS-1-2-2017-01"
|
||||
```
|
||||
|
||||
#### PROXY protocol support on AWS
|
||||
|
||||
To enable [PROXY protocol](https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt)
|
||||
support for clusters running on AWS, you can use the following service
|
||||
annotation:
|
||||
|
||||
```yaml
|
||||
metadata:
|
||||
name: my-service
|
||||
annotations:
|
||||
service.beta.kubernetes.io/aws-load-balancer-proxy-protocol: "*"
|
||||
```
|
||||
|
||||
Since version 1.3.0 the use of this annotation applies to all ports proxied by the ELB
|
||||
and cannot be configured otherwise.
|
||||
|
||||
#### ELB Access Logs on AWS
|
||||
|
||||
There are several annotations to manage access logs for ELB services on AWS.
|
||||
|
||||
The annotation `service.beta.kubernetes.io/aws-load-balancer-access-log-enabled`
|
||||
controls whether access logs are enabled.
|
||||
|
||||
The annotation `service.beta.kubernetes.io/aws-load-balancer-access-log-emit-interval`
|
||||
controls the interval in minutes for publishing the access logs. You can specify
|
||||
an interval of either 5 or 60.
|
||||
|
||||
The annotation `service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-name`
|
||||
controls the name of the Amazon S3 bucket where load balancer access logs are
|
||||
stored.
|
||||
|
||||
The annotation `service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-prefix`
|
||||
specifies the logical hierarchy you created for your Amazon S3 bucket.
|
||||
|
||||
```yaml
|
||||
metadata:
|
||||
name: my-service
|
||||
annotations:
|
||||
service.beta.kubernetes.io/aws-load-balancer-access-log-enabled: "true"
|
||||
# Specifies whether access logs are enabled for the load balancer
|
||||
service.beta.kubernetes.io/aws-load-balancer-access-log-emit-interval: "60"
|
||||
# The interval for publishing the access logs. You can specify an interval of either 5 or 60 (minutes).
|
||||
service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-name: "my-bucket"
|
||||
# The name of the Amazon S3 bucket where the access logs are stored
|
||||
service.beta.kubernetes.io/aws-load-balancer-access-log-s3-bucket-prefix: "my-bucket-prefix/prod"
|
||||
# The logical hierarchy you created for your Amazon S3 bucket, for example `my-bucket-prefix/prod`
|
||||
```
|
||||
|
||||
#### Connection Draining on AWS
|
||||
|
||||
Connection draining for Classic ELBs can be managed with the annotation
|
||||
`service.beta.kubernetes.io/aws-load-balancer-connection-draining-enabled` set
|
||||
to the value of `"true"`. The annotation
|
||||
`service.beta.kubernetes.io/aws-load-balancer-connection-draining-timeout` can
|
||||
also be used to set maximum time, in seconds, to keep the existing connections open before deregistering the instances.
|
||||
|
||||
|
||||
```yaml
|
||||
metadata:
|
||||
name: my-service
|
||||
annotations:
|
||||
service.beta.kubernetes.io/aws-load-balancer-connection-draining-enabled: "true"
|
||||
service.beta.kubernetes.io/aws-load-balancer-connection-draining-timeout: "60"
|
||||
```
|
||||
|
||||
#### Other ELB annotations
|
||||
|
||||
There are other annotations to manage Classic Elastic Load Balancers that are described below.
|
||||
|
||||
```yaml
|
||||
metadata:
|
||||
name: my-service
|
||||
annotations:
|
||||
service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout: "60"
|
||||
# The time, in seconds, that the connection is allowed to be idle (no data has been sent over the connection) before it is closed by the load balancer
|
||||
|
||||
service.beta.kubernetes.io/aws-load-balancer-cross-zone-load-balancing-enabled: "true"
|
||||
# Specifies whether cross-zone load balancing is enabled for the load balancer
|
||||
|
||||
service.beta.kubernetes.io/aws-load-balancer-additional-resource-tags: "environment=prod,owner=devops"
|
||||
# A comma-separated list of key-value pairs which will be recorded as
|
||||
# additional tags in the ELB.
|
||||
|
||||
service.beta.kubernetes.io/aws-load-balancer-healthcheck-healthy-threshold: ""
|
||||
# The number of successive successful health checks required for a backend to
|
||||
# be considered healthy for traffic. Defaults to 2, must be between 2 and 10
|
||||
|
||||
service.beta.kubernetes.io/aws-load-balancer-healthcheck-unhealthy-threshold: "3"
|
||||
# The number of unsuccessful health checks required for a backend to be
|
||||
# considered unhealthy for traffic. Defaults to 6, must be between 2 and 10
|
||||
|
||||
service.beta.kubernetes.io/aws-load-balancer-healthcheck-interval: "20"
|
||||
# The approximate interval, in seconds, between health checks of an
|
||||
# individual instance. Defaults to 10, must be between 5 and 300
|
||||
service.beta.kubernetes.io/aws-load-balancer-healthcheck-timeout: "5"
|
||||
# The amount of time, in seconds, during which no response means a failed
|
||||
# health check. This value must be less than the service.beta.kubernetes.io/aws-load-balancer-healthcheck-interval
|
||||
# value. Defaults to 5, must be between 2 and 60
|
||||
|
||||
service.beta.kubernetes.io/aws-load-balancer-extra-security-groups: "sg-53fae93f,sg-42efd82e"
|
||||
# A list of additional security groups to be added to ELB
|
||||
```
|
||||
|
||||
#### Network Load Balancer support on AWS [alpha]
|
||||
|
||||
**Warning:** This is an alpha feature and not recommended for production clusters yet.
|
||||
|
||||
Starting in version 1.9.0, Kubernetes supports Network Load Balancer (NLB). To
|
||||
use a Network Load Balancer on AWS, use the annotation `service.beta.kubernetes.io/aws-load-balancer-type`
|
||||
with the value set to `nlb`.
|
||||
|
||||
```yaml
|
||||
metadata:
|
||||
name: my-service
|
||||
annotations:
|
||||
service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
|
||||
```
|
||||
|
||||
Unlike Classic Elastic Load Balancers, Network Load Balancers (NLBs) forward the
|
||||
client's IP through to the node. If a service's `spec.externalTrafficPolicy` is
|
||||
set to `Cluster`, the client's IP address will not be propagated to the end
|
||||
pods.
|
||||
|
||||
By setting `spec.externalTrafficPolicy` to `Local`, client IP addresses will be
|
||||
propagated to the end pods, but this could result in uneven distribution of
|
||||
traffic. Nodes without any pods for a particular LoadBalancer service will fail
|
||||
the NLB Target Group's health check on the auto-assigned
|
||||
`spec.healthCheckNodePort` and not receive any traffic.
|
||||
|
||||
In order to achieve even traffic, either use a DaemonSet, or specify a
|
||||
[pod anti-affinity](/docs/concepts/configuration/assign-pod-node/#inter-pod-affinity-and-anti-affinity-beta-feature)
|
||||
to not locate pods on the same node.
|
||||
|
||||
NLB can also be used with the [internal load balancer](/docs/concepts/services-networking/service/#internal-load-balancer)
|
||||
annotation.
|
||||
|
||||
In order for client traffic to reach instances behind an NLB, the Node security
|
||||
groups are modified with the following IP rules:
|
||||
|
||||
| Rule | Protocol | Port(s) | IpRange(s) | IpRange Description |
|
||||
|------|----------|---------|------------|---------------------|
|
||||
| Health Check | TCP | NodePort(s) (`spec.healthCheckNodePort` for `spec.externalTrafficPolicy = Local`) | VPC CIDR | kubernetes.io/rule/nlb/health=\<loadBalancerName\> |
|
||||
| Client Traffic | TCP | NodePort(s) | `spec.loadBalancerSourceRanges` (defaults to `0.0.0.0/0`) | kubernetes.io/rule/nlb/client=\<loadBalancerName\> |
|
||||
| MTU Discovery | ICMP | 3,4 | `spec.loadBalancerSourceRanges` (defaults to `0.0.0.0/0`) | kubernetes.io/rule/nlb/mtu=\<loadBalancerName\> |
|
||||
|
||||
Be aware that if `spec.loadBalancerSourceRanges` is not set, Kubernetes will
|
||||
allow traffic from `0.0.0.0/0` to the Node Security Group(s). If nodes have
|
||||
public IP addresses, be aware that non-NLB traffic can also reach all instances
|
||||
in those modified security groups.
|
||||
|
||||
In order to limit which client IP's can access the Network Load Balancer,
|
||||
specify `loadBalancerSourceRanges`.
|
||||
|
||||
```yaml
|
||||
spec:
|
||||
loadBalancerSourceRanges:
|
||||
- "143.231.0.0/16"
|
||||
```
|
||||
|
||||
**Note:** NLB only works with certain instance classes, see the [AWS documentation](http://docs.aws.amazon.com/elasticloadbalancing/latest/network/target-group-register-targets.html#register-deregister-targets)
|
||||
for supported instance types.
|
||||
|
||||
|
||||
### External IPs
|
||||
|
||||
If there are external IPs that route to one or more cluster nodes, Kubernetes services can be exposed on those
|
||||
`externalIPs`. Traffic that ingresses into the cluster with the external IP (as destination IP), on the service port,
|
||||
will be routed to one of the service endpoints. `externalIPs` are not managed by Kubernetes and are the responsibility
|
||||
of the cluster administrator.
|
||||
|
||||
In the `ServiceSpec`, `externalIPs` can be specified along with any of the `ServiceTypes`.
|
||||
In the example below, "`my-service`" can be accessed by clients on "`80.11.12.10:80`"" (`externalIP:port`)
|
||||
|
||||
```yaml
|
||||
kind: Service
|
||||
apiVersion: v1
|
||||
metadata:
|
||||
name: my-service
|
||||
spec:
|
||||
selector:
|
||||
app: MyApp
|
||||
ports:
|
||||
- name: http
|
||||
protocol: TCP
|
||||
port: 80
|
||||
targetPort: 9376
|
||||
externalIPs:
|
||||
- 80.11.12.10
|
||||
```
|
||||
|
||||
## Shortcomings
|
||||
|
||||
Using the userspace proxy for VIPs will work at small to medium scale, but will
|
||||
not scale to very large clusters with thousands of Services. See [the original
|
||||
design proposal for portals](http://issue.k8s.io/1107) for more details.
|
||||
|
||||
Using the userspace proxy obscures the source-IP of a packet accessing a `Service`.
|
||||
This makes some kinds of firewalling impossible. The iptables proxier does not
|
||||
obscure in-cluster source IPs, but it does still impact clients coming through
|
||||
a load-balancer or node-port.
|
||||
|
||||
The `Type` field is designed as nested functionality - each level adds to the
|
||||
previous. This is not strictly required on all cloud providers (e.g. Google Compute Engine does
|
||||
not need to allocate a `NodePort` to make `LoadBalancer` work, but AWS does)
|
||||
but the current API requires it.
|
||||
|
||||
## Future work
|
||||
|
||||
In the future we envision that the proxy policy can become more nuanced than
|
||||
simple round robin balancing, for example master-elected or sharded. We also
|
||||
envision that some `Services` will have "real" load balancers, in which case the
|
||||
VIP will simply transport the packets there.
|
||||
|
||||
We intend to improve our support for L7 (HTTP) `Services`.
|
||||
|
||||
We intend to have more flexible ingress modes for `Services` which encompass
|
||||
the current `ClusterIP`, `NodePort`, and `LoadBalancer` modes and more.
|
||||
|
||||
## The gory details of virtual IPs
|
||||
|
||||
The previous information should be sufficient for many people who just want to
|
||||
use `Services`. However, there is a lot going on behind the scenes that may be
|
||||
worth understanding.
|
||||
|
||||
### Avoiding collisions
|
||||
|
||||
One of the primary philosophies of Kubernetes is that users should not be
|
||||
exposed to situations that could cause their actions to fail through no fault
|
||||
of their own. In this situation, we are looking at network ports - users
|
||||
should not have to choose a port number if that choice might collide with
|
||||
another user. That is an isolation failure.
|
||||
|
||||
In order to allow users to choose a port number for their `Services`, we must
|
||||
ensure that no two `Services` can collide. We do that by allocating each
|
||||
`Service` its own IP address.
|
||||
|
||||
To ensure each service receives a unique IP, an internal allocator atomically
|
||||
updates a global allocation map in etcd prior to creating each service. The map object
|
||||
must exist in the registry for services to get IPs, otherwise creations will
|
||||
fail with a message indicating an IP could not be allocated. A background
|
||||
controller is responsible for creating that map (to migrate from older versions
|
||||
of Kubernetes that used in memory locking) as well as checking for invalid
|
||||
assignments due to administrator intervention and cleaning up any IPs
|
||||
that were allocated but which no service currently uses.
|
||||
|
||||
### IPs and VIPs
|
||||
|
||||
Unlike `Pod` IP addresses, which actually route to a fixed destination,
|
||||
`Service` IPs are not actually answered by a single host. Instead, we use
|
||||
`iptables` (packet processing logic in Linux) to define virtual IP addresses
|
||||
which are transparently redirected as needed. When clients connect to the
|
||||
VIP, their traffic is automatically transported to an appropriate endpoint.
|
||||
The environment variables and DNS for `Services` are actually populated in
|
||||
terms of the `Service`'s VIP and port.
|
||||
|
||||
We support three proxy modes - userspace, iptables and ipvs which operate
|
||||
slightly differently.
|
||||
|
||||
#### Userspace
|
||||
|
||||
As an example, consider the image processing application described above.
|
||||
When the backend `Service` is created, the Kubernetes master assigns a virtual
|
||||
IP address, for example 10.0.0.1. Assuming the `Service` port is 1234, the
|
||||
`Service` is observed by all of the `kube-proxy` instances in the cluster.
|
||||
When a proxy sees a new `Service`, it opens a new random port, establishes an
|
||||
iptables redirect from the VIP to this new port, and starts accepting
|
||||
connections on it.
|
||||
|
||||
When a client connects to the VIP the iptables rule kicks in, and redirects
|
||||
the packets to the `Service proxy`'s own port. The `Service proxy` chooses a
|
||||
backend, and starts proxying traffic from the client to the backend.
|
||||
|
||||
This means that `Service` owners can choose any port they want without risk of
|
||||
collision. Clients can simply connect to an IP and port, without being aware
|
||||
of which `Pods` they are actually accessing.
|
||||
|
||||
#### Iptables
|
||||
|
||||
Again, consider the image processing application described above.
|
||||
When the backend `Service` is created, the Kubernetes master assigns a virtual
|
||||
IP address, for example 10.0.0.1. Assuming the `Service` port is 1234, the
|
||||
`Service` is observed by all of the `kube-proxy` instances in the cluster.
|
||||
When a proxy sees a new `Service`, it installs a series of iptables rules which
|
||||
redirect from the VIP to per-`Service` rules. The per-`Service` rules link to
|
||||
per-`Endpoint` rules which redirect (Destination NAT) to the backends.
|
||||
|
||||
When a client connects to the VIP the iptables rule kicks in. A backend is
|
||||
chosen (either based on session affinity or randomly) and packets are
|
||||
redirected to the backend. Unlike the userspace proxy, packets are never
|
||||
copied to userspace, the kube-proxy does not have to be running for the VIP to
|
||||
work, and the client IP is not altered.
|
||||
|
||||
This same basic flow executes when traffic comes in through a node-port or
|
||||
through a load-balancer, though in those cases the client IP does get altered.
|
||||
|
||||
#### Ipvs
|
||||
|
||||
Iptables operations slow down dramatically in large scale cluster e.g 10,000 Services. IPVS is designed for load balancing and based on in-kernel hash tables. So we can achieve performance consistency in large number of services from IPVS-based kube-proxy. Meanwhile, IPVS-based kube-proxy has more sophisticated load balancing algorithms (least conns, locality, weighted, persistence).
|
||||
|
||||
## API Object
|
||||
|
||||
Service is a top-level resource in the Kubernetes REST API. More details about the
|
||||
API object can be found at:
|
||||
[Service API object](/docs/reference/generated/kubernetes-api/{{< param "version" >}}/#service-v1-core).
|
||||
|
||||
## For More Information
|
||||
|
||||
Read [Connecting a Front End to a Back End Using a Service](/docs/tasks/access-application-cluster/connecting-frontend-backend/).
|
||||
Reference in New Issue
Block a user