Hello World Kubernetes Service on Minikube
This is part 2 of a series on Kubernetes a la minikube. Minikube is (probably) the easiest way of installing a small Kubernetes system including a graphical user interface. In part 1 we have shown how to install such a system on a fresh CentOS Linux system. In this part, we will create our first Hello World Kubernetes Service accessible from the Internet.

For that, we will create a kubernetes deployment, which automatically creates a POD with a single Docker container. Then, we create a Kubernetes Service of type NodePort, which is accessible from the outside world.
In the appendix, we will show, how to tweak the automatically generated kubernetes dashboard service, so we can reach it from the Internet.
Within this blog post, we will work on minikube installed on a fresh CentOS cloud system we have installed in part 1 of this series.

Contents [hide]
- Step 0: Get Access to a Minishift Installation
- Step 1 (optional): Explore the Status
- Step 2: Create an Application: Deployment vs POD
- Step 3 (optional): Explore Docker processes, PODs, and Services
- Step 4: Expose the Service
- Summary
- Appendix: Make Kubernetes Dashboard available to the Internet
Step 0: Get Access to a Minishift Installation
One way of achieving this step is to follow steps 1 to 4 of part 1 of this series. However, there are other possibilities to get access to Kubernetes systems as well. For example, you may want to access a Minishift installation as provided by Ben Hall on his Katacoda platform. Check out e.g. the tutorial „Launch A Single Node Cluster„.
Step 1 (optional): Explore the Status
To get acquainted with your minikube installation, you may repeat step 5 of part 1 of this series and run the commands
1 | kubectl version |
Step 2: Create an Application: Deployment vs POD
In Kubernetes, there are, among others, two ways of creating application containers:
- creating POD directly
- creating POD via deployments (recommended)
Step 2.1: Creating a POD directly
Even though it is not recommended for most cases (see a discussion of this topic on StackOverflow) we can create a POD directly like follows:
Create a single POD:
1 | # pod.yaml |
1 | kubectl apply -f pod.yaml |
1 | kubectl |
This will create a pod as expected:
1 | $ kubectl get pods |
Note that it is not possible to create a POD with a kubectl create pod command (crossed out for not confusing the quick reader). Above, we had to create it by reading in a YAML file instead.
kubectl create pod mypod –image=nginx
If the STATUS of your pod is not Running, type following command to show pod status:
1 | $ kubectl describe pod gitea |
Note also that the POD is restarted, if a container process is killed:
1 | $ ps -ef | grep nginx | grep -v grep |
In that sense, the POD we have created directly seems to be durable, even though the discussions below may hint into another direction: they say that only a deployment will restart a POD if it fails. Since we only have a single node cluster, we cannot test, whether a POD is created on another node, if a node fails.
Step 2.2: Creating a POD via a Deployment (recommended)
The recommended way of creating a POD is to create a deployment. Why? What is the difference between creating a deployment and creating a pod? What is a deployment, anyway? For an answer to that, let us consult google:
What is a kubernetes deployment?
Google: A Deployment runs multiple replicas of your application and automatically replaces any instances that fail or become unresponsive. In this way, Deployments help ensure that one or more instances of your application are available to serve user requests. Deployments are managed by the Kubernetes Deployment controller.
Okay, when we create a deployment and tell the deployment to create 5 replicas of a POD, this is different from just creating 5 replicas of a POD, because a deployment will restart PODs that have failed. Let us test this.
Most tutorials do that with commands as follows:
1 | kubectl run first-deployment --image=katacoda/docker-http-server --port=80 |
However, as there is a hint that this kind of commands is deprecated, let us create the deployment differently:
If you have done so, and you want to test the recommended way, let us delete the deployment again:
1 | $ kubectl delete deployment first-deployment |
Now we can create the deployment in the recommended way:
1 | cat <<EOF | kubectl create -f - |
To be honest, I have liked the kubectl run command more…
😉
The reason for the depreciation is discussed in this StackOverflow Q&A.
Step 3 (optional): Explore Docker processes, PODs, and Services
This is creating two docker containers: a „pause“ container per POD and the service container in the POD:
1 | # docker ps | grep "^CONTAINER\|deployment" |
This is quite similar to what is created with the ‚oc new-app‘ command on an OpenShift installation. See e.g. our blog post Getting started with OpenShift. But not quite: here, the service has not yet been created, as can be seen below.
We can see, that no service is created by deployment:
1 | # kubectl get svc |
However, we will find that a POD is created:
1 | # kubectl get pod |
To see the services or pods of all namespaces, you also can use the –all-namespaces option:
1 | # kubectl get pod --all-namespaces |
and
1 | # kubectl get svc --all-namespaces |
Here, we can see, that minikube has started a kubernetes dashboard and a DNS server in the kube-system namespace.
We can get even more details on the POD by using the describe command:
1 | # kubectl describe pod first-deployment-59f6bb4956-fqrhd |
Even though the service is not yet exposed, we still can reach it from the Docker host: The Container IP address is 172.17.0.6, as we can read it from the output of the kubectl describe pod command above. The service is running on port 80. So, let us try to access the POD:
1 | # curl 172.17.0.6:80 |
Note, however, that the POD IP address 172.17.0.6 is a private address that is not accessible from the outside world. In the next step, we will make sure that the service can be reached from the Internet as well.
Step 4: Expose the Service
Now, we want to expose the service to the outside world. Kubernetes knows three ways of doing this:
- exposing via ClusterIP:
reachable internally, only - exposing via NodePorts:
reachable internally and externally - exposing via LoadBalancers:
means of configuring cloud load balancers by way of labels See e.g. https://kubernetes.io/docs/concepts/services-networking/service/ for details on Kubernetes Load Balancer interaction.
The ClusterIP way is the default, but it is reachable from within the kubernetes network only. On the other hand, the LoadBalancer option works only in certain cloud environments. Therefore, we choose to expose the service via NodePort. This way, we can make the service reachable from the Internet and still need no external load balancers.
Let us now demonstrate the NodePorts ways of exposing a service.
Step 4.1: Exposing the Service via NodePorts
If the Node the service is running on has a publicly available IP address (mapped or not), we can access the service by exposing the deployment to a node port as follows:
1 | kubectl expose deployment first-deployment --port=80 --type=NodePort |
Since we have not added an option like --target-port=<static-port>, the port is allocated dynamically. Therefore, we decide to retrieve the port value from via kubectl as follows:
1 | export PORT=$(kubectl get svc first-deployment -o go-template='{{range.spec.ports}}{{if .nodePort}}{{.nodePort}}{{"\n"}}{{end}}{{end}}') |
We need that information to access the service via curl:
1 | # curl 127.0.0.1:$PORT |
Since our Docker host is accessible from the Internet, we also can retrieve the same information from any browser on the Internet:

Okay, the random port is not nice. On the other hand, we cannot run all containers on the same well-known ports like port 80 (HTTP) or port 443 (HTTPS) by specifying the same target ports on the expose commands. This issue is something that can only be resolved with the help of a reverse proxy or an HTTP load balancer, which is out of scope for this blog post.
Summary
In this blog post, we have learned how to create, run, and access applications in a Kubernetes environment. For that, we have created Kubernetes PODs, Deployments and Services. We have learned that Deployments help with the management of PODs. E.g. they restart PODs if they fail.