How to Upload Files from Flask to MinIO on Docker

I Putu Julianta
Data Engineering Indonesia
3 min readSep 23, 2023
Photo by Ruchindra Gunasekara on Unsplash

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.

Flask Service
MinIO Server

Conclusion

By using object storage you will get many benefits, namely cost savings, large capacity, and high scalability.

--

--