Home » Как создать первое веб-приложение с Flask и Python 3
Как создать первое веб-приложение с Flask и Python 3

Как создать первое веб-приложение с Flask и Python 3

Сегодня поговорим о том, как создать своё первое веб-приложение с Flask и Python 3. Если ты системный администратор или девопс-инженер, который привык работать с серверами, но никогда не пробовал создавать веб-приложения, то эта статья именно для тебя. Flask — это микрофреймворк для Python, который позволяет быстро создавать веб-приложения без лишних сложностей. Он отлично подходит для создания API, дашбордов для мониторинга, инструментов автоматизации и различных админских панелей.

Зачем это нужно? Представь, что тебе нужно создать простой веб-интерфейс для мониторинга серверов, или API для автоматизации задач, или даже простую админскую панель. Flask справится с этими задачами гораздо быстрее и проще, чем более тяжёлые решения типа Django. К тому же, понимание основ веб-разработки сделает тебя более универсальным специалистом.

Как это работает: архитектура Flask

Flask построен на концепции WSGI (Web Server Gateway Interface) — стандарта взаимодействия между веб-серверами и Python-приложениями. Когда пользователь отправляет HTTP-запрос, веб-сервер передаёт его Flask-приложению через WSGI, приложение обрабатывает запрос и возвращает HTTP-ответ.

Основные компоненты Flask:

  • Роутинг — определяет, какая функция будет обрабатывать конкретный URL
  • Шаблоны — используется движок Jinja2 для генерации HTML
  • Контекст запроса — объекты request и response доступны в любой функции
  • Расширения — модульная архитектура для добавления функционала

Быстрый старт: пошаговая настройка

Для начала тебе понадобится VPS-сервер с установленным Python 3. Если планируешь серьёзные нагрузки, то лучше сразу взять выделенный сервер.

Шаг 1: Установка Python и виртуального окружения

# Обновляем систему (Ubuntu/Debian)
sudo apt update && sudo apt upgrade -y

# Устанавливаем Python 3 и pip
sudo apt install python3 python3-pip python3-venv -y

# Создаём директорию для проекта
mkdir ~/flask_app && cd ~/flask_app

# Создаём виртуальное окружение
python3 -m venv venv

# Активируем виртуальное окружение
source venv/bin/activate

# Устанавливаем Flask
pip install Flask

Шаг 2: Создание первого приложения

Создай файл app.py:

from flask import Flask, render_template, request, jsonify
import os
import subprocess

app = Flask(__name__)

@app.route('/')
def index():
    return '''
    <h1>Админская панель</h1>
    <p>Добро пожаловать в систему мониторинга сервера!</p>
    <ul>
        <li><a href="/system">Информация о системе</a></li>
        <li><a href="/processes">Процессы</a></li>
        <li><a href="/api/status">API статус</a></li>
    </ul>
    '''

@app.route('/system')
def system_info():
    # Получаем информацию о системе
    uptime = subprocess.check_output(['uptime']).decode('utf-8')
    df = subprocess.check_output(['df', '-h']).decode('utf-8')
    
    return f'''
    <h2>Информация о системе</h2>
    <h3>Uptime:</h3>
    <pre>{uptime}</pre>
    <h3>Дисковое пространство:</h3>
    <pre>{df}</pre>
    <a href="/">Назад</a>
    '''

@app.route('/processes')
def processes():
    # Получаем список процессов
    ps = subprocess.check_output(['ps', 'aux']).decode('utf-8')
    
    return f'''
    <h2>Процессы</h2>
    <pre>{ps}</pre>
    <a href="/">Назад</a>
    '''

@app.route('/api/status')
def api_status():
    # API эндпоинт для получения статуса в JSON
    try:
        load_avg = os.getloadavg()
        status = {
            'status': 'ok',
            'load_average': {
                '1min': load_avg[0],
                '5min': load_avg[1],
                '15min': load_avg[2]
            },
            'memory': get_memory_info(),
            'disk': get_disk_info()
        }
        return jsonify(status)
    except Exception as e:
        return jsonify({'status': 'error', 'message': str(e)}), 500

def get_memory_info():
    # Простая функция для получения информации о памяти
    with open('/proc/meminfo', 'r') as f:
        lines = f.readlines()
    
    memory_info = {}
    for line in lines[:3]:  # Берём только первые 3 строки
        key, value = line.split(':')
        memory_info[key] = value.strip()
    
    return memory_info

def get_disk_info():
    # Информация о дисковом пространстве
    statvfs = os.statvfs('/')
    free_bytes = statvfs.f_frsize * statvfs.f_bavail
    total_bytes = statvfs.f_frsize * statvfs.f_blocks
    used_bytes = total_bytes - free_bytes
    
    return {
        'total_gb': round(total_bytes / (1024**3), 2),
        'used_gb': round(used_bytes / (1024**3), 2),
        'free_gb': round(free_bytes / (1024**3), 2),
        'usage_percent': round((used_bytes / total_bytes) * 100, 2)
    }

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=5000)

Шаг 3: Запуск приложения

# Запускаем приложение
python3 app.py

Теперь твоё приложение доступно по адресу http://your-server-ip:5000. Но для продакшена такой способ запуска не подойдёт.

Продакшен-настройка: Gunicorn + Nginx

Установка Gunicorn

# Устанавливаем Gunicorn
pip install gunicorn

# Создаём файл конфигурации
cat > gunicorn_config.py << 'EOF'
bind = "127.0.0.1:5000"
workers = 4
worker_class = "sync"
worker_connections = 1000
max_requests = 1000
max_requests_jitter = 100
timeout = 30
keepalive = 2
user = "www-data"
group = "www-data"
tmp_upload_dir = None
errorlog = "/var/log/gunicorn/error.log"
accesslog = "/var/log/gunicorn/access.log"
loglevel = "info"
EOF

# Создаём директорию для логов
sudo mkdir -p /var/log/gunicorn
sudo chown www-data:www-data /var/log/gunicorn

# Запускаем с Gunicorn
gunicorn -c gunicorn_config.py app:app

Настройка Nginx

# Устанавливаем Nginx
sudo apt install nginx -y

# Создаём конфигурацию для нашего приложения
sudo cat > /etc/nginx/sites-available/flask_app << 'EOF'
server {
    listen 80;
    server_name your-domain.com;  # Замени на свой домен
    
    location / {
        proxy_pass http://127.0.0.1:5000;
        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;
    }
    
    location /static {
        alias /home/user/flask_app/static;  # Путь к статическим файлам
        expires 30d;
    }
    
    # Логирование
    access_log /var/log/nginx/flask_app_access.log;
    error_log /var/log/nginx/flask_app_error.log;
}
EOF

# Активируем конфигурацию
sudo ln -s /etc/nginx/sites-available/flask_app /etc/nginx/sites-enabled/
sudo rm /etc/nginx/sites-enabled/default

# Проверяем конфигурацию и перезапускаем Nginx
sudo nginx -t
sudo systemctl reload nginx

Создание systemd-сервиса

# Создаём systemd-сервис
sudo cat > /etc/systemd/system/flask_app.service << 'EOF'
[Unit]
Description=Flask App with Gunicorn
After=network.target

[Service]
User=www-data
Group=www-data
WorkingDirectory=/home/user/flask_app
Environment="PATH=/home/user/flask_app/venv/bin"
ExecStart=/home/user/flask_app/venv/bin/gunicorn -c gunicorn_config.py app:app
ExecReload=/bin/kill -s HUP $MAINPID
KillMode=mixed
TimeoutStopSec=5
PrivateTmp=true

[Install]
WantedBy=multi-user.target
EOF

# Активируем и запускаем сервис
sudo systemctl daemon-reload
sudo systemctl enable flask_app
sudo systemctl start flask_app

# Проверяем статус
sudo systemctl status flask_app

Практические примеры и кейсы

Пример 1: API для управления системными службами

@app.route('/api/service/<service_name>/<action>', methods=['POST'])
def manage_service(service_name, action):
    allowed_services = ['nginx', 'apache2', 'mysql', 'postgresql']
    allowed_actions = ['start', 'stop', 'restart', 'status']
    
    if service_name not in allowed_services:
        return jsonify({'error': 'Service not allowed'}), 403
    
    if action not in allowed_actions:
        return jsonify({'error': 'Action not allowed'}), 400
    
    try:
        result = subprocess.run(['systemctl', action, service_name], 
                              capture_output=True, text=True)
        
        if result.returncode == 0:
            return jsonify({
                'status': 'success',
                'service': service_name,
                'action': action,
                'output': result.stdout
            })
        else:
            return jsonify({
                'status': 'error',
                'service': service_name,
                'action': action,
                'error': result.stderr
            }), 500
    
    except Exception as e:
        return jsonify({'error': str(e)}), 500

Пример 2: Мониторинг логов в реальном времени

from flask import Response
import time

@app.route('/api/logs/<log_file>/tail')
def tail_log(log_file):
    allowed_logs = {
        'nginx': '/var/log/nginx/access.log',
        'auth': '/var/log/auth.log',
        'syslog': '/var/log/syslog'
    }
    
    if log_file not in allowed_logs:
        return jsonify({'error': 'Log file not allowed'}), 403
    
    def generate():
        try:
            with open(allowed_logs[log_file], 'r') as f:
                # Переходим к концу файла
                f.seek(0, 2)
                while True:
                    line = f.readline()
                    if line:
                        yield f"data: {line}\n\n"
                    else:
                        time.sleep(1)
        except Exception as e:
            yield f"data: ERROR: {str(e)}\n\n"
    
    return Response(generate(), mimetype='text/plain')

Сравнение с альтернативными решениями

Характеристика Flask Django FastAPI Bottle
Сложность изучения Низкая Высокая Средняя Очень низкая
Производительность Хорошая Средняя Отличная Хорошая
Размер фреймворка Микро Полноценный Современный Ультра-мини
API разработка Требует расширений DRF нужен Из коробки Ручная настройка
Экосистема Большая Огромная Растущая Малая

Для системных администраторов Flask — оптимальный выбор, так как он:

  • Быстро изучается
  • Не навязывает архитектуру
  • Отлично подходит для небольших инструментов
  • Имеет минимальные зависимости
  • Легко интегрируется с системными командами

Расширения и интеграции

Полезные расширения для админских задач:

# Устанавливаем полезные расширения
pip install flask-sqlalchemy flask-migrate flask-login flask-wtf celery redis

# Пример интеграции с базой данных
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime

app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///monitoring.db'
db = SQLAlchemy(app)

class ServerLog(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    server_name = db.Column(db.String(100), nullable=False)
    log_level = db.Column(db.String(20), nullable=False)
    message = db.Column(db.Text, nullable=False)
    timestamp = db.Column(db.DateTime, default=datetime.utcnow)

# Создание таблиц
with app.app_context():
    db.create_all()

@app.route('/api/logs', methods=['POST'])
def add_log():
    data = request.get_json()
    log = ServerLog(
        server_name=data['server_name'],
        log_level=data['log_level'],
        message=data['message']
    )
    db.session.add(log)
    db.session.commit()
    return jsonify({'status': 'success'})

Интеграция с мониторингом

# Интеграция с Prometheus
from prometheus_client import Counter, Histogram, generate_latest

REQUEST_COUNT = Counter('requests_total', 'Total requests', ['method', 'endpoint'])
REQUEST_LATENCY = Histogram('request_duration_seconds', 'Request latency')

@app.before_request
def before_request():
    request.start_time = time.time()

@app.after_request
def after_request(response):
    REQUEST_COUNT.labels(method=request.method, endpoint=request.endpoint).inc()
    REQUEST_LATENCY.observe(time.time() - request.start_time)
    return response

@app.route('/metrics')
def metrics():
    return Response(generate_latest(), mimetype='text/plain')

Интересные факты и нестандартные применения

1. Flask как инструмент для CI/CD

Многие команды создают простые Flask-приложения для управления деплоями. Например, webhook-эндпоинты для автоматического деплоя при пуше в Git:

@app.route('/webhook/deploy', methods=['POST'])
def deploy_webhook():
    # Проверяем подпись от GitHub/GitLab
    signature = request.headers.get('X-Hub-Signature-256')
    if not verify_signature(request.data, signature):
        return jsonify({'error': 'Invalid signature'}), 403
    
    # Запускаем деплой в фоне
    subprocess.Popen(['./deploy.sh'])
    return jsonify({'status': 'Deploy started'})

2. Микросервисная архитектура

Flask идеально подходит для создания микросервисов. Каждый сервис может быть небольшим Flask-приложением с одной ответственностью.

3. Интеграция с Docker

# Dockerfile
FROM python:3.9-slim

WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt

COPY . .

EXPOSE 5000
CMD ["gunicorn", "-c", "gunicorn_config.py", "app:app"]

Автоматизация и скрипты

Flask открывает множество возможностей для автоматизации:

  • Веб-интерфейсы для скриптов — превращай консольные утилиты в веб-приложения
  • API для автоматизации — создавай REST API для управления серверами
  • Дашборды мониторинга — визуализируй метрики и логи
  • Интеграция с внешними системами — создавай мосты между разными сервисами

Пример автоматизации бэкапов:

@app.route('/api/backup/create', methods=['POST'])
def create_backup():
    backup_type = request.json.get('type', 'full')
    
    if backup_type == 'database':
        cmd = ['mysqldump', '-u', 'root', '-p', 'mydb']
    elif backup_type == 'files':
        cmd = ['tar', '-czf', f'/backups/files_{datetime.now().strftime("%Y%m%d_%H%M%S")}.tar.gz', '/var/www']
    else:
        return jsonify({'error': 'Invalid backup type'}), 400
    
    try:
        result = subprocess.run(cmd, capture_output=True, text=True)
        if result.returncode == 0:
            return jsonify({'status': 'success', 'message': 'Backup created'})
        else:
            return jsonify({'status': 'error', 'message': result.stderr}), 500
    except Exception as e:
        return jsonify({'status': 'error', 'message': str(e)}), 500

Безопасность и лучшие практики

Основные принципы безопасности:

# Защита от CSRF и XSS
from flask_wtf.csrf import CSRFProtect
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address

csrf = CSRFProtect(app)
limiter = Limiter(
    app,
    key_func=get_remote_address,
    default_limits=["200 per day", "50 per hour"]
)

# Конфигурация для продакшена
app.config.update(
    SECRET_KEY='your-secret-key',  # Используй os.urandom(24)
    SESSION_COOKIE_SECURE=True,
    SESSION_COOKIE_HTTPONLY=True,
    SESSION_COOKIE_SAMESITE='Lax',
    PERMANENT_SESSION_LIFETIME=timedelta(minutes=30)
)

# Аутентификация
@app.before_request
def require_auth():
    if request.endpoint and request.endpoint.startswith('api/'):
        auth_header = request.headers.get('Authorization')
        if not auth_header or not verify_token(auth_header):
            return jsonify({'error': 'Unauthorized'}), 401

Мониторинг и логирование

import logging
from logging.handlers import RotatingFileHandler

# Настройка логирования
if not app.debug:
    file_handler = RotatingFileHandler('logs/app.log', maxBytes=10240, backupCount=10)
    file_handler.setFormatter(logging.Formatter(
        '%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'
    ))
    file_handler.setLevel(logging.INFO)
    app.logger.addHandler(file_handler)
    app.logger.setLevel(logging.INFO)

# Структурированное логирование
import json

@app.after_request
def log_request_info(response):
    app.logger.info(json.dumps({
        'method': request.method,
        'url': request.url,
        'status_code': response.status_code,
        'remote_addr': request.remote_addr,
        'user_agent': request.headers.get('User-Agent'),
        'response_time': time.time() - request.start_time
    }))
    return response

Производительность и оптимизация

Кэширование

from flask_caching import Cache

cache = Cache(app, config={'CACHE_TYPE': 'redis'})

@app.route('/api/stats')
@cache.cached(timeout=300)  # Кэш на 5 минут
def get_stats():
    # Тяжёлые вычисления
    return jsonify(expensive_calculation())

# Инвалидация кэша
@app.route('/api/stats/refresh', methods=['POST'])
def refresh_stats():
    cache.delete('view//api/stats')
    return jsonify({'status': 'cache cleared'})

Оптимизация для высоких нагрузок:

  • Используй Redis для кэширования
  • Настрой connection pooling для БД
  • Используй CDN для статики
  • Настрой gzip-сжатие в Nginx
  • Мониторь метрики с помощью Prometheus

Заключение и рекомендации

Flask — это отличный выбор для системных администраторов и девопс-инженеров, которые хотят быстро создавать веб-интерфейсы для своих инструментов. Его главные преимущества:

  • Простота изучения — можно начать писать полезные приложения уже через несколько часов
  • Гибкость — не навязывает архитектуру, позволяет решать задачи по-своему
  • Минимализм — включает только необходимое, остальное добавляется по мере необходимости
  • Отличная документацияофициальная документация очень качественная

Когда стоит использовать Flask:

  • Создание API для автоматизации
  • Веб-интерфейсы для системных инструментов
  • Дашборды мониторинга
  • Прототипирование веб-приложений
  • Микросервисная архитектура

Когда лучше выбрать что-то другое:

  • Большие корпоративные приложения (Django)
  • Высокопроизводительные API (FastAPI)
  • Простейшие однофайловые решения (Bottle)

Начни с простых задач — создай веб-интерфейс для одного из своих скриптов, API для мониторинга или простую админскую панель. Flask позволит тебе сфокусироваться на логике приложения, а не на изучении сложного фреймворка.

Помни про безопасность, особенно если приложение будет доступно из интернета. Используй HTTPS, аутентификацию, валидацию входных данных и регулярно обновляй зависимости.

Полезные ссылки для дальнейшего изучения:


В этой статье собрана информация и материалы из различных интернет-источников. Мы признаем и ценим работу всех оригинальных авторов, издателей и веб-сайтов. Несмотря на то, что были приложены все усилия для надлежащего указания исходного материала, любая непреднамеренная оплошность или упущение не являются нарушением авторских прав. Все упомянутые товарные знаки, логотипы и изображения являются собственностью соответствующих владельцев. Если вы считаете, что какой-либо контент, использованный в этой статье, нарушает ваши авторские права, немедленно свяжитесь с нами для рассмотрения и принятия оперативных мер.

Данная статья предназначена исключительно для ознакомительных и образовательных целей и не ущемляет права правообладателей. Если какой-либо материал, защищенный авторским правом, был использован без должного упоминания или с нарушением законов об авторском праве, это непреднамеренно, и мы исправим это незамедлительно после уведомления. Обратите внимание, что переиздание, распространение или воспроизведение части или всего содержимого в любой форме запрещено без письменного разрешения автора и владельца веб-сайта. Для получения разрешений или дополнительных запросов, пожалуйста, свяжитесь с нами.

Leave a reply

Your email address will not be published. Required fields are marked