Intro: Ending the Environment Nightmare
For developers, the scariest phrase is: “Weird, it works fine on my machine.”
To avoid this tragedy, we need Docker. Today, let’s skip the complex theory and get our hands dirty by “containerizing” a Node.js app.
Step 1: Prepare Your Node App
Assuming you have a simple app.js (or an Express project). If not, create a new folder and write the following:
// app.js
const http = require('http');
const hostname = '0.0.0.0';
const port = 3000;
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('Hello from Docker!\n');
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
And you need a package.json:
{
"name": "docker-node-demo",
"version": "1.0.0",
"main": "app.js",
"scripts": {
"start": "node app.js"
},
"dependencies": {}
}
Step 2: Write the Dockerfile (The Core Step)
Create a file named Dockerfile (no extension) in the root directory. This is the “instruction manual” telling Docker how to build the image.
# 1. Select the base image (Use LTS version)
FROM node:18-alpine
# 2. Set the working directory inside the container
WORKDIR /app
# 3. Copy dependency files (Leveraging Docker cache)
COPY package*.json ./
# 4. Install dependencies
RUN npm install
# 5. Copy the source code
COPY . .
# 6. Expose the port
EXPOSE 3000
# 7. Start command
CMD ["npm", "start"]
💡 Key Takeaways:
FROM node:18-alpine: Why Alpine? Because it’s a super lightweight Linux distribution. Compared to standard Node images (hundreds of MB), the Alpine version is usually only a few dozen MB.
COPY package*.json: We copy package.json first, run install, and then copy the source code. This leverages Docker’s Layer Caching. If you only change code but not dependencies, the build will be instant.
Step 3: Don’t Forget .dockerignore
You definitely don’t want to copy your massive local node_modules folder into the image, right?
Create a .dockerignore file:
node_modules
npm-debug.log
Step 4: Build and Run
Now, time for the magic. Open your terminal:
Build the Image
docker build -t my-node-app .
-t my-node-app: Tag (name) the image.
Run the Container
docker run -p 3000:3000 -d my-node-app
-p 3000:3000: Maps your computer’s port 3000 to the container’s port 3000.
-d: Runs in the background.
Open your browser at http://localhost:3000, and you should see “Hello from Docker!”.
Conclusion
Now, your Node.js app is an independent, portable container. You can toss it onto any server with Docker installed, and it will run perfectly.
This is the beauty of containerization: Build Once, Run Anywhere.