The type field sets a Service's reach, each type building on the last: ClusterIP (the default) is reachable only inside the cluster; NodePort adds a port from 30000-32767 on every node; LoadBalancer adds an external address from a cloud controller. BookNest's API needs only a ClusterIP; targetPort: http names the container port:
apiVersion: v1
kind: Service
metadata: { name: api, labels: { app: booknest, tier: api } }
spec:
selector: { app: booknest, tier: api }
ports: [{ name: http, port: 3000, targetPort: http }]Call it from a client Pod, then call a NodePort copy from the host:
kubectl apply -f k8s/api-service.yaml && kubectl get service api
kubectl run client --image=localhost:33500/booknest-web:1.3 --command -- sleep 86400
kubectl wait --for=condition=Ready pod/client >/dev/null
kubectl exec client -- wget -qO- http://api:3000/version && echo
kubectl expose deployment api --name=api-np --type=NodePort --port=3000 --target-port=http
NODE=$(kubectl get node l3-booknest-worker -o jsonpath='{.status.addresses[0].address}')
PORT=$(kubectl get service api-np -o jsonpath='{.spec.ports[0].nodePort}')
sleep 2; curl -s http://$NODE:$PORT/version && echo && kubectl delete service api-npOutput
service/api created
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
api ClusterIP 10.96.121.82 <none> 3000/TCP 0s
pod/client created
{"version":"1.4.0"}
service/api-np exposed
{"version":"1.4.0"}
service "api-np" deleted from booknest namespaceThe ClusterIP exists only in kube-proxy's rules; nothing answers ping on it. The NodePort works on every node's IP. On kind 14,561 , cloud-provider-kind 508 supplies LoadBalancer addresses (Local Feature Comparison).