What it is
Docker is the most common tool for building and running containers. A Dockerfile is a recipe: start from a base image, copy files, install dependencies, set a command. docker build produces an image. docker run starts a container, a process (plus its children) isolated with that image's filesystem. Docker Compose runs several containers together for local development: an app and a database, for example.
Docker is not the only container runtime. Podman and others exist. Kubernetes is an orchestrator that runs containers, often built by Docker or a compatible builder. This page is the developer tool. The concept of isolation is the containers page.
Why and when it is used
Use Docker when "works on my machine" is about system libraries, language versions, or a dependency you do not want to install globally. Use it so CI and production build the same image. Use Compose when local development needs Postgres and Redis beside the app.
Do not containerise a trivial script you run once. Do not treat a container as a security boundary against untrusted code you would not otherwise trust; it is isolation, not a magic sandbox, and misconfiguration is common. Do not put the database's only data inside a container's writable layer without a volume. When the container is removed, that layer can go with it.
How it works
Images are layers. Each Dockerfile instruction can create a layer, and unchanged layers are cached. Order the file so dependencies install before you copy source that changes every commit; otherwise every build reinstalls the world. The container shares the host's kernel. It does not boot a second operating system (that would be a virtual machine). Port mapping (-p 8080:8080) publishes a port. Environment variables configure the process. A volume mounts a host or named directory into the container so data outlives it.
The default user in many images is root. Your process then runs as root inside the container, which is a bigger blast radius if the app is compromised. Set a user. .dockerignore keeps secrets and node_modules out of the build context. A secret copied into an image layer remains in the layer even if a later instruction deletes the file.
Technologies and dependencies
Docker Engine or a compatible runtime, a Dockerfile, and a registry (GitHub Container Registry, ECR, Artifact Registry, Docker Hub) if you deploy elsewhere. CI should build and push. Environment Variables or a secret manager supply configuration at run time, not at image-build time, for anything sensitive. Base images need updates; pin by digest when you need reproducibility, and still rebuild for patches.
How to get started
- Install Docker. Run the hello-world image to prove the daemon works.
- Write a Dockerfile for a tiny app that listens on a port. Use a small base image, not a desktop OS.
- Build and run it. Map the port. Call the health endpoint.
- Change source and rebuild. If the dependency layer reran, reorder the Dockerfile.
- Add a
.dockerignore. Confirm a.envfile did not enter the image (docker historyand a careful look, or a scan). - Add Compose only when you need a second process. Mount a volume for database files and restart to prove the data survives.
Tag images with the Git SHA you built, not only latest. latest is not a version.
Cautions and trade-offs
Images grow when you install build tools and leave them in the final stage. Multi-stage builds keep the compiler out of production. Running as root, mounting the Docker socket into a container, and using --privileged are decisions with security consequences, not defaults.
Registries are public unless you make them private. A pushed image with a secret is a leaked secret. Compose files that bake passwords into the YAML get committed. And containers do not remove the need to understand the process. If the app ignores SIGTERM, your deploys will cut requests. Handle shutdown. Docker is packaging and process isolation, not an architecture.