← Back to Knowledge Base
GENERAL Beginner License: CC-BY-SA-4.0 #docker #containers #linux #software

Docker: A Beginner-Friendly Guide

Updated 2026-09-17 • Edit or improve this page on GitHub →

Docker: A Beginner-Friendly Guide

Docker lets you run applications in isolated environments called containers. Instead of installing every application directly on your system, you can package it together with its dependencies and run it in a predictable environment.

This makes Docker useful for development, self-hosting, testing, and running services on servers.

How Docker works

Docker uses several important concepts:

  • An image is a template used to create containers.
  • A container is a running instance of an image.
  • A volume stores data outside the container's writable filesystem.
  • Docker Compose lets you define and run multiple containers as one application.

A simple example:

Docker image
     │
     ▼
  Container
     │
     ├── Application
     ├── Dependencies
     └── Configuration

Containers are isolated from the host system, but they still share the host's Linux kernel.

Installing Docker

On Arch Linux, Docker is available directly from the official repositories:

sudo pacman -S docker

Enable and start the Docker service:

sudo systemctl enable --now docker

Check that Docker is working:

docker version

You can also run a small test container:

docker run hello-world

If Docker prints a welcome message, the installation is working.

Running Docker without root

By default, Docker commands require access to the Docker daemon, which commonly means using root privileges.

You can add your user to the docker group:

sudo usermod -aG docker "$USER"

Log out and back in for the new group membership to take effect.

Then check:

docker ps

Security note: Membership in the docker group effectively grants root-level control over the host. Do not add untrusted users to this group.

Running your first container

Let's run an Nginx web server:

docker run --name my-nginx -p 8080:80 nginx

Docker will download the nginx image if it is not already available locally and start a container from it.

The -p 8080:80 option maps port 8080 on the host to port 80 inside the container.

You can now open:

http://localhost:8080

To see running containers:

docker ps

To stop the container:

docker stop my-nginx

To start it again:

docker start my-nginx

To remove it:

docker rm my-nginx

Working with images

Images are usually downloaded from a container registry, such as Docker Hub.

Pull an image manually:

docker pull nginx

List downloaded images:

docker images

Remove an image:

docker rmi nginx

You normally do not need to manually pull an image before running it. docker run will download it automatically if necessary.

Container lifecycle

A container can be running, stopped, or removed.

Useful commands:

docker ps

Show running containers.

docker ps -a

Show all containers, including stopped ones.

docker stop <container>

Stop a running container.

docker start <container>

Start an existing container.

docker restart <container>

Restart a container.

docker rm <container>

Remove a stopped container.

A stopped container still exists and can usually be started again. Removing it deletes the container itself.

Viewing logs

If an application inside a container is not behaving as expected, check its logs:

docker logs <container>

Follow new log messages:

docker logs -f <container>

This is often the first thing to check when a container starts and immediately exits.

Executing commands inside a container

You can open a shell inside a running container:

docker exec -it <container> sh

Some images include Bash instead:

docker exec -it <container> bash

For example, you can check the filesystem or inspect configuration files from inside the container.

Avoid modifying containers manually when possible. If configuration needs to be reproducible, put it in the Dockerfile, Compose configuration, or mounted configuration files instead.

Persistent data

Containers are designed to be disposable. Data stored only inside a container can disappear when the container is removed.

For persistent data, use a volume.

Create a volume:

docker volume create app-data

Use it with a container:

docker run \
  --name my-app \
  -v app-data:/data \
  my-image

The /data directory inside the container is now backed by the Docker volume.

List volumes:

docker volume ls

Remove a volume:

docker volume rm app-data

Be careful when removing volumes: they may contain important application data.

Bind mounts

Instead of a Docker-managed volume, you can mount a directory from the host:

docker run \
  -v "$PWD/config:/app/config" \
  my-image

This is useful when you want to edit configuration files directly on the host.

A bind mount is different from a Docker volume because the data lives at a specific path on the host.

Environment variables

Many Docker images use environment variables for configuration.

For example:

docker run \
  -e APP_ENV=production \
  -e APP_PORT=8080 \
  my-image

You can also load variables from a file:

docker run --env-file .env my-image

Do not put passwords, API keys, or other sensitive credentials into images or Git repositories.

Docker Compose

Running one container with docker run is simple, but applications often consist of multiple services.

For example:

Web application
      │
      ├── Backend
      ├── PostgreSQL
      └── Redis

Docker Compose allows these services to be described in one YAML file.

A minimal example:

services:
  web:
    image: nginx:latest
    ports:
      - "8080:80"

  redis:
    image: redis:alpine

Save it as compose.yaml.

Start the application:

docker compose up -d

Stop it:

docker compose down

Show the service status:

docker compose ps

View logs:

docker compose logs

Follow logs:

docker compose logs -f

Compose is especially useful for development environments and self-hosted applications.

Building your own image

You can create an image using a Dockerfile.

For example:

FROM python:3.13-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY . .

CMD ["python", "app.py"]

Build it:

docker build -t my-python-app .

Run it:

docker run --rm my-python-app

The --rm option automatically removes the container after it exits.

Keeping images up to date

Docker images do not automatically update when the image on the registry changes.

For example, if you have:

services:
  web:
    image: nginx:latest

you can pull the newest image with:

docker compose pull

Then recreate the containers:

docker compose up -d

For production systems, avoid blindly using floating tags such as latest. Pinning a specific version makes deployments more predictable.

Cleaning up unused resources

Docker can accumulate stopped containers, unused images, networks, and build cache.

You can inspect disk usage:

docker system df

Remove unused resources:

docker system prune

Docker will ask for confirmation before removing resources.

Be careful with aggressive cleanup commands, especially on servers. Make sure you understand what is unused before deleting it.

Common mistakes

Treating containers like virtual machines

Containers are not full virtual machines. They share the host kernel and are usually much lighter than traditional VMs.

Storing important data inside containers

If an application needs persistent data, use a volume or bind mount.

Using latest everywhere

A moving tag can change underneath you. Pin versions when reproducibility matters.

Publishing every port

Only expose ports that need to be reachable from outside the container or host.

Putting secrets into Dockerfiles

Anything included in an image can potentially be extracted from it. Keep secrets outside the image and provide them at runtime.