Skip to main content

Running and Managing Docker Containers

1. Docker Commands for Running, Stopping, and Restarting Containers

Containers are like mini-computers running inside your computer. You can start, stop, or restart them using a few simple commands.

  • Running a Container
    The basic command to run a container is:

    docker run <options> <image>

    Example: Running a simple web server (nginx) container:

    docker run -d --name mynginx -p 8080:80 nginx
    • -d: Runs the container in the background (detached mode).
    • --name: Gives the container a friendly name.
    • -p 8080:80: Maps port 80 inside the container to port 8080 on your machine.
    • nginx: The name of the image we’re running.
  • Stopping a Container
    To stop a running container:

    docker stop <container_name_or_id>

    Example:

    docker stop mynginx
  • Restarting a Container
    To restart a stopped container:

    docker restart <container_name_or_id>

    Example:

    docker restart mynginx
  • Checking Running Containers
    To see which containers are running:

    docker ps

    This will show all currently running containers. To see all running and currently stopped containers:

    docker ps -a

2. Container Networking

Containers need to communicate with each other, just like different programs on your computer. Docker gives each container its own network.

  • Bridge Network (Default)
    When you run a container, Docker connects it to a default network called the "bridge" network. Containers on the same network can talk to each other. Example:

    docker network ls

    This shows all networks, and you’ll see one named bridge.

  • Creating Your Own Network
    Sometimes, you might want to put containers on a custom network. For example, if you have a web server and a database, and they need to talk to each other. You can create a network like this:

    docker network create mynetwork

    Then, run containers on that network:

    docker run -d --name webserver --network mynetwork nginx
    docker run -d --name mydb --network mynetwork mysql

Now both webserver and mydb are on the mynetwork and can communicate.


Example: Flask Application Communicating with MySQL Using Dockerfile and Docker Compose

We’ll create:

  1. A Flask application with its own Dockerfile.
  2. A MySQL database container.
  3. A Docker Compose configuration to manage both containers.

1. Flask Application with Dockerfile

  1. Create a Flask Application:

    Create a file named app.py with the following Flask code:

    from flask import Flask
    import mysql.connector

    app = Flask(__name__)

    @app.route('/')
    def index():
    conn = mysql.connector.connect(
    host='mysql-db',
    user='root',
    password='my-secret-pw',
    database='mydatabase'
    )
    cursor = conn.cursor()
    cursor.execute("SELECT DATABASE()")
    db = cursor.fetchone()
    cursor.close()
    conn.close()
    return f'Connected to MySQL database: {db[0]}'

    if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)
  2. Create a Dockerfile for the Flask Application:

    Create a file named Dockerfile in the same directory as app.py:

    # Use the official Python image from the Docker Hub
    FROM python:3.9-slim

    # Set the working directory in the container
    WORKDIR /usr/src/app

    # Copy the current directory contents into the container at /usr/src/app
    COPY . .

    # Install any needed packages specified in requirements.txt
    RUN pip install --no-cache-dir flask mysql-connector-python

    # Make port 5000 available to the world outside this container
    EXPOSE 5000

    # Define environment variable
    ENV FLASK_APP=app.py

    # Run app.py when the container launches
    CMD ["flask", "run", "--host=0.0.0.0"]

    This Dockerfile:

    • Uses a lightweight Python image.
    • Copies your Flask application code into the container.
    • Installs Flask and MySQL connector.
    • Exposes port 5000.
    • Runs the Flask application.

2. Docker Compose Setup

  1. Create a docker-compose.yml File:

    Create a file named docker-compose.yml in the same directory:

    version: '3'
    services:
    mysql-db:
    image: mysql
    container_name: mysql-db
    environment:
    MYSQL_ROOT_PASSWORD: my-secret-pw
    MYSQL_DATABASE: mydatabase
    networks:
    - mynetwork

    flask-app:
    build: .
    container_name: flask-app
    depends_on:
    - mysql-db
    networks:
    - mynetwork
    ports:
    - "5000:5000"

    networks:
    mynetwork:

    In this setup:

    • mysql-db: Uses the official MySQL image.
    • flask-app: Builds the Flask application from the Dockerfile.
    • Both services are connected to a custom network (mynetwork).

3. Build and Run the Containers

  1. Build and Start the Containers:

    Run the following command to build and start the containers defined in docker-compose.yml:

    docker compose up --build

    This command:

    • Builds the Docker image for the Flask app.
    • Starts both the Flask and MySQL containers.
    • Creates the mynetwork network and connects the containers to it.
Running the docker compose
  1. Access the Flask Application:

    Open your browser and go to http://localhost:5000. You should see a message indicating that the Flask application is connected to the MySQL database.

Note : This docker container will be stopped when the terminal is stopped because we are not running it in detached mode. To run in detached mode, use docker compose up -d.


3. Docker Volumes: Persistent Data Storage

I’ll cover:

  1. Understanding Docker Volumes
  2. Directory Mounts vs. Named Volumes
  3. Using Docker Volumes with Docker Compose
  4. Practical Example: MySQL Data Persistence

Understanding Docker Volumes

Docker volumes are used to store data that needs to persist beyond the lifecycle of a container. They are managed by Docker and can be shared between containers. Volumes provide several benefits:

  • Data Persistence: Data in volumes persists even if the container is removed.
  • Container Independence: Volumes can be used by multiple containers simultaneously.
  • Ease of Backup and Migration: Volumes can be easily backed up and migrated.

Types of Docker Volumes

  1. Named Volumes: Created and managed by Docker. They are stored in Docker's default storage directory and can be referenced by name.
  2. Bind Mounts (Directory Mounts): Bind a specific directory on the host machine to a directory in the container. Useful for development as changes on the host are reflected inside the container.

Directory Mounts vs. Named Volumes

Directory Mounts:

  • Usage: Directly mount a directory from the host machine into the container.
  • Syntax:
    volumes:
    - /host/path:/container/path
  • No Explicit Volume Creation Needed: Docker does not manage the lifecycle of bind mounts. You don’t need to create these mounts explicitly; just specify them in your Docker Compose file or docker run command.

Named Volumes:

  • Usage: Created and managed by Docker, stored in Docker’s storage directory.
  • Syntax:
    volumes:
    - volume_name:/container/path
  • Creation: Docker automatically creates named volumes if they don’t exist. You don’t need to create them manually.

Key Differences:

  • Directory Mounts: Directly map host directories, useful for development and debugging.
  • Named Volumes: Managed by Docker, ideal for persistent data and production environments.

Using Docker Volumes with Docker Compose

In Docker Compose, you can define volumes in the docker-compose.yml file. Docker Compose handles the creation and management of volumes.

Example with Docker Compose:

Let’s set up a MySQL database with persistent storage using Docker Compose.

  1. Create a docker-compose.yml File:

    version: '3'
    services:
    mysql-db:
    image: mysql
    container_name: mysql-db
    environment:
    MYSQL_ROOT_PASSWORD: my-secret-pw
    MYSQL_DATABASE: mydatabase
    volumes:
    - mysql-data:/var/lib/mysql
    networks:
    - mynetwork

    volumes:
    mysql-data:

    networks:
    mynetwork:
    • Named Volume (mysql-data):
      • Defined under volumes in the docker-compose.yml file.
      • Docker Compose creates this volume automatically if it doesn’t exist.
      • The data stored in /var/lib/mysql inside the container is persisted in the mysql-data volume.
  2. Build and Run the Containers:

    Use Docker Compose to start the services and manage the volume:

    docker-compose up -d
  3. Verify the Volume:

    After starting the containers, you can list volumes and inspect them:

    docker volume ls
    docker volume inspect docker-volumes_mysql-data

This command shows information about the mysql-data volume, including its mount point on the host.

Note: If the name you specified for your volume in docker-compose is mysql-data, then the actual name of the volume created by docker will be docker-volumes_mysql-data.

Example with Directory Mount:

Here’s an example of using a bind mount (directory mount) instead of a named volume:

  1. Create a docker-compose.yml File:

    version: '3'
    services:
    mysql-db:
    image: mysql
    container_name: mysql-db
    environment:
    MYSQL_ROOT_PASSWORD: my-secret-pw
    MYSQL_DATABASE: mydatabase
    volumes:
    - ./data:/var/lib/mysql
    networks:
    - mynetwork

    networks:
    mynetwork:
    • Bind Mount (./data):
      • Maps a specific directory on the host to the container directory.
      • Any data stored in /var/lib/mysql inside the container is directly mapped to data directory on the host.

In this case, docker will create folder named data on the directory where the docker-compose.yml is present and mounts it to the /var/lib/mysql directory inside the docker container.

In this example, if you don't use a volume or directory mount with this mysql container, all the data in your database will be erased everytime the container is deleted since containers don't have permanent storage. Here the location /var/lib/mysql inside the container is where mysql stores it's data hence we mount a volume to that location.


Summary

  1. Running and Managing Docker Containers:

    • Commands: Use docker run to start containers, docker stop and docker restart to manage their state, and docker rm to remove them.
    • Networking: Containers can communicate over custom networks created with docker network create. Use container names for communication within the same network.
  2. Docker Volumes:

    • Named Volumes: Managed by Docker, providing persistent storage that automatically persists data even if containers are removed. Defined in Docker Compose under the volumes key.
    • Directory Mounts (Bind Mounts): Map specific directories from the host to the container. Useful for development as changes on the host are reflected inside the container. Not managed by Docker; specified directly in the Docker Compose file.
  3. Using Docker Volumes with Docker Compose:

    • Named Volume Example: Docker Compose can automatically create and manage volumes for persistent data. Example configuration:
      volumes:
      mydata:
    • Bind Mount Example: Mounts a directory from the host to the container. Example configuration:
      volumes:
      - /host/path:/container/path
  4. Network Communication Example:

    • Containers on the Same Network: Containers can communicate using their service names when they are on the same Docker network, as defined in Docker Compose or manually created networks.