Docker for Beginners: Containers Explained

What a container actually is, how a Dockerfile works, and how to ship an app that runs identically everywhere.

"Works on my machine" dies with Docker. A container packages your app and its entire environment into one unit that runs identically on any machine with Docker installed.

Image vs container

An image is a read-only snapshot of a filesystem plus a start command. A container is a running instance of that image. Think image = class, container = object.

Your first Dockerfile

dockerfile
# start from a small, pinned base image
FROM node:20-alpine

# set the working directory inside the container
WORKDIR /app

# copy dependencies first (leverages layer caching)
COPY package*.json ./
RUN npm ci --only=production

# then copy the rest of the code
COPY . .

# document the port
EXPOSE 3000

# the command that runs on start
CMD ["node", "index.js"]

Build and run

bash
docker build -t my-app .
docker run -p 3000:3000 my-app
# open http://localhost:3000

The commands that matter

bash
docker ps                 # running containers
docker images             # local images
docker logs -f <id>       # follow logs
docker exec -it <id> sh   # shell into a running container
docker stop <id>          # stop
docker rm <id>            # remove container
docker rmi <image>        # remove image

Layer caching is the trick

Each RUN/COPY line is a cached layer. That's why we copy package.json first: dependency installs only re-run when dependencies actually change, not on every code edit.

Use .dockerignore to keep node_modules, .git and secrets out of the build context — it makes builds faster and images smaller.

Once your app runs in a container, deploying anywhere — Render, a VPS, Kubernetes — is just a matter of pointing the platform at your image.

Your move

Want us to build this for you?

We turn tutorials like these into production systems every day. Tell us what you need.

Start a project →