Skip to main content

Lesson 4 of 4 20 min read

Docker containers and the purpose of CI/CD

Package an application in a Docker container and see how continuous integration and delivery automate testing and releases.

In this lesson you will

  • Explain containers, images and how they differ from virtual machines
  • Read and write a simple Dockerfile and run it with Docker commands
  • Describe CI and CD and read a basic GitHub Actions workflow

The "works on my machine" problem

An application that runs perfectly on your laptop can fail on a server because of a different operating system version, a missing library or a different runtime version. Containers solve this by packaging the application together with everything it needs into one portable unit.

Containers and virtual machines

Virtual machineContainer
IncludesA full guest operating systemJust the app and its dependencies
Shares the host kernelNoYes
Start-up timeMinutesSeconds
SizeGigabytesOften tens to hundreds of megabytes

Because containers are light, one server can run many of them, and the same container runs identically on a laptop, a test server and in the cloud.

What a container shares with its host

Layers from top to bottom: Your app and its libraries, Container runtime, Host operating system, Hardware

Images and containers

  • An image is a read-only template: the app, its runtime and its files, built in layers.
  • A container is a running instance of an image. You can start many containers from one image.
  • A registry such as Docker Hub stores and shares images.
  1. Dockerfile
  2. docker build
  3. Image
  4. docker run
  5. Container
5-step diagram

A Dockerfile

A Dockerfile is a recipe for building an image. Here is one for a small Node.js web server:

Dockerfile
# Start from an official image that already contains Node.js
FROM node:22-alpine

# Work inside /app in the image
WORKDIR /app

# Install dependencies first so Docker can cache this layer
COPY package*.json ./
RUN npm ci --omit=dev

# Copy the application code
COPY . .

# Document the port the app listens on, then define the start command
EXPOSE 3000
CMD ["node", "server.js"]

Build the image and run a container from it:

Terminal
docker build -t devcrest-demo .
docker run -d -p 8080:3000 --name demo devcrest-demo
# The app is now at http://localhost:8080

docker ps            # list running containers
docker logs demo     # view the container's output
docker stop demo     # stop it

-p 8080:3000 maps port 8080 on your computer to port 3000 inside the container.

CI/CD: automating the path to production

Teams merge many changes every day. Testing and deploying each one by hand is slow and error-prone. CI/CD automates it:

  • Continuous integration (CI): every push or pull request automatically builds the code and runs the tests. Broken changes are caught within minutes, before they are merged.
  • Continuous delivery (CD): every change that passes CI is automatically packaged and ready to release; continuous deployment goes further and releases it to production automatically.
  1. Push code
  2. Build
  3. Run tests
  4. Build image
  5. Deploy to staging
  6. Deploy to production
6-step diagram

A GitHub Actions workflow

GitHub Actions runs CI/CD pipelines defined in YAML files inside the repository, under .github/workflows/:

YAML
name: CI

on:
  push:
    branches: [main]
  pull_request:

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
      - run: npm ci
      - run: npm test

On every push to main and on every pull request, GitHub starts a fresh Linux machine, checks out the code, installs Node.js and the dependencies, and runs the tests. The result appears as a green tick or red cross on the pull request, so reviewers know whether the change is safe to merge.

Hands-on exercise

Install Docker Desktop and run docker run hello-world to check it works. Then write a Dockerfile for the personal website from the Web Development Basics path using the official nginx:alpine image (copy your files into /usr/share/nginx/html), build it and run it with docker run -p 8080:80. Finally, sketch the steps of a CI pipeline for that site: what would you check automatically on every pull request?

Knowledge check

3 questions • 70% to pass • Practice only, no certificate

  1. 1.What does -p 8080:3000 mean in docker run?
  2. 2.Why does the Dockerfile copy package*.json and install dependencies before copying the rest of the code?
  3. 3.A pull request breaks a test. When does CI tell the team?
0 of 3 answered

Key concepts

  • Containers package an app with its dependencies so it runs the same everywhere; they share the host kernel and start in seconds.
  • A Dockerfile builds an image; containers are running instances of an image; registries share images.
  • CI builds and tests every change automatically; CD keeps every passing change ready to release or deploys it.
  • GitHub Actions workflows in .github/workflows define pipelines that report results on pull requests.

Optional next step: DevCrest Academy

Cloud Engineering with AWS, Docker & Kubernetes

Ready to deploy real systems? The academy course covers AWS, Docker, Kubernetes and CI/CD pipelines through hands-on labs, building on the ideas in this path.

  • Intermediate
  • 12 weeks • 90 hours
  • Hybrid
  • From ₹7,500 per student

Fees and batch dates are sample data pending confirmation

Or keep learning for free with Programming Fundamentals.