DEV Community

Orbit Websites
Orbit Websites

Posted on

Docker for Developers: From Zero to Containerized App in No Time

Docker for Developers: From Zero to Containerized App in No Time

You're building an app. It works on your machine. But when your teammate runs it, something breaks. Or worse — it fails in production. Sound familiar? Docker solves that by packaging your app and its dependencies into isolated, reproducible containers. Let’s cut through the noise and get you from zero to running a containerized app in under 15 minutes.


1. What Docker Actually Solves (And Why You Should Care)

Docker isn’t just hype. It’s a tool that ensures your app runs the same way everywhere: your laptop, staging, production.

Before Docker:

  • “It works on my machine.”
  • Different OS, versions, dependencies = chaos.
  • Devs spend hours debugging environment issues.

With Docker:

  • Everything your app needs is defined in code.
  • Share a single Dockerfile and docker-compose.yml, and everyone runs the same thing.

You don’t need to be a DevOps wizard. You just need to know the basics.


2. Install Docker (Seriously, It’s Fast)

Go to docker.com and install Docker Desktop (macOS/Windows) or Docker Engine (Linux).

Verify it works:

docker --version
docker run hello-world
Enter fullscreen mode Exit fullscreen mode

If you see a “Hello from Docker!” message, you’re good.

💡 Pro tip: On Linux, you might need to add your user to the docker group to avoid typing sudo every time:

sudo usermod -aG docker $USER

(Log out and back in.)


3. Write a Simple App (We’ll Use Node.js)

Let’s containerize a minimal Express app. If you use Python, Go, or Ruby — same principles apply.

Create a project:

mkdir my-docker-app
cd my-docker-app
npm init -y
npm install express
Enter fullscreen mode Exit fullscreen mode

Create app.js:

const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;

app.get('/', (req, res) => {
  res.send(`Hello from Docker! Running on ${process.platform}`);
});

app.listen(PORT, () => {
  console.log(`App running on http://localhost:${PORT}`);
});
Enter fullscreen mode Exit fullscreen mode

Test it:

node app.js
Enter fullscreen mode Exit fullscreen mode

Hit http://localhost:3000 — you should see the message.


4. Create a Dockerfile

This file defines how to build your container image.

Create Dockerfile (no extension):

# Use an official Node runtime as base
FROM node:18-alpine

# Set working directory inside container
WORKDIR /app

# Copy package files
COPY package*.json ./

# Install dependencies
RUN npm install

# Copy app source
COPY . .

# Expose port
EXPOSE 3000

# Run app
CMD ["node", "app.js"]
Enter fullscreen mode Exit fullscreen mode

Breakdown:

  • FROM: Start from a lightweight Node 18 image.
  • WORKDIR: Set where the app lives inside the container.
  • COPY: Bring in package.json first (Docker caches layers — this speeds up rebuilds).
  • RUN: Install deps.
  • COPY . .: Copy the rest of your code.
  • EXPOSE: Document that the container listens on port 3000.
  • CMD: Command to run when container starts.

5. Build and Run the Image

Build the Docker image:

docker build -t my-node-app .
Enter fullscreen mode Exit fullscreen mode
  • -t my-node-app: Tags the image with a name.
  • .: Build from current directory.

Run it:

docker run -p 3000:3000 my-node-app
Enter fullscreen mode Exit fullscreen mode
  • -p 3000:3000: Maps host port 3000 → container port 3000.

Now go to http://localhost:3000. Your app is running — inside a container.

🐳 You just containerized your app. That’s the hard part — done.


6. Speed Up Development with docker-compose

Rebuilding the image every time you change code is slow. Let’s mount your code as a volume so changes reflect instantly.

Create docker-compose.yml:

version: '3.8'

services:
  app:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - ./:/app
    environment:
      - NODE_ENV=development
Enter fullscreen mode Exit fullscreen mode

Now run:

docker-compose up
Enter fullscreen mode Exit fullscreen mode

This:

  • Builds the image (if needed).
  • Mounts your current directory into /app in the container.
  • Any code change is reflected immediately — no rebuild.

Stop with Ctrl+C. Want to rebuild? docker-compose up --build.


7. Ignore Node Modules (And Other Junk)

Add a .dockerignore file:

node_modules
npm-debug.log
.git
.env
Enter fullscreen mode Exit fullscreen mode

This prevents local files from being copied into the image — keeps builds fast and secure.


8. Common Pitfalls (And How to Avoid Them)

❌ Don’t run as root

Node apps shouldn’t run as root inside containers.

Update your Dockerfile:

# Add non-root user
RUN addgroup -g 1001 -S nodejs
RUN adduser -S nextjs -u 1001

USER nextjs
Enter fullscreen mode Exit fullscreen mode

Place this before CMD.

❌ Don’t install dev tools in production image

Use multi-stage builds if you’re compiling code (e.g., TypeScript, React).

Example:

# Build stage
FROM node:18-alpine as builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

# Production stage
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/package*.json ./
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/dist ./dist
EXPOSE 3000
CMD ["node", "dist/index.js"]
Enter fullscreen mode Exit fullscreen mode

Smaller, more secure image.


9. Push to a Registry (Optional)

Want to deploy this? Push to Docker Hub or GitHub Container Registry.

Tag and push:

docker tag my-node-app your-dockerhub/my-node-app:latest
docker push your-dockerhub/my-node-app:latest
Enter fullscreen mode Exit fullscreen mode

Now you can pull and run it anywhere.


Final Thoughts

Docker isn’t magic — it’s a tool. And like any tool, it’s most powerful when used simply.

You just:

  • Wrote a simple app.
  • Containerized it with a Dockerfile.
  • Ran it locally.
  • Set up hot-reloading with docker-compose.
  • Avoided common traps.

You don’t need to master Kubernetes or write 500-line compose files to benefit from Docker. Start small. Use it to make your local setup consistent and your deploys predictable.

Now go containerize something. And stop saying “it works on my machine.”

Top comments (0)