# Exposing containers

## Exposing containers

* `kubectl expose` creates a service for existing pods
* A service is a stable address for pod(s)
* If we want to connect to pod(s) we need a service
* CoreDNS (part of control plane) allows us to resolve services by name
* There are different types of services
  * **ClusterIP** (default)
    * Single, internal virtual IP allocated
    * Only reachable from within cluster (nodes and pods)
    * Pods can reach service on apps port number
    * Always available in Kubernetes
  * **NodePort**
    * High port allocated on each node
    * Port is open on every node's IP
    * Anyone can connect (if they can reach node)
    * Other pods need to be updated to this port
    * Always available in Kubernetes
  * **LoadBalancer**
    * Controls LB endpoint external to the cluster
    * Only available when infrastructure provider gives you a load balancer (AWS ELB, etc)
    * Creates NodePort + ClusterIP services, tells external load balancer to send traffic to NodePort
  * **ExternalName**
    * Adds CNAME DNS records to CoreDNS only
    * Not used for pods, but for giving pods a DNS name to use for something outside Kubernetes

### Creating a ClusterIP service

* `kubectl get pods -w`
* `kubectl create deployment httpenv --image=bretfisher/httpenv`
* `kubectl scale deployment/httpenv --replicas=5`
* `kubectl expose deployment/httpenv --port 8888`
* `kubectl get service`
* `kubectl run --generator run-pod/v1 tmp-shell --rm -it --image=bretfisher/netshoot -- bash`
* `curl httpenv:8888`

```
{
  "HOME": "/root",
  "HOSTNAME": "httpenv-7cc9888d59-s9sj6",
  "KUBERNETES_PORT": "tcp://10.96.0.1:443",
  "KUBERNETES_PORT_443_TCP": "tcp://10.96.0.1:443",
  "KUBERNETES_PORT_443_TCP_ADDR": "10.96.0.1",
  "KUBERNETES_PORT_443_TCP_PORT": "443",
  "KUBERNETES_PORT_443_TCP_PROTO": "tcp",
  "KUBERNETES_SERVICE_HOST": "10.96.0.1",
  "KUBERNETES_SERVICE_PORT": "443",
  "KUBERNETES_SERVICE_PORT_HTTPS": "443",
  "PATH": "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
}
```

### Creating a NodePort service

* `kubectl expose deployment/httpenv --port 8888 --name httpenv-np --type NodePort`
* `kubectl get services`

| NAME       | TYPE      | CLUSTER-IP    | EXTERNAL-IP | PORT(S)        | AGE   |
| ---------- | --------- | ------------- | ----------- | -------------- | ----- |
| httpenv    | ClusterIP | 10.107.92.157 | none        | 8888/TCP       | 24h   |
| httpenv-np | NodePort  | 10.109.25.172 | none        | 8888:31642/TCP | 8s    |
| kubernetes | ClusterIP | 10.96.0.1     | none        | 443/TCP        | 2d13h |

* 8888:31642/TCP - from port 8888 inside the cluster to port 31642 externally accessible
* Default port ranges in the cluster 30000-32767
* These 3 service types are additive, each one creates one above it:
  * ClusterIP
  * NodePort
  * LoadBalancer
* `curl localhost:31642` (on Linux - goes directly to NodePort, on Mac/Windows goes through Docker VPNKit)

### Creating a LoadBalancer service

* Docker Desktop provides a built-in LoadBalancer that publishes the port on localhost
* `kubectl expose deployment/httpenv --port 8888 --name httpenv-lb --type LoadBalancer`
* `curl localhost:8888`

| NAME       | TYPE         | CLUSTER-IP    | EXTERNAL-IP | PORT(S)        | AGE   |
| ---------- | ------------ | ------------- | ----------- | -------------- | ----- |
| httpenv    | ClusterIP    | 10.107.92.157 | none        | 8888/TCP       | 24h   |
| httpenv-np | NodePort     | 10.109.25.172 | none        | 8888:31642/TCP | 8s    |
| httpenv-lb | LoadBalancer | 10.98.39.13   | localhost   | 8888:30695/TCP | 19s   |
| kubernetes | ClusterIP    | 10.96.0.1     | none        | 443/TCP        | 2d13h |

### Cleanup

* `kubectl delete service/httpenv service/httpenv-np service/httpenv-lb deployment/httpenv`

## Kubernetes Service DNS

* Starting with 1.11, internal DNS is provided by CoreDNS
* Like Swarm, this is DNS-based service discovery&#x20;
* Accessing services by hostname works only if they're in the same namespace
* `kubectl get namespaces`
* Services also have a FQDN

  &#x20; `curl <hostname>.<namespace>.svc.cluster.local`
