Post

How to Dockerize Your Application and Deploy It

How to Dockerize Your Application and Deploy It

Modern applications don’t live in isolation. They run across laptops, servers, CI pipelines, and cloud platforms—and things break when environments don’t match. Docker solves this by packaging your application and its dependencies into a portable, reproducible container.

In this guide, you’ll learn:

  • What Docker is and why it matters

  • How to Dockerize an application step by step

  • Best practices for writing a Dockerfile

  • How to deploy your Dockerized app to a server or cloud platform

We’ll use a simple example, but the concepts apply to almost any stack.

What Does “Dockerizing” an Application Mean?

Dockerizing an application means:

  • Defining how your app runs in a file called a Dockerfile

  • Packaging the app, runtime, libraries, and configuration into an image

  • Running that image as a container anywhere Docker is installed

This eliminates the classic problem:

“It works on my machine.”

With Docker, the machine is the same everywhere.

Prerequisites

Before starting, make sure you have:

  • Basic familiarity with the command line

  • Docker installed (Docker Desktop is the easiest option)

  • An application to containerize (Node.js, Python, Java, etc.)

For examples, we’ll assume a Node.js app, but the structure is similar for other languages.

Step 1: Understand Your Application

Before writing a Dockerfile, answer these questions:

  • What language/runtime does the app use?

  • How is it started? (node app.js, npm start, python main.py)

  • Which port does it listen on?

  • Does it need environment variables?

  • Does it depend on external services (databases, APIs)?

Example app structure:

1
2
3
4
5
6
7
```csharp
my-app/
├── package.json
├── package-lock.json
├── index.js
└── .env
```

Step 2: Create a Dockerfile

A Dockerfile is a recipe for building your image.

Create a file named Dockerfile in your project root:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 1. Use an official base image
FROM node:18-alpine

# 2. Set the working directory
WORKDIR /app

# 3. Copy dependency files first (for caching)
COPY package*.json ./

# 4. Install dependencies
RUN npm install --production

# 5. Copy the rest of the application
COPY . .

# 6. Expose the application port
EXPOSE 3000

# 7. Start the application
CMD ["node", "index.js"]

What’s Happening Here?

  1. Base image: node:18-alpine is lightweight and secure
  2. Layer caching: Copying package.json first speeds up rebuilds
  3. EXPOSE: Documents the port your app uses
  4. CMD: Defines how the container starts

Step 3: Add a .dockerignore File

Just like .gitignore, this keeps unnecessary files out of your image.

Create .dockerignore:

1
2
3
4
node_modules
npm-debug.log
.git
.env

This:

  • Reduces image size

  • Prevents leaking secrets

  • Speeds up builds

Step 4: Build the Docker Image

From your project root, run:

1
docker build -t my-app:1.0 .

Check that it exists:

1
docker images

You should see my-app listed.

Step 5: Run the Container Locally

Now test it:

1
docker run -p 3000:3000 my-app:1.0

-p 3000:3000 maps your machine’s port to the container

Visit http://localhost:3000 to confirm it works

If it doesn’t, check logs:

1
docker logs <container_id>

Step 6: Use Environment Variables

Hardcoding config is a bad idea. Docker supports environment variables cleanly.

  • Option 1: Pass variables at runtime
1
2
3
4
docker run -p 3000:3000 \
  -e NODE_ENV=production \
  -e API_KEY=example \
  my-app:1.0
  • Option 2: Use an env file
1
docker run --env-file .env my-app:1.0

Step 7: Push the Image to a Registry

To deploy, your image needs to live somewhere accessible—like Docker Hub or a cloud registry.

Example: Docker Hub

Log in:

1
docker login

Tag your image:

1
docker tag my-app:1.0 username/my-app:1.0

Push it:

1
docker push username/my-app:1.0

Now your image is available anywhere.

Step 8: Deploy the Container

  • Option 1: Deploy to a Virtual Server (VM)

On your server:

1
2
docker pull username/my-app:1.0
docker run -d -p 80:3000 username/my-app:1.0

Your app is now live on port 80 🎉

  • Option 2: Deploy with Docker Compose

For apps with databases or multiple services, use docker-compose.yml:

1
2
3
4
5
6
7
8
9
version: "3.9"

services:
  app:
    image: username/my-app:1.0
    ports:
      - "80:3000"
    env_file:
      - .env

Run it:

1
docker compose up -d
  • Option 3: Deploy to the Cloud

Most cloud platforms support Docker natively:

  1. AWS ECS / EKS
  2. Google Cloud Run
  3. Azure Container Apps
  4. DigitalOcean App Platform
  5. Railway / Fly.io

The core idea is the same:

Build once → run anywhere

Docker Best Practices

  • Use small base images (alpine when possible)

  • Never store secrets in images

  • Use multi-stage builds for production

  • Pin versions to avoid surprise updates

  • Run containers as non-root users when possible

  • Keep images immutable—rebuild instead of patching

Common Mistakes to Avoid

❌ Copying node_modules into the image

❌ Running multiple processes in one container

❌ Using latest tags in production

❌ Ignoring container logs

❌ Treating containers like virtual machines

Final Thoughts

Dockerizing your application is one of the highest-leverage skills in modern development. Once your app is containerized:

  1. Local development becomes consistent

  2. CI/CD pipelines simplify

  3. Deployments are predictable and repeatable

  4. Scaling becomes easier

If you can run docker build and docker run, you can deploy anywhere.

Happy containerizing 🐳

Get in Touch

Have suggestions, feedback, or specific topics you’d like us to cover? Don’t hesitate to reach out:

Thank you for stopping by, and let the learning adventure begin! 🚀

Appreciation:

Shawn

Thank you for being a part of this journey. Keep the flame alive. Here’s to more learning and growth together!

This post is licensed under CC BY 4.0 by the author.