Docker and Kubernetes are often mentioned together in modern software development—but they solve different problems. Docker makes it easy to package applications into containers. Kubernetes takes those containers and runs them at scale, across many servers, with reliability and automation.
Although my previous post on Docker and Kubernetes was part of an assignment, it got me thinking and curious about the DevOps space and about Docker and Kubernetes in general. Having used Docker previously, doing this research really broadened my understanding.
In this tutorial, we’ll:
- Build a simple app using Docker.
- Push the container image to Docker Hub (a registry).
- Deploy the app on Kubernetes.
- Scale it up and explore how Kubernetes manages it.
Along the way, I’ll explain each step, so you don’t just copy commands but actually understand what’s happening (this is feedback I got from a work with a client that said my article lacked technical depth and was just full of copy<=>paste code).
Prerequisites
Before we begin, make sure you have the following installed:
-
- To verify, on your terminal, run:
node -v
-
Docker Desktop (or Docker Engine)
To verify, run:
docker --version
-
Kubectl (Kubernetes CLI)
to Verify, run:
kubectl version --client
-
A Kubernetes cluster
- Beginners can use Minikube (local cluster)
- Or enable Kubernetes directly in Docker Desktop.
I like to think of Docker Hub as the GitHub for container images.
Scaling Your Application From Local To Cloud
Create a Simple Node.js Application
We’ll create a Node.js app that returns a simple message.
Create a project folder:
mkdir docker-k8s-demo cd docker-k8s-demo
Inside the folder, create a file named app.js
:
const http = require('http'); const port = 3000; const requestHandler = (req, res) => { res.end('Hello from Docker and Kubernetes!'); }; const server = http.createServer(requestHandler); server.listen(port, () => { console.log(`Server running on port ${port}`); });
Create a package.json
file:
{ "name": "docker-k8s-demo", "version": "1.0.0", "main": "app.js", "dependencies": {} }
At this point, we have a simple Node.js app.
Writing a Dockerfile file
Write a Dockerfile
A Dockerfile is just a plain text file (no extension, usually named Dockerfile
) that tells Docker how to build an image. It lives in the root of your project.
Create a file called Dockerfile
:
# Start from the Node.js base image FROM node:18-alpine # Set working directory inside container WORKDIR /usr/src/app # Copy project files into container COPY package*.json ./ COPY app.js ./ # Install dependencies RUN npm install # Expose the app’s port EXPOSE 3000 # Start the app CMD ["node", "app.js"]
Build the image:
docker build -t myapp:1.0 .
-
-t myapp:1.0
→ names the imagemyapp
with version1.0
. -
.
means “use the Dockerfile in this directory.”
If this was run properly and successfully, you should see a success message like this on your terminal.
Running a Docker Container
Run the docker container:
docker run -p 3000:3000 myapp:1.0
Visit http://localhost:3000. You should see:
Hello from Docker and Kubernetes!
How To Push An Image To Docker Hub
Pushing the Image to Docker Hub
Kubernetes won’t know about your local image—it needs to pull it from a registry.
Log in to Docker Hub:
docker login
A success message like this should be seen on your terminal
Tag your image with your Docker Hub username:
docker tag myapp:1.0 your-username/myapp:1.0
Push it:
docker push your-username/myapp:1.0
Now your image is public in Docker Hub, ready for Kubernetes.
You are seeing "Layer already exists" in this screenshot because I had run this command once before but it failed at execution due to a lag in my internet.
Deploying Docker Containers on Kubernetes
A Kubernetes deployment needs a YAML file describing what to run.
Create deployment.yaml
file:
apiVersion: apps/v1 kind: Deployment metadata: name: myapp-deployment spec: replicas: 3 selector: matchLabels: app: myapp template: metadata: labels: app: myapp spec: containers: - name: myapp image: your-username/myapp:1.0 ports: - containerPort: 3000 --- apiVersion: v1 kind: Service metadata: name: myapp-service spec: selector: app: myapp ports: - protocol: TCP port: 80 targetPort: 3000 type: LoadBalancer
Apply it (run on your terminal):
kubectl apply -f deployment.yaml
Check pods:
kubectl get pods
_This sample script creates three replicas. In the previous article, I explained what replicas are and how they relate to the problem of scaling. _
After running, you should see three pods running in your terminal window.
On your terminal, you should see three pods active and running.
Check service:
kubectl get service myapp-service
- If using Docker Desktop or cloud Kubernetes, you’ll get an external IP.
- If using Minikube:
minikube service myapp-service
This opens the app in your browser.
Scaling An Application With Kubernetes
Scale the Application with Kubernetes
In the example above, we scaled to three replicas. As a system or application grows, more replicas or instances of it are needed to effectively scale up to the demand.
This can be done easily by running this command with the number of replicas you need per time.
kubectl scale deployment myapp-deployment --replicas=5
Kubernetes will spin up two more pods automatically.
This workflow—build with Docker, deploy with Kubernetes—is the foundation of cloud-native applications. Docker ensures consistency across environments, and Kubernetes ensures reliability in production.
💡 Enjoyed this article? Let’s connect!
I’d love to hear your thoughts, feedback.
I am also open to collaborations on technical articles, documentation, or white papers! 🚀
Top comments (0)