Exposing a Kubernetes Cluster Externally with a Service
This page explains how to expose applications inside and outside a cluster by using a Service.
Connecting from inside the cluster
First, check connectivity inside the cluster. Create a Pod that contains a curl container, connect to its Shell, and then test access from curl to the helloworld Pod.
First, create and run a test Pod.
% kubectl run --port 8080 --image gcr.io/google-samples/hello-app:1.0 --restart Never helloworld
pod/helloworld created
Display the Pod list including IP addresses by adding -o wide.
% kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
helloworld 1/1 Running 0 3m44s 172.17.0.3 minikube <none> <none>
Enter the cluster and run curl.
% kubectl run --image curlimages/curl:latest -it --restart Never --rm curl sh
If you don't see a command prompt, try pressing enter.
/ $ curl 172.17.0.3:8080
Hello, world!
Version: 1.0.0
Hostname: helloworld
/ $
This result shows that the curl container can connect to the helloworld container because it specifies helloworld’s IP address, 172.17.0.3, and accesses port 8080.
To confirm that the Pods are inside the same cluster, leave the curl container running, open another terminal, and display the Pod list with IP addresses.
% kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
curl 1/1 Running 0 23s 172.17.0.4 minikube <none> <none>
helloworld 1/1 Running 0 12m 172.17.0.3 minikube <none> <none>
You can confirm that the containers exist on the same network.
Connecting from outside the cluster
Next, if you try to connect from outside the cluster, it will not work. This is the same as Docker, because the host IP range and the Pod IP range are different. To make access possible, you must create a Service and expose the Pod externally.
A Service is an L4 load balancer with a static IP address that exposes Pods inside or outside the cluster. Because a Pod itself may stop at any time, the Service is said to expose the destination that traffic is distributed to.
There are three types of Service, each with the following characteristics.
- ClusterIP Service (access from inside the cluster)
It abstracts the IP of a Pod, which may disappear at any time, and places a proxy with a static IP. This has the following advantages.- You do not need to know the Pod IP when accessing a Pod.
- It load balances access to Pods.
- NodePort Service (access from inside and outside the cluster)
It makes it possible to expose Pods outside the cluster through a Node IP and NodePort, which ClusterIP cannot do.
However, it also has the following disadvantages.- You must know the Node IP.
- You must know the Node Port.
- LoadBalancer Service (access from inside and outside the cluster)
It routes from the provider’s L4 load balancer DNS to a specific port on each node and accesses the Pod.
Therefore, you do not need to know the Node IP or Node port. However, it also has the following disadvantages.- One load balancer is created for each Service, which makes it expensive.
- Because it is an L4 load balancer, it cannot perform LB distribution by L7 HTTP host or path.
Now let’s check each Service type above.
ClusterIP Service
Expose the HelloWorld Pod inside the cluster with a ClusterIP Service and check that it can be accessed from another Pod in the same cluster.
You can expose a running Pod as a ClusterIP Service by specifying the --type ClusterIP option as follows.
kubectl expose pod [Pod name] --type ClusterIP [Service name]
First, create and run a test Pod. *(If a Pod with the same name already exists, delete it with kubectl delete pod helloworld.)
% kubectl run --image gcr.io/google-samples/hello-app:1.0 --restart Never helloworld
pod/helloworld created
Expose the helloworld Pod with the Service name helloworld-clusterip.
% kubectl expose pod helloworld --type ClusterIP --port 8080 --name helloworld-clusterip
service/helloworld-clusterip exposed
Use the following command to list Services.
% kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
helloworld-clusterip ClusterIP 10.98.60.0 <none> 8080/TCP 25s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 16h
The result shows that a Service whose Type is ClusterIP has been created in the first row.
Next, start the curl container again and access helloworld through helloworld-clusterip from inside that container.
% kubectl run --image curlimages/curl:7.68.0 -it --restart Never --rm curl sh
If you don't see a command prompt, try pressing enter.
/ $
Use the curl command from the opened Shell.
/ $ curl 10.98.60.0:8080
Hello, world!
Version: 1.0.0
Hostname: helloworld
The result confirms that helloworld can be accessed. This result is the same as the result in “Connecting from inside the cluster” above.
However, the earlier example connected directly from the curl container to the helloworld container. In this run, the curl container accesses the helloworld-clusterip Service, and then the Service connects to helloworld through its load balancing function, although only one Pod has been created so the destination is effectively fixed. The meaning is different, so be careful.
NodePort Service
Expose the HelloWorld Pod inside and outside the cluster with a NodePort Service and check that it can be accessed from another Pod in the same cluster.
You can expose a running Pod as a NodePort Service simply by specifying the --type NodePort option as follows.
kubectl expose pod [Pod name] --type NodePort [Service name]
Expose the helloworld Pod with the Service name helloworld-nodeport.
% kubectl expose pod helloworld --type NodePort --port 8080 --name helloworld-nodeport
service/helloworld-nodeport exposed
Use the following command to list Services.
% kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
helloworld-nodeport NodePort 10.110.238.186 <none> 8080:31942/TCP 38s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 16h
The result shows that a Service whose Type is NodePort has been created in the first row.
Next, check whether it can be accessed from inside the same cluster. The procedure is the same as ClusterIP.
First, delete the existing curl container and create it again.
% kubectl delete pod curl
% kubectl run --image curlimages/curl:7.68.0 -it --restart Never --rm curl sh
If you don't see a command prompt, try pressing enter.
/ $
Then, from inside that container, access helloworld through helloworld-nodeport.
/ $ curl 10.110.238.186:8080
Hello, world!
Version: 1.0.0
Hostname: helloworld
/ $
The result confirms that helloworld can be accessed through helloworld-nodeport.
Next, check whether it can be accessed from outside the cluster, meaning the local environment. You need the minikube IP for the connection, so run the following command to look up the IP.
% minikube ip
192.168.49.2
Run curl against this IP from the local environment. Specify the Pod’s port 31942.
/ $ curl 192.168.49.2:31942
Hello, world!
Version: 1.0.0
Hostname: helloworld
The connection result confirms that helloworld can be accessed.
(Depending on the settings used when starting minikube, access may not be possible. In that case, run minikube service --url helloworld-nodeport and execute curl against the printed URL.)
LoadBalancer Service
Expose the HelloWorld Pod inside and outside the cluster with a LoadBalancer Service and check that it can be accessed from another Pod in the same cluster.
You can expose a running Pod as a LoadBalancer Service by specifying the --type LoadBalancer option as follows.
kubectl expose pod [Pod name] --type LoadBalancer [Service name]
Expose the helloworld Pod with the Service name helloworld-loadbalancer.
% kubectl expose pod helloworld --type LoadBalancer --port 8080 --name helloworld-loadbalancer
service/helloworld-loadbalancer exposed
Use the following command to list Services.
% kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
helloworld-loadbalancer LoadBalancer 10.104.176.59 <pending> 8080:30100/TCP 27s
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 16h
The result shows that a Service whose Type is LoadBalancer has been created in the first row.
First, check whether it can be accessed from inside the same cluster. The procedure is the same as ClusterIP.
% kubectl run --image curlimages/curl:7.68.0 -it --restart Never --rm curl sh
If you don't see a command prompt, try pressing enter.
/ $
Use the curl command from the opened Shell.
/ $ curl 10.104.176.59:8080
Hello, world!
Version: 1.0.0
Hostname: helloworld
/ $
The connection result confirms that helloworld can be accessed through helloworld-LoadBalancer.
Then check whether it can be accessed from outside the cluster, meaning the local environment.
% minikube service helloworld-loadbalancer --url
http://127.0.0.1:53240
❗ Because you are using a Docker driver on darwin, the terminal needs to be open to run it.
Leave the console open, open another console, and check access with the following command.
% curl http://127.0.0.1:53240
Hello, world!
Version: 1.0.0
Hostname: helloworld
When executed, you can confirm that helloworld is accessible.