Flask ist ein leichtgewichtiges Python-Webframework. Es eignet sich ideal für APIs, kleine Webapps und Microservices. Für den Produktionsbetrieb wird Gunicorn als WSGI-Server empfohlen.
Flask vs Django
| Aspekt | Flask | Django | |--------|-------|--------| | Philosophie | Minimal, flexibel | Batteries included | | Lernkurve | Flach | Steiler | | ORM | Optional (SQLAlchemy) | Integriert | | Admin | Nicht integriert | Integriert | | Anwendung | APIs, Microservices | Vollständige Webapps |
Projekt-Setup
Verzeichnis erstellen
mkdir -p /var/www/flaskapp
cd /var/www/flaskappVirtual Environment
python3 -m venv venv
source venv/bin/activateDependencies installieren
pip install flask gunicorn python-dotenvEinfache Flask-App
# /var/www/flaskapp/app.py
from flask import Flask, jsonify
app = Flask(__name__)
@app.route('/')
def index():
return jsonify({'message': 'Hello from Flask!'})
@app.route('/health')
def health():
return jsonify({'status': 'healthy'})
if __name__ == '__main__':
app.run()Application Factory
# /var/www/flaskapp/app/__init__.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
import os
db = SQLAlchemy()
def create_app():
app = Flask(__name__)
# Konfiguration
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY', 'dev')
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get(
'DATABASE_URL', 'sqlite:///app.db'
)
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# Extensions initialisieren
db.init_app(app)
# Blueprints registrieren
from app.routes import main
app.register_blueprint(main)
return app# /var/www/flaskapp/app/routes.py
from flask import Blueprint, jsonify
main = Blueprint('main', __name__)
@main.route('/')
def index():
return jsonify({'message': 'Hello from Flask!'})
@main.route('/api/users')
def get_users():
return jsonify({'users': []})# /var/www/flaskapp/wsgi.py
from app import create_app
application = create_app()
if __name__ == '__main__':
application.run()requirements.txt
flask==3.0.0
gunicorn==21.2.0
python-dotenv==1.0.0
flask-sqlalchemy==3.1.1
psycopg2-binary==2.9.9Gunicorn-Konfiguration
gunicorn.conf.py
# /var/www/flaskapp/gunicorn.conf.py
import multiprocessing
# Socket
bind = "unix:/run/gunicorn/flaskapp.sock"
# Worker
workers = multiprocessing.cpu_count() * 2 + 1
worker_class = "sync"
threads = 2
worker_connections = 1000
# Timeout
timeout = 30
keepalive = 2
# User
user = "www-data"
group = "www-data"
# Logging
errorlog = "/var/log/gunicorn/flaskapp-error.log"
accesslog = "/var/log/gunicorn/flaskapp-access.log"
loglevel = "info"
# Process
proc_name = "flaskapp"
daemon = FalseSystemd-Service
# /etc/systemd/system/flaskapp.service
[Unit]
Description=Gunicorn daemon for Flask app
After=network.target
[Service]
User=www-data
Group=www-data
WorkingDirectory=/var/www/flaskapp
RuntimeDirectory=gunicorn
EnvironmentFile=/var/www/flaskapp/.env
ExecStart=/var/www/flaskapp/venv/bin/gunicorn \
--config /var/www/flaskapp/gunicorn.conf.py \
wsgi:application
ExecReload=/bin/kill -s HUP $MAINPID
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.targetService starten
mkdir -p /var/log/gunicorn
chown www-data:www-data /var/log/gunicorn
systemctl daemon-reload
systemctl enable flaskapp
systemctl start flaskappNginx-Konfiguration
# /etc/nginx/sites-available/flaskapp
upstream flaskapp {
server unix:/run/gunicorn/flaskapp.sock fail_timeout=0;
}
server {
listen 80;
server_name api.example.de;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name api.example.de;
ssl_certificate /etc/letsencrypt/live/api.example.de/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/api.example.de/privkey.pem;
client_max_body_size 5M;
access_log /var/log/nginx/flaskapp-access.log;
error_log /var/log/nginx/flaskapp-error.log;
location /static/ {
alias /var/www/flaskapp/static/;
expires 30d;
}
location / {
proxy_pass http://flaskapp;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect off;
}
}ln -s /etc/nginx/sites-available/flaskapp /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginxUmgebungsvariablen
.env-Datei
# /var/www/flaskapp/.env
FLASK_APP=wsgi.py
FLASK_ENV=production
SECRET_KEY=dein_sehr_langes_secret_key
DATABASE_URL=postgresql://user:pass@localhost/flaskappLaden in Flask
# /var/www/flaskapp/wsgi.py
from dotenv import load_dotenv
load_dotenv()
from app import create_app
application = create_app()Datenbank
PostgreSQL einrichten
sudo -u postgres psql
CREATE DATABASE flaskapp;
CREATE USER flaskapp WITH PASSWORD 'sicheres_passwort';
GRANT ALL PRIVILEGES ON DATABASE flaskapp TO flaskapp;
\qFlask-Migrate
pip install flask-migrate# app/__init__.py
from flask_migrate import Migrate
migrate = Migrate()
def create_app():
app = Flask(__name__)
# ...
db.init_app(app)
migrate.init_app(app, db)
# ...# Migrationen
flask db init
flask db migrate -m "Initial migration"
flask db upgradeREST-API mit Flask-RESTful
pip install flask-restful# app/api.py
from flask import Blueprint
from flask_restful import Api, Resource, reqparse
api_bp = Blueprint('api', __name__, url_prefix='/api')
api = Api(api_bp)
class UserResource(Resource):
def get(self, user_id):
user = User.query.get_or_404(user_id)
return {'id': user.id, 'name': user.name}
def put(self, user_id):
parser = reqparse.RequestParser()
parser.add_argument('name', required=True)
args = parser.parse_args()
user = User.query.get_or_404(user_id)
user.name = args['name']
db.session.commit()
return {'id': user.id, 'name': user.name}
def delete(self, user_id):
user = User.query.get_or_404(user_id)
db.session.delete(user)
db.session.commit()
return '', 204
class UserListResource(Resource):
def get(self):
users = User.query.all()
return [{'id': u.id, 'name': u.name} for u in users]
def post(self):
parser = reqparse.RequestParser()
parser.add_argument('name', required=True)
args = parser.parse_args()
user = User(name=args['name'])
db.session.add(user)
db.session.commit()
return {'id': user.id, 'name': user.name}, 201
api.add_resource(UserListResource, '/users')
api.add_resource(UserResource, '/users/<int:user_id>')Async mit Gevent
pip install gevent# gunicorn.conf.py
worker_class = "gevent"
worker_connections = 1000Background Tasks mit Celery
pip install celery redis# app/celery.py
from celery import Celery
def make_celery(app):
celery = Celery(
app.import_name,
backend=app.config['CELERY_RESULT_BACKEND'],
broker=app.config['CELERY_BROKER_URL']
)
celery.conf.update(app.config)
class ContextTask(celery.Task):
def __call__(self, *args, **kwargs):
with app.app_context():
return self.run(*args, **kwargs)
celery.Task = ContextTask
return celery# app/__init__.py
from app.celery import make_celery
celery = None
def create_app():
global celery
app = Flask(__name__)
app.config['CELERY_BROKER_URL'] = 'redis://localhost:6379/0'
app.config['CELERY_RESULT_BACKEND'] = 'redis://localhost:6379/0'
# ...
celery = make_celery(app)
return app# app/tasks.py
from app import celery
@celery.task
def send_email(to, subject, body):
# Email senden
passLogging
# app/__init__.py
import logging
from logging.handlers import RotatingFileHandler
def create_app():
app = Flask(__name__)
# ...
if not app.debug:
file_handler = RotatingFileHandler(
'/var/log/flask/flaskapp.log',
maxBytes=10240000,
backupCount=10
)
file_handler.setFormatter(logging.Formatter(
'%(asctime)s %(levelname)s: %(message)s'
))
file_handler.setLevel(logging.INFO)
app.logger.addHandler(file_handler)
app.logger.setLevel(logging.INFO)
app.logger.info('Flask app startup')
return appDeployment-Skript
#!/bin/bash
# /var/www/flaskapp/deploy.sh
set -e
cd /var/www/flaskapp
git pull origin main
source venv/bin/activate
pip install -r requirements.txt
flask db upgrade
sudo systemctl restart flaskapp
echo "Deployment erfolgreich"Zusammenfassung
| Komponente | Funktion | |------------|----------| | Flask | Webframework | | Gunicorn | WSGI-Server | | Nginx | Reverse Proxy | | SQLAlchemy | ORM | | Celery | Background Tasks |
| Datei | Funktion | |-------|----------| | wsgi.py | WSGI-Einstiegspunkt | | gunicorn.conf.py | Gunicorn-Config | | .env | Umgebungsvariablen |
| Befehl | Funktion | |--------|----------| | flask db migrate | Migration erstellen | | flask db upgrade | Migration ausführen | | flask run | Development Server |
Fazit
Flask ist ideal für APIs und kleinere Webanwendungen. Die minimale Grundstruktur ermöglicht maximale Flexibilität. Mit Gunicorn und Nginx ist Flask produktionsbereit. SQLAlchemy bietet ein mächtiges ORM. Die Application Factory Pattern ermöglicht saubere Projektstruktur. Für komplexe Anwendungen mit Admin-Interface ist Django oft besser geeignet.