Перейти к основному контенту
Tech Path Finder
КурсыИнтервьюКод-ревьюБлог
Tech Path Finder

Персонализированный путеводитель в IT. Квизы, мок-интервью, код ревью и аналитика прогресса.

@potapov_me

Платформа

  • Курсы
  • Прогресс
  • Мок-интервью
  • Код ревью
  • Живое ревью с ИИ
  • Тренажёр переговоров
  • Закладки

Контент

  • Блог
  • Главная
  • Обратная связь

Компания

  • О проекте
  • Тарифы
  • Условия использования
  • Конфиденциальность
  • Согласие на обработку данных
  • Cookie
  • Реквизиты

Аккаунт

  • Войти
  • Зарегистрироваться
  • Профиль

© 2026 Tech Path Finder. Все права защищены.

·ИП Потапов К.С.·Политика конфиденциальности·
Сделано с ❤️ в России
  1. Port Binding — привязка портов
port_binding

Port Binding — привязка портов

Самодостаточность через экспорт сервисов посредством привязки портов

Port Binding: Привязка портов

Экспортируйте сервисы посредством привязки портов

#Суть принципа

Port Binding — седьмой фактор 12-Factor App. Принцип гласит:

Приложение должно быть самодостаточным и экспортировать свои сервисы через привязку к порту, а не полагаться на внешний веб-сервер.

# ❌ Неправильно: приложение зависит от внешнего веб-сервера # app.wsgi для Apache mod_wsgi # Требуется конфигурация Apache/Nginx для запуска # ✅ Правильно: приложение само запускает веб-сервер from flask import Flask app = Flask(__name__) if __name__ == '__main__': app.run(host='0.0.0.0', port=5000) # Привязка к порту

#Почему привязка портов?

#Проблема: зависимость от внешнего веб-сервера

Традиционный подход (до 12-Factor):

┌─────────────────┐     ┌──────────────┐     ┌─────────────┐
│    Nginx/Apache │────▶│  mod_wsgi/   │────▶│  Приложение │
│    (веб-сервер) │     │  PHP-FPM     │     │  (код)      │
└─────────────────┘     └──────────────┘     └─────────────┘

Проблемы:

  1. Зависимость от инфраструктуры — требуется настройка веб-сервера
  2. Сложность развёртывания — нужно устанавливать и конфигурировать Nginx/Apache
  3. Непереносимость — конфигурация веб-сервера специфична для среды
  4. Сложность масштабирования — каждый экземпляр требует настройки веб-сервера

#Решение: самодостаточное приложение

┌─────────────────────────────────┐
│  Приложение + веб-сервер        │
│  (Gunicorn, uWSGI, Tornado)     │
│  Привязка к порту 5000          │
└─────────────────────────────────┘
           │
           ▼
    Порт 5000

Преимущества:

  • ✅ Самодостаточность — приложение запускается самостоятельно
  • ✅ Переносимость — одинаковый запуск в любой среде
  • ✅ Масштабируемость — легко запустить несколько экземпляров
  • ✅ Контейнеризация — идеально для Docker и Kubernetes

#Веб-серверы для Python

#Встроенный сервер (только для разработки)

from flask import Flask app = Flask(__name__) @app.route('/') def hello(): return 'Hello, World!' if __name__ == '__main__': # ❌ Только для разработки! app.run(host='0.0.0.0', port=5000, debug=True)
# Запуск python app.py # Доступ curl http://localhost:5000

Важно: Встроенный сервер Flask не предназначен для production!

#Gunicorn (Green Unicorn)

# Установка pip install gunicorn
# app.py from flask import Flask app = Flask(__name__) @app.route('/') def hello(): return 'Hello, World!' # Не нужно указывать host/port в коде! # Gunicorn управляет запуском
# Запуск с Gunicorn gunicorn --bind 0.0.0.0:5000 app:app # С указанием воркеров gunicorn --bind 0.0.0.0:5000 --workers 4 app:app # С указанием типа воркера gunicorn --bind 0.0.0.0:5000 --workers 4 --worker-class sync app:app

#Uvicorn (ASGI сервер)

# Установка pip install uvicorn[standard]
# app.py (FastAPI или Starlette) from fastapi import FastAPI app = FastAPI() @app.get('/') def hello(): return {'message': 'Hello, World!'}
# Запуск с Uvicorn uvicorn app:app --host 0.0.0.0 --port 5000 # С reload для разработки uvicorn app:app --host 0.0.0.0 --port 5000 --reload # С несколькими воркерами uvicorn app:app --host 0.0.0.0 --port 5000 --workers 4

#Gunicorn + Uvicorn (production)

# Gunicorn как процесс-менеджер, Uvicorn как воркер gunicorn app:app \ --bind 0.0.0.0:5000 \ --workers 4 \ --worker-class uvicorn.workers.UvicornWorker

#Конфигурация привязки

#Переменные окружения для порта

import os from flask import Flask app = Flask(__name__) # Чтение порта из переменной окружения port = int(os.environ.get('PORT', 5000)) host = os.environ.get('HOST', '0.0.0.0') if __name__ == '__main__': app.run(host=host, port=port)
# Запуск с разным портом PORT=8080 python app.py # В Docker docker run -e PORT=8080 -p 8080:8080 myapp

#Конфигурация для Gunicorn

# gunicorn_config.py import multiprocessing # Привязка к порту bind = '0.0.0.0:5000' # Количество воркеров workers = multiprocessing.cpu_count() * 2 + 1 # Тип воркера worker_class = 'sync' # Таймаут timeout = 30 # Логирование accesslog = '-' # stdout errorlog = '-' # stderr loglevel = 'info'
# Запуск с конфигом gunicorn --config gunicorn_config.py app:app

#Привязка в Docker

#Dockerfile

FROM python:3.12-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir gunicorn flask COPY . . # Приложение экспортирует порт 5000 EXPOSE 5000 # Gunicorn привязывается к 0.0.0.0:5000 CMD ["gunicorn", "--bind", "0.0.0.0:5000", "--workers", "4", "app:app"]

#Docker Compose

version: '3.8' services: web: build: . ports: - "5000:5000" # Хост:Контейнер environment: - PORT=5000 restart: unless-stopped # Несколько экземпляров для масштабирования web-replica: build: . ports: - "5001:5000" # Разные порты на хосте environment: - PORT=5000 depends_on: - web
# Запуск docker-compose up # Масштабирование docker-compose up --scale web=3

#Привязка в Kubernetes

#Deployment с Service

# deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: myapp spec: replicas: 3 selector: matchLabels: app: myapp template: metadata: labels: app: myapp spec: containers: - name: web image: myapp:latest ports: - containerPort: 5000 # Порт внутри контейнера env: - name: PORT value: "5000"
# service.yaml apiVersion: v1 kind: Service metadata: name: myapp-service spec: selector: app: myapp ports: - protocol: TCP port: 80 # Порт сервиса targetPort: 5000 # Порт контейнера type: ClusterIP # Внутренний сервис
# ingress.yaml (внешний доступ) apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: myapp-ingress spec: rules: - host: myapp.example.com http: paths: - path: / pathType: Prefix backend: service: name: myapp-service port: number: 80

#Типы привязки

#IPv4

# Привязка ко всем IPv4 интерфейсам gunicorn --bind 0.0.0.0:5000 app:app # Привязка к конкретному IP gunicorn --bind 192.168.1.100:5000 app:app # Привязка к localhost (только локальный доступ) gunicorn --bind 127.0.0.1:5000 app:app

#IPv6

# Привязка ко всем IPv6 интерфейсам gunicorn --bind [::]:5000 app:app # Привязка к localhost IPv6 gunicorn --bind [::1]:5000 app:app

#Unix-сокеты (для локальной связи)

# Привязка к Unix-сокету gunicorn --bind unix:/var/run/myapp.sock app:app # С указанием прав gunicorn --bind unix:/var/run/myapp.sock --umask 007 app:app
# Docker Compose с Unix-сокетом services: web: image: myapp volumes: - /var/run/myapp:/var/run command: gunicorn --bind unix:/var/run/myapp.sock app:app nginx: image: nginx volumes: - /var/run/myapp:/var/run # Nginx подключается к сокету

#Архитектура с привязкой портов

#Прямая привязка

┌─────────────────┐
│   Приложение    │
│   Порт 5000     │
└────────┬────────┘
         │
         ▼
    Интернет

Использование: Development, внутренние сервисы

#За обратным прокси

┌─────────────┐     ┌─────────────────┐
│    Nginx    │────▶│   Приложение    │
│   Порт 80   │     │   Порт 5000     │
└─────────────┘     └─────────────────┘

Использование: Production с SSL, кэшированием

#Через балансировщик нагрузки

┌─────────────┐
│  Load       │
│  Balancer   │
│   Порт 443  │
└──────┬──────┘
       │
   ┌───┴───┬───┬───┐
   ▼       ▼   ▼   ▼
┌─────┐ ┌─────┐ ┌─────┐
│ App │ │ App │ │ App │
│:5000│ │:5000│ │:5000│
└─────┘ └─────┘ └─────┘

Использование: Масштабирование, высокая доступность

#Антипаттерны

#❌ Жёстко заданный порт в коде

# ❌ Неправильно: порт зашит в коде if __name__ == '__main__': app.run(host='127.0.0.1', port=5000) # Только localhost!

Проблема: Невозможно запустить в Docker с другим портом.

#❌ Привязка только к localhost

# ❌ Неправильно: недоступно извне контейнера app.run(host='127.0.0.1', port=5000)

Проблема: В Docker контейнер изолирован, 127.0.0.1 недоступен снаружи.

Решение:

# ✅ Правильно app.run(host='0.0.0.0', port=5000)

#❌ Зависимость от внешнего веб-сервера

# ❌ Неправильно: требуется Apache с mod_wsgi <VirtualHost *:80> WSGIDaemonProcess myapp python-path=/app WSGIProcessGroup myapp WSGIScriptAlias / /app/wsgi.py </VirtualHost>

Проблема: Приложение не самодостаточно, требует настройки Apache.

#❌ Несколько приложений на одном порту

# ❌ Конфликт портов gunicorn --bind 0.0.0.0:5000 app1:app gunicorn --bind 0.0.0.0:5000 app2:app # Ошибка: порт занят!

Решение: Разные порты или Unix-сокеты.

#Проверка привязки

#Проверка слушающих портов

# Linux ss -tlnp | grep 5000 netstat -tlnp | grep 5000 # macOS lsof -i :5000 # В Docker docker exec <container> ss -tlnp

#Проверка доступности

# Локальная проверка curl http://localhost:5000/health # Проверка из контейнера docker exec <container> curl http://localhost:5000/health # Проверка с хоста curl http://$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' <container>):5000/health

#Health check endpoint

from flask import Flask, jsonify app = Flask(__name__) @app.route('/health') def health(): return jsonify({'status': 'healthy'}), 200 if __name__ == '__main__': app.run(host='0.0.0.0', port=5000)

#Production-конфигурация

#Gunicorn с оптимизациями

gunicorn app:app \ --bind 0.0.0.0:5000 \ --workers 4 \ --worker-class sync \ --worker-connections 1000 \ --timeout 30 \ --keep-alive 5 \ --access-logfile - \ --error-logfile - \ --loglevel info \ --pid /var/run/gunicorn.pid \ --graceful-timeout 30

#Nginx как обратный прокси

# /etc/nginx/nginx.conf upstream myapp { server 127.0.0.1:5000; server 127.0.0.1:5001; server 127.0.0.1:5002; } server { listen 80; server_name myapp.example.com; location / { proxy_pass http://myapp; 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 /health { access_log off; return 200 'healthy'; add_header Content-Type text/plain; } }

#Связь с другими факторами

  • Processes — каждый процесс привязывается к своему порту
  • Concurrency — масштабирование через запуск процессов на разных портах
  • Disposability — быстрая утилизация процессов с портами
  • Dev/Prod Parity — одинаковая привязка во всех средах

#Пример из практики

#До: зависимость от Apache

# /etc/apache2/sites-available/myapp.conf <VirtualHost *:80> ServerName myapp.example.com WSGIDaemonProcess myapp \ python-path=/var/www/myapp \ processes=2 \ threads=15 WSGIProcessGroup myapp WSGIScriptAlias / /var/www/myapp/wsgi.py <Directory /var/www/myapp> Require all granted </Directory> </VirtualHost>

Проблемы:

  • Требуется установка и настройка Apache
  • Конфигурация специфична для сервера
  • Сложно масштабировать

#После: самодостаточное приложение

# app.py from flask import Flask app = Flask(__name__) @app.route('/') def hello(): return 'Hello from self-contained app!'
# Dockerfile FROM python:3.12 WORKDIR /app COPY requirements.txt . RUN pip install gunicorn flask COPY . . EXPOSE 5000 CMD ["gunicorn", "--bind", "0.0.0.0:5000", "app:app"]
# docker-compose.yml version: '3.8' services: web: build: . ports: - "5000:5000" restart: unless-stopped
# Запуск одной командой docker-compose up # Масштабирование docker-compose up --scale web=5

Результат:

  • ✅ Приложение самодостаточно
  • ✅ Одинаковый запуск в любой среде
  • ✅ Легко масштабировать
  • ✅ Идеально для контейнеров

Ключевой вывод: Приложение должно быть самодостаточным и экспортировать свои сервисы через привязку к порту. Это обеспечивает переносимость, упрощает развёртывание и масштабирование в облачных средах.

Далее: Concurrency — конкурентность