f in x
Docker from scratch: containers, images, registries, and essential commands
> cd .. / HUB_EDITORIALE
Analisi dei dati e metriche

Docker from scratch: containers, images, registries, and essential commands

[2026-05-30] Author: Ing. Calogero Bono

Have you ever spent an afternoon setting up PHP, MySQL, and a web server on a new machine, only to find that production behaves differently? We have — and we hated it. Docker fixes exactly that: every developer, every server, every client gets the same identical environment. No more "it works on my machine".

What is a container and why it changes your day

A container is a lightweight, isolated package that includes everything needed to run an application: code, runtime, libraries, environment variables. Unlike a virtual machine, it doesn't emulate an entire OS — it shares the host's kernel. Result: less disk space, starts in seconds, consumes fewer resources.

At Meteora Web, we started using Docker in 2018 for a client project with a legacy PHP application. Before, development on Linux, Mac, and Windows was a nightmare. After Docker, setup became a single command: docker compose up. Onboarding time dropped by 70%.

Practical analogy: shipping containers

Before shipping containers, cargo was loaded piece by piece — inefficient, slow, damage-prone. Standard containers made it possible to move any freight uniformly. Docker does the same for software: it packages application and dependencies into a standard format that runs on any machine with Docker installed.

Images and containers: the critical difference

An image is an immutable template (a read-only filesystem) containing the application and its dependencies. A container is a runnable instance created from that image. You can have multiple containers from the same image, each isolated.

# Pull the official Nginx image
docker pull nginx:latest

# Start a container from that image
docker run -d -p 8080:80 --name my-nginx nginx:latest

# Check it's running
docker ps

Here, nginx:latest is the image. The created container has its own filesystem, network, and processes, but shares the kernel. Open http://localhost:8080 and you'll see Nginx's default page.

The registry: where to find and share images

Registries are image repositories. The most well-known is Docker Hub, but alternatives like GitHub Container Registry, GitLab Container Registry, or self-hosted private registries exist. You can push your images and pull public ones.

Why use a registry? To avoid reinventing the wheel. Instead of manually configuring PHP, Apache, and MySQL each time, grab an official ready-made image. We do this for our clients: a base image with PHP 8.x, necessary extensions, preinstalled Composer — all in a single Dockerfile.

# Search images on Docker Hub from the command line
docker search ubuntu

# Pull a specific version
docker pull php:8.2-fpm

Warning: don't use the latest tag in production. Images change, and you risk unexpected updates. Always specify an exact version, like nginx:1.27.0.

Essential commands to work with Docker

We use these commands every day at Meteora Web. Learn them and they'll become second nature.

Container management

# List running containers
docker ps

# List all containers (including stopped)
docker ps -a

# Start a container in background (-d), map port (-p), name (--name)
docker run -d -p 8080:80 --name my-web nginx:1.27.0

# Stop a container
docker stop my-web

# Remove a container (must be stopped)
docker rm my-web

# Force remove while running
docker rm -f my-web

Image management

# List local images
docker images

# Remove an image
docker rmi nginx:1.27.0

# Remove unused images (clean up space)
docker image prune -a

Explore a running container

# Open an interactive shell inside the container
docker exec -it my-web /bin/bash

# View logs in real time
docker logs -f my-web

Full practical example: want to test a Node.js app on a machine without Node installed? One command does it:

docker run -it --rm -v "$(pwd):/app" -w /app node:20-alpine node app.js

The --rm flag removes the container when done, -v mounts the current directory, -w sets the working directory. Clean environment, no installation.

From code to image: the Dockerfile

When official images aren't enough, you create your own. The Dockerfile is a recipe that describes how to build an image. We write one for every client project — it guarantees that development, staging, and production environments are identical.

# Use an official base image
FROM nginx:alpine

# Copy app files into the server directory
COPY ./site /usr/share/nginx/html

# Expose port 80
EXPOSE 80

# Default command (already in the base image, but explicit)
CMD ["nginx", "-g", "daemon off;"]

Now build the image and run it:

docker build -t my-site:v1 .
docker run -d -p 8080:80 my-site:v1

Common Dockerfile mistakes:

  • Copying everything (COPY . .) without .dockerignore — includes node_modules, temp files, bloating the image.
  • Using latest as base — better pin an exact version (e.g. nginx:1.27-alpine).
  • Running system updates in every build — use already updated base images.

Build and push: share your image

# Build with a tag that includes registry and username
docker build -t your-username/my-site:v1 .

# Log in to Docker Hub (or another registry)
docker login

# Upload the image to the registry
docker push your-username/my-site:v1

From now on, anyone (or any server) can run docker pull your-username/my-site:v1 and get the exact same application. We use this to deploy updates to clients without manually configuring each server.

Optimization: smaller images, lower costs

One e-commerce client had Docker images of 2.1 GB for a Node.js app. Analyzing the layers, we found dev tools, npm cache, and unnecessary files. Using a multi-stage build and Alpine images, we reduced it to 120 MB — a 94% reduction. Across 10 servers, the space and bandwidth savings were huge.

# Multi-stage build: separate compilation from runtime
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production

FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]

Security: don't leave ports open

Containers aren't inherently secure. If you run a container as root, an attacker might escalate privileges. At Meteora Web, we follow these rules:

  • Use official, well-known images (Docker Official Images or verified ones).
  • Run containers with a non-root user (USER directive in Dockerfile).
  • Don't expose unnecessary ports — map only what's needed.
  • Update base images regularly: an outdated container is a vulnerability.
# Create a non-root user
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser

In summary — what to do now

  1. Install Docker on your OS: follow the official guide at docs.docker.com.
  2. Run your first container: docker run hello-world — verify everything works.
  3. Get your hands on Nginx: pull the image (docker pull nginx:alpine), start a container with a mapped port, modify the default page and reload.
  4. Write a Dockerfile for an existing project (even a static HTML page) and build your own image.
  5. Explore Docker Hub to find useful images for your stack (PHP, Python, PostgreSQL).

From here on, everything becomes reproducible, portable, and measurable. Exactly how we like it.

Sponsored Protocol

Ing. Calogero Bono

> AUTHOR_EXTRACTED

Ing. Calogero Bono

Co-founder di Meteora Web. Ingegnere informatico, sviluppo ecosistemi digitali ad alte prestazioni. AI, automazione, SEO tecnica e infrastrutture web. Scrivo di tecnologia per rendere complesso… semplice.

[ Read Full Dossier ]

Hai bisogno di applicare questa strategia?

Esegui il protocollo di contatto per iniziare un progetto con noi.

> INIZIA_PROGETTO

Sponsored

> MW_JOURNAL

> READ_ALL()