Get Started with Docker

 

๐Ÿณ Get Started with Docker: Step-by-Step Guide to Build & Modify a Web App

✅ What You’ll Do: 

  • Clone a ready-made app project

  • Start the app using Docker

  • Make simple changes to backend, frontend, and design

  • See updates live in your browser


๐Ÿ”ง Step 1: Install Docker Desktop

Make sure you’ve installed Docker Desktop on your system.
๐Ÿ‘‰ Download here if not done yet


๐Ÿ“ Step 2: Download the Project

Open your terminal and clone the example project from GitHub:

git clone https://github.com/docker/getting-started-todo-app

Move into the project folder:

cd getting-started-todo-app

๐Ÿš€ Step 3: Start the Application

Start the application using Docker Compose Watch (which auto-reloads on changes):

docker compose watch

๐Ÿ‘‰ This command:

  • Pulls necessary Docker images

  • Starts containers (backend, frontend, DB, etc.)

  • Sets up the full environment for development

Wait until setup completes (a few seconds to a couple of minutes).


๐ŸŒ Step 4: Open the App in Browser

Go to:

http://localhost

✅ You’ll see a simple To-Do app.


๐Ÿ” What's Inside the Docker Environment?

You’re now running 5 services inside Docker containers:

ServicePurpose
๐Ÿ–ฅ React frontendBuilt with Vite, handles user interface
๐Ÿ›  Node backendHandles API (Add/Delete/Get to-do items)
๐Ÿ—ƒ MySQL DBStores your to-do list
๐Ÿง‘‍๐Ÿ’ป phpMyAdminManage DB at http://db.localhost
๐Ÿ” Traefik proxyRoutes requests to correct services (port 80)

๐Ÿ‘‰ You didn’t need to install Node, MySQL, or phpMyAdmin manually—Docker did it for you.


✏️ Step 5: Make Backend Change (Greeting Message)

  1. Open this file in a text editor:

backend/src/routes/getGreeting.js
  1. Replace its content with:

const GREETINGS = [ "Whalecome!", "All hands on deck!", "Charting the course ahead!", ]; module.exports = async (req, res) => { res.send({ greeting: GREETINGS[ Math.floor( Math.random() * GREETINGS.length )], }); };
  1. Save the file.

  2. Refresh your browser and you’ll see a random greeting message each time.


✏️ Step 6: Change Placeholder Text (Frontend)

  1. Open this file:

client/src/components/AddNewItemForm.jsx
  1. Find the following code and update the placeholder:

<Form.Control value={newItem} onChange={(e) => setNewItem(e.target.value)} type="text" placeholder="What do you need to do?" aria-label="New item" />
  1. Save the file and check your browser—it will update automatically!


๐ŸŽจ Step 7: Change the Background Color

  1. Open this file:

client/src/index.scss
  1. Modify the background-color like this:

body { background-color: #99bbff; // Or any color you like margin-top: 50px; font-family: 'Lato'; }
  1. Save the file and refresh your browser to see the change instantly.


✅ Recap – What You Achieved

✔️ Started a complete development app with Docker (no need to install Node, MySQL, etc.)
✔️ Edited backend logic and saw results instantly
✔️ Updated frontend text and style, live in your browser
✔️ Experienced the power of container-based development

docker compose file for above repo is 



services:
  proxy:
    image: traefik:v3.4
    command: --providers.docker
    ports:
      - 80:80
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock

  backend:
    build:
      context: ./
      target: backend-dev
    environment:
      MYSQL_HOST: mysql
      MYSQL_USER: root
      MYSQL_PASSWORD: secret
      MYSQL_DB: todos
    depends_on:
      mysql:
        condition: service_healthy
    develop:
      watch:
        - path: ./backend/src
          action: sync
          target: /usr/local/app/src
        - path: ./backend/package.json
          action: rebuild
    labels:
      traefik.http.routers.backend.rule: Host(`localhost`) && PathPrefix(`/api`)
      traefik.http.services.backend.loadbalancer.server.port: 3000

  client:
    build:
      context: ./
      target: client-dev
    develop:
      watch:
        - path: ./client/src
          action: sync
          target: /usr/local/app/src
        - path: ./client/package.json
          action: rebuild
    labels:
      traefik.http.routers.client.rule: Host(`localhost`)
      traefik.http.services.client.loadbalancer.server.port: 5173

  mysql:
    image: mysql:9.3
    volumes:
      - todo-mysql-data:/var/lib/mysql
    environment: 
      MYSQL_ROOT_PASSWORD: secret
      MYSQL_DATABASE: todos
    healthcheck:
      test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
      interval: 5s
      timeout: 5s
      retries: 5

  phpmyadmin:
    image: phpmyadmin
    environment:
      PMA_HOST: mysql
      PMA_USER: root
      PMA_PASSWORD: secret
    labels:
      traefik.http.routers.phpmyadmin.rule: Host(`db.localhost`)
      traefik.http.services.phpmyadmin.loadbalancer.server.port: 80

volumes:
  todo-mysql-data:

๐Ÿงฑ Step-by-Step Breakdown of Each Service


๐Ÿšฆ 1. proxy — Reverse Proxy using Traefik

  • Acts like a traffic cop: decides whether a request should go to the backend, frontend, or phpMyAdmin.

  • Exposes port 80 to the outside world.

  • Uses Docker socket to watch containers and apply rules using labels (you’ll see labels in other services).

๐Ÿ’ป 2. backend — Node.js API

  • Built from the Dockerfile in the root (context: ./), using the stage backend-dev.

  • Environment variables are used to connect to the MySQL database.

  • Uses develop.watch to auto-sync code changes (hot reload).

  • Labels tell Traefik to route localhost/api traffic here.

๐ŸŒ 3. client — React Frontend

  • Also built from the root directory but targets client-dev stage.

  • Hot reloads code using the develop.watch.

  • Routes all traffic to localhost (except /api and db.localhost) to this service on port 5173.

๐Ÿ›ข️ 4. mysql — MySQL Database

  • Uses the MySQL official image.

  • Stores data in a volume so it doesn’t get lost when containers stop.

  • Runs a health check to make sure it's ready before backend connects.

๐Ÿงฐ 5. phpmyadmin — DB Admin Interface

  • Web UI for MySQL (handy for debugging).

  • Access it via http://db.localhost (routed by Traefik).

  • Connects to the mysql service with default login credentials.

๐Ÿ—ƒ️ Volume: todo-mysql-data

This volume is used to store MySQL data, so that it's not lost when the container stops.

Service URL
React Frontend http://localhost
Backend API http://localhost/api
phpMyAdmin http://db.localhost

๐Ÿ”น Top-Level Key: services

Defines all the individual containers (services) to be run.


๐Ÿ”ธ proxy service:

image: traefik:v3.4
  • Use the Traefik v3.4 image (a reverse proxy/load balancer).

command: --providers.docker
  • Tells Traefik to watch Docker containers for dynamic routing configuration.

ports: - 80:80
  • Maps port 80 of the host to port 80 of the container, exposing HTTP traffic.

volumes: - /var/run/docker.sock:/var/run/docker.sock
  • Mounts the Docker socket so Traefik can detect running containers and route traffic accordingly.


๐Ÿ”ธ backend service:

build: context: ./ target: backend-dev
  • Builds the image from the current directory.

  • Uses the backend-dev stage from the Dockerfile.

environment: MYSQL_HOST: mysql MYSQL_USER: root MYSQL_PASSWORD: secret MYSQL_DB: todos
  • Sets environment variables (used to connect to the MySQL database container).

depends_on: mysql: condition: service_healthy
  • Waits for the MySQL service to be healthy before starting this container.

develop: watch: - path: ./backend/src action: sync target: /usr/local/app/src - path: ./backend/package.json action: rebuild
  • Watches files during development:

    • Syncs changes in src to container.

    • Rebuilds container if package.json changes.

labels: traefik.http.routers.backend.rule: Host(`localhost`) && PathPrefix(`/api`) traefik.http.services.backend.loadbalancer.server.port: 3000
  • Tells Traefik to route traffic to /api path on localhost to this service.

  • Port 3000 is exposed inside the container.


๐Ÿ”ธ client service:

build: context: ./ target: client-dev
  • Similar to backend, builds client image using Dockerfile with target client-dev.

develop: watch: - path: ./client/src action: sync target: /usr/local/app/src - path: ./client/package.json action: rebuild
  • Same as backend — watches files for sync or rebuild during development.

labels: traefik.http.routers.client.rule: Host(`localhost`) traefik.http.services.client.loadbalancer.server.port: 5173
  • Traefik routes all localhost traffic (not /api) to this service on port 5173.


๐Ÿ”ธ mysql service:

image: mysql:9.3
  • Uses official MySQL version 9.3 image.

volumes: - todo-mysql-data:/var/lib/mysql
  • Mounts persistent storage volume to keep database data even if container is destroyed.

environment: MYSQL_ROOT_PASSWORD: secret MYSQL_DATABASE: todos
  • Creates a MySQL DB named todos and sets the root password.

healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost"] interval: 5s timeout: 5s retries: 5
  • Docker checks if MySQL is alive and responsive every 5 seconds. It will retry 5 times.


๐Ÿ”ธ phpmyadmin service:

image: phpmyadmin
  • Uses official phpMyAdmin image for DB GUI.

environment: PMA_HOST: mysql PMA_USER: root PMA_PASSWORD: secret
  • Connects phpMyAdmin to the MySQL container using provided credentials.

labels: traefik.http.routers.phpmyadmin.rule: Host(`db.localhost`) traefik.http.services.phpmyadmin.loadbalancer.server.port: 80
  • Traefik will expose phpMyAdmin on http://db.localhost.


๐Ÿ”น volumes (bottom of file):

volumes: todo-mysql-data:
  • Defines a named volume to store MySQL data persistently.

๐Ÿณ Build & Push Your First Docker Image to Docker Hub — Step-by-Step Guide


✅ Prerequisites

  1. Install Docker Desktop
    ๐Ÿ‘‰ Download it here

  2. Create a Docker Hub account
    ๐Ÿ‘‰ Sign up here

  3. Login to Docker Hub from terminal
    Run:

    docker login

    Enter your Docker Hub username and password when prompted.


๐Ÿ› ️ Step 1: Create a Project Directory

  1. Create a folder for your project:

    mkdir my-docker-app cd my-docker-app
  2. Create a simple app file, e.g., app.py (Python example):

    # app.py print("Hello from Docker!")
  3. Create a Dockerfile in the same folder:

    # Dockerfile FROM python:3.9-slim WORKDIR /app COPY app.py . CMD ["python", "app.py"]

๐Ÿงฑ Step 2: Build the Docker Image

Run the following command to build your image:

docker build -t your-dockerhub-username/my-docker-app .

๐Ÿ”ธ Replace your-dockerhub-username with your actual Docker Hub username.

Example:

docker build -t obul123/my-docker-app .

✅ If successful, you’ll see Successfully tagged obul123/my-docker-app:latest at the end.


๐Ÿงช Step 3: Run the Docker Image (Optional Test)

Make sure your image works by running:

docker run obul123/my-docker-app

Expected output:

Hello from Docker!

๐Ÿš€ Step 4: Push Image to Docker Hub

Now, push your image to your Docker Hub repository:

docker push your-dockerhub-username/my-docker-app

Example:

docker push obul123/my-docker-app

✅ If successful, you’ll see upload progress and then pushed confirmation.


๐Ÿ” Step 5: Verify on Docker Hub

  1. Go to https://hub.docker.com/

  2. Log in to your account

  3. You’ll see the newly pushed image under Repositories


๐Ÿ“Œ Recap

StepAction
Install DockerInstall Docker Desktop
LoginUse docker login to authenticate with Docker Hub
Create AppWrite a simple Python app and a Dockerfile
Build ImageUse docker build -t username/image-name . to build the image
Test ImageRun locally with docker run
Push to DockerPush the image using docker push
VerifyCheck your image on Docker Hub

Comments