🇧🇷 Leia a versão em português aqui
In previous parts of this series, we built the cluster from scratch: prepared the environment (Part 1), installed containerd and Kubernetes (Part 2), initialized the control-plane (Part 3), and joined the workers (Part 4). With the cluster up and all nodes in Ready state, it's time to actually put it to work: let's deploy our first application.
In this article, we'll use Nginx as an example — a classic use case for validating that the cluster is working end to end, from pod creation to service exposure.
Organizing the files
First, create a directory to organize this deployment's manifests:
mkdir nginx
cd nginx
Keeping Kubernetes manifests organized in per-application directories is a good practice that makes maintenance and versioning (e.g., with Git) easier as the cluster grows.
Creating the Deployment
A Deployment is the Kubernetes object responsible for managing pod replicas, ensuring the desired number of instances is always running — and handling things like rolling updates and automatic recovery in case of failure.
Create the file nginx-deployment.yaml with the following content:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.0
ports:
- containerPort: 80
This manifest defines:
-
2 replicas of the Nginx pod (
replicas: 2), distributed across the available workers; - A selector that ties the Deployment to the pods via the
app: nginxlabel; - The
nginx:1.14.0image, exposing container port80.
Applying the Deployment
With the file saved, apply it to the cluster:
kubectl apply -f nginx-deployment.yaml
kubectl will create the Deployment, and from there Kubernetes takes care of scheduling the 2 pods across the available workers.
Checking the Deployment
To confirm the Deployment was created and has the desired number of replicas running:
kubectl get deployments
And, for more complete details (events, conditions, rollout strategy, etc.):
kubectl describe deployment nginx-deployment
If everything's fine, you should see all 2 replicas ready (2/2) in the availability column.
Creating the Service
The Deployment alone isn't enough to access the application from outside the cluster — pods are ephemeral and their IPs change every time they're recreated. That's what the Service is for: a stable access point that routes traffic to the correct pods, based on labels.
Create the file nginx-service.yaml:
apiVersion: v1
kind: Service
metadata:
name: nginx-service
labels:
run: nginx-service
spec:
type: NodePort
ports:
- port: 80
protocol: TCP
selector:
app: nginx
Here, the NodePort type is used to expose the service on a port directly accessible through any node's IP in the cluster — a simple and practical option for on-premise environments, without relying on an external load balancer (unlike the LoadBalancer type, more common in cloud providers).
Applying the Service
kubectl apply -f nginx-service.yaml
Checking the Service
kubectl get service
This command shows, among other information, the external port (NodePort) automatically allocated by Kubernetes — usually in the range between 30000 and 32767.
For more details:
kubectl describe service nginx-service
With the port in hand, Nginx can now be accessed through the IP of any node in the cluster (master or workers) on the indicated port — for example: http://10.0.10.100:<nodeport>.
What we validated here
If you managed to access Nginx's default page through the NodePort, this confirms the whole cluster is working correctly end to end:
- The control-plane is scheduling pods normally;
- The pod network (CNI) is allowing communication between components;
-
kube-proxyis routing the Service's traffic to the correct pods; - The workers are running containers without issues.
Wrap-up
With this, we've covered the essentials for building and validating an on-premise Kubernetes cluster from scratch: environment preparation, component installation, control-plane initialization, worker joining, and the first real application deployment.
From here, natural next steps include topics like persistent storage (Persistent Volumes), Ingress Controllers, configuration and secrets management (ConfigMaps and Secrets), monitoring (Prometheus/Grafana), and cluster backup strategies (like etcd backups). This is left as a suggestion for a possible continuation of this series.
If you've followed all five articles up to here, you now have a functional on-premise Kubernetes cluster, built and validated from scratch — without depending on any cloud provider.
Now, in Part 6 of this series, we’ll spin up the container with our application and understand how everything works.
Continued in Part 6.
Top comments (0)