Services
Services¶
A Kubernetes Service is an abstraction layer which defines a logical set of Pods and enables external traffic exposure, load balancing and service discovery for those Pods.
- A Service in Kubernetes is an abstraction which defines a logical set of Pods and a policy by which to access them.
- Services enable a loose coupling between dependent Pods.
- The set of Pods targeted by a Service is usually determined by a LabelSelector
- Although each Pod has a unique IP address, those IPs are not exposed outside the cluster without a Service
- Services allow your applications to receive traffic
- You can create a Service at the same time you create a Deployment by using --expose in kubectl.
Create a service¶
To create a new service and expose it to external traffic we’ll use the expose command with NodePort as parameter
$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 4m
$ kubectl get deployments
NAME DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
kubernetes-bootcamp 1 1 1 1 1h
$ kubectl expose deployment/kubernetes-bootcamp --type="NodePort" --port 8080
service "kubernetes-bootcamp" exposed
$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 6m
kubernetes-bootcamp NodePort 10.103.120.102 <none> 8080:31989/TCP 48s
We have now a running Service called kubernetes-bootcamp. Here we see that the Service received a unique cluster-IP, an internal port and an external-IP (the IP of the Node).
$ kubectl describe services/kubernetes-bootcamp
Name: kubernetes-bootcamp
Namespace: default
Labels: run=kubernetes-bootcamp
Annotations: <none>
Selector: run=kubernetes-bootcamp
Type: NodePort
IP: 10.103.120.102
Port: <unset> 8080/TCP
TargetPort: 8080/TCP
NodePort: <unset> 31989/TCP
Endpoints: 172.18.0.4:8080
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>
$ export NODE_PORT=$(kubectl get services/kubernetes-bootcamp -o go-template='{{(index .spec.ports 0).nodePort}}')
$ echo NODE_PORT=$NODE_PORT
NODE_PORT=31989
$ curl host01:$NODE_PORT
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-5dbf48f7d4-m55fc | v=1
Note
kubectl port-forward can be used Forward one or more local ports to a pod
Deleting a service¶
To delete Services
$ kubectl delete service -l run=kubernetes-bootcamp
service "kubernetes-bootcamp" deleted
Confirm that the service is gone
$ kubectl get services
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 13h
To confirm that route is not exposed anymore you can curl the previously exposed IP and port
$ curl host01:$NODE_PORT
curl: (6) Could not resolve host: host01
You can confirm that the app is still running with a curl inside the pod:
$ kubectl exec -ti $POD_NAME curl localhost:8080
Hello Kubernetes bootcamp! | Running on: kubernetes-bootcamp-5d7f968ccb-njgzx | v=1
Services Types¶
- ClusterIP
- NodePort
- LoadBalancer
ClusterIP¶
A ClusterIP service is the default Kubernetes service. It gives you a service inside your cluster that other apps inside your cluster can access. There is no external access. You can access it using the Kubernetes proxy
The YAML for a ClusterIP service looks like this:
apiVersion: v1
kind: Service
metadata:
name: my-internal-service
spec:
selector:
app: my-app
type: ClusterIP
ports:
- name: http
port: 80
targetPort: 80
protocol: TCP
To access the ClusterIp Service, first start the Kubernets proxy
1 |
|
Now, you can navigate through the Kubernetes API to access this service using this scheme:
http://localhost:8080/api/v1/namespaces/<NAMESPACE>/services/<SERVICE-NAME>:<PORT-NAME>/proxy
http://localhost:8080/api/v1/namespaces/challenge/services/jupyter-service:80/proxy/
NodePort¶
A NodePort service is the most primitive way to get external traffic directly to your service. NodePort, as the name implies, opens a specific port on all the Nodes (the VMs), and any traffic that is sent to this port is forwarded to the service.
The YAML for a NodePort service looks like this:
apiVersion: v1
kind: Service
metadata:
name: my-nodeport-service
spec:
selector:
app: my-app
type: NodePort
ports:
- name: http
port: 80
targetPort: 80
nodePort: 30036
protocol: TCP
Basically, a NodePort service has two differences from a normal “ClusterIP” service. First, the type is “NodePort.” There is also an additional port called the nodePort that specifies which port to open on the nodes. If you don’t specify this port, it will pick a random port. Most of the time you should let Kubernetes choose the port
There are many downsides to this method:
- You can only have once service per port
- You can only use ports 30000–32767
- If your Node/VM IP address change, you need to deal with that
LoadBalancer¶
A LoadBalancer service is the standard way to expose a service to the internet. On AWS or GKE, this will spin up a Load Balancer that will give you a single IP address that will forward all traffic to your service
If you want to directly expose a service, this is the default method. All traffic on the port you specify will be forwarded to the service. There is no filtering, no routing, etc. This means you can send almost any kind of traffic to it, like HTTP, TCP, UDP, Websockets, gRPC, or whatever.
Bug
The big downside of LoadBalancer Service is that each service you expose with a LoadBalancer will get its own IP address, and you have to pay for a LoadBalancer per exposed service, which can get expensive!
YAML for LoadbalancerSerivce
{
"kind":"Service",
"apiVersion":"v1",
"metadata":{
"name":"guestbook",
"labels":{
"app":"guestbook"
}
},
"spec":{
"ports": [
{
"port":3000,
"targetPort":"http-server"
}
],
"selector":{
"app":"guestbook"
},
"type": "LoadBalancer"
}
}