Software Engineering·July 21, 2026·3 min read

Containerisation Basics

A container packages your app and everything it needs to run into a single portable unit. This guide explains Docker, images, Dockerfiles, Docker Compose, and when to use containers.

dockercontainersdevopsinfrastructuredeployment

A container packages your application and everything it needs to run — code, runtime, libraries, environment variables — into a single portable unit. Run it on your laptop, a CI server, or a cloud VM, and it behaves identically in all three.

The most common containerisation tool is Docker. When developers say "container," they almost always mean a Docker container.

If Cartara flagged this in your diff, you likely added or modified a Dockerfile, docker-compose.yml, or a container-related deployment config.


The Problem Containers Solve

The classic complaint: "It works on my machine."

This happens because software depends on its environment — the specific version of Node.js installed, the system libraries available, the OS. When those differ between development, CI, and production, things break in hard-to-reproduce ways.

Containers solve this by making the environment part of the application. If it runs in the container on your machine, it runs in the container in production.


Core Concepts

Image

A read-only template that defines a container. Built from a Dockerfile. An image contains the OS layer, runtime, dependencies, and application code.

Think of an image as a recipe. You build it once; you can create many containers from it.

Container

A running instance of an image. Lightweight, isolated, and ephemeral. You can run multiple containers from the same image simultaneously.

Dockerfile

A text file with instructions for building an image:

# Start from an official Node.js image
FROM node:20-alpine

# Set the working directory inside the container
WORKDIR /app

# Install dependencies
COPY package*.json ./
RUN npm ci --only=production

# Copy application code
COPY . .

# Expose the port the app runs on
EXPOSE 3000

# Command to start the app
CMD ["node", "server.js"]

Docker Compose

A tool for running multi-container applications locally. A docker-compose.yml file defines all the services your app needs (app server, database, Redis) and how they connect — so your entire local environment starts with one command:

services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgresql://postgres:password@db:5432/myapp
    depends_on:
      - db

  db:
    image: postgres:16
    environment:
      - POSTGRES_PASSWORD=password
      - POSTGRES_DB=myapp
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:

docker compose up starts all services. docker compose down stops them. This replaces "install Postgres locally, configure it, remember which port it's on" for every developer on your team.


What You'll See in Your Code

Container-related files in a diff:

  • Dockerfile — instructions for building the app's container image
  • docker-compose.yml — defines local services (app, database, Redis, worker)
  • .dockerignore — lists files to exclude from the image (like .env, node_modules, __tests__)
  • railway.toml, fly.toml, render.yaml — platform-specific deployment configs that often reference Docker

A typical .dockerignore:

node_modules
.env
.env.*
__tests__
*.test.ts
.git

Containers vs. Serverless

ContainersServerless
Startup timeSecondsMilliseconds–seconds
ManagementYou manage the runtimeFully managed
ScalingManual or autoAutomatic
Cost at low trafficAlways-onNear zero (scales to zero)
Execution timeUnlimitedLimited (minutes)
Cold startsNoYes

Use containers when: You have long-running services, need consistent latency (no cold starts), or have complex dependencies.

Use serverless when: Traffic is variable or low, tasks are short-lived, or you don't want to think about infrastructure.

Most small apps start serverless (Vercel, Netlify) and add containers later as specific needs arise.


Running Containers in Production

Managed container platforms handle the infrastructure for you — you just provide the image:

PlatformNotes
RailwaySimplest deployment, great developer experience
RenderSimilar to Railway, good free tier
Fly.ioMore control, runs containers globally
Google Cloud RunServerless containers — scales to zero, pay per request
AWS App RunnerSimilar to Cloud Run, AWS ecosystem

Cloud Run is particularly worth knowing: it runs containers but bills like serverless — you pay only when requests are handled, and scale to zero when idle.


Best Practices

Keep images small. Use Alpine-based images (node:20-alpine) and add a .dockerignore to exclude unnecessary files. Smaller images build faster and deploy faster.

Don't store state in containers. Containers are ephemeral — they can be stopped and replaced at any time. Store files and persistent data in external storage (S3, a database, a volume).

Pass secrets as environment variables. Never bake API keys or database URLs into the image. Pass them at runtime. See Secrets and Config Management.

Pin base image versions. FROM node:20-alpine is more predictable than FROM node:alpine (which follows the latest version and can change unexpectedly).


Common Docker Commands

# Build an image from your Dockerfile
docker build -t myapp:latest .

# Run a container from the image
docker run -p 3000:3000 myapp:latest

# Start all services defined in docker-compose.yml
docker compose up

# Start in the background
docker compose up -d

# View running containers
docker ps

# View logs from a container
docker logs <container_id>

# Open a shell inside a container (for debugging)
docker exec -it <container_id> sh

# Stop all services
docker compose down

Related concepts

GitOps and Kubernetes
What Kubernetes does, what GitOps adds on top of it, and when this combination is worth adopting — explained for builders who haven't managed clusters before.
CI/CD Basics
CI/CD automates the process of testing and shipping code. This guide explains continuous integration, continuous deployment, how pipelines work, and how to set one up.
Deployment Strategies
A deployment strategy controls how a new version of your app reaches users — all at once, gradually, or behind a feature flag. This guide explains the main approaches and when to use each.

Turn shipping into understanding

Cartara measures what your team actually learns from every AI coding session.

Join the waitlist