Docker Container Guide: Practical Tutorial & Best Practices

5 min read

Docker container guide — short, practical, and honest. If you’re new to containerization or moving from VMs, this article explains what Docker containers are, how they work, and how to use them day-to-day. I’ll share hands-on examples, common pitfalls I’ve seen, and best practices that actually matter. Read this and you’ll be able to build images, run services with Docker Compose, push to Docker Hub, and think about orchestration with Kubernetes.

Ad loading...

What is Docker and why it matters

At its core, Docker packages software into units called containers that run reliably across environments. Containers are lightweight compared to VMs because they share the host OS kernel while isolating processes and file systems. For a quick background, see the Docker Wikipedia page for history and context.

Core concepts: image, container, Dockerfile, Docker Hub

Images vs. containers

An image is a read-only template (think: a snapshot of a filesystem + metadata). A container is a running instance of that image with ephemeral state. Stop the container, and unless you persisted data, it’s gone. In my experience, thinking in terms of immutable images helps avoid messy production surprises.

Dockerfile basics

A Dockerfile is a small, version-controlled script that builds an image. Minimal example (build a simple Node app):

FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install –production
COPY . .
CMD [“node”, “server.js”]

Use a slim base image and layer ordering to speed builds and reduce image size.

Docker Hub and registries

Docker Hub is the default public registry where you push and pull images. For private or enterprise needs, use a private registry or services like GitHub Container Registry. Official Docker docs explain registry workflows well: Docker Documentation.

Getting started: install, first container, Docker Compose

Install Docker Desktop on macOS/Windows or Docker Engine on Linux. Follow platform-specific steps on the official docs to avoid permission issues.

Your first commands

Try this sequence locally to verify everything works:

docker run –rm hello-world
docker pull nginx:latest
docker run -d -p 8080:80 –name web nginx:latest

That last command runs nginx on port 8080. Check http://localhost:8080.

Docker Compose for multi-service apps

When your app has multiple services (web, db, cache), use Docker Compose. Example docker-compose.yml (very simple):

version: ‘3.8’
services:
web:
build: ./web
ports:
– ‘8080:80’
db:
image: postgres:15
environment:
POSTGRES_PASSWORD: example

Compose streamlines local dev, testing, and CI steps. It’s my go-to for reproducible local environments.

Practical examples and workflows

Build, tag, push

Typical image lifecycle:

  • docker build -t yourname/app:1.0 .
  • docker tag yourname/app:1.0 yourrepo/yourname/app:1.0
  • docker push yourrepo/yourname/app:1.0

Automate these steps in CI. Keep tags immutable (use commit SHA) and a latest tag for convenience.

Persisting data

Containers are ephemeral. Use volumes for durable data:

docker run -d -v mydata:/var/lib/postgresql/data postgres:15

Named volumes are easier to manage than host mounts for portability.

Working with orchestration: when to consider Kubernetes

If you need automated scaling, self-healing, or rolling updates across many nodes, orchestration matters. Kubernetes is the industry standard. It adds complexity, so weigh operational overhead. For introductions and setup guides, the Kubernetes docs are extensive (searchable and official).

Best practices I actually use

  • Small images: Use minimal base images (alpine or distroless) to reduce attack surface and faster pulls.
  • Multi-stage builds: Build artifacts in one stage, copy only what’s needed into the runtime stage.
  • Immutable tags: Use commit-based tags for deployments; avoid relying only on latest.
  • Scan images: Integrate vulnerability scanning into CI before pushing to registries.
  • Limit container privileges: Run as non-root when possible and drop unnecessary capabilities.

Common troubleshooting tips

  • If containers fail to start, check logs: docker logs CONTAINER.
  • Use docker ps -a to see exited containers and inspect exit codes.
  • Networking issues? Verify port mappings and firewall rules. For Compose, check service health and depends_on semantics.
  • Image build slow? Use cache wisely, reorder Dockerfile steps, and use .dockerignore to skip unnecessary files.

Real-world example: migrating a small Rails app

I migrated a small Rails app by creating a Dockerfile, using a multi-stage build, and a docker-compose stack including Postgres and Redis. The team gained faster onboarding (no more “works on my machine”), but we also learned the hard way about proper logging — set stdout/stderr to avoid losing logs to local files.

Resources and further reading

Official docs and trustworthy references are worth bookmarking: the Docker Documentation is the primary reference for commands and concepts. For a historical overview and additional links, check the Docker Wikipedia entry. If you want to publish images, explore Docker Hub for registry workflows.

Next steps: Build a simple image, push it to a registry, and run it on another machine or CI. Then add Compose and test a multi-service setup. From what I’ve seen, iterative practice is the fastest path to confidence.

Frequently asked questions

Note: See the FAQ section below for quick answers to common questions.

Frequently Asked Questions

A Docker container is a lightweight, standalone executable package that includes software and all its dependencies, sharing the host OS kernel while running isolated processes.

Write a Dockerfile that defines base image, files, dependencies, and commands, then run: docker build -t yourname/app:tag .

Use Docker Compose for local development and testing when your application has multiple services like web, database, and cache that must run together.

Persist data using Docker volumes or bind mounts. Named volumes are portable and easier to manage across environments.

Not always. Kubernetes is useful for production-level orchestration (scaling, self-healing). For single-node or small deployments, Docker and Compose may be sufficient.