更新小程序配置,切换 API 地址为本地开发环境。新增会员详情页面的头像逻辑,确保用户信息展示一致性。优化多个页面的交互提示,提升用户体验。调整图标组件,更新图标映射以支持新样式。
This commit is contained in:
@@ -3,10 +3,18 @@
|
||||
"""
|
||||
soul-api 一键部署到宝塔【测试环境】
|
||||
|
||||
打包原则:优先使用本地已有资源,不边打包边下载(省时)。
|
||||
- 默认:本地 go build → Dockerfile.local 打镜像(--pull=false 不拉 base 镜像)
|
||||
- 首次部署前请本地先拉好:alpine:3.19、redis:7-alpine,后续一律用本地缓存
|
||||
|
||||
两种模式均部署到测试环境 /www/wwwroot/self/soul-dev:
|
||||
|
||||
- binary:Go 二进制 + 宝塔 soulDev 项目,用 .env.development
|
||||
- docker:Docker 镜像 + 蓝绿无缝切换,用 .env.development 打包进镜像
|
||||
- docker(默认):本地 go build → Dockerfile.local 打镜像 → 蓝绿无缝切换
|
||||
- 镜像内包含:二进制、soul-api/certs/ → /app/certs/、选定环境文件 → /app/.env
|
||||
- 环境文件:--env-file 或 DOCKER_ENV_FILE,否则自动 .env.development > .env.production > .env(.dockerignore 已放行)
|
||||
- 不加 --docker-in-go 时:本地 Go 编译 + 本地 base 镜像,不联网
|
||||
- 加 --docker-in-go 时:在 Docker 内用 golang 镜像编译(需本地已有 golang:1.25)
|
||||
|
||||
环境变量:DEPLOY_DOCKER_PATH、DEPLOY_NGINX_CONF、DEPLOY_HOST 等
|
||||
"""
|
||||
@@ -117,7 +125,7 @@ def run_build(root):
|
||||
|
||||
# ==================== 打包 ====================
|
||||
|
||||
DEPLOY_PORT = 8081
|
||||
DEPLOY_PORT = 9001
|
||||
|
||||
|
||||
def set_env_port(env_path, port=DEPLOY_PORT):
|
||||
@@ -163,22 +171,32 @@ def set_env_mini_program_state(env_path, state):
|
||||
f.writelines(new_lines)
|
||||
|
||||
|
||||
def resolve_binary_pack_env_src(root):
|
||||
"""binary 模式 tar 包内 .env 的来源,与 Docker 自动优先级一致。"""
|
||||
for name in (".env.development", ".env.production", ".env"):
|
||||
p = os.path.join(root, name)
|
||||
if os.path.isfile(p):
|
||||
return p, name
|
||||
return None, None
|
||||
|
||||
|
||||
def pack_deploy(root, binary_path, include_env=True):
|
||||
"""打包二进制和 .env 为 tar.gz"""
|
||||
print("[2/4] 打包部署文件 ...")
|
||||
staging = tempfile.mkdtemp(prefix="soul_api_deploy_")
|
||||
try:
|
||||
shutil.copy2(binary_path, os.path.join(staging, "soul-api"))
|
||||
env_src = os.path.join(root, ".env.development")
|
||||
staging_env = os.path.join(staging, ".env")
|
||||
if include_env and os.path.isfile(env_src):
|
||||
shutil.copy2(env_src, staging_env)
|
||||
print(" [已包含] .env.development -> .env")
|
||||
else:
|
||||
env_example = os.path.join(root, ".env.example")
|
||||
if os.path.isfile(env_example):
|
||||
shutil.copy2(env_example, staging_env)
|
||||
print(" [已包含] .env.example -> .env (请服务器上检查配置)")
|
||||
if include_env:
|
||||
env_src, env_label = resolve_binary_pack_env_src(root)
|
||||
if env_src:
|
||||
shutil.copy2(env_src, staging_env)
|
||||
print(" [已包含] %s -> .env" % env_label)
|
||||
else:
|
||||
env_example = os.path.join(root, ".env.example")
|
||||
if os.path.isfile(env_example):
|
||||
shutil.copy2(env_example, staging_env)
|
||||
print(" [已包含] .env.example -> .env (请服务器上检查配置)")
|
||||
if os.path.isfile(staging_env):
|
||||
set_env_port(staging_env, DEPLOY_PORT)
|
||||
set_env_mini_program_state(staging_env, "developer")
|
||||
@@ -392,6 +410,37 @@ def deploy_nginx_via_bt_api(cfg, nginx_conf_path, new_port):
|
||||
# ==================== Docker 部署(蓝绿无缝切换) ====================
|
||||
|
||||
|
||||
def resolve_docker_env_file(root, explicit=None):
|
||||
"""
|
||||
选择打入镜像的环境文件(相对 soul-api 根目录,须能被 Docker 构建上下文包含)。
|
||||
Dockerfile: COPY ${ENV_FILE} /app/.env;certs/ 由 COPY certs/ 一并打入。
|
||||
优先级:explicit → DOCKER_ENV_FILE → 自动 .env.development > .env.production > .env(与测试环境默认一致)
|
||||
"""
|
||||
if explicit:
|
||||
name = os.path.basename(explicit.replace("\\", "/"))
|
||||
path = os.path.join(root, name)
|
||||
if os.path.isfile(path):
|
||||
print(" [镜像配置] 打入镜像的环境文件: %s(--env-file)" % name)
|
||||
return name
|
||||
print(" [失败] --env-file 不存在: %s" % path)
|
||||
return None
|
||||
override = (os.environ.get("DOCKER_ENV_FILE") or "").strip()
|
||||
if override:
|
||||
name = os.path.basename(override.replace("\\", "/"))
|
||||
path = os.path.join(root, name)
|
||||
if os.path.isfile(path):
|
||||
print(" [镜像配置] 打入镜像的环境文件: %s(DOCKER_ENV_FILE)" % name)
|
||||
return name
|
||||
print(" [失败] DOCKER_ENV_FILE 指向的文件不存在: %s" % path)
|
||||
return None
|
||||
for name in (".env.development", ".env.production", ".env"):
|
||||
if os.path.isfile(os.path.join(root, name)):
|
||||
print(" [镜像配置] 打入镜像的环境文件: %s(自动选择)" % name)
|
||||
return name
|
||||
print(" [失败] 未找到 .env.development / .env.production / .env,无法 COPY 进镜像")
|
||||
return None
|
||||
|
||||
|
||||
def run_docker_build(root, env_file=".env.development"):
|
||||
"""本地构建 Docker 镜像(使用 Docker 内的 golang 镜像)"""
|
||||
print("[1/5] 构建 Docker 镜像 ...(进度见下方 Docker 输出)")
|
||||
@@ -415,14 +464,14 @@ def run_docker_build(root, env_file=".env.development"):
|
||||
|
||||
|
||||
def run_docker_build_local(root, env_file=".env.development"):
|
||||
"""使用本地 Go 交叉编译后构建 Docker 镜像(不拉取 golang 镜像)"""
|
||||
"""使用本地 Go 交叉编译后构建 Docker 镜像(不拉取 golang 镜像,--pull=false 不拉 base 镜像)"""
|
||||
print("[1/5] 使用本地 Go 交叉编译 ...")
|
||||
binary_path = run_build(root)
|
||||
if not binary_path:
|
||||
return None
|
||||
print("[2/5] 使用 Dockerfile.local 构建镜像 ...(进度见下方 Docker 输出)")
|
||||
print("[2/5] 使用 Dockerfile.local 构建镜像 ...(--pull=false 仅用本地缓存)")
|
||||
try:
|
||||
cmd = ["docker", "build", "-f", "deploy/Dockerfile.local", "-t", "soul-api:latest",
|
||||
cmd = ["docker", "build", "--pull=false", "-f", "deploy/Dockerfile.local", "-t", "soul-api:latest",
|
||||
"--build-arg", "ENV_FILE=%s" % env_file, "--progress=plain", "."]
|
||||
r = subprocess.run(cmd, cwd=root, shell=False, timeout=120)
|
||||
if r.returncode != 0:
|
||||
@@ -444,7 +493,7 @@ def run_docker_build_local(root, env_file=".env.development"):
|
||||
def pack_docker_image(root):
|
||||
"""将 soul-api 与 redis 镜像一并导出为 tar.gz,服务器无需拉取"""
|
||||
import gzip
|
||||
print("[2/5] 导出镜像为 tar.gz(soul-api + redis)...")
|
||||
print("[3/5] 导出镜像为 tar.gz(soul-api + redis)...")
|
||||
out_tar = os.path.join(tempfile.gettempdir(), "soul_api_image.tar.gz")
|
||||
try:
|
||||
r = subprocess.run(
|
||||
@@ -479,7 +528,7 @@ def upload_and_deploy_docker(cfg, image_tar_path, include_env=True, deploy_metho
|
||||
nginx_conf = os.environ.get("DEPLOY_NGINX_CONF", DEPLOY_NGINX_CONF)
|
||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
print("[3/5] SSH 上传镜像与配置 ...")
|
||||
print("[4/5] SSH 上传镜像与配置 ...")
|
||||
if not cfg.get("password") and not cfg.get("ssh_key"):
|
||||
print(" [失败] 请设置 DEPLOY_PASSWORD 或 DEPLOY_SSH_KEY")
|
||||
return False
|
||||
@@ -506,9 +555,11 @@ def upload_and_deploy_docker(cfg, image_tar_path, include_env=True, deploy_metho
|
||||
if os.path.isfile(deploy_local):
|
||||
sftp.put(deploy_local, deploy_path + "/docker-deploy-remote.sh")
|
||||
print(" [已上传] docker-deploy-remote.sh")
|
||||
# 注意:docker-compose.bluegreen.yml 未配置 env_file,容器实际以镜像内 /app/.env 为准;
|
||||
# 此处上传仅供服务器目录备份或手工改 compose 后使用。
|
||||
if include_env and os.path.isfile(env_local):
|
||||
sftp.put(env_local, deploy_path.rstrip("/") + "/.env")
|
||||
print(" [已上传] .env.production -> .env(覆盖镜像内配置)")
|
||||
print(" [已上传] .env.production -> 服务器 %s/.env(可选;默认不挂载进容器)" % deploy_path.rstrip("/"))
|
||||
|
||||
# btapi 模式:需先读取 .active 计算新端口,脚本内跳过 Nginx
|
||||
current_active = "blue"
|
||||
@@ -523,7 +574,7 @@ def upload_and_deploy_docker(cfg, image_tar_path, include_env=True, deploy_metho
|
||||
|
||||
sftp.close()
|
||||
|
||||
print("[4/5] 执行蓝绿部署 ...")
|
||||
print("[5/5] 执行蓝绿部署 ...")
|
||||
env_exports = ""
|
||||
if nginx_conf:
|
||||
env_exports += "export DEPLOY_NGINX_CONF='%s'; " % nginx_conf.replace("'", "'\\''")
|
||||
@@ -546,12 +597,12 @@ def upload_and_deploy_docker(cfg, image_tar_path, include_env=True, deploy_metho
|
||||
# btapi 模式:通过宝塔 API 更新 Nginx 配置并重载(new_port 已在上方计算)
|
||||
if deploy_method == "btapi" and nginx_conf:
|
||||
try:
|
||||
print("[5/5] 宝塔 API 更新 Nginx ...")
|
||||
print(" [宝塔 API] 更新 Nginx ...")
|
||||
deploy_nginx_via_bt_api(cfg, nginx_conf, new_port)
|
||||
except Exception as e:
|
||||
print(" [警告] 宝塔 Nginx API 失败:", str(e))
|
||||
|
||||
print("[5/5] 部署完成,蓝绿无缝切换")
|
||||
print(" 部署完成,蓝绿无缝切换")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(" [失败] SSH 错误:", str(e))
|
||||
@@ -568,14 +619,17 @@ def main():
|
||||
parser.add_argument("--mode", choices=("binary", "docker"), default="docker",
|
||||
help="docker=Docker 蓝绿部署 (默认), binary=Go 二进制")
|
||||
parser.add_argument("--no-build", action="store_true", help="跳过本地编译/构建")
|
||||
parser.add_argument("--no-env", action="store_true", help="不打包 .env")
|
||||
parser.add_argument("--no-env", action="store_true",
|
||||
help="binary: 不打进 tar;docker: 不上传服务器目录 .env.production(镜像内配置不变)")
|
||||
parser.add_argument("--no-restart", action="store_true", help="[binary] 上传后不重启")
|
||||
parser.add_argument("--restart-method", choices=("auto", "btapi", "ssh"), default="auto",
|
||||
help="[binary] 重启方式: auto/btapi/ssh")
|
||||
parser.add_argument("--local-go", action="store_true",
|
||||
help="[docker] 使用本地 Go 交叉编译后打镜像,不拉取 golang 镜像")
|
||||
parser.add_argument("--docker-in-go", action="store_true",
|
||||
help="[docker] 在 Docker 内用 golang 镜像编译(默认:本地 go build → 再打镜像)")
|
||||
parser.add_argument("--deploy-method", choices=("ssh", "btapi"), default="ssh",
|
||||
help="[docker] 部署方式: ssh=脚本内 Nginx 切换, btapi=宝塔 API 更新 Nginx 配置并重载 (默认 ssh)")
|
||||
parser.add_argument("--env-file", default=None, metavar="NAME",
|
||||
help="[docker] 打入镜像的环境文件名(默认自动:.env.development > .env.production > .env)")
|
||||
args = parser.parse_args()
|
||||
|
||||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||||
@@ -592,11 +646,19 @@ def main():
|
||||
print("=" * 60)
|
||||
|
||||
if not args.no_build:
|
||||
ok = run_docker_build_local(root) if args.local_go else run_docker_build(root)
|
||||
env_for_image = resolve_docker_env_file(root, explicit=args.env_file)
|
||||
if env_for_image is None:
|
||||
return 1
|
||||
# 默认:本地 go build → Dockerfile.local 打镜像;--docker-in-go 时在容器内编译
|
||||
ok = (
|
||||
run_docker_build(root, env_file=env_for_image)
|
||||
if args.docker_in_go
|
||||
else run_docker_build_local(root, env_file=env_for_image)
|
||||
)
|
||||
if not ok:
|
||||
return 1
|
||||
else:
|
||||
print("[1/5] 跳过构建,使用现有 soul-api:latest")
|
||||
print("[1/5] 跳过构建,使用现有 soul-api:latest(无需本地环境文件)")
|
||||
|
||||
image_tar = pack_docker_image(root)
|
||||
if not image_tar:
|
||||
|
||||
Reference in New Issue
Block a user