<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Madhav Nakra</title>
    <description>The latest articles on DEV Community by Madhav Nakra (@madhavnakra).</description>
    <link>https://dev.to/madhavnakra</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3944547%2F1dded4cf-b050-4ed7-9d21-795782aeacad.jpg</url>
      <title>DEV Community: Madhav Nakra</title>
      <link>https://dev.to/madhavnakra</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/madhavnakra"/>
    <language>en</language>
    <item>
      <title>Deploying a Dockerized Node.js Application on Kubernetes 🚀</title>
      <dc:creator>Madhav Nakra</dc:creator>
      <pubDate>Tue, 09 Jun 2026 21:08:21 +0000</pubDate>
      <link>https://dev.to/madhavnakra/deploying-a-dockerized-nodejs-application-on-kubernetes-34e4</link>
      <guid>https://dev.to/madhavnakra/deploying-a-dockerized-nodejs-application-on-kubernetes-34e4</guid>
      <description>&lt;p&gt;After containerizing an application with Docker, the next logical step is deploying it on Kubernetes.&lt;/p&gt;

&lt;p&gt;Kubernetes helps automate application deployment, scaling, networking, and management of containerized workloads. Instead of manually running containers, Kubernetes ensures your application remains available and can easily scale when needed.&lt;/p&gt;

&lt;p&gt;In this guide, we'll deploy a Docker image of a Node.js application on Kubernetes using a Deployment and a Service.&lt;/p&gt;




&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before starting, make sure you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Docker installed&lt;/li&gt;
&lt;li&gt;Kubernetes cluster running (Docker Desktop Kubernetes, Minikube, Kind, EKS, etc.)&lt;/li&gt;
&lt;li&gt;kubectl configured&lt;/li&gt;
&lt;li&gt;A Docker image pushed to Docker Hub&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In my case, the image was:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;madhavnaks/node-app:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Why Kubernetes?
&lt;/h2&gt;

&lt;p&gt;Running a container using Docker is straightforward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 3000:3000 madhavnaks/node-app:latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, in production environments we need much more than simply running a container.&lt;/p&gt;

&lt;p&gt;Kubernetes provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;High availability&lt;/li&gt;
&lt;li&gt;Self-healing containers&lt;/li&gt;
&lt;li&gt;Load balancing&lt;/li&gt;
&lt;li&gt;Service discovery&lt;/li&gt;
&lt;li&gt;Horizontal scaling&lt;/li&gt;
&lt;li&gt;Rolling updates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes it the industry standard for container orchestration.&lt;/p&gt;




&lt;h1&gt;
  
  
  Understanding the Kubernetes Architecture for This Deployment
&lt;/h1&gt;

&lt;p&gt;For this deployment, we'll use two Kubernetes resources:&lt;/p&gt;

&lt;h3&gt;
  
  
  Deployment
&lt;/h3&gt;

&lt;p&gt;A Deployment is responsible for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating Pods&lt;/li&gt;
&lt;li&gt;Maintaining desired replica count&lt;/li&gt;
&lt;li&gt;Recreating failed Pods automatically&lt;/li&gt;
&lt;li&gt;Managing updates and rollbacks&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Service
&lt;/h3&gt;

&lt;p&gt;A Service provides a stable network endpoint for Pods.&lt;/p&gt;

&lt;p&gt;Since Pod IPs change frequently, Services allow applications and users to communicate reliably with Pods.&lt;/p&gt;




&lt;h1&gt;
  
  
  Deployment and Service Manifest
&lt;/h1&gt;

&lt;p&gt;Create a file named:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;app.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the following configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node-app&lt;/span&gt;

&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;

  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node-app&lt;/span&gt;

  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node-app&lt;/span&gt;

    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node-app&lt;/span&gt;
          &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;madhavnaks/node-app:latest&lt;/span&gt;

          &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3000&lt;/span&gt;

&lt;span class="nn"&gt;---&lt;/span&gt;

&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;

&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node-app&lt;/span&gt;

&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;node-app&lt;/span&gt;

  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NodePort&lt;/span&gt;

  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;123&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3000&lt;/span&gt;
      &lt;span class="na"&gt;nodePort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;32000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Understanding the Deployment Configuration
&lt;/h1&gt;

&lt;h3&gt;
  
  
  Replica Count
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kubernetes will maintain two running Pod instances of the application.&lt;/p&gt;

&lt;p&gt;If one Pod crashes, Kubernetes automatically creates another one to maintain the desired state.&lt;/p&gt;




&lt;h3&gt;
  
  
  Docker Image
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;madhavnaks/node-app:latest&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kubernetes pulls the image directly from Docker Hub and uses it to create containers.&lt;/p&gt;




&lt;h3&gt;
  
  
  Container Port
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This specifies the port on which the Node.js application listens inside the container.&lt;/p&gt;




&lt;h1&gt;
  
  
  Understanding the Service Configuration
&lt;/h1&gt;

&lt;p&gt;The Service exposes our Pods to network traffic.&lt;/p&gt;

&lt;h3&gt;
  
  
  Service Port
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;123&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the port exposed by the Kubernetes Service inside the cluster.&lt;/p&gt;




&lt;h3&gt;
  
  
  Target Port
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Traffic arriving at the Service is forwarded to port 3000 inside the container.&lt;/p&gt;




&lt;h3&gt;
  
  
  NodePort
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;nodePort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;32000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This exposes the application outside the cluster.&lt;/p&gt;

&lt;p&gt;Requests reaching:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;Node-IP&amp;gt;:32000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;are forwarded to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Service Port → Target Port → Container
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which means:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;32000 → 123 → 3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Deploying the Application
&lt;/h1&gt;

&lt;p&gt;Apply the manifest:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; complete.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;deployment.apps/node-app created
service/node-app created
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Verify the Deployment
&lt;/h1&gt;

&lt;p&gt;Check Deployments:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get deployments
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;NAME       READY   UP-TO-DATE   AVAILABLE
node-app   2/2     2            2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Check Pods:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;NAME                        READY   STATUS
node-app-xxxxx              1/1     Running
node-app-yyyyy              1/1     Running
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice that Kubernetes created two Pods because we specified:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;Check Services:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get svc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;NAME         TYPE       CLUSTER-IP      PORT&lt;span class="o"&gt;(&lt;/span&gt;S&lt;span class="o"&gt;)&lt;/span&gt;
node-app     NodePort   10.x.x.x        123:32000/TCP
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Accessing the Application
&lt;/h1&gt;

&lt;p&gt;To access the application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:32000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://&amp;lt;Node-IP&amp;gt;:32000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;depending on your Kubernetes setup.&lt;/p&gt;

&lt;p&gt;The request flow looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User
   │
   ▼
NodePort (32000)
   │
   ▼
Service Port (123)
   │
   ▼
Target Port (3000)
   │
   ▼
Node.js Container
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Benefits of Using a Deployment
&lt;/h1&gt;

&lt;p&gt;Deployments provide several production-grade capabilities:&lt;/p&gt;

&lt;h3&gt;
  
  
  Self-Healing
&lt;/h3&gt;

&lt;p&gt;If a Pod crashes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete pod &amp;lt;pod-name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kubernetes automatically creates a replacement Pod.&lt;/p&gt;




&lt;h3&gt;
  
  
  Scaling
&lt;/h3&gt;

&lt;p&gt;Increase replicas easily:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apply again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; complete.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kubernetes creates additional Pods automatically.&lt;/p&gt;




&lt;h3&gt;
  
  
  Rolling Updates
&lt;/h3&gt;

&lt;p&gt;When a new Docker image version is pushed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;madhavnaks/node-app:v2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Applying the updated manifest performs a rolling update with minimal downtime.&lt;/p&gt;




&lt;h1&gt;
  
  
  Key Takeaways
&lt;/h1&gt;

&lt;p&gt;✅ Deployments manage Pods automatically&lt;/p&gt;

&lt;p&gt;✅ Replica count ensures high availability&lt;/p&gt;

&lt;p&gt;✅ Services provide stable networking&lt;/p&gt;

&lt;p&gt;✅ NodePort exposes applications outside the cluster&lt;/p&gt;

&lt;p&gt;✅ Kubernetes continuously maintains the desired state of the application&lt;/p&gt;




&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Deploying a containerized application on Kubernetes is a major step toward building production-ready cloud-native applications.&lt;/p&gt;

&lt;p&gt;Using a Deployment and Service, Kubernetes can automatically manage application availability, networking, scaling, and recovery without manual intervention.&lt;/p&gt;

&lt;p&gt;Once you're comfortable with these fundamentals, the next topics to explore are ConfigMaps, Secrets, Ingress, Persistent Volumes, and Helm Charts.&lt;/p&gt;

&lt;p&gt;Happy Learning and Happy Kubernetes! 🚀&lt;/p&gt;

</description>
      <category>devops</category>
      <category>kubernetes</category>
      <category>docker</category>
      <category>beginners</category>
    </item>
    <item>
      <title>From Dockerfile to Docker Hub: A Complete Beginner's Guide to Docker 🚀</title>
      <dc:creator>Madhav Nakra</dc:creator>
      <pubDate>Tue, 02 Jun 2026 21:06:56 +0000</pubDate>
      <link>https://dev.to/madhavnakra/from-dockerfile-to-docker-hub-a-complete-beginners-guide-to-docker-2o1b</link>
      <guid>https://dev.to/madhavnakra/from-dockerfile-to-docker-hub-a-complete-beginners-guide-to-docker-2o1b</guid>
      <description>&lt;p&gt;Containerization has become a fundamental skill for DevOps Engineers, Cloud Engineers, and Software Developers.&lt;/p&gt;

&lt;p&gt;However, many beginners learn Docker commands without understanding the complete workflow behind them.&lt;/p&gt;

&lt;p&gt;Questions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What exactly is a Docker Image?&lt;/li&gt;
&lt;li&gt;How does a Dockerfile become a running Container?&lt;/li&gt;
&lt;li&gt;Why do we push images to Docker Hub?&lt;/li&gt;
&lt;li&gt;How do organizations deploy the same application everywhere?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;are common when starting out.&lt;/p&gt;

&lt;p&gt;In this blog, we'll build a simple Node.js application, containerize it using Docker, run it locally, and finally push the image to Docker Hub.&lt;/p&gt;

&lt;p&gt;By the end of this guide, you'll understand the complete Docker workflow used in real-world DevOps environments.&lt;/p&gt;




&lt;h2&gt;
  
  
  Docker Workflow Overview
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flowchart LR
    A[Application Code] --&amp;gt; B[Dockerfile]
    B --&amp;gt; C[Docker Build]
    C --&amp;gt; D[Docker Image]
    D --&amp;gt; E[Docker Run]
    E --&amp;gt; F[Docker Container]
    D --&amp;gt; G[Docker Push]
    G --&amp;gt; H[Docker Hub]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the same workflow followed by developers and DevOps teams worldwide.&lt;/p&gt;




&lt;h1&gt;
  
  
  What Are We Building?
&lt;/h1&gt;

&lt;p&gt;We'll create a simple Node.js application that returns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A welcome message&lt;/li&gt;
&lt;li&gt;Environment information&lt;/li&gt;
&lt;li&gt;Container hostname&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This helps us verify that our application is actually running inside a Docker container.&lt;/p&gt;




&lt;h1&gt;
  
  
  Project Structure
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
├── Dockerfile
├── app.js
└── package.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Step 1: Create the Node.js Application
&lt;/h1&gt;

&lt;h2&gt;
  
  
  app.js
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PORT&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ENV&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ENV_VALUE&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;No env set&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;HOSTNAME&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HOSTNAME&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;os&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Hello from Simple App (Node)&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ENV&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;container&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;HOSTNAME&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Node Hello listening on &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;PORT&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  package.json
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"hello-app-node"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1.0.0"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"main"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"app.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"express"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^5.2.1"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Application Architecture
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flowchart LR
    User --&amp;gt; Browser
    Browser --&amp;gt; Container
    Container --&amp;gt; NodeJS
    NodeJS --&amp;gt; JSONResponse
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Whenever a user accesses the application, the request reaches the containerized Node.js application, which returns a JSON response.&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 2: Create the Dockerfile
&lt;/h1&gt;

&lt;p&gt;A Dockerfile is simply a blueprint that tells Docker how to build an image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:24-slim&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package*.json ./&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--production&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;

&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 3000&lt;/span&gt;

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["node", "app.js"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Understanding the Dockerfile
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Base Image
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:24-slim&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We start with an official lightweight Node.js image from Docker Hub.&lt;/p&gt;




&lt;h3&gt;
  
  
  Working Directory
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Creates and switches to the &lt;code&gt;/app&lt;/code&gt; directory inside the container.&lt;/p&gt;




&lt;h3&gt;
  
  
  Copy Dependency Files
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; package*.json ./&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copies package files first.&lt;/p&gt;

&lt;p&gt;This is considered a Docker best practice because Docker can cache dependency layers and speed up future builds.&lt;/p&gt;




&lt;h3&gt;
  
  
  Install Dependencies
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;RUN &lt;/span&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--production&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Installs only production dependencies.&lt;/p&gt;




&lt;h3&gt;
  
  
  Copy Application Source Code
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copies the entire project into the container.&lt;/p&gt;




&lt;h3&gt;
  
  
  Expose Application Port
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 3000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Documents that the application listens on port 3000.&lt;/p&gt;




&lt;h3&gt;
  
  
  Start the Application
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["node", "app.js"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Runs the Node.js application when the container starts.&lt;/p&gt;




&lt;h1&gt;
  
  
  What Happens During Docker Build?
&lt;/h1&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flowchart TD
    A[Dockerfile]
    --&amp;gt; B[Pull Node Base Image]
    --&amp;gt; C[Create Working Directory]
    --&amp;gt; D[Copy package.json]
    --&amp;gt; E[Install Dependencies]
    --&amp;gt; F[Copy Application Code]
    --&amp;gt; G[Create Image Layers]
    --&amp;gt; H[Docker Image Ready]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Docker executes each instruction sequentially and creates image layers.&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 3: Build the Docker Image
&lt;/h1&gt;

&lt;p&gt;Run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; madhavnaks/node-app &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's understand this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Builds an image from a Dockerfile.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nt"&gt;-t&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Assigns a tag to the image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;madhavnaks/node-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Image name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Current directory containing the Dockerfile.&lt;/p&gt;




&lt;p&gt;After a successful build you'll see output similar to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; naming to docker.io/madhavnaks/node-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Docker has now created an image locally on your machine.&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 4: Verify the Image
&lt;/h1&gt;

&lt;p&gt;To see locally available images:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker images
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;REPOSITORY                TAG       IMAGE ID       SIZE
madhavnaks/node-app       latest    42c936686000   234MB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, the image exists but is not running.&lt;/p&gt;




&lt;h1&gt;
  
  
  Docker Image vs Docker Container
&lt;/h1&gt;

&lt;p&gt;Many beginners confuse these two concepts.&lt;/p&gt;

&lt;p&gt;Think of it like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Docker Image = Blueprint&lt;/li&gt;
&lt;li&gt;Docker Container = Running Application
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flowchart LR
    A[Docker Image]
    --&amp;gt; B[Container 1]

    A --&amp;gt; C[Container 2]

    A --&amp;gt; D[Container 3]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A single image can create multiple containers.&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 5: Run a Container
&lt;/h1&gt;

&lt;p&gt;Now let's start our application.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; node-app &lt;span class="nt"&gt;-p&lt;/span&gt; 3001:3000 madhavnaks/node-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Understanding the Command
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Detached Mode
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Runs the container in the background.&lt;/p&gt;




&lt;h3&gt;
  
  
  Container Name
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nt"&gt;--name&lt;/span&gt; node-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Assigns a friendly name to the container.&lt;/p&gt;




&lt;h3&gt;
  
  
  Port Mapping
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nt"&gt;-p&lt;/span&gt; 3001:3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Maps:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Host Port      → Container Port
3001           → 3000
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The application listens on port 3000 inside the container but is accessible on port 3001 from your machine.&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 6: Verify the Container
&lt;/h1&gt;

&lt;p&gt;Check running containers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker ps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;CONTAINER ID   IMAGE                 STATUS
10265698c978   madhavnaks/node-app   Up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Step 7: Access the Application
&lt;/h1&gt;

&lt;p&gt;Open:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;http://localhost:3001
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected response:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hello from Simple App (Node)"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"env"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"No env set"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"container"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"10265698c978"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the hostname.&lt;/p&gt;

&lt;p&gt;The hostname corresponds to the container ID, proving the application is running inside Docker.&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 8: Login to Docker Hub
&lt;/h1&gt;

&lt;p&gt;Before pushing images, authenticate with Docker Hub.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Login Succeeded
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Docker is now authorized to push images to your repository.&lt;/p&gt;




&lt;h1&gt;
  
  
  Why Push Images to Docker Hub?
&lt;/h1&gt;

&lt;p&gt;Docker Hub acts as a centralized registry.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flowchart LR
    A[Developer Machine]
    --&amp;gt;|Push| B[Docker Hub]

    B --&amp;gt;|Pull| C[Server]

    B --&amp;gt;|Pull| D[Kubernetes Cluster]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once an image is pushed, it can be pulled and run from anywhere.&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 9: Push the Image
&lt;/h1&gt;

&lt;p&gt;Push the image to Docker Hub:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker push madhavnaks/node-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;latest: digest: sha256:d1081ec542f521e100bd886943c13ab7568c663b56e36200e6d846163975f979
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This confirms that the image has been successfully uploaded.&lt;/p&gt;




&lt;h1&gt;
  
  
  Step 10: Verify on Docker Hub
&lt;/h1&gt;

&lt;p&gt;Visit your Docker Hub account.&lt;/p&gt;

&lt;p&gt;You should now see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;madhavnaks/node-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;listed under repositories.&lt;/p&gt;

&lt;p&gt;You can even share the image with others.&lt;/p&gt;

&lt;p&gt;Anyone can now run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker pull madhavnaks/node-app

docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 3001:3000 madhavnaks/node-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;without needing your source code.&lt;/p&gt;




&lt;h1&gt;
  
  
  Real-World DevOps Workflow
&lt;/h1&gt;

&lt;p&gt;In production environments, the workflow usually looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;flowchart LR
    A[Developer Writes Code]
    --&amp;gt; B[GitHub]

    B --&amp;gt; C[CI/CD Pipeline]

    C --&amp;gt; D[Docker Build]

    D --&amp;gt; E[Docker Hub]

    E --&amp;gt; F[Kubernetes Cluster]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is exactly how modern DevOps teams package and deploy applications.&lt;/p&gt;




&lt;h1&gt;
  
  
  Key Takeaways
&lt;/h1&gt;

&lt;p&gt;✅ Dockerfile defines how an image should be built&lt;/p&gt;

&lt;p&gt;✅ Docker Build creates an image&lt;/p&gt;

&lt;p&gt;✅ Docker Run creates a container&lt;/p&gt;

&lt;p&gt;✅ Docker Hub stores and distributes images&lt;/p&gt;

&lt;p&gt;✅ One image can create multiple containers&lt;/p&gt;

&lt;p&gt;✅ Containerization ensures consistency across environments&lt;/p&gt;




&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;In this guide, we covered the complete Docker workflow from source code to Docker Hub.&lt;/p&gt;

&lt;p&gt;We learned how to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a Dockerfile&lt;/li&gt;
&lt;li&gt;Build a Docker image&lt;/li&gt;
&lt;li&gt;Run a container&lt;/li&gt;
&lt;li&gt;Verify application execution&lt;/li&gt;
&lt;li&gt;Push images to Docker Hub&lt;/li&gt;
&lt;li&gt;Understand how images move through real-world DevOps pipelines&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Mastering these Docker fundamentals is the first step toward advanced topics like Docker Compose, Kubernetes, Helm, CI/CD pipelines, and cloud-native deployments.&lt;/p&gt;

&lt;p&gt;If you're learning DevOps, try containerizing applications in different languages such as Python, Java, Go, or .NET to strengthen your understanding of Docker.&lt;/p&gt;

&lt;p&gt;Happy Containerizing! 🚀&lt;/p&gt;

</description>
      <category>docker</category>
      <category>devops</category>
      <category>containers</category>
      <category>cloud</category>
    </item>
    <item>
      <title>Configuring AWS CLI on Ubuntu for Local Machine ☁️🐧</title>
      <dc:creator>Madhav Nakra</dc:creator>
      <pubDate>Thu, 21 May 2026 17:26:05 +0000</pubDate>
      <link>https://dev.to/madhavnakra/configuring-aws-cli-on-ubuntu-for-local-machine-5elf</link>
      <guid>https://dev.to/madhavnakra/configuring-aws-cli-on-ubuntu-for-local-machine-5elf</guid>
      <description>&lt;p&gt;When people start learning AWS, they usually focus only on installing the AWS CLI.&lt;br&gt;
But installing it is just the first step.&lt;/p&gt;

&lt;p&gt;To actually interact with AWS services from your Ubuntu machine, you also need to configure AWS credentials properly.&lt;/p&gt;

&lt;p&gt;In this guide, we’ll go through the complete setup process for AWS CLI on Ubuntu — from installation to configuration and verification.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why AWS CLI?
&lt;/h2&gt;

&lt;p&gt;AWS CLI allows you to manage AWS services directly from your terminal.&lt;/p&gt;

&lt;p&gt;You can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Launch EC2 instances&lt;/li&gt;
&lt;li&gt;Upload files to S3&lt;/li&gt;
&lt;li&gt;Configure IAM&lt;/li&gt;
&lt;li&gt;Manage EKS clusters&lt;/li&gt;
&lt;li&gt;Automate cloud operations using scripts&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of clicking through the AWS Console every time, AWS CLI helps automate everything efficiently.&lt;/p&gt;


&lt;h2&gt;
  
  
  Step 1: Update Packages
&lt;/h2&gt;

&lt;p&gt;First, update your system packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This ensures your package manager has the latest repository information.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Install Required Dependencies
&lt;/h2&gt;

&lt;p&gt;Install &lt;code&gt;curl&lt;/code&gt; and &lt;code&gt;unzip&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;unzip curl &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These tools are required to download and extract the AWS CLI installer.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: Download AWS CLI v2 Installer
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="s2"&gt;"https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip"&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="s2"&gt;"awscliv2.zip"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This downloads the latest AWS CLI v2 package for Ubuntu/Linux systems.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbg4u0m4kan12svme29j8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbg4u0m4kan12svme29j8.png" alt=" " width="800" height="124"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 4: Unzip the Installer
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;unzip awscliv2.zip
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This extracts the installation files.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 5: Run the Install Script
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo&lt;/span&gt; ./aws/install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;AWS CLI will now be installed on your machine.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 6: Verify Installation
&lt;/h2&gt;

&lt;p&gt;Check whether AWS CLI is installed successfully:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws &lt;span class="nt"&gt;--version&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example output:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frw2fyc22q8fq5z20yu14.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frw2fyc22q8fq5z20yu14.png" alt=" " width="797" height="109"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 7: Configure AWS CLI
&lt;/h2&gt;

&lt;p&gt;Now comes the important part — configuration.&lt;/p&gt;

&lt;p&gt;Run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws configure
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You’ll be asked for:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;AWS Access Key ID
AWS Secret Access Key
Default region name
Default output format
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;AWS Access Key ID &lt;span class="o"&gt;[&lt;/span&gt;None]: AKIAXXXXX
AWS Secret Access Key &lt;span class="o"&gt;[&lt;/span&gt;None]: &lt;span class="k"&gt;********&lt;/span&gt;
Default region name &lt;span class="o"&gt;[&lt;/span&gt;None]: ap-south-1
Default output format &lt;span class="o"&gt;[&lt;/span&gt;None]: json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can generate Access Keys from:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;AWS Console → IAM → Users → Security Credentials → Create Access Key&lt;/code&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 8: Verify Configured Profiles
&lt;/h2&gt;

&lt;p&gt;To check configured AWS profiles and settings:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws configure list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This helps verify whether your credentials and region are configured correctly.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 9: View Stored Credentials
&lt;/h2&gt;

&lt;p&gt;AWS stores credentials locally inside the &lt;code&gt;.aws&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;Check credentials file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; ~/.aws/credentials
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check config file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat&lt;/span&gt; ~/.aws/config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr5xbt1zmtfqdzblyq7cy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr5xbt1zmtfqdzblyq7cy.png" alt=" " width="799" height="211"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the Files
&lt;/h2&gt;

&lt;h3&gt;
  
  
  credentials file
&lt;/h3&gt;

&lt;p&gt;Stores:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Access Key ID&lt;/li&gt;
&lt;li&gt;Secret Access Key&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[default]&lt;/span&gt;
&lt;span class="py"&gt;aws_access_key_id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;XXXXX&lt;/span&gt;
&lt;span class="py"&gt;aws_secret_access_key&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;XXXXX&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  config file
&lt;/h3&gt;

&lt;p&gt;Stores:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Default region&lt;/li&gt;
&lt;li&gt;Output format&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[default]&lt;/span&gt;
&lt;span class="py"&gt;region&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;ap-south-1&lt;/span&gt;
&lt;span class="py"&gt;output&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;json&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Important Security Tip ⚠️
&lt;/h2&gt;

&lt;p&gt;Never share:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Access Key ID&lt;/li&gt;
&lt;li&gt;Secret Access Key&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.aws/credentials&lt;/code&gt; file&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also, add &lt;code&gt;.aws/&lt;/code&gt; to &lt;code&gt;.gitignore&lt;/code&gt; if you're working inside projects.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Installing AWS CLI is easy, but properly configuring it is what actually enables you to work with AWS services from your local Ubuntu machine.&lt;/p&gt;

&lt;p&gt;Once configured, you can automate cloud operations directly from the terminal and integrate AWS into scripts, CI/CD pipelines, and DevOps workflows.&lt;/p&gt;

&lt;p&gt;If you're starting your cloud or DevOps journey, AWS CLI is one of the most essential tools to learn 🚀&lt;/p&gt;

</description>
      <category>devops</category>
      <category>aws</category>
      <category>ubuntu</category>
      <category>beginners</category>
    </item>
  </channel>
</rss>
