You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker部署Flask后端遇uWSGI报错:未找到Python应用

问题描述

执行docker-compose -f dev.yml up启动服务后,前端运行正常,但所有后端请求都返回500状态码。相关错误日志显示uWSGI无法加载Python应用。

文件结构

nginx
`-- default.conf
mysql
client
server
|-- app
|   |-- db
|   |-- lib
|   |-- __init__.py
`-- app.ini
`-- dev.Dockerfile
`-- main.py
`-- requirements.txt
dev.yml

各文件内容

app.ini

[uwsgi]
wsgi-file: /app/main.py
uid = www-data
gid = www-data
socket = :5555
processes = 1
threads = 1
master = true
chmod-socket = 660
vacuum = true
callable = app
die-on-term = true

后续添加了logto = %n.log用于输出日志

main.py

from app import create_app

app = create_app()

if __name__ == '__main__':
    app.run('0.0.0.0', 5000, False)

后端dev.Dockerfile

FROM python:3.9.16

WORKDIR /app

COPY requirements.txt .
RUN /usr/local/bin/python -m pip install --upgrade pip
RUN /usr/local/bin/python -m pip install -r requirements.txt

RUN  cd /app

ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

CMD ["uwsgi", "app.ini"]

app/init.py

#!/usr/bin/python

import os
from datetime import timedelta
from flask import Flask, jsonify
from app.db import db, mm
from app.resourses import initialize_routes
from app.resourses.auth import AuthError
from app.error_handeler import handler
from app.lib import get_db_string
from dotenv import load_dotenv
from flask_cors import CORS
from app.db.models import get_user_by_id
from app.lib import set_default_companies

BASE_DIR = os.path.abspath(os.path.dirname(__file__))

if os.environ.get('ENV') == 'development':
    load_dotenv(f'{os.getcwd()}/.env.dev', override=True)
else:
    load_dotenv(f'{os.getcwd()}/.env', override=True)


def create_app():

    api = Flask(__name__)

    api.config['JWT_PRIVATE_KEY'] = os.environ.get("PRIVATE_KEY")
    api.config['JWT_PUBLIC_KEY'] = os.environ.get("PUB_KEY")
    api.config["JWT_SECRET_KEY"] = os.environ.get("JWT_SECRET")
    api.config["JWT_HEADER_NAME"] = "access_token"
    api.config["JWT_HEADER_TYPE"] = ""
    api.config["JWT_TOKEN_LOCATION"] = ["headers", "cookies", "json"]
    api.config["JWT_COOKIE_SECURE"] = os.environ.get('FLASK_ENV') == 'production'
    api.config['PROPAGATE_EXCEPTIONS'] = True
    api.config["JWT_ACCESS_TOKEN_EXPIRES"] = timedelta(minutes=1)
    api.config["JWT_REFRESH_TOKEN_EXPIRES"] = timedelta(days=90)
    api.config['JWT_ACCESS_COOKIE_PATH'] = '/api/'
    api.config['JWT_REFRESH_COOKIE_PATH'] = '/token/refresh'
    api.config['JWT_ACCESS_COOKIE_NAME'] = 'access_token'
    api.config['JWT_REFRESH_COOKIE_NAME'] = 'refresh_token'
    api.config['JWT_COOKIE_CSRF_PROTECT'] = False
    api.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
    api.config["PROPAGATE_EXCEPTIONS"] = True
    api.config['SQLALCHEMY_DATABASE_URI'] = get_db_string()
    api.config['SQLALCHEMY_ECHO'] = True
    api.config['SQLALCHEMY_ENGINE_OPTIONS'] = {
        'pool_size': 100,
    }
    api.config['SQLALCHEMY_POOL_SIZE'] = 100
    api.config['SQLALCHEMY_POOL_RECYCLE'] = 280
    api.secret_key = os.environ.get('FLASK_SECRET')

    db.init_app(api)
    mm.mm.init_app(api)
    with api.app_context():
        db.create_all()
        set_default_companies()

    handler(api)
    initialize_routes(api)
    CORS(api)
    api.config['TESTING'] = os.environ.get("TEST_MODE", default=False)

    @api.errorhandler(AuthError)
    def handle_auth_error(ex):
        response = jsonify(ex.error)
        response.status_code = ex.status_code
        return response
    return api


if __name__ == '__main__':
    create_app().run(port=5000, debug=True)

dev.yml

version: "3.7"

services:

  nginx:
    build:
      context: ./nginx
      dockerfile: ./dev.Dockerfile
    container_name: nginx
    networks:
      - nginx_network
    restart: always
    depends_on:
      - backend
    ports:
      - "80:80"
    extra_hosts:
      - "host.docker.internal:host-gateway"
    volumes:
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf
      - ./client/build:/usr/share/nginx/html

  db:
    container_name: db
    build: ./mysql
    restart: always
    command: '--authentication_policy=mysql_native_password'
    healthcheck:
      test: [ "CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "--silent" ]
      interval: 3s
      retries: 5
      start_period: 30s

    networks:
      mysql_net:
        aliases:
            - db
    ports:
      - "3306:3306"
    volumes:
      - ./data/data_volume:/var/lib/mysql

  backend:
    build:
      context: ./server
      dockerfile: ./dev.Dockerfile
    container_name: server
    restart: always
    networks:
      mysql_net:
        aliases:
          - server
      nginx_network:
        aliases:
          - server
    links:
      - db
    depends_on:
      - db
    env_file:
      - ./server/.env
    ports:
      - "5555:5555"
    volumes:
      - ./server:/app

  adminer:
    container_name: adminer
    image: adminer
    restart: always
    networks:
      mysql_net:
        aliases:
          - adminer
      nginx_network:
        aliases:
          - adminer
    ports:
      - "8080:8080"

volumes:
  data_volume:
    driver: local

networks:
  nginx_network:
    driver: bridge
  mysql_net:
    driver: bridge

Nginx default.conf

underscores_in_headers on;

server {
    listen 0.0.0.0:80;
    server_name localhost;

    location /api {
        include uwsgi_params;
        add_header  Content-Type    application/json;
        uwsgi_pass server:5555;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
        proxy_read_timeout 300s;
        proxy_connect_timeout 75s;
    }

    location /adminer {
        proxy_set_header X-Forwarded-Prefix "/adminer";
        proxy_pass http://adminer:8080;
    }

   location ~* \.(?:css|js|json)$ {
        root /usr/share/nginx/html;
        try_files $uri $uri/;
    }

    location / {
        root /usr/share/nginx/html;
        index index.html;
        try_files $uri $uri/ /index.html =404;
    }
}

错误日志

Docker Compose启动日志片段

db              | 2022-12-15T22:37:45.439021Z 0 [System] [MY-011323] [Server] X Plugin ready for connections. Bind-address: '::' port: 33060, socket: /var/run/mysqld/mysqlx.sock
db              | 2022-12-15T22:37:45.439178Z 0 [System] [MY-010931] [Server] /usr/sbin/mysqld: ready for connections. Version: '8.0.28'  socket: '/var/run/mysqld/mysqld.sock'  port: 3306  MySQL Community Server - GPL.
server  | --- no python application found, check your startup logs for errors ---
server  | [pid: 7|app: -1|req: -1/1] 172.19.0.1 () {64 vars in 1258 bytes} [Thu Dec 15 22:45:44 2022] POST /api/users/login => generated 21 bytes in 0 msecs (HTTP/1.1 500) 2 headers in 83 bytes (0 switches on core 0)
nginx           | 172.19.0.1 - - [15/Dec/2022:22:45:44 +0000] "POST /api/users/login HTTP/1.1" 500 32 "http://localhost/login" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36" "-"

uWSGI日志(app.log)

*** Starting uWSGI 2.0.21 (64bit) on [Fri Dec 16 18:47:11 2022] ***
compiled with version: 10.2.1 20210110 on 15 December 2022 21:55:56
os: Linux-5.15.49-linuxkit #1 SMP Tue Sep 13 07:51:46 UTC 2022
nodename: 5338311c006d
machine: x86_64
clock source: unix
pcre jit disabled
detected number of CPU cores: 6
current working directory: /app
detected binary path: /usr/local/bin/uwsgi
setgid() to 33
setuid() to 33
your memory page size is 4096 bytes
detected max file descriptor number: 1048576
lock engine: pthread robust mutexes
thunder lock: disabled (you can enable it with --thunder-lock)
uwsgi socket 0 bound to TCP address :5555 fd 3
Python version: 3.9.16 (main, Dec  8 2022, 02:40:11)  [GCC 10.2.1 20210110]
Python main interpreter initialized at 0x55569cd5a090
python threads support enabled
your server socket listen backlog is limited to 100 connections
your mercy for graceful operations on workers is 60 seconds
mapped 145840 bytes (142 KB) for 1 cores
*** Operational MODE: single process ***
*** no app loaded. going in full dynamic mode ***
*** uWSGI is running in multiple interpreter mode ***
spawned uWSGI master process (pid: 1)
spawned uWSGI worker 1 (pid: 7, cores: 1)
--- no python application found, check your startup logs for errors ---
[pid: 7|app: -1|req: -1/1] 172.19.0.1 () {64 vars in 1239 bytes} [Fri Dec 16 18:47:51 2022] POST /api/users/login => generated 21 bytes in 1 msecs (HTTP/1.1 500) 2 headers in 83 bytes (0 switches on core 0)
解决建议

1. 验证Flask应用能否正常启动

进入后端容器直接运行main.py,排查应用初始化时的错误:

docker exec -it server bash
python main.py

如果启动失败,根据终端输出的错误信息修复(比如依赖缺失、环境变量错误、数据库连接失败等)。

2. 修复Dockerfile代码复制逻辑

当前后端Dockerfile仅复制了requirements.txt,未复制main.py、app.ini和app目录。虽然dev.yml挂载了宿主机目录,但镜像本身缺少文件可能导致加载异常,修改Dockerfile:

FROM python:3.9.16

WORKDIR /app

# 复制所有代码文件
COPY . .

RUN /usr/local/bin/python -m pip install --upgrade pip
RUN /usr/local/bin/python -m pip install -r requirements.txt

ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONUNBUFFERED 1

CMD ["uwsgi", "app.ini"]

3. 检查环境变量加载情况

app/__init__.py根据ENV变量加载不同的.env文件,需确认:

  • .env文件中是否设置了ENV=development,否则会加载.env而非.env.dev,若配置缺失会导致应用初始化失败
  • 进入容器查看环境变量是否正确加载:
    docker exec -it server env
    

4. 排查数据库初始化异常

create_app()中执行db.create_all()和set_default_companies(),若数据库连接失败会导致app对象无法创建。临时修改main.py添加异常捕获:

from app import create_app
import traceback

try:
    app = create_app()
    print("App created successfully")
except Exception as e:
    print(f"Failed to create app: {e}")
    traceback.print_exc()

if __name__ == '__main__':
    app.run('0.0.0.0', 5000, False)

重启容器后查看日志,定位具体错误。

5. 增强uWSGI调试日志

在app.ini中添加调试配置,获取更详细的加载日志:

[uwsgi]
wsgi-file: /app/main.py
uid = www-data
gid = www-data
socket = :5555
processes = 1
threads = 1
master = true
chmod-socket = 660
vacuum = true
callable = app
die-on-term = true
logto = %n.log
# 新增调试配置
log-level = debug
py-autoreload = 1

内容的提问来源于stack exchange,提问作者Oleg Dudkin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 07:15:59