# Docker Basics & Advanced Challenge

![Ultimate Docker Fast-Track Beginner to Advanced | Udemy](https://img-c.udemycdn.com/course/750x422/2842220_eda3_4.jpg align="left")

Welcome to the Week 5 Docker Challenge! In this task, you will work with Docker concepts and tools. This challenge covers the following topics:

* **Introduction and Purpose:** Understand Docker’s role in modern development.
    
* **Virtualization vs. Containerization:** Learn the differences and benefits.
    
* **What is build :** Understand the Docker build process.
    
* **Docker Terminologies:** Get familiar with key Docker terms.
    
* **Docker Components:** Explore Docker Engine, images, containers, and more.
    
* **Project Building Using Docker:** Containerize a sample project.
    
* **Multi-stage Docker Builds / Distroless Images:** Optimize your images.
    
* **Docker Hub (Push/Tag/Pull):** Manage and distribute your Docker images.
    
* **Docker Volumes:** Persist data across container runs.
    
* **Docker Networking:** Connect containers using networks.
    
* **Docker Compose:** Orchestrate multi-container applications.
    

### Task 1: Introduction and Conceptual Understanding

1. Docker plays a crucial role in modern DevOps by enabling containerization. Here’s a brief overview of its purpose:
    
    1. **Consistent Environments:** Docker ensures that applications run the same way in different environments by packaging them along with their dependencies into containers.
        
    2. **Scalability:** Containers can be easily scaled up or down based on demand, making it ideal for handling fluctuating workloads.
        
    3. **CI/CD Integration:** Docker integrates seamlessly with Continuous Integration/Continuous Deployment (CI/CD) pipelines, automating the testing and deployment processes.
        
    4. **Microservices Architecture:** Docker supports the microservices architecture, allowing applications to be broken down into smaller, manageable services that can be developed, deployed, and scaled independently.
        
    
    By simplifying deployment, enhancing scalability, and ensuring consistency across environments, Docker has become a key player in the DevOps landscape.
    
    * **Compare Virtualization vs. Containerization and explain why containerization is the preferred approach for microservices and CI/CD pipelines**
        
    * ### Virtualization
        
        * **What it is:** Runs multiple virtual machines (VMs) on one physical server.
            
        * **How it works:** Each VM has its own operating system (OS).
            
        * **Resource Use:** Heavy because each VM needs its own OS.
            
        * **Boot Time:** Slow because it takes time to start each OS.
            
        
        ### Containerization
        
        * **What it is:** Runs multiple containers on one server or VM.
            
        * **How it works:** Containers share the host OS.
            
        * **Resource Use:** Light because containers share the same OS.
            
        * **Boot Time:** Fast because they don't need to start a new OS.
            
        
        ### Why Containers are Better for Microservices and CI/CD
        
        * **Lightweight:** Uses less resources, perfect for small services.
            
        * **Fast Deployment:** Starts quickly, speeds up development.
            
        * **Consistency:** Works the same in all environments (dev, test, prod).
            
        * **Portability:** Can run anywhere (laptop, cloud, etc.).
            
        
        In short, containerization is preferred because it's light, fast, consistent, and portable, making it ideal for modern applications and development practices.
        
    
    ### Task 2: Create a Dockerfile for a Sample Project
    
    1. **Select or Create a Sample Application:**
        
        * Choose a simple application (for example, a basic Node.js, Python, or Java app that prints “Hello, Docker!” or using a flask ).
            

* Create a `Dockerfile` that defines how to build an image for your application.
    
* Include comments in your Dockerfile explaining each instruction.
    
    ### **Step 1: Create the Flask App**
    
    1. Inside the `hello-docker` directory, create [`app.py`](http://app.py):
        
    
    ```plaintext
    from flask import Flask
    
    app = Flask(__name__)
    
    @app.route("/")
    def home():
        return "Hello, Docker!"
    
    if __name__ == "__main__":
        app.run(host="0.0.0.0", port=5000)
    ```
    

2. ### **Step 2: Create a** `requirements.txt` file
    
    ```plaintext
    flask
    ```
    
3. ### **Step 3: Create a** `Dockerfile`
    
    ```plaintext
    bashCopyEdit# Use official Python image
    FROM python:3.9
    
    # Set working directory
    WORKDIR /app
    
    # Copy project files
    COPY . .
    
    # Install dependencies
    RUN pip install -r requirements.txt
    
    # Expose port 5000
    EXPOSE 5000
    
    # Run the Flask app
    CMD ["python", "app.py"]
    ```
    
4. Update and install docker using the following the command:
    
    ```plaintext
    Sudo apt-get update && sudo apt-get install docker.io
    ```
    
5. Add the user in docker group
    
    By default, **Docker requires root (sudo) permissions** to run commands because it interacts with the system’s kernel and manages containers. Adding your user to the `docker` group allows you to run Docker commands **without using** `sudo`.
    
    ```plaintext
    sudo usermod -aG docker $USER
    newgrp docker
    ```
    
6. Verify that you can run Docker without sudo:
    
    ```plaintext
    docker ps
    ```
    
7. Build the Docker image:
    
    ```plaintext
    docker build -t hello-docker:latest .
    ```
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1743618970944/073ccd49-1bcd-4f8e-8b04-8fe70f675f35.png align="center")
    
8. Check the image using the following command:
    
    ```plaintext
    docker images
    ```
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1743619048872/375bb7bb-1e16-4080-b79c-69c3df9d0464.png align="center")
    
9. Run a Container in Detached Mode (Background)
    
    ```plaintext
    docker run -dp 5000:5000 hello-docker:latest
    
    #check the container
    docker ps
    ```
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1743619218236/9d678f0f-968f-4d9d-b795-7caef63703df.png align="center")
    
10. To allow incoming traffic to a specific port in an **AWS EC2 Security Group**, follow these steps:
    
    * Open the AWS EC2 Security Groups Page
        
    * Find and Edit Your Security Group
        
    * Add a New Inbound Rule : 5000
        
    * Find your **EC2 Public IP** in the AWS Console
        
    * Open `http://<EC2-PUBLIC-IP>:5000` in your browser
        
        ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1743620253697/2c4e7d39-ee92-45f6-a8a4-e485f1614260.png align="center")
        
11. Check logs using
    
    ```plaintext
    docker logs <container-id>
    ```
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1743621083623/36836cf0-45fd-49cc-8318-b7914e14e9d4.png align="center")
    

### Task 3: Explore Docker Terminologies and Components

1. **Document Key Terminologies:**
    
    * **Image:**
        
        A Docker Image is like a blueprint for your application. It contains everything needed to run a program, including the code, dependencies, and configurations.
        
    * **Container:**
        
        A Docker Container is a running instance of an image. It’s where your application actually runs.
        
    * **Dockerfile:**
        
        A Dockerfile is a set of instructions used to create a Docker Image. It defines what goes inside the image (like which OS, dependencies, and commands to run).
        
    * **Explain the main Docker components (Docker Engine, Docker CLI, Docker Hub, etc.) and how they interact.**
        
    * **Docker Engine (Core of Docker)**
        
        🔹 **What it is:** The software that runs and manages containers.  
        🔹 **How it works:** It takes your Docker images and runs them as containers.
        
    * **Docker CLI (Command Line Interface)**
        
        🔹 **What it is:** A tool that lets you interact with Docker using commands.  
        🔹 **How it works:** You use commands like `docker run` to start containers, `docker build` to create
        
    * **Docker Hub (Public Image Registry)**
        
        🔹 **What it is:** A cloud-based repository where Docker images are stored and shared.  
        🔹 **How it works:** You can pull images (`docker pull nginx`) or push your own images (`docker push my-app`).
        

### Task 4: Optimize Your Docker Image with Multi-Stage Builds

1. **Implement a Multi-Stage Docker Build:**
    
    * Modify your existing `Dockerfile` to include multi-stage builds.
        
    * Aim to produce a lightweight, **distroless** (or minimal) final image.
        
        ```plaintext
        # Start with the official Python base image
        FROM python:3.11-slim as builder
        
        # Set the working directory
        WORKDIR /app
        
        # Copy and install dependencies
        COPY requirements.txt .
        RUN pip install --no-cache-dir --upgrade -r requirements.txt
        
        # Copy the app files
        COPY . .
        
        # Use Google's Distroless base image (only contains runtime essentials)
        FROM gcr.io/distroless/python3
        
        # Set the working directory again
        WORKDIR /app
        
        # Copy the installed dependencies and app from the builder stage
        COPY --from=builder /usr/local /usr/local
        COPY --from=builder /app /app
        
        # Expose port (if needed)
        EXPOSE 5000
        
        # Run the Flask app
        CMD ["app.py"]
        ```
        
    
    Then build the image by using the following command:
    
    ```plaintext
    docker build -t hello-docker:latest .
    #check the image size after multistage 
    docker images
    ```
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1743623952095/ee2e9ec9-a02f-4968-a123-6491a6ac5672.png align="center")
    
    Before Multistage :
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1743623985148/c3a6d7bc-8c68-4eac-8bc1-a92cee1afd8c.png align="center")
    
    ### **Distroless Dockerfile (Minimal, Secure Image)**
    
    A **Distroless Docker Image** is a **lightweight, secure, and minimal** image that contains only the necessary dependencies to run an application—**without** unnecessary OS tools, shells, or package managers.
    
    ---
    
    ### **Why Use Distroless?**
    
    **Smaller Size** → Reduces attack surface and speeds up deployments  
    **More Secure** → No package manager (`apt`, `yum`), no shell (`bash`), fewer vulnerabilities  
    **Faster Startup** → Less overhead, optimized for containerized applications.
    

### Task 5: Manage Your Image with Docker Hub

Create a docker hub account : [https://hub.docker.com/](https://hub.docker.com/) and create a repository called hello-docker

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1743625036139/3d376b9c-88b0-4c13-af92-f7238f70b3ab.png align="center")

**Tag Your Image:**

* Tag your image appropriately:
    
    ```plaintext
    docker tag hello-docker:latest varpriya/hello-docker:latest
    ```
    

1. **Push Your Image to Docker Hub:**
    
    * Log in to Docker Hub if necessary:
        
        ```plaintext
        docker login
        ```
        
        ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1743625274008/67065b1a-d722-4ff9-964c-ced2d2ee0f25.png align="center")
        
        When authenticating to a private Docker registry (like GitHub Container Registry, AWS ECR, or Docker Hub) using docker login, you might need to use a Personal Access Token (PAT) instead of a password.
        
        ### **How to Create a Personal Access Token on Docker Hub** **🔑**
        
        If you have **Two-Factor Authentication (2FA) enabled** on Docker Hub, you **must use a Personal Access Token (PAT)** instead of your password for authentication.
        
        ---
        
        ### **Steps to Create a Docker Hub Access Token**
        
        1\. **Log in to Docker Hub**
        
        * Go to **Docker Hub**
            
        * Sign in with your **Docker credent\*\*\*\*ials**
            
        
        2\. **Go to Security Settings**
        
        * Click on your profile icon (top right corner)
            
        * Select **Accoun\*\*\*\*t Settings**
            
        * Navigate to the **Security** tab
            
        
        3\. **Generate a New Access Token**
        
        * Scroll down to **"Access Tokens"**
            
        * Click **"New Access** **Token"**
            
        * Give it a name (e.g., "Docker CLI Token")
            
        * Click \*\*"\*\***Generate"**
            
        
        4\. **Copy & Save the Token**
        
        * **Copy the generated toke\*\*\*\*n** (You **won**\*\*’t see it again\*\* after leaving the page)
            
        * Save it securely .
            
    * Push the image:
        
        ```plaintext
        docker push varpriya/hello-docker:latest
        ```
        
        ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1743625623296/c0045a55-7cf6-4196-976b-a01e4a6185ec.png align="center")
        
2. **(Optional) Pull the Image:**
    
    * Verify by pulling your image:
        
        ```plaintext
        docker pull varpriya/hello-docker:latest
        ```
        

### Task 6: Persist Data with Docker Volumes

### What is a Docker Volume?

A **volume** is a persistent storage area managed by Docker. Even if the container is deleted, the volume **keeps the data**.

Volumes are **persistent storage mechanisms managed by the Docker daemon**. They retain data even after the containers using them are removed.

1. **Create a Docker Volume:**
    
    * Create a Docker volume:
        
        ```plaintext
        docker volume create my_volume
        #check the volume 
        docker volume ls
        ```
        
        ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1743861855226/a6b7f172-95f7-4659-a841-ac185a3324c8.png align="center")
        
2. **Run a Container with the Volume:**
    
    * Run a container using the volume to persist data:
        
        ```plaintext
        docker run -d -p 5000:5000 -v my_volume:/app/data hello-docker:latest
        ```
        
        ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1743861936087/d1140c16-4be5-4829-8ab8-bb02be9f98f5.png align="center")
        
        Then you can test the volume :
        
        ```plaintext
        docker exec -it <your-container-id> sh
        #create a test file inside the container 
        # echo "hello from container" > /app/data/test.txt
        # ls 
        test.txt
        ```
        
    
    Now you can check the test file in my\_volume
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1743862103337/2b8179ca-9d0e-4bc9-a919-094d8d78133c.png align="center")
    

### Task 7: Configure Docker Networking

Docker creates **virtual networks** so that containers can communicate with each other — either:

* On the **same host**, or
    
* Across **multiple hosts** .
    

Each container is like a mini computer with its own IP address, and Docker helps them talk over isolated or shared networks.

| Type | Use Case |
| --- | --- |
| `bridge` | Default network for standalone containers on the same Docker host |
| `host` | Shares the host’s network namespace (no isolation) |
| `none` | No networking at all |
| `overlay` | For multi-host communication (used in Docker Swarm) |
| `macvlan` | Assigns MAC addresses (advanced use cases) |

## How Communication Works

* Each container gets its own **IP address**.
    
* If they're on the **same custom bridge**, they can **resolve each other by container name**.
    
* Docker handles the internal DNS resolution for you.
    

1. **Create a Custom Docker Network:**
    
    ```plaintext
    docker network create my_network
    #check the network 
    docker network ls
    ```
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1743869227068/45099c5f-a73d-4948-ae96-c9e5466e062e.png align="center")
    

2\. Now you can modify app.py and requirements.txt for mysql database and rebuild the image :

```plaintext
# add for mysql i app.py
from flask import Flask
import mysql.connector

app = Flask(__name__)

@app.route("/")
def home():
    try:
        conn = mysql.connector.connect(
            host="db",  # service name from docker-compose
            user="user",
            password="password",
            database="testdb"
        )
        return "Connected to MySQL!"
    except Exception as e:
        return f"MySQL connection failed: {str(e)}"

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)
```

```plaintext
# add mysql-connector-python in requirements.txt
flask
mysql-connector-python
# rebuild the image 
 docker build . -t hello-docker:latest
```

3. **Run Containers on the Same Network:**
    
    Run two containers (e.g., your sample app and a simple database like MySQL) on the same network to demonstrate inter-container communication:
    
    ```plaintext
    docker run -d -p 5000:5000 --name flask-app --network my_network hello-docker:latest
    docker run -d --name db -v my_sql_data:/var/lib/mysql --network my_network -e MYSQL_ROOT_PASSWORD=rootpass -e MYSQL_DATABASE=te
    stdb -e MYSQL_USER=user -e MYSQL_PASSWORD=password mysql:5.7
    
    #check the containers 
    docker ps 
    ```
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1743869783540/9cad8d0d-7cff-4390-a6bc-f3fc798b0c5a.png align="center")
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1743869670267/f3971648-83a1-4baf-a888-eba544c31d82.png align="center")
    
    Now you can inspect the network :
    
    ```plaintext
    docker network inspect my_network
    ```
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1743869923316/31d239bb-e2e2-4bd4-9eb4-b9a5a42c1daf.png align="center")
    
    Now you can see the both the containers(flask-app and db) are on same network named my\_network
    
4. Once your container is up and running, you should see logs indicating that the Flask app is running on all interfaces:
    
    ```plaintext
     * Running on http://127.0.0.1:5000
     * Running on http://172.18.0.3:5000
    ```
    
    This means the app is now accessible on your **local machine at**:
    
    ```plaintext
    http://localhost:5000
    ```
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1743870089633/a5e8ac37-5138-4097-b1b5-c7bd71216a27.png align="center")
    

You can delete docker container using the following command:

```plaintext
docker kill <Container-ID>
```

You can delete docker network using the following command:

```plaintext
docker network ls
docker network rm <Network-ID>
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1743871306413/980e5de9-62c0-48f0-bdee-9c440922dea7.png align="center")

You can delete docker volume using the following command:

```plaintext
docker volume ls
docker stop $(docker ps -a -q --filter volume=volume-name)
docker rm $(docker ps -a -q --filter volume=volume-name)
docker volume rm <volume name>
```

If you're cleaning house:

```plaintext
docker volume prune
```

Note: This removes **all unused volumes**.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1743871260940/3a04f5f1-75f8-4154-84aa-ec331addc52d.png align="center")

### Task 8: Orchestrate with Docker Compose

1. **Create a docker-compose.yml File:**
    
    * Write a `docker-compose.yml` file that defines at least two services (e.g., your sample app and a database).
        
        ```plaintext
        services:
            web:
              build: .
              ports:
                - "5000:5000"
              depends_on:
                - db
              networks:
                - my_network
        
            db:
              image: mysql:5.7
              environment:
                MYSQL_ROOT_PASSWORD: rootpass
                MYSQL_DATABASE: testdb
                MYSQL_USER: user
                MYSQL_PASSWORD: password
              volumes:
                - my_sql_data:/var/lib/mysql
              networks:
                - my_network
        
        volumes:
          my_sql_data:
        
        networks:
          my_network:
        ```
        

### **Services:**

#### 1\. **web**

* Builds from the local Dockerfile.
    
* Maps container port `5000` to host port `5000`.
    
* Depends on the `db` service to start first.
    
* Connected to the custom network `my_network`.
    

#### 2\. **db** (MySQL)

* Uses the official `mysql:5.7` image.
    
* Configured with:
    
    * `root` password: `rootpass`
        
    * Database name: `testdb`
        
    * User: `user`
        
    * User password: `password`
        
* Persists data using a named volume `my_sql_data`.
    
* Also connected to `my_network`.
    

---

### **Volumes:**

* `my_sql_data`: Stores MySQL data persistently across container restarts.
    

---

### **Networks:**

* `my_network`: A user-defined bridge network allowing services to communicate by name (e.g., `web` can connect to `db` using the hostname `db`).
    
    **Deploy Your Application:**
    
    * Bring up your application using:
        
        ```plaintext
        docker-compose up -d
        ```
        
        ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1743871960571/424ceea5-d31a-4208-bbdd-1a0855b8dfa2.png align="center")
        
        * Test the setup, then shut it down using:
            
            ```plaintext
            #check containers 
            docker ps 
            ```
            
        
        ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1743872210536/37396e7b-c611-4c44-ac83-88d2921f51f3.png align="center")
        
    * Test the setup, then shut it down using:
        
        ```plaintext
        docker-compose down
        ```
        

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1743874534430/2543bc71-0e17-4cee-a8d2-86dfb1e4ca1d.png align="center")

### Task 9: Analyze Your Image with Docker Scout

**Docker Scout** is a tool provided by Docker to help you **analyze your Docker images for vulnerabilities, outdated dependencies, and best practices**.

Here’s how you can use Docker Scout to analyze your image:

## **What Docker Scout Does**

* Scans your Docker image for:
    
    * Known **vulnerabilities (CVEs)**.
        
    * **Outdated packages** or base images.
        
    * **Misconfigurations** (e.g. running as root).
        
* Gives insights on how to **remediate issues** (e.g., upgrading a package or using a newer base image).
    
* Helps ensure images follow **security and compliance standards**.
    

### 1\. Enable Docker Scout CLI (Docker Desktop ≥ v4.17)

Make sure you're using the latest Docker version and logged into Docker Hub.

To check:

```plaintext
 curl -fsSL https://raw.githubusercontent.com/docker/scout-cli/main/install.sh -o install-scout.sh
 sh install-scout.sh
```

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1743875415477/30d866f0-5f7a-4c1f-bbc5-76ba675836c6.png align="center")

1. [**Run Docker Scout Anal**](https://github.com/docker/scout-cli)**ysis:**
    
    * Execute Docker S[cout on your image to genera](https://github.com/docker/scout-cli)te a detailed report of vulnerabilities and insigh[ts:](https://github.com/docker/scout-cli)
        
        ```plaintext
        docker scout cves hello-docker:latest
        ```
        
        [Alternatively, if](https://github.com/docker/scout-cli) available, run:
        
        ```plaintext
        docker scout quickview hello-docker:latest
        ```
        
        to get a summarized view of the image’s security posture.
        
    
    ![](https://cdn.hashnode.com/res/hashnode/image/upload/v1743877228491/4815d53b-fc35-4871-81ba-ddb247dac696.png align="center")
    
    * **Optional:** Save the output to a file for further analysis:
        
        ```plaintext
        docker scout cves hello-docker:latest > scout_report.txt
        ```
        

### **Summary:**

In Week 5 of the challenge, we explore both basic and advanced Docker concepts. You'll start by understanding Docker's importance in modern software development, compare virtualization with containerization, and dive into the Docker build process. As the challenge progresses, you'll work with essential Docker components like images, containers, and volumes, and learn to containerize a sample project. Advanced topics include multi-stage builds, using distroless images for optimization, managing images with Docker Hub, and orchestrating services using Docker Compose. You'll also get a glimpse of Docker Scout to analyze image vulnerabilities and improve your container security.

Thank you for reading :-)
