diff --git a/api_delete/release.sh b/api_delete/release.sh index ce67d86..8e1a816 100755 --- a/api_delete/release.sh +++ b/api_delete/release.sh @@ -33,6 +33,9 @@ fi echo "开始将镜像 ${FULL_IMAGE} 打包为 ${TAR_FILE}..." if sudo docker save -o "${TAR_FILE}" "${FULL_IMAGE}"; then echo "镜像打包成功!生成文件:${TAR_FILE}" + # 添加最高级别的可读写权限 + sudo chmod 777 "${TAR_FILE}" + echo "已为 ${TAR_FILE} 设置最高权限(777)" else echo "错误:镜像打包失败" >&2 exit 1 diff --git a/api_gateway/release.sh b/api_gateway/release.sh index 35a1ae7..cbea1db 100755 --- a/api_gateway/release.sh +++ b/api_gateway/release.sh @@ -33,6 +33,9 @@ fi echo "开始将镜像 ${FULL_IMAGE} 打包为 ${TAR_FILE}..." if sudo docker save -o "${TAR_FILE}" "${FULL_IMAGE}"; then echo "镜像打包成功!生成文件:${TAR_FILE}" + # 添加最高级别的可读写权限 + sudo chmod 777 "${TAR_FILE}" + echo "已为 ${TAR_FILE} 设置最高权限(777)" else echo "错误:镜像打包失败" >&2 exit 1 diff --git a/api_login/release.sh b/api_login/release.sh index 13aac5a..c2915bb 100755 --- a/api_login/release.sh +++ b/api_login/release.sh @@ -33,6 +33,9 @@ fi echo "开始将镜像 ${FULL_IMAGE} 打包为 ${TAR_FILE}..." if sudo docker save -o "${TAR_FILE}" "${FULL_IMAGE}"; then echo "镜像打包成功!生成文件:${TAR_FILE}" + # 添加最高级别的可读写权限 + sudo chmod 777 "${TAR_FILE}" + echo "已为 ${TAR_FILE} 设置最高权限(777)" else echo "错误:镜像打包失败" >&2 exit 1 diff --git a/api_register/release.sh b/api_register/release.sh index 33eb292..b2ed40f 100755 --- a/api_register/release.sh +++ b/api_register/release.sh @@ -33,6 +33,9 @@ fi echo "开始将镜像 ${FULL_IMAGE} 打包为 ${TAR_FILE}..." if sudo docker save -o "${TAR_FILE}" "${FULL_IMAGE}"; then echo "镜像打包成功!生成文件:${TAR_FILE}" + # 添加最高级别的可读写权限 + sudo chmod 777 "${TAR_FILE}" + echo "已为 ${TAR_FILE} 设置最高权限(777)" else echo "错误:镜像打包失败" >&2 exit 1 diff --git a/api_template/release.sh b/api_template/release.sh index 5227044..6e457bf 100755 --- a/api_template/release.sh +++ b/api_template/release.sh @@ -33,6 +33,9 @@ fi echo "开始将镜像 ${FULL_IMAGE} 打包为 ${TAR_FILE}..." if sudo docker save -o "${TAR_FILE}" "${FULL_IMAGE}"; then echo "镜像打包成功!生成文件:${TAR_FILE}" + # 添加最高级别的可读写权限 + sudo chmod 777 "${TAR_FILE}" + echo "已为 ${TAR_FILE} 设置最高权限(777)" else echo "错误:镜像打包失败" >&2 exit 1 diff --git a/api_update_account/release.sh b/api_update_account/release.sh index 1822805..e9844a8 100755 --- a/api_update_account/release.sh +++ b/api_update_account/release.sh @@ -33,6 +33,9 @@ fi echo "开始将镜像 ${FULL_IMAGE} 打包为 ${TAR_FILE}..." if sudo docker save -o "${TAR_FILE}" "${FULL_IMAGE}"; then echo "镜像打包成功!生成文件:${TAR_FILE}" + # 添加最高级别的可读写权限 + sudo chmod 777 "${TAR_FILE}" + echo "已为 ${TAR_FILE} 设置最高权限(777)" else echo "错误:镜像打包失败" >&2 exit 1 diff --git a/api_update_password/release.sh b/api_update_password/release.sh index f66f5a0..de2a5c2 100755 --- a/api_update_password/release.sh +++ b/api_update_password/release.sh @@ -33,6 +33,9 @@ fi echo "开始将镜像 ${FULL_IMAGE} 打包为 ${TAR_FILE}..." if sudo docker save -o "${TAR_FILE}" "${FULL_IMAGE}"; then echo "镜像打包成功!生成文件:${TAR_FILE}" + # 添加最高级别的可读写权限 + sudo chmod 777 "${TAR_FILE}" + echo "已为 ${TAR_FILE} 设置最高权限(777)" else echo "错误:镜像打包失败" >&2 exit 1 diff --git a/build.py b/build.py index 6da24ae..4ea23fc 100644 --- a/build.py +++ b/build.py @@ -1,5 +1,5 @@ import os -import shutil # 新增导入shutil用于文件复制 +import shutil import yaml import subprocess from typing import Dict, Any @@ -26,7 +26,6 @@ def run_shell_command(command: str, cwd: str = None) -> bool: def cleanup_dangling_images() -> bool: """清除docker虚悬镜像(dangling images)""" print("开始清除虚悬镜像...") - # 清除所有:的虚悬镜像,xargs -r确保无镜像时不执行删除命令 return run_shell_command('sudo docker images -f "dangling=true" -q | xargs -r sudo docker rmi') def execute_release_scripts(root_dir: str) -> bool: @@ -35,8 +34,13 @@ def execute_release_scripts(root_dir: str) -> bool: # 定义目标镜像目录 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文件夹 @@ -65,12 +69,47 @@ def execute_release_scripts(root_dir: str) -> bool: 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): - os.remove(dest_path) - # 复制文件 - shutil.copy2(src_path, dest_path) - print(f"已将 {src_path} 替换复制到 {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}") + 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,跳过") @@ -80,24 +119,20 @@ def execute_release_scripts(root_dir: str) -> bool: def merge_yaml_files(root_dir: str) -> Dict[str, Any]: """合并所有 docker-compose 相关 YAML 文件内容(排除api_template)""" merged = { - 'version': '3.8', # 默认使用 3.8 版本 + 'version': '3.8', 'services': {}, 'networks': {}, 'volumes': {} } - # 查找所有 docker-compose 相关 YAML 文件 yaml_files = [] - # 1. 根目录下的 docker-compose.*.yaml + # 根目录下的 docker-compose.*.yaml for file in os.listdir(root_dir): - if file.startswith('docker-compose.') and file.endswith('.yaml'): - if file == 'docker-compose.yaml': # 跳过目标文件本身 - continue + if file.startswith('docker-compose.') and file.endswith('.yaml') and file != 'docker-compose.yaml': yaml_files.append(os.path.join(root_dir, file)) - # 2. api_ 目录下的 docker-compose.*.yaml(排除api_template) + # api_ 目录下的 docker-compose.*.yaml(排除api_template) for dir_name in os.listdir(root_dir): - # 排除api_template文件夹 if dir_name == "api_template": print(f"跳过模板目录的yaml文件: {dir_name}") continue @@ -111,34 +146,50 @@ def merge_yaml_files(root_dir: str) -> Dict[str, Any]: # 合并所有 YAML 文件内容 for file_path in yaml_files: print(f"合并文件: {file_path}") - with open(file_path, 'r', encoding='utf-8') as f: - try: + try: + with open(file_path, 'r', encoding='utf-8') as f: data = yaml.safe_load(f) if not data: continue - # 合并 services if 'services' in data: merged['services'].update(data['services']) - - # 合并 networks if 'networks' in data: merged['networks'].update(data['networks']) - - # 合并 volumes if 'volumes' in data: merged['volumes'].update(data['volumes']) - - # 保留最高版本号 if 'version' in data and data['version'] > merged['version']: merged['version'] = data['version'] - except yaml.YAMLError as e: - print(f"解析 {file_path} 失败: {e}") - continue + except yaml.YAMLError as e: + print(f"解析 {file_path} 失败: {e}") + continue + except PermissionError: + print(f"错误:无权限读取 {file_path},跳过该文件") + continue return merged +def stop_docker_compose(root_dir: str) -> bool: + """停止docker-compose""" + print("开始停止docker-compose...") + compose_file = os.path.join(root_dir, 'docker-compose.yaml') + if not os.path.exists(compose_file): + print(f"未找到docker-compose文件: {compose_file}") + return False + + return run_shell_command(f"sudo docker-compose -f {compose_file} down", root_dir) + +def start_docker_compose(root_dir: str) -> bool: + """启动docker-compose""" + print("开始启动docker-compose...") + compose_file = os.path.join(root_dir, 'docker-compose.yaml') + if not os.path.exists(compose_file): + print(f"未找到docker-compose文件: {compose_file}") + return False + + return run_shell_command(f"sudo docker-compose -f {compose_file} up -d", root_dir) + def main(): # 先执行清除虚悬镜像操作 print("部署流程开始,先执行清除虚悬镜像操作...") @@ -161,25 +212,48 @@ def main(): # 输出到根目录的docker-compose.yaml output_path = os.path.join(root_dir, 'docker-compose.yaml') - 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目录存在 - dest_compose_path = os.path.join(deploy_dir, 'docker-compose.yaml') - # 替换方式复制:若目标存在则先删除 - if os.path.exists(dest_compose_path): - os.remove(dest_compose_path) - shutil.copy2(output_path, dest_compose_path) - print(f"已将 {output_path} 替换复制到 {dest_compose_path}") + 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():