diff --git a/api_delete/main.go b/api_delete/main.go index 5f19355..67bea35 100644 --- a/api_delete/main.go +++ b/api_delete/main.go @@ -141,6 +141,6 @@ func deleteAccountHandler(c *gin.Context) { log.Printf("[%s] 账号删除成功,用户ID: %s", reqID, req.UserID) c.JSON(http.StatusOK, DeleteAccountResponse{ Success: true, - Message: "账号删除成功", + Message: "账号删除成功。", }) } \ No newline at end of file diff --git a/api_delete/user-delete-api-1.0.0.tar b/api_delete/user-delete-api-1.0.0.tar new file mode 100755 index 0000000..0e372c9 Binary files /dev/null and b/api_delete/user-delete-api-1.0.0.tar differ diff --git a/api_gateway/user-gateway-api-1.0.0.tar b/api_gateway/user-gateway-api-1.0.0.tar new file mode 100755 index 0000000..0f86629 Binary files /dev/null and b/api_gateway/user-gateway-api-1.0.0.tar differ diff --git a/api_login/user-login-api-1.0.0.tar b/api_login/user-login-api-1.0.0.tar new file mode 100755 index 0000000..7f66e9b Binary files /dev/null and b/api_login/user-login-api-1.0.0.tar differ diff --git a/api_register/user-register-api-1.0.0.tar b/api_register/user-register-api-1.0.0.tar new file mode 100755 index 0000000..2048068 Binary files /dev/null and b/api_register/user-register-api-1.0.0.tar differ diff --git a/api_update_account/user-update-account-api-1.0.0.tar b/api_update_account/user-update-account-api-1.0.0.tar new file mode 100755 index 0000000..dd603eb Binary files /dev/null and b/api_update_account/user-update-account-api-1.0.0.tar differ diff --git a/api_update_password/user-update-password-api-1.0.0.tar b/api_update_password/user-update-password-api-1.0.0.tar new file mode 100755 index 0000000..180aeda Binary files /dev/null and b/api_update_password/user-update-password-api-1.0.0.tar differ diff --git a/build_service.py b/build_service.py deleted file mode 100644 index 9f9a8ed..0000000 --- a/build_service.py +++ /dev/null @@ -1,184 +0,0 @@ -import os -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("开始清除虚悬镜像...") - # 清除所有:的虚悬镜像,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: - """遍历所有api_目录并执行release.sh脚本(排除api_template)""" - print("开始执行所有api_目录下的release.sh脚本...") - - 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 - 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 = { - 'version': '3.8', # 默认使用 3.8 版本 - 'services': {}, - 'networks': {}, - 'volumes': {} - } - - # 查找所有 docker-compose 相关 YAML 文件 - yaml_files = [] - # 1. 根目录下的 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 - yaml_files.append(os.path.join(root_dir, file)) - - # 2. 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 - - 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}") - with open(file_path, 'r', encoding='utf-8') as f: - try: - 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 - - 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("部署流程开始,先执行清除虚悬镜像操作...") - 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') - 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}") - - print("\n===== 清理虚悬镜像 =====") - if not cleanup_dangling_images(): - print("清除虚悬镜像失败(非致命错误,继续部署流程)") - else: - print("虚悬镜像清除完成") - -if __name__ == "__main__": - # 需要安装 pyyaml 库: pip install pyyaml - main() \ No newline at end of file diff --git a/deploy/.env b/deploy/.env index 21e982a..9a5b466 100644 --- a/deploy/.env +++ b/deploy/.env @@ -9,4 +9,7 @@ TZ=Asia/Shanghai # pgAdmin配置 PGADMIN_EMAIL=fish@fish.com -PGADMIN_PASSWORD=12345678 \ No newline at end of file +PGADMIN_PASSWORD=12345678 + +# 网关端口 +GATEWAY_PORT=80 \ No newline at end of file diff --git a/deploy/deploy.sh b/deploy/deploy.sh index fb37c0c..b27ef68 100644 --- a/deploy/deploy.sh +++ b/deploy/deploy.sh @@ -7,86 +7,124 @@ GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # 重置颜色 -# 步骤1:停止当前运行的 docker-compose 编排 -echo -e "${YELLOW}===== 第一步:停止当前 docker-compose 服务 ====="${NC} -if [ -f "./docker-compose.yaml" ]; then - echo "正在停止现有服务..." - docker-compose -f ./docker-compose.yaml down +COMPOSE_PROJECT_NAME="user_service" +DOCKER_COMPOSE_FILE="./docker-compose.yaml" + +# 步骤1:停止指定名称的docker-compose编排 +echo -e "${YELLOW}===== 第一步:停止编排名称为 $COMPOSE_PROJECT_NAME 的服务 ====="${NC} +if [ -f "$DOCKER_COMPOSE_FILE" ]; then + echo "正在停止服务..." + docker-compose -f "$DOCKER_COMPOSE_FILE" -p "$COMPOSE_PROJECT_NAME" down if [ $? -eq 0 ]; then - echo -e "${GREEN}现有 docker-compose 服务已成功停止${NC}" + echo -e "${GREEN}编排 $COMPOSE_PROJECT_NAME 已成功停止${NC}" else - echo -e "${RED}停止 docker-compose 服务失败!${NC}" + echo -e "${RED}停止编排 $COMPOSE_PROJECT_NAME 失败!${NC}" exit 1 fi else - echo -e "${RED}错误:未找到当前目录下的 docker-compose.yaml 文件${NC}" + echo -e "${RED}错误:未找到 $DOCKER_COMPOSE_FILE 文件${NC}" exit 1 fi -# 步骤2:遍历 api_ 开头的目录并执行 release.sh -echo -e "\n${YELLOW}===== 第二步:处理 api_ 开头的服务目录 ====="${NC} -for dir in ./api_*/; do - # 提取目录名称(移除路径和末尾斜杠) - dir_name=$(basename "${dir%/}") - - # 步骤3:跳过 api_template 目录 - if [ "$dir_name" = "api_template" ]; then - echo -e "${YELLOW} 跳过目录:$dir_name${NC}" - continue - fi - - # 检查目录是否有效 - if [ ! -d "$dir" ]; then - echo -e "${RED} 警告:$dir 不是有效目录,已跳过${NC}" - continue - fi - - echo -e "\n处理目录:$dir_name" - # 进入目标目录 - cd "$dir" || { - echo -e "${RED} 错误:无法进入目录 $dir_name${NC}" +# 步骤2:进入images目录加载所有镜像 +echo -e "\n${YELLOW}===== 第二步:加载images目录下的所有镜像 ====="${NC} +IMAGES_DIR="./images" +if [ -d "$IMAGES_DIR" ]; then + cd "$IMAGES_DIR" || { + echo -e "${RED}错误:无法进入目录 $IMAGES_DIR${NC}" exit 1 } - # 检查并执行 release.sh - if [ -f "release.sh" ]; then - # 添加执行权限 - chmod +x release.sh - echo " 已为 release.sh 添加执行权限" - - # 执行脚本 - echo " 正在执行 release.sh..." - ./release.sh - if [ $? -eq 0 ]; then - echo -e " ${GREEN}release.sh 执行成功${NC}" - else - echo -e " ${RED}release.sh 执行失败!${NC}" - exit 1 - fi + # 遍历所有镜像文件(支持.tar和.tar.gz格式) + image_files=$(find . -type f -name "*.tar" -o -name "*.tar.gz") + if [ -z "$image_files" ]; then + echo -e "${YELLOW}警告:$IMAGES_DIR 目录下未找到镜像文件${NC}" else - echo -e "${YELLOW} 警告:目录 $dir_name 中未找到 release.sh,已跳过${NC}" + for file in $image_files; do + echo "处理镜像文件:$file" + + # 临时加载镜像并获取输出(修复判断逻辑) + temp_load_output=$(docker load -i "$file" 2>&1) + # 检查临时加载是否成功(通过返回码判断,而非输出内容) + if [ $? -ne 0 ]; then + echo -e " ${RED}临时加载镜像 $file 失败:$temp_load_output${NC}" + exit 1 + fi + + # 从输出中提取镜像ID(兼容不同格式的输出) + temp_image_id=$(echo "$temp_load_output" | awk '/Loaded image ID: / {print $4}') + # 如果未提取到ID,尝试从"Loaded image: 镜像名:标签"中获取标签 + if [ -z "$temp_image_id" ]; then + image_tag=$(echo "$temp_load_output" | awk '/Loaded image: / {print $3}') + if [ -n "$image_tag" ]; then + temp_image_id=$(docker images --format '{{.ID}}' "$image_tag" | head -n 1) + fi + fi + + # 再次检查是否获取到镜像ID + if [ -z "$temp_image_id" ]; then + echo -e " ${RED}无法获取镜像 $file 的ID,加载失败${NC}" + exit 1 + fi + + # 获取镜像标签 + image_tags=$(docker image inspect --format '{{range .RepoTags}}{{.}} {{end}}' "$temp_image_id") + if [ -z "$image_tags" ]; then + echo -e " ${YELLOW}警告:镜像 $file 没有标签信息,直接删除临时镜像${NC}" + docker rmi -f "$temp_image_id" >/dev/null 2>&1 + else + # 先删除已存在的同名标签镜像 + for tag in $image_tags; do + if docker images --format '{{.Repository}}:{{.Tag}}' | grep -q "^$tag$"; then + echo " 发现已存在镜像 $tag,正在删除..." + if docker rmi -f "$tag" >/dev/null 2>&1; then + echo -e " ${GREEN}成功删除镜像 $tag${NC}" + else + echo -e " ${RED}删除镜像 $tag 失败!${NC}" + exit 1 + fi + fi + done + + # 删除临时加载的镜像 + docker rmi -f "$temp_image_id" >/dev/null 2>&1 + fi + + # 正式加载镜像 + echo " 正在加载镜像:$file" + load_output=$(docker load -i "$file" 2>&1) + if [ $? -eq 0 ]; then + echo -e " ${GREEN}镜像 $file 加载成功:$load_output${NC}" + else + echo -e " ${RED}镜像 $file 加载失败:$load_output${NC}" + exit 1 + fi + done fi - # 返回上级目录,继续处理其他目录 + # 返回根目录 cd .. || { - echo -e "${RED} 错误:无法返回上级目录${NC}" + echo -e "${RED}错误:无法返回根目录${NC}" exit 1 } -done +else + echo -e "${RED}错误:未找到 $IMAGES_DIR 目录${NC}" + exit 1 +fi -# 步骤4:启动新的 docker-compose 编排 -echo -e "\n${YELLOW}===== 第三步:启动新的 docker-compose 服务 ====="${NC} -if [ -f "./docker-compose.yaml" ]; then +# 步骤3:启动指定名称的docker-compose编排 +echo -e "\n${YELLOW}===== 第三步:启动编排名称为 $COMPOSE_PROJECT_NAME 的服务 ====="${NC} +if [ -f "$DOCKER_COMPOSE_FILE" ]; then echo "正在启动服务..." - docker-compose -f ./docker-compose.yaml up -d + docker-compose -f "$DOCKER_COMPOSE_FILE" -p "$COMPOSE_PROJECT_NAME" up -d if [ $? -eq 0 ]; then - echo -e "${GREEN}docker-compose 服务启动成功!${NC}" + echo -e "${GREEN}编排 $COMPOSE_PROJECT_NAME 启动成功!${NC}" else - echo -e "${RED}启动 docker-compose 服务失败!${NC}" + echo -e "${RED}启动编排 $COMPOSE_PROJECT_NAME 失败!${NC}" exit 1 fi else - echo -e "${RED}错误:未找到当前目录下的 docker-compose.yaml 文件${NC}" + echo -e "${RED}错误:未找到 $DOCKER_COMPOSE_FILE 文件${NC}" exit 1 fi diff --git a/deploy/docker-compose.yaml b/deploy/docker-compose.yaml new file mode 100644 index 0000000..d963c70 --- /dev/null +++ b/deploy/docker-compose.yaml @@ -0,0 +1,122 @@ +services: + pgadmin: + image: dpage/pgadmin4:9.5.0 + container_name: user_pgadmin + ports: + - 20001:80 + environment: + PGADMIN_DEFAULT_EMAIL: ${PGADMIN_EMAIL} + PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_PASSWORD} + TZ: ${TZ} + volumes: + - ./shared_data/data4pgadmin:/var/lib/pgadmin + networks: + - user-network + depends_on: + - postgres + postgres: + image: postgres:17.4-alpine + container_name: user_db + restart: always + entrypoint: + - /scripts/db-lanuch-entrypoint.sh + environment: + POSTGRES_USER: ${DB_USER} + POSTGRES_PASSWORD: ${DB_PASSWORD} + POSTGRES_DB: ${DB_NAME} + TZ: ${TZ} + volumes: + - ./shared_data/user_db:/var/lib/postgresql/data + - ./sql:/docker-entrypoint-initdb.d + - ./scripts:/scripts + networks: + - user-network + user_login: + image: user-login-api:1.0.0 + container_name: api_user_login + restart: always + depends_on: + - postgres + networks: + - user-network + environment: + DB_HOST: postgres + DB_PORT: ${DB_PORT} + DB_USER: ${DB_USER} + DB_PASSWORD: ${DB_PASSWORD} + DB_NAME: ${DB_NAME} + TZ: ${TZ} + user_update_account: + image: user-update-account-api:1.0.0 + container_name: api_user_update_account + restart: always + depends_on: + - postgres + networks: + - user-network + environment: + DB_HOST: postgres + DB_PORT: ${DB_PORT} + DB_USER: ${DB_USER} + DB_PASSWORD: ${DB_PASSWORD} + DB_NAME: ${DB_NAME} + TZ: ${TZ} + user_gateway: + image: user-gateway-api:1.0.0 + container_name: api_user_gateway + restart: always + ports: + - 20000:80 + networks: + - user-network + environment: + GATEWAY_PORT: ${GATEWAY_PORT} + user_update_password: + image: user-update-password-api:1.0.0 + container_name: api_user_update_password + restart: always + depends_on: + - postgres + networks: + - user-network + environment: + DB_HOST: postgres + DB_PORT: ${DB_PORT} + DB_USER: ${DB_USER} + DB_PASSWORD: ${DB_PASSWORD} + DB_NAME: ${DB_NAME} + TZ: ${TZ} + user_register: + image: user-register-api:1.0.0 + container_name: api_user_register + restart: always + depends_on: + - postgres + networks: + - user-network + environment: + DB_HOST: postgres + DB_PORT: ${DB_PORT} + DB_USER: ${DB_USER} + DB_PASSWORD: ${DB_PASSWORD} + DB_NAME: ${DB_NAME} + TZ: ${TZ} + user_delete: + image: user-delete-api:1.0.0 + container_name: api_user_delete + restart: always + depends_on: + - postgres + networks: + - user-network + environment: + DB_HOST: postgres + DB_PORT: ${DB_PORT} + DB_USER: ${DB_USER} + DB_PASSWORD: ${DB_PASSWORD} + DB_NAME: ${DB_NAME} + TZ: ${TZ} +networks: + user-network: + driver: bridge +volumes: {} diff --git a/deploy/images/user-delete-api-1.0.0.tar b/deploy/images/user-delete-api-1.0.0.tar new file mode 100644 index 0000000..0e372c9 Binary files /dev/null and b/deploy/images/user-delete-api-1.0.0.tar differ diff --git a/deploy/images/user-gateway-api-1.0.0.tar b/deploy/images/user-gateway-api-1.0.0.tar new file mode 100644 index 0000000..0f86629 Binary files /dev/null and b/deploy/images/user-gateway-api-1.0.0.tar differ diff --git a/deploy/images/user-login-api-1.0.0.tar b/deploy/images/user-login-api-1.0.0.tar new file mode 100644 index 0000000..7f66e9b Binary files /dev/null and b/deploy/images/user-login-api-1.0.0.tar differ diff --git a/deploy/images/user-register-api-1.0.0.tar b/deploy/images/user-register-api-1.0.0.tar new file mode 100644 index 0000000..2048068 Binary files /dev/null and b/deploy/images/user-register-api-1.0.0.tar differ diff --git a/deploy/images/user-update-account-api-1.0.0.tar b/deploy/images/user-update-account-api-1.0.0.tar new file mode 100644 index 0000000..dd603eb Binary files /dev/null and b/deploy/images/user-update-account-api-1.0.0.tar differ diff --git a/deploy/images/user-update-password-api-1.0.0.tar b/deploy/images/user-update-password-api-1.0.0.tar new file mode 100644 index 0000000..180aeda Binary files /dev/null and b/deploy/images/user-update-password-api-1.0.0.tar differ diff --git a/docker-compose.yaml b/docker-compose.yaml index 9e62f6d..970fad2 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,5 +1,20 @@ version: '3.8' services: + pgadmin: + image: dpage/pgadmin4:9.5.0 + container_name: user_pgadmin + ports: + - 20001:80 + environment: + PGADMIN_DEFAULT_EMAIL: ${PGADMIN_EMAIL} + PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_PASSWORD} + TZ: ${TZ} + volumes: + - ./shared_data/data4pgadmin:/var/lib/pgadmin + networks: + - user-network + depends_on: + - postgres postgres: image: postgres:17.4-alpine container_name: user_db @@ -17,36 +32,6 @@ services: - ./scripts:/scripts networks: - user-network - pgadmin: - image: dpage/pgadmin4:9.5.0 - container_name: user_pgadmin - ports: - - 20001:80 - environment: - PGADMIN_DEFAULT_EMAIL: ${PGADMIN_EMAIL} - PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_PASSWORD} - TZ: ${TZ} - volumes: - - ./shared_data/data4pgadmin:/var/lib/pgadmin - networks: - - user-network - depends_on: - - postgres - user_delete: - image: user-delete-api:1.0.0 - container_name: api_user_delete - restart: always - depends_on: - - postgres - networks: - - user-network - environment: - DB_HOST: postgres - DB_PORT: ${DB_PORT} - DB_USER: ${DB_USER} - DB_PASSWORD: ${DB_PASSWORD} - DB_NAME: ${DB_NAME} - TZ: ${TZ} user_login: image: user-login-api:1.0.0 container_name: api_user_login @@ -62,6 +47,31 @@ services: DB_PASSWORD: ${DB_PASSWORD} DB_NAME: ${DB_NAME} TZ: ${TZ} + user_update_account: + image: user-update-account-api:1.0.0 + container_name: api_user_update_account + restart: always + depends_on: + - postgres + networks: + - user-network + environment: + DB_HOST: postgres + DB_PORT: ${DB_PORT} + DB_USER: ${DB_USER} + DB_PASSWORD: ${DB_PASSWORD} + DB_NAME: ${DB_NAME} + TZ: ${TZ} + user_gateway: + image: user-gateway-api:1.0.0 + container_name: api_user_gateway + restart: always + ports: + - 20000:80 + networks: + - user-network + environment: + GATEWAY_PORT: ${GATEWAY_PORT} user_update_password: image: user-update-password-api:1.0.0 container_name: api_user_update_password @@ -92,19 +102,9 @@ services: DB_PASSWORD: ${DB_PASSWORD} DB_NAME: ${DB_NAME} TZ: ${TZ} - user_gateway: - image: user-gateway-api:1.0.0 - container_name: api_user_gateway - restart: always - ports: - - 20000:80 - networks: - - user-network - environment: - GATEWAY_PORT: ${GATEWAY_PORT} - user_update_account: - image: user-update-account-api:1.0.0 - container_name: api_user_update_account + user_delete: + image: user-delete-api:1.0.0 + container_name: api_user_delete restart: always depends_on: - postgres