From 7e9930ae6b64b300547d557b88ff01cd78d63a0e Mon Sep 17 00:00:00 2001 From: vipg Date: Thu, 9 Oct 2025 16:38:20 +0800 Subject: [PATCH] Update --- README.md | 159 +++++++++++++++++++++++++++++++++- build.py | 253 ------------------------------------------------------ 2 files changed, 158 insertions(+), 254 deletions(-) delete mode 100644 build.py diff --git a/README.md b/README.md index dd17e5a..318f2b1 100644 --- a/README.md +++ b/README.md @@ -1 +1,158 @@ -# REAMDME +# 用户服务部署使用手册 + +## 一、概述 + +本文档介绍用户服务系统的创建、构建和部署流程,涉及`create_api.py`、`build.py`和`deploy/deploy.sh`三个核心脚本的使用方法,帮助使用者快速搭建和部署用户服务相关的API模块。 + +## 二、环境准备 + +1. 确保系统安装以下工具: + - Python 3.x + - Docker + - Docker Compose + +2. 克隆代码库后,进入项目根目录: + ```bash + cd user_service + ``` + +## 三、核心脚本功能说明 + +### 1. 创建新API服务(create_api.py) + +用于基于模板快速创建新的API服务模块,自动生成目录结构和配置文件。 + +#### 使用方法: +1. 编辑`create_api.py`文件,设置`a`(功能名)和`b`(次功能名)参数: + ```python + a = "aaaa" # 主功能名 + b = "bbbb" # 次功能名(可选,如果不需要,留空) + ``` + +2. 执行脚本: + ```bash + sudo python3 create_api.py + ``` + +#### 功能说明: +- 自动在`deploy/api`目录下创建新服务目录(格式:`api_{a}_{b}` 或 `api_{a}`) +- 复制`api_template`模板文件并替换其中的占位符 +- 生成对应的`docker-compose.{a}.{b}.yaml`或`docker-compose.{a}.yaml`文件 +- 自动修改`release.sh`、`init.py`和`README.md`中的服务标识 + +### 2. 构建API服务镜像(build.py) + +用于批量构建所有API服务的Docker镜像,并将构建结果整理到指定目录。 + +#### 使用方法: +```bash +python3 build.py +``` + +#### 功能说明: +1. 遍历所有以`api_`开头的目录(排除`api_template`) +2. 执行每个目录下的`release.sh`脚本: + - 为脚本添加执行权限 + - 运行脚本删除旧镜像并构建新镜像 +3. 收集构建生成的`.tar`镜像文件: + - 复制到`deploy/images`目录 + - 自动处理文件权限问题 + - 清理原始目录中的`.tar`文件 + +#### 注意事项: +- 若遇到权限问题,可尝试使用`sudo`运行: + ```bash + sudo python3 build.py + ``` +- 脚本会自动跳过不存在`release.sh`的目录 + +### 3. 部署服务(deploy/deploy.sh) + +用于停止现有服务、构建API并启动新的Docker Compose编排。 + +#### 使用方法: +```bash +cd deploy +./deploy.sh +``` + +#### 功能说明: +1. **步骤1:停止现有服务** + - 停止`docker-compose.yaml`定义的`user_service`项目 + +2. **步骤2:构建所有API服务** + - 遍历`./api`目录下的所有服务 + - 执行每个服务的`release.sh`脚本 + - 若构建失败则终止部署流程 + +3. **步骤3:启动新服务** + - 使用`docker-compose.yaml`启动服务 + - 项目名称为`user_service` + +#### 配置说明: +脚本开头可修改以下配置参数: +```bash +COMPOSE_PROJECT_NAME="user_service" # Docker Compose项目名称 +DOCKER_COMPOSE_FILE="./docker-compose.yaml" # 配置文件路径 +API_DIR="./api" # API服务所在目录 +``` + +## 四、完整工作流程 + +1. **创建新API服务**: + ```bash + # 编辑create_api.py设置功能名 + python3 create_api.py + ``` + +2. **开发API功能**: + - 在生成的`deploy/api/api_{a}_{b}`目录中编写代码(如`main.go`) + - 根据需要修改`init.py`中的初始化逻辑 + +3. **构建服务镜像**: + ```bash + python3 build.py + ``` + +4. **部署服务**: + ```bash + cd deploy + ./deploy.sh + ``` + +## 五、常见问题处理 + +1. **权限错误**: + - 执行脚本时若出现`Permission denied`,尝试添加执行权限: + ```bash + chmod +x deploy/deploy.sh + ``` + - 或使用`sudo`运行相关命令 + +2. **镜像构建失败**: + - 检查`release.sh`中的镜像名称和构建命令是否正确 + - 确保Docker服务正常运行:`systemctl status docker` + +3. **服务启动失败**: + - 检查`docker-compose.yaml`配置是否正确 + - 查看容器日志排查问题:`docker logs <容器名>` + +4. **端口冲突**: + - 若启动时提示端口被占用,修改`init.py`中的端口映射配置 + +## 六、服务目录结构说明 + +成功创建并部署后,项目主要目录结构如下: +``` +user_service_副本/ +├── deploy/ +│ ├── api/ # 所有API服务目录 +│ │ ├── api_login/ # 登录服务 +│ │ ├── api_register/ # 注册服务 +│ │ └── ... # 其他API服务 +│ ├── images/ # 构建好的镜像文件 +│ ├── docker-compose.yaml # 服务编排配置 +│ └── deploy.sh # 部署脚本 +├── create_api.py # 创建新API的脚本 +└── build.py # 构建镜像的脚本 +``` \ No newline at end of file diff --git a/build.py b/build.py deleted file mode 100644 index 3565d64..0000000 --- a/build.py +++ /dev/null @@ -1,253 +0,0 @@ -import os -import shutil -import yaml -import subprocess -from typing import Dict, Any - -def run_shell_command(command: str, cwd: str = None) -> bool: - """执行shell命令并返回执行结果""" - try: - print(f"执行命令: {command} (工作目录: {cwd or os.getcwd()})") - result = subprocess.run( - command, - cwd=cwd, - shell=True, - check=True, - stdout=subprocess.PIPE, - stderr=subprocess.PIPE, - text=True - ) - print(f"命令输出: {result.stdout}") - return True - except subprocess.CalledProcessError as e: - print(f"命令执行失败: {e.stderr}") - return False - -def cleanup_dangling_images() -> bool: - """清除docker虚悬镜像(dangling images)""" - print("开始清除虚悬镜像...") - return run_shell_command('sudo docker images -f "dangling=true" -q | xargs -r sudo docker rmi') - -def execute_release_scripts(root_dir: str) -> bool: - """遍历所有api_目录并执行release.sh脚本(排除api_template)""" - print("开始执行所有api_目录下的release.sh脚本...") - - # 定义目标镜像目录 - images_dir = os.path.join(root_dir, 'deploy', 'images') - # 确保目标目录存在并设置权限 - os.makedirs(images_dir, exist_ok=True) - # 尝试设置目录可写权限(解决目标目录权限问题) - try: - os.chmod(images_dir, 0o755) - except PermissionError: - print(f"警告:无法修改目录权限 {images_dir},可能导致文件复制失败") - - for dir_name in os.listdir(root_dir): - # 排除api_template文件夹 - if dir_name == "api_template": - print(f"跳过模板目录: {dir_name}") - continue - - dir_path = os.path.join(root_dir, dir_name) - if os.path.isdir(dir_path) and dir_name.startswith('api_'): - release_script = os.path.join(dir_path, 'release.sh') - if os.path.exists(release_script): - print(f"处理目录: {dir_path}") - - # 添加执行权限 - if not run_shell_command(f"chmod +x {release_script}", dir_path): - print(f"为 {release_script} 添加权限失败,跳过执行") - continue - - # 执行release.sh - if not run_shell_command(f"./release.sh", dir_path): - print(f"{release_script} 执行失败,跳过后续步骤") - return False - - # 复制目录下的.tar文件到根目录的deploy/images下(替换方式) - for file in os.listdir(dir_path): - if file.endswith('.tar'): - src_path = os.path.join(dir_path, file) - dest_path = os.path.join(images_dir, file) - - # 检查源文件是否存在且可读 - if not os.path.exists(src_path): - print(f"警告:源文件不存在 {src_path},跳过") - continue - - if not os.access(src_path, os.R_OK): - print(f"警告:无权限读取 {src_path},尝试修复权限...") - try: - # 尝试赋予源文件读权限 - os.chmod(src_path, 0o644) - # 再次检查权限 - if not os.access(src_path, os.R_OK): - print(f"错误:仍无法读取 {src_path},请手动检查权限") - continue - except PermissionError: - print(f"错误:无法修复 {src_path} 权限,跳过该文件") - continue - - # 处理目标文件 - if os.path.exists(dest_path): - try: - os.remove(dest_path) - print(f"已删除旧文件: {dest_path}") - except PermissionError: - print(f"警告:无权限删除旧文件 {dest_path},尝试用sudo运行脚本") - continue - - # 复制文件(带权限处理) - try: - shutil.copy2(src_path, dest_path) - # 复制后确保目标文件可读写 - os.chmod(dest_path, 0o644) - print(f"已将 {src_path} 替换复制到 {dest_path}") - - # 复制成功后删除原文件 - try: - os.remove(src_path) - print(f"已删除原文件: {src_path}") - except PermissionError: - print(f"警告:无权限删除原文件 {src_path},请手动清理") - except Exception as e: - print(f"删除原文件 {src_path} 时发生错误: {str(e)}") - - except PermissionError: - print(f"错误:复制 {src_path} 失败(权限不足)") - print("建议:使用 sudo 权限重新运行脚本(sudo python3 build.py)") - return False - except Exception as e: - print(f"复制文件时发生错误: {str(e)},跳过该文件") - continue - else: - print(f"{dir_path} 中未找到release.sh,跳过") - - print("所有release.sh脚本执行完成") - return True - -def merge_yaml_files(root_dir: str) -> Dict[str, Any]: - """合并所有 docker-compose 相关 YAML 文件内容(排除api_template)""" - merged = { - 'services': {}, - 'networks': {}, - 'volumes': {} - } - - yaml_files = [] - # 根目录下的 docker-compose.*.yaml - for file in os.listdir(root_dir): - if file.startswith('docker-compose.') and file.endswith('.yaml') and file != 'docker-compose.yaml': - yaml_files.append(os.path.join(root_dir, file)) - - # api_ 目录下的 docker-compose.*.yaml(排除api_template) - for dir_name in os.listdir(root_dir): - if dir_name == "api_template": - print(f"跳过模板目录的yaml文件: {dir_name}") - continue - - dir_path = os.path.join(root_dir, dir_name) - if os.path.isdir(dir_path) and dir_name.startswith('api_'): - for file in os.listdir(dir_path): - if file.startswith('docker-compose.') and file.endswith('.yaml'): - yaml_files.append(os.path.join(dir_path, file)) - - # 合并所有 YAML 文件内容 - for file_path in yaml_files: - print(f"合并文件: {file_path}") - try: - with open(file_path, 'r', encoding='utf-8') as f: - data = yaml.safe_load(f) - if not data: - continue - - if 'services' in data: - merged['services'].update(data['services']) - if 'networks' in data: - merged['networks'].update(data['networks']) - if 'volumes' in data: - merged['volumes'].update(data['volumes']) - - except yaml.YAMLError as e: - print(f"解析 {file_path} 失败: {e}") - continue - except PermissionError: - print(f"错误:无权限读取 {file_path},跳过该文件") - continue - - return merged - -def main(): - # 先执行清除虚悬镜像操作 - print("部署流程开始,先执行清除虚悬镜像操作...") - if not cleanup_dangling_images(): - print("清除虚悬镜像失败(非致命错误,继续部署流程)") - else: - print("虚悬镜像清除完成") - - # 获取项目根目录(deploy.py 所在目录) - root_dir = os.path.dirname(os.path.abspath(__file__)) - print(f"项目根目录: {root_dir}") - - # 1. 执行所有api_目录下的release.sh脚本 - if not execute_release_scripts(root_dir): - print("执行release脚本失败,终止部署流程") - return - - # 2. 合并所有YAML文件 - merged_data = merge_yaml_files(root_dir) - - # 输出到根目录的docker-compose.yaml - output_path = os.path.join(root_dir, 'docker-compose.yaml') - try: - with open(output_path, 'w', encoding='utf-8') as f: - yaml.dump( - merged_data, - f, - sort_keys=False, - allow_unicode=True, - default_flow_style=False - ) - print(f"已生成合并后的 docker-compose.yaml: {output_path}") - - # 将新的docker-compose.yaml以替换方式复制到根目录的deploy/下 - deploy_dir = os.path.join(root_dir, 'deploy') - os.makedirs(deploy_dir, exist_ok=True) - # 确保deploy目录可写 - try: - os.chmod(deploy_dir, 0o755) - except PermissionError: - print(f"警告:无法修改目录权限 {deploy_dir}") - - dest_compose_path = os.path.join(deploy_dir, 'docker-compose.yaml') - # 替换方式复制 - if os.path.exists(dest_compose_path): - try: - os.remove(dest_compose_path) - except PermissionError: - print(f"警告:无权限删除旧文件 {dest_compose_path}") - return False - - shutil.copy2(output_path, dest_compose_path) - # 设置目标文件权限 - os.chmod(dest_compose_path, 0o644) - print(f"已将 {output_path} 替换复制到 {dest_compose_path}") - - except PermissionError as e: - print(f"错误:无权限操作文件 {output_path} 或 {dest_compose_path}") - print(f"详细错误: {str(e)}") - print("建议:使用 sudo 权限重新运行脚本(sudo python3 build.py)") - return False - except Exception as e: - print(f"生成或复制docker-compose.yaml时出错: {str(e)}") - return False - - print("\n===== 清理虚悬镜像 =====") - if not cleanup_dangling_images(): - print("清除虚悬镜像失败(非致命错误,继续部署流程)") - else: - print("虚悬镜像清除完成") - -if __name__ == "__main__": - # 需要安装 pyyaml 库: pip install pyyaml - main() \ No newline at end of file