Dockerizing Your Web Application on Debian and Sharing via Docker Hub

In modern software development, deploying applications consistently across different environments (development, testing, production) is crucial. Differences in operating systems, system libraries, or installed package versions can lead to the infamous “it works on my machine” problem. Docker solves this by allowing you to package your application, along with all its dependencies and required system configurations, into a standardized unit called a container image. This image can then be run reliably anywhere Docker is installed. Docker Hub acts as a central registry, like GitHub for code, allowing you to store, share, and retrieve these container images.

Why Dockerize Your Application?

  1. Consistency: Docker containers encapsulate your application and its entire runtime environment (OS libraries, Python version, specific package versions). Running the container guarantees the application executes in the exact same environment, regardless of the underlying host OS (as long as it can run Docker). This eliminates inconsistencies between development, staging, and production.
  2. Dependency Management: Forget complex setup scripts or dependency conflicts on the host machine. All dependencies (Python packages via requirements.txt, system libraries via apt-get) are installed within the image during the build process.
  3. Isolation: Containers run in isolation from the host system and other containers. This improves security and prevents applications from interfering with each other.
  4. Portability: A Docker image built on your Debian machine can be run on another Linux machine, a Windows machine (with Docker Desktop), a Mac (with Docker Desktop), or in cloud environments (like Google Cloud Run, AWS ECS, Azure Container Instances) without modification.
  5. Scalability: Container orchestration platforms (like Kubernetes or Docker Swarm) make it easy to scale your application by running multiple identical container instances based on your image.
  6. Simplified Deployment: Deploying becomes as simple as pulling the correct image version and running it. Updates involve building a new image version, pushing it, and deploying the new container.

How to Dockerize a Python Flask Application on Debian

Let’s assume you have a Flask application structure like this on your Debian machine:

/home/your_user/my_flask_app/
├── app.py             # Your Flask application code
├── requirements.txt   # Python dependencies (Flask, Gunicorn, NumPy, etc.)
├── templates/         # HTML templates
│   └── index.html
│   └── ...
└── static/            # Static files (CSS, JS, images)
    └── css/
    └── js/

Step 1: Install Docker on Debian

If you haven’t already, install Docker Engine. The official Docker documentation provides the most up-to-date method, but it generally involves:

# Update package list
sudo apt-get update

# Install prerequisite packages
sudo apt-get install -y ca-certificates curl gnupg

# Add Docker's official GPG key
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg

# Set up the Docker repository
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian \
  $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# Update package list again with Docker repo
sudo apt-get update

# Install Docker Engine, CLI, Containerd, and Buildx plugin
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

# Verify installation
sudo docker run hello-world

# Add your user to the docker group (to avoid using sudo constantly)
sudo usermod -aG docker $USER
# IMPORTANT: Log out and log back in for this group change to take effect!

Step 2: Prepare requirements.txt

Ensure your requirements.txt lists all Python dependencies, including a production WSGI server like Gunicorn:

Flask>=2.0
gunicorn>=20.0
numpy>=1.20
scipy>=1.6
matplotlib>=3.4
.......
# Add any other specific dependencies your app uses

Step 3: Create the Dockerfile

In your project’s root directory (/home/your_user/my_flask_app/), create a file named Dockerfile with the following content:

# 1. Base Image: Start from an official Python image based on Debian
FROM python:3.11-slim-bookworm

# 2. Environment Variables: Set recommended variables
ENV PYTHONDONTWRITEBYTECODE 1  # Prevent .pyc file creation
ENV PYTHONUNBUFFERED 1      # Ensure logs appear immediately
ENV VIRTUAL_ENV=/app/.venv  # Define path for virtual environment
ENV PATH="$VIRTUAL_ENV/bin:$PATH" # Add venv bin directory to the system PATH

# 3. Working Directory: Set the context for subsequent commands
WORKDIR /app

# 4. System Dependencies: Install needed Debian packages
#    (Only include if your Python packages require them, e.g., for C extensions)
RUN apt-get update && \
    apt-get install -y --no-install-recommends gcc libgomp1 && \
    # Clean up apt cache to reduce image size
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

# 5. Create Virtual Environment: Isolate Python dependencies
RUN python3 -m venv $VIRTUAL_ENV

# 6. Install Python Dependencies:
#    Copy requirements first to leverage Docker build cache
COPY requirements.txt .
#    Install packages into the virtual environment (pip finds the venv pip via PATH)
RUN pip install --no-cache-dir -r requirements.txt

# 7. Copy Application Code: Copy your Flask app into the image
COPY . .

# 8. Create Runtime Directories: Make directories needed by app (if any)
RUN mkdir -p /app/uploads /app/F_field

# 9. Expose Port: Inform Docker which port the application listens on
EXPOSE 5000 # Change if your Gunicorn binds to a different port

# 10. Default Command (CMD): Specify how to run the application
#     Uses Gunicorn from the virtual environment to serve the Flask app
#     'app:app' means: in file 'app.py', find the Flask instance named 'app'
CMD ["gunicorn", "--workers", "4", "--bind", "0.0.0.0:5000", "app:app"]

Step 4: Create .dockerignore File

In the same directory, create .dockerignore to exclude files/folders from the build context, keeping the image lean:

# (Content from previous answers, including venv, pycache, .git, etc.)
.venv/
venv/
__pycache__/
*.pyc
.git/
.gitignore
Dockerfile
.dockerignore
uploads/
F_field/
# Add any other files/dirs you don't want in the image

Step 5: Build the Docker Image

  1. Navigate to your project directory in the terminal.
  2. Run the build command: bash docker build -t my-flask-app:latest . * -t my-flask-app:latest: Tags the image as my-flask-app with the latest tag. Choose a meaningful name.
    • .: Specifies the current directory as the build context.
  3. Monitor the build output for errors. A successful build ends with “Successfully built…” and “Successfully tagged…”.

Step 6: Test the Image Locally (Optional but Recommended)

  1. Run a container from your new image:
    bash docker run -d -p 5001:5000 --name test-app my-flask-app:latest
    (Maps host port 5001 to container port 5000)
  2. Access http://localhost:5001 in your browser to ensure the app runs correctly inside the container.
  3. Stop and remove the test container:
    bash docker stop test-app docker rm test-app

Sharing Your Image on Docker Hub

Step 1: Log in to Docker Hub

docker login

Enter your Docker Hub username and password (or access token).

Step 2: Tag the Image for Docker Hub

You need to tag your image with your username and a repository name.

# Format: docker tag <local_image>:<tag> <username>/<repo_name>:<tag>
docker tag my-flask-app:latest your_dockerhub_username/my-flask-app:1.0
  • Replace your_dockerhub_username with your actual username.
  • Replace my-flask-app with your desired repository name on Docker Hub.
  • Replace 1.0 with a specific version tag (recommended over just latest).

Step 3: Push the Image

# Format: docker push <username>/<repo_name>:<tag>
docker push your_dockerhub_username/my-flask-app:1.0

Docker will upload the image layers.

Step 4: Verify & Clean

Check your Docker Hub account online. You should see the new repository and the pushed tag.

  1. Periodically remove stopped containers you no longer need: docker container prune
  2. Periodically remove dangling images: docker image prune
  3. If you are sure you don’t need certain named volumes, remove them explicitly: docker volume rm <volume_name>

Conclusion

Dockerizing your application on Debian provides immense benefits in consistency, portability, and deployment simplicity. By creating a Dockerfile that defines the environment and dependencies, building an image, and pushing it to Docker Hub, you create a self-contained, shareable unit that can run reliably almost anywhere. This process streamlines the development lifecycle and makes deploying web applications significantly more robust.

Leave a Comment