modify: docker 支持

This commit is contained in:
2026-04-26 15:26:01 +08:00
parent 871b7abf02
commit 450be84020
8 changed files with 257 additions and 87 deletions
+3
View File
@@ -16,3 +16,6 @@ output.md
# resources # resources
uploads/ uploads/
# docker
*.tar
+26
View File
@@ -56,3 +56,29 @@ build
cd build cd build
chongming # windows chongming.exe chongming # windows chongming.exe
``` ```
## docker镜像
打包镜像
```shell
docker build -t chongming:latest .
```
导出镜像
```shell
docker save -o chongming_v1.0.tar chongming:v1.0
```
导入镜像
```shell
docker load -i chongming_v1.0.tar
```
运行镜像
```shell
mkdir -p /data/chongming
docker run -d -p 8000:8000 \
-v /data/chongming/database.db:/app/database.db \
-v /data/chongming/uploads:/app/uploads \
--name chongming chongming:v1.0
```
+23
View File
@@ -0,0 +1,23 @@
# 使用 Debian 的极简版,确保有基础的 glibc(推荐)
FROM debian:bookworm-slim
# 可选:设置时区、安装 ca-certificates 等
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
# 复制打包好的可执行文件
COPY build/chongming /app/
# 复制运行时需要的静态资源、配置文件、.mbank 等
COPY build/config.toml /app/
COPY build/resources/ /app/resources/
COPY build/static.svfs /app/
# 暴露端口
EXPOSE 8000
# 启动
CMD ["./chongming"]
+24 -12
View File
@@ -5,10 +5,12 @@ FastAPI chongming 示例
主入口文件,适配 chongming 打包系统 主入口文件,适配 chongming 打包系统
""" """
import sys import sys
import platform
from utils.launch import launch from utils.launch import launch
from multiprocessing import freeze_support from multiprocessing import freeze_support
import server import server
use_shell = platform.system() == "Windows"
def app_run(app_config: dict, default_config: dict): def app_run(app_config: dict, default_config: dict):
""" """
@@ -18,7 +20,6 @@ def app_run(app_config: dict, default_config: dict):
app_config: 应用配置 app_config: 应用配置
default_config: 默认配置 default_config: 默认配置
""" """
import uvicorn
from app.core.logger import get_logger # type: ignore from app.core.logger import get_logger # type: ignore
logger = get_logger("app") logger = get_logger("app")
@@ -47,17 +48,28 @@ def app_run(app_config: dict, default_config: dict):
logger.info(f"👥 Workers: {workers}") logger.info(f"👥 Workers: {workers}")
logger.info("=" * 50) logger.info("=" * 50)
uvicorn.run( if use_shell:
"server:app", import uvicorn
host=host, uvicorn.run(
port=port, "server:app",
reload=reload, host=host,
workers=workers, port=port,
log_level="debug" if app_config.get("debug", False) else "info", reload=reload,
access_log=False, workers=workers,
timeout_keep_alive=timeout_keep_alive, log_level="debug" if app_config.get("debug", False) else "info",
) access_log=False,
timeout_keep_alive=timeout_keep_alive,
)
else:
from gunicorn.app.wsgiapp import run
sys.argv = [
"gunicorn",
"server:app",
"-k", "uvicorn.workers.UvicornWorker",
"-w", str(workers),
"-b", f"{host}:{port}"
]
run()
def main(): def main():
freeze_support() freeze_support()
+2
View File
@@ -48,3 +48,5 @@ packages = ["src/chongming"]
[project.scripts] [project.scripts]
build = "chongming.scripts.build:build" build = "chongming.scripts.build:build"
serve = "chongming:serve" serve = "chongming:serve"
# gunicorn = "gunicorn chongming.app:app -k uvicorn.workers.UvicornWorker -w 4 -b 0.0.0.0:8000"
gunicorn = "chongming:gunicorn_serve"
+17
View File
@@ -13,6 +13,23 @@ def serve():
logget.info(f"启动日志: {log_config}") logget.info(f"启动日志: {log_config}")
uvicorn.run("chongming.app:app", **server_config) uvicorn.run("chongming.app:app", **server_config)
def gunicorn_serve():
"""使用 gunicorn 启动服务"""
import sys
from gunicorn.app.wsgiapp import run
config = load_config()
env = config["default"]["env"]
server_config = config[env]["server"]
# 设置 gunicorn 参数
sys.argv = [
"gunicorn",
"chongming.app:app",
"-k", "uvicorn.workers.UvicornWorker",
"-w", f"{server_config.get('workers', 4)}",
"-b", f"{server_config.get('host', '0.0.0.0')}:{server_config.get('port', 8000)}"
]
run()
if __name__ == "__main__": if __name__ == "__main__":
serve() serve()
+161 -75
View File
@@ -1,3 +1,5 @@
import platform
from module_bank import PythonToSQLite from module_bank import PythonToSQLite
from module_bank.encryption import Encryption from module_bank.encryption import Encryption
import os import os
@@ -10,6 +12,8 @@ from sqlite_vfs.core import SQLiteVFS
from sqlite_vfs.folder_packer import FolderPacker from sqlite_vfs.folder_packer import FolderPacker
is_windows = platform.system() == "Windows"
def build_vue_web(): def build_vue_web():
"""打包 Vue Web""" """打包 Vue Web"""
# 构建 Vue Web 命令 # 构建 Vue Web 命令
@@ -26,26 +30,37 @@ def build_vue_web():
cwd="./src/chongming-web", cwd="./src/chongming-web",
capture_output=True, capture_output=True,
text=True, text=True,
shell=True, shell=is_windows,
encoding="utf-8", encoding="utf-8",
errors="replace", errors="replace",
) )
if result.returncode != 0: if result.returncode != 0:
print("打包 Vue Web 失败") print("打包 Vue Web 失败")
print(result.stderr) print("标准输出:", result.stdout)
print("错误输出:", result.stderr)
return
else: else:
vfs = SQLiteVFS(output_db, compress=False) print("Vue Web 打包成功")
packer = FolderPacker( if result.stdout:
sqlite_vfs=vfs, print(result.stdout)
exclude_patterns=[],
fs_name=fs_name,
)
try: # 检查 dist 目录是否存在
packer.pack_folder(dist_dir) if not os.path.exists(dist_dir):
print(f"✅ 打包完成,文件保存为 {output_db}") print(f"错误: dist 目录不存在: {dist_dir}")
finally: return
vfs.close()
vfs = SQLiteVFS(output_db, compress=False)
packer = FolderPacker(
sqlite_vfs=vfs,
exclude_patterns=[],
fs_name=fs_name,
)
try:
packer.pack_folder(dist_dir)
print(f"✅ 打包完成,文件保存为 {output_db}")
finally:
vfs.close()
def run_pyarmor_obfuscate(): def run_pyarmor_obfuscate():
@@ -77,68 +92,139 @@ def run_pyinstaller():
"""运行 PyInstaller 打包成可执行文件""" """运行 PyInstaller 打包成可执行文件"""
try: try:
# 构建 PyInstaller 命令 # 构建 PyInstaller 命令
cmd = [ if is_windows:
sys.executable, cmd = [
"-m", sys.executable,
"PyInstaller", "-m",
"--onefile", "PyInstaller",
"--name", "--onefile",
"chongming", "--name",
"--distpath", "chongming",
".", "--distpath",
"--workpath", ".",
"./build_temp", "--workpath",
"--specpath", "./build_temp",
"./specs", "--specpath",
"--clean", "./specs",
# 隐藏导入 "--clean",
"--hidden-import", # 隐藏导入
"utils", "--hidden-import",
"--hidden-import", "utils",
"utils.launch", "--hidden-import",
"--hidden-import", "utils.launch",
"utils.config", "--hidden-import",
"--hidden-import", "utils.config",
"server", "--hidden-import",
"--hidden-import", "server",
"module_bank", "--hidden-import",
"--hidden-import", "module_bank",
"fastapi", "--hidden-import",
"--hidden-import", "fastapi",
"fastapi.staticfiles", "--hidden-import",
"--hidden-import", "fastapi.staticfiles",
"fastapi.middleware.cors", "--hidden-import",
"--hidden-import", "fastapi.middleware.cors",
"uvicorn", "--hidden-import",
"--hidden-import", "uvicorn",
"sqlmodel", "--hidden-import",
"--hidden-import", "sqlmodel",
"aiosqlite", "--hidden-import",
"--hidden-import", "aiosqlite",
"aiofiles", "--hidden-import",
"--hidden-import", "aiofiles",
"apscheduler", "--hidden-import",
"--hidden-import", "apscheduler",
"diskcache", "--hidden-import",
"--hidden-import", "diskcache",
"passlib", "--hidden-import",
"--hidden-import", "passlib",
"passlib.context", "--hidden-import",
"--hidden-import", "passlib.context",
"passlib.handlers.bcrypt", "--hidden-import",
"--hidden-import", "passlib.handlers.bcrypt",
"sqlite_vfs", "--hidden-import",
"--hidden-import", "sqlite_vfs",
"python_multipart", "--hidden-import",
"--hidden-import", "python_multipart",
"sqlite_vfs.core", "--hidden-import",
"--hidden-import", "sqlite_vfs.core",
"jwt", "--hidden-import",
# 其他选项 "jwt",
"--icon", # 其他选项
"../../public/chongming.ico", "--icon",
"main.py", "../../public/chongming.ico",
] "main.py",
]
else:
cmd = [
sys.executable,
"-m",
"PyInstaller",
"--onefile",
"--name",
"chongming",
"--distpath",
".",
"--workpath",
"./build_temp",
"--specpath",
"./specs",
"--clean",
# 隐藏导入
"--hidden-import",
"utils",
"--hidden-import",
"utils.launch",
"--hidden-import",
"utils.config",
"--hidden-import",
"server",
"--hidden-import",
"module_bank",
"--hidden-import",
"fastapi",
"--hidden-import",
"fastapi.staticfiles",
"--hidden-import",
"fastapi.middleware.cors",
"--hidden-import",
"uvicorn",
"--hidden-import",
"sqlmodel",
"--hidden-import",
"aiosqlite",
"--hidden-import",
"aiofiles",
"--hidden-import",
"apscheduler",
"--hidden-import",
"diskcache",
"--hidden-import",
"passlib",
"--hidden-import",
"passlib.context",
"--hidden-import",
"passlib.handlers.bcrypt",
"--hidden-import",
"sqlite_vfs",
"--hidden-import",
"python_multipart",
"--hidden-import",
"sqlite_vfs.core",
"--hidden-import",
"jwt",
# gunicorn
"--hidden-import",
"gunicorn.glogging",
"--hidden-import",
"gunicorn.app",
"--hidden-import",
"gunicorn.app.wsgiapp",
# 其他选项
"--icon",
"../../public/chongming.ico",
"main.py",
]
print(f"正在运行 PyInstaller: {' '.join(cmd)}") print(f"正在运行 PyInstaller: {' '.join(cmd)}")
result = subprocess.run(cmd, cwd="./build", capture_output=True, text=True) result = subprocess.run(cmd, cwd="./build", capture_output=True, text=True)
+1
View File
@@ -22,6 +22,7 @@ def generate_markdown_from_py_files(directory, output_file):
or file.endswith(".ts") or file.endswith(".ts")
or file.endswith(".json") or file.endswith(".json")
or file.endswith(".html") or file.endswith(".html")
or file == "dockerfile"
): ):
file_path = os.path.join(root, file) file_path = os.path.join(root, file)
if file == "output.md" or file == "package-lock.json": if file == "output.md" or file == "package-lock.json":