初次提交
This commit is contained in:
200
backend/package-app.py
Normal file
200
backend/package-app.py
Normal file
@@ -0,0 +1,200 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
应用打包脚本 - 将Python应用打包为可执行文件
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import shutil
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
def check_dependencies():
|
||||
"""检查必要的依赖"""
|
||||
try:
|
||||
import PyInstaller
|
||||
print("OK PyInstaller 已安装")
|
||||
except ImportError:
|
||||
print("正在安装 PyInstaller...")
|
||||
subprocess.check_call([sys.executable, "-m", "pip", "install", "pyinstaller"])
|
||||
print("OK PyInstaller 安装完成")
|
||||
|
||||
def create_spec_file():
|
||||
"""创建 PyInstaller spec 文件"""
|
||||
spec_content = '''
|
||||
# -*- mode: python ; coding: utf-8 -*-
|
||||
|
||||
block_cipher = None
|
||||
|
||||
a = Analysis(
|
||||
['main.py'],
|
||||
pathex=[],
|
||||
binaries=[],
|
||||
datas=[
|
||||
('app', 'app'),
|
||||
('uploads', 'uploads'),
|
||||
('logs', 'logs'),
|
||||
],
|
||||
hiddenimports=[
|
||||
'uvicorn',
|
||||
'fastapi',
|
||||
'sqlalchemy',
|
||||
'pymysql',
|
||||
'pydantic',
|
||||
'pydantic_settings',
|
||||
'redis',
|
||||
'passlib',
|
||||
'python_jose',
|
||||
'uvicorn.protocols.http.httptools_impl',
|
||||
],
|
||||
hookspath=[],
|
||||
hooksconfig={},
|
||||
runtime_hooks=[],
|
||||
excludes=[],
|
||||
win_no_prefer_redirects=False,
|
||||
win_private_assemblies=False,
|
||||
cipher=block_cipher,
|
||||
noarchive=False,
|
||||
)
|
||||
|
||||
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
|
||||
|
||||
exe = EXE(
|
||||
pyz,
|
||||
a.scripts,
|
||||
a.binaries,
|
||||
a.zipfiles,
|
||||
a.datas,
|
||||
[],
|
||||
name='cloud-drive-server',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
upx_exclude=[],
|
||||
runtime_tmpdir=None,
|
||||
console=True,
|
||||
disable_windowed_traceback=False,
|
||||
argv_emulation=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None,
|
||||
icon=None
|
||||
)
|
||||
'''
|
||||
|
||||
with open('cloud-drive-server.spec', 'w', encoding='utf-8') as f:
|
||||
f.write(spec_content)
|
||||
print("OK 创建了 cloud-drive-server.spec 文件")
|
||||
|
||||
def build_executable():
|
||||
"""构建可执行文件"""
|
||||
print("开始构建可执行文件...")
|
||||
|
||||
try:
|
||||
# 使用 PyInstaller 构建
|
||||
result = subprocess.run([
|
||||
sys.executable, '-m', 'PyInstaller',
|
||||
'--clean',
|
||||
'--noconfirm',
|
||||
'cloud-drive-server.spec'
|
||||
], capture_output=True, text=True)
|
||||
|
||||
if result.returncode == 0:
|
||||
print("OK 可执行文件构建成功")
|
||||
print("输出目录: dist/")
|
||||
return True
|
||||
else:
|
||||
print("ERROR 构建失败:")
|
||||
print(result.stdout)
|
||||
print(result.stderr)
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"ERROR 构建过程中出现错误: {e}")
|
||||
return False
|
||||
|
||||
def create_dockerfile_for_executable():
|
||||
"""为可执行文件创建最小化的 Dockerfile"""
|
||||
dockerfile_content = '''# 最小化运行环境 - 使用可执行文件
|
||||
FROM alpine:latest
|
||||
|
||||
# 安装运行时依赖
|
||||
RUN apk add --no-cache \\
|
||||
curl \\
|
||||
tzdata \\
|
||||
ca-certificates \\
|
||||
&& rm -rf /var/cache/apk/*
|
||||
|
||||
# 设置时区
|
||||
ENV TZ=Asia/Shanghai
|
||||
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
|
||||
|
||||
# 创建应用用户
|
||||
RUN adduser -D -s /bin/sh app
|
||||
|
||||
# 设置工作目录
|
||||
WORKDIR /app
|
||||
|
||||
# 复制可执行文件
|
||||
COPY dist/cloud-drive-server /app/cloud-drive-server
|
||||
|
||||
# 创建必要的目录
|
||||
RUN mkdir -p /app/uploads /app/logs \\
|
||||
&& chown -R app:app /app
|
||||
|
||||
# 切换到非root用户
|
||||
USER app
|
||||
|
||||
# 暴露端口
|
||||
EXPOSE 8002
|
||||
|
||||
# 健康检查
|
||||
HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \\
|
||||
CMD curl -f http://localhost:8002/api/v1/health || exit 1
|
||||
|
||||
# 启动命令
|
||||
CMD ["./cloud-drive-server"]
|
||||
'''
|
||||
|
||||
with open('Dockerfile.executable', 'w', encoding='utf-8') as f:
|
||||
f.write(dockerfile_content)
|
||||
print("OK 创建了 Dockerfile.executable 文件")
|
||||
|
||||
def main():
|
||||
"""主函数"""
|
||||
print("=== 云盘应用打包工具 ===")
|
||||
print("正在将应用打包为Docker镜像...")
|
||||
|
||||
# 检查当前目录
|
||||
if not Path('main.py').exists():
|
||||
print("ERROR 错误: 在当前目录未找到 main.py 文件")
|
||||
print("请在 backend 目录中运行此脚本")
|
||||
return False
|
||||
|
||||
# 检查依赖
|
||||
check_dependencies()
|
||||
|
||||
# 创建 spec 文件
|
||||
create_spec_file()
|
||||
|
||||
# 构建可执行文件
|
||||
if not build_executable():
|
||||
return False
|
||||
|
||||
# 创建可执行文件的 Dockerfile
|
||||
create_dockerfile_for_executable()
|
||||
|
||||
print("\n=== 打包完成 ===")
|
||||
print("OK 应用已成功打包")
|
||||
print("OK 可执行文件位于: dist/cloud-drive-server")
|
||||
print("OK Dockerfile: Dockerfile.executable")
|
||||
print("\n下一步命令:")
|
||||
print(" docker build -f Dockerfile.executable -t cloud-drive-backend:latest .")
|
||||
print(" docker run -d -p 8002:8002 --name cloud-drive-backend cloud-drive-backend:latest")
|
||||
|
||||
return True
|
||||
|
||||
if __name__ == "__main__":
|
||||
success = main()
|
||||
sys.exit(0 if success else 1)
|
||||
Reference in New Issue
Block a user