Kubernetes Services
Here are more notes while learning Kubernetes, now it is about Services:
Imperative Way
Given the following manifest for a Deployment:
❯ cat deploy.yml
apiVersion: apps/v1
kind: Deployment <<<======
metadata:
name: svc-test <<<<=====
spec:
replicas: 10
selector:
matchLabels:
chapter: services
template:
metadata:
labels:
chapter: services
spec:
containers:
- name: hello-ctr
image: nigelpoulton/k8sbook:1.0
ports:
- containerPort: 8080
First, we will create this one in a declarative way:
❯ kubectl apply -f deploy.yml
deployment.apps/svc-test created
❯ kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
hello-deploy 10/10 10 10 8d
svc-test 10/10 10 10 5m30s <<<=======
Now that the “svc-test” Deployment is running, we can add a Service for it. (Again, in a imperative way):
❯ kubectl expose deployment svc-test --type=NodePort
service/svc-test exposed
❯ kubectl get svc -o wide
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTOR
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 38d <none>
svc-test NodePort 10.96.46.88 <none> 8080:34937/TCP 2m35s chapter=services
From the previous output we can interpret the following:
- The firt line, “kubernetes” service is a system Service that exposes the Kubernetes API on the cluster.
- svc-test is our Service. Notice how this took the name of the Deployment.
- Notice that the label was also taken from the svc-test Deployment.
If we want more details about the Service, we can use the following:
❯ kubectl describe svc svc-test
Name: svc-test
Namespace: default
Labels: <none>
Annotations: <none>
Selector: chapter=services
Type: NodePort
IP Families: <none>
IP: 10.96.46.88 <<==== Internal ClusterIP
IPs: 10.96.46.88
Port: <unset> 8080/TCP <<<====== Listening port on ClusterIP.
TargetPort: 8080/TCP <<<====== Listening port on application
NodePort: <unset> 34937/TCP <<<====== Listening port on Node.
Endpoints: 192.168.255.77:8080,192.168.255.79:8080,192.168.255.80:8080 + 7 more...
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>
Additionally, if we want to check the list of endpoints available for this Service:
❯ kubectl get endpoints
NAME ENDPOINTS AGE
kubernetes 10.0.112.3:12388,10.0.115.129:12388,10.0.142.193:12388 38d
svc-test 192.168.255.77:8080,192.168.255.79:8080,192.168.255.80:8080 + 7 more... 21m
❯ kubectl get endpointslices
NAME ADDRESSTYPE PORTS ENDPOINTS AGE
kubernetes IPv4 12388 10.0.112.3,10.0.115.129,10.0.142.193 38d
svc-test-2kmq8 IPv4 8080 192.168.255.82,192.168.255.83,192.168.255.79 + 7 more... 21m
Notice how the second output provides the PORTS column.
Declarative Way (Kubernetes prefered way)
Given the following Service manifest:
❯ cat svc.yml
apiVersion: v1
kind: Service <<<=======
metadata:
name: svc-test
labels:
chapter: services
spec:
type: NodePort <<<=====
ports:
- port: 8080
nodePort: 32768
targetPort: 8080
protocol: TCP
selector:
chapter: services
We can create the Service which includes an exposed port already, so no need to use “kubectl expose” as we did previously:
❯ kubectl apply -f svc.yml
service/svc-test created
❯ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 38d
svc-test NodePort 10.96.41.50 <none> 8080:32768/TCP 9s
Notice the PORT column listing the available port on the node where we could externally (coming outside the cluster, via Internet) access the applicationn.
Last, we can take a look at the endpoints associated to this Service:
❯ kubectl describe endpointslices svc-test-zsqnf
Name: svc-test-zsqnf
Namespace: default
Labels: chapter=services
endpointslice.kubernetes.io/managed-by=endpointslice-controller.k8s.io
kubernetes.io/service-name=svc-test
Annotations: endpoints.kubernetes.io/last-change-trigger-time: 2022-03-25T13:49:13Z
AddressType: IPv4
Ports:
Name Port Protocol
---- ---- --------
<unset> 8080 TCP
Endpoints:
- Addresses: 192.168.64.80
Conditions:
Ready: true
Hostname: <unset>
TargetRef: Pod/svc-test-84db6ff656-fmccs
Topology: kubernetes.io/hostname=mke-node-1
- Addresses: 192.168.255.80
Conditions:
Ready: true
Hostname: <unset>
TargetRef: Pod/svc-test-84db6ff656-ccxzb
Topology: kubernetes.io/hostname=mke-node-0
- Addresses: 192.168.64.81
Conditions:
Ready: true
Hostname: <unset>
TargetRef: Pod/svc-test-84db6ff656-j7frk
Topology: kubernetes.io/hostname=mke-node-1
.
.
(TRUNCATED OUTPUT)
.
LoadBalancer Services
Given the below manifest, we can create the cloud-lb Service (LoadBalance type):
❯ cat lb.yml
apiVersion: v1
kind: Service
metadata:
name: cloud-lb
spec:
type: LoadBalancer <<<======
ports:
- port: 9000
targetPort: 8080
selector:
chapter: services
❯ kubectl apply -f lb.yml
service/cloud-lb created
❯ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
cloud-lb LoadBalancer 10.96.213.57 <pending> 9000:33351/TCP 37s <<<====
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 38d
svc-test NodePort 10.96.41.50 <none> 8080:32768/TCP 27m
The EXTERNAL-IP colum should show the public IP for the load balancer cloud to access. In my case, it seems there is something pending to fix.