How to Upload Files from Flask to MinIO on Docker
Hello everyone, this is my first article. In this article, I can share a tutorial about How to Upload Files from Flask to MinIO on Docker — What is MinIO, it’s an Object Storage for storing unstructured data for example images, videos, more extensive data, etc.
Dockerizing MinIO
First, Create a folder and navigate into it.
mkdir flask-minio && cd flask-minio
Create a docker-compose.yml and include this code.
version: "3.8"
services:
minio:
image: quay.io/minio/minio:RELEASE.2023-02-22T18-23-45Z
command: server --console-address ":9090"
ports:
- 9000:9000
- 9090:9090
env_file:
- .env
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 30s
timeout: 20s
retries: 3
hostname: minio
volumes:
- minio-data:/mnt/data
volumes:
minio-data:
Create an .env file and include these variables:
SECRET_KEY=secret-key
MINIO_ROOT_USER=minioadmin
MINIO_ROOT_PASSWORD=minioadmin
MINIO_VOLUMES="/mnt/data"
MINIO_SERVER_PORT=9000
MINIO_HOST=minio
MINIO_BUCKET=flask-minio
MINIO_ENDPOINT=${MINIO_HOST}:${MINIO_SERVER_PORT}
To execute docker-compose.yml, execute this code.
docker-compose up -d
The MinIO server starts running in localhost:9090
To remove the container, execute this code.
docker-compose down
Dockerizing Flask with MinIO
First, create virtual environments and use it
python -m venv .venv && source .venv/bin/activate
Install the requirements package using pip.
pip install flask minio
Generate requirements.txt from pip freeze.
pip install -r requirements.txt
Create an app.py for the basic application flask, and include this function.
from flask import Flask, request, redirect
from werkzeug.utils import secure_filename
from minio import Minio
import os
ALLOWED_EXTENSIONS = {"txt", "pdf", "png", "jpg", "jpeg", "gif"}
ACCESS_KEY = os.environ.get("MINIO_ROOT_USER")
SECRET_KEY = os.environ.get("MINIO_ROOT_PASSWORD")
BUCKET_NAME = os.environ.get("MINIO_BUCKET")
MINIO_API_HOST = os.environ.get("MINIO_ENDPOINT")
def upload_object(filename, data, length):
client = Minio(MINIO_API_HOST, ACCESS_KEY, SECRET_KEY, secure=False)
# Make bucket if not exist.
found = client.bucket_exists(BUCKET_NAME)
if not found:
client.make_bucket(BUCKET_NAME)
else:
print(f"Bucket {BUCKET_NAME} already exists")
client.put_object(BUCKET_NAME, filename, data, length)
print(f"{filename} is successfully uploaded to bucket {BUCKET_NAME}.")
def allowed_file(filename):
return "." in filename and filename.rsplit(".", 1)[1].lower() in ALLOWED_EXTENSIONS
app = Flask(__name__)
app.config["SECRET_KEY"] = os.environ.get("SECRET_KEY")
@app.route("/", methods=["GET", "POST"])
def upload_file():
if request.method == "POST":
# check if the post request has the file part
if "file" not in request.files:
return redirect(request.url)
file = request.files["file"]
# If the user does not select a file, the browser submits an
# empty file without a filename.
if file.filename == "":
return redirect(request.url)
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
size = os.fstat(file.fileno()).st_size
upload_object(filename, file, size)
return redirect(request.url)
return """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>UPLOAD</title>
</head>
<body>
<h1>Upload File</h1>
<form method=post enctype=multipart/form-data>
<input type=file name=file>
<input type=submit value=Upload>
</form>
</body>
</html>
"""
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000)
Create a Dockerfile for the flask image and include this code.
FROM python:3.10
WORKDIR /usr/src/app
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 5000
Update docker-compose.yml, and add flask service.
version: "3.8"
services:
minio:
image: quay.io/minio/minio:RELEASE.2023-02-22T18-23-45Z
command: server --console-address ":9090"
ports:
- 9000:9000
- 9090:9090
env_file:
- .env
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 30s
timeout: 20s
retries: 3
hostname: minio
volumes:
- minio-data:/mnt/data
web:
build:
context: .
dockerfile: Dockerfile
command: ["python", "app.py"]
env_file:
- .env
ports:
- 5000:5000
restart: always
hostname: web
depends_on:
- minio
volumes:
minio-data:
For running docker compose, execute this code.
docker-compose up -d
The MinIO server starts running in localhost:9090, and Flask runs in localhost:5000. To test this program work you can visit localhost:5000 and upload a file to MinIO Server. Then, log in to the MinIO server and check on Object Browser.
Conclusion
By using object storage you will get many benefits, namely cost savings, large capacity, and high scalability.