chore: prepare repository for submodule split
This commit is contained in:
@@ -18,12 +18,21 @@ CORS_ALLOW_ORIGINS=*
|
||||
TARGET_PLATFORM=windows
|
||||
TARGET_ARCH=x64
|
||||
|
||||
# 业务主程序文件名。必须和你发布目录根级的主 exe 名称一致。
|
||||
RELEASE_MAIN_EXECUTABLE=SimCAE.exe
|
||||
# 业务主程序相对发布根目录的路径。SimCAE 默认在 bin/SimCAE.exe。
|
||||
RELEASE_MAIN_EXECUTABLE=bin/SimCAE.exe
|
||||
|
||||
# Manifest 签名密钥编号。通常不用改,换签名密钥体系时再改。
|
||||
SIGNING_KEY_ID=manifest-key-v1
|
||||
|
||||
# 发布新版本保护。超过上限会直接拒绝,避免大目录上传把服务器磁盘或内存拖死。
|
||||
# 如果你的正式发布包超过 4GB,可以按服务器磁盘空间调大。
|
||||
PUBLISH_MAX_REQUEST_MB=4096
|
||||
PUBLISH_MAX_FILES=20000
|
||||
# 通常不用改;每个上传文件还会带一个 relative_paths 字段,所以要大于 PUBLISH_MAX_FILES。
|
||||
PUBLISH_MAX_FIELDS=20100
|
||||
# 上传时额外保留的磁盘空间,单位 MB。通常不用改。
|
||||
UPLOAD_SPACE_RESERVE_MB=256
|
||||
|
||||
# 客户端访问服务端 API 的令牌。已给默认值,可直接试跑;正式部署建议修改,并填到客户端 app_config.json 的 client_token。
|
||||
CLIENT_API_TOKEN=SimCAEClientToken2026
|
||||
|
||||
|
||||
+9
-2
@@ -6,11 +6,11 @@ SERVER_PORT=8000
|
||||
APP_UID=1000
|
||||
APP_GID=1000
|
||||
SERVICE_TITLE=Software Update Service
|
||||
ADMIN_HTML_PATH=../client/admin.html
|
||||
ADMIN_HTML_PATH=admin.html
|
||||
CORS_ALLOW_ORIGINS=*
|
||||
TARGET_PLATFORM=windows
|
||||
TARGET_ARCH=x64
|
||||
RELEASE_MAIN_EXECUTABLE=MainApp.exe
|
||||
RELEASE_MAIN_EXECUTABLE=bin/SimCAE.exe
|
||||
SIGNING_KEY_ID=manifest-key-v1
|
||||
|
||||
# 客户端访问服务端 API 的令牌。已给默认值,可直接试跑;正式部署建议修改,并填到客户端 app_config.json 的 client_token。
|
||||
@@ -27,6 +27,13 @@ MANIFEST_PRIVATE_KEY_PATH=keys/manifest_private_key.pem
|
||||
# 上传暂存和本地兜底存储目录。通常不用改。
|
||||
UPLOAD_SPOOL_DIR=upload_spool
|
||||
UPLOAD_SPACE_RESERVE_MB=256
|
||||
|
||||
# 发布新版本保护。超过上限会直接拒绝,避免大目录上传把服务器磁盘或内存拖死。
|
||||
# 如果你的正式发布包超过 4GB,可以按服务器磁盘空间调大。
|
||||
PUBLISH_MAX_REQUEST_MB=4096
|
||||
PUBLISH_MAX_FILES=20000
|
||||
# 通常不用改;每个上传文件还会带一个 relative_paths 字段,所以要大于 PUBLISH_MAX_FILES。
|
||||
PUBLISH_MAX_FIELDS=20100
|
||||
LOCAL_UPLOAD_ROOT=local_uploads
|
||||
LOCAL_FILE_URL_BASE=http://127.0.0.1:8000/static
|
||||
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
# Operating systems and editors
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
Desktop.ini
|
||||
.vscode/
|
||||
.idea/
|
||||
|
||||
# Temporary files
|
||||
*.tmp
|
||||
*.temp
|
||||
*.bak
|
||||
*.swp
|
||||
*.log
|
||||
*~
|
||||
|
||||
# Private requirement / handover documents
|
||||
*.doc
|
||||
*.docx
|
||||
*交付说明*.md
|
||||
|
||||
# Python environments and caches
|
||||
venv/
|
||||
.venv/
|
||||
__pycache__/
|
||||
**/__pycache__/
|
||||
*.py[cod]
|
||||
.pytest_cache/
|
||||
.mypy_cache/
|
||||
.ruff_cache/
|
||||
.coverage
|
||||
htmlcov/
|
||||
|
||||
# Local configuration and secrets
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
!.env.docker.example
|
||||
admin_token.sha256
|
||||
keys/*private*.pem
|
||||
keys/*private*.key
|
||||
|
||||
# Runtime databases, uploads, object storage and generated packages
|
||||
*.db
|
||||
*.db-journal
|
||||
*.db-wal
|
||||
*.db-shm
|
||||
local_uploads/
|
||||
upload_spool/
|
||||
crash_storage/
|
||||
minio_data/
|
||||
runtime/
|
||||
dist/
|
||||
minio
|
||||
|
||||
# Runtime files
|
||||
*.pid
|
||||
|
||||
# Docker/local generated files
|
||||
.dockerignore.local
|
||||
+4
-1
@@ -6,12 +6,15 @@ ENV PYTHONDONTWRITEBYTECODE=1 \
|
||||
WORKDIR /app
|
||||
|
||||
RUN addgroup --system updateapp && adduser --system --ingroup updateapp updateapp
|
||||
RUN apt-get update \
|
||||
&& apt-get install -y --no-install-recommends libarchive-tools \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY server/requirements.txt ./requirements.txt
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
COPY server/main.py server/db.py server/minio_tool.py server/tables.sql ./
|
||||
COPY --chown=updateapp:updateapp client/admin.html ./admin.html
|
||||
COPY --chown=updateapp:updateapp server/admin.html ./admin.html
|
||||
|
||||
RUN mkdir -p /data/uploads /data/upload_spool /run/secrets/update-keys \
|
||||
&& chown -R updateapp:updateapp /app /data \
|
||||
|
||||
+2428
File diff suppressed because it is too large
Load Diff
@@ -42,12 +42,13 @@ services:
|
||||
environment:
|
||||
SERVER_HOST: 0.0.0.0
|
||||
SERVER_PORT: 8000
|
||||
ENV_FILE_PATH: /app/.env
|
||||
DB_FILE: /data/mini.db
|
||||
SQL_FILE: /app/tables.sql
|
||||
ADMIN_HTML_PATH: /app/admin.html
|
||||
LOCAL_UPLOAD_ROOT: /data/uploads
|
||||
UPLOAD_SPOOL_DIR: /data/upload_spool
|
||||
MINIO_DATA_DIR: /data
|
||||
MINIO_DATA_DIR: /minio_data
|
||||
CRASH_STORAGE_ROOT: /data/crash_storage
|
||||
MANIFEST_PRIVATE_KEY_PATH: /run/secrets/update-keys/manifest_private_key.pem
|
||||
MINIO_ENDPOINT: minio:9000
|
||||
@@ -57,7 +58,9 @@ services:
|
||||
ports:
|
||||
- "${SERVER_PORT:-8000}:8000"
|
||||
volumes:
|
||||
- ./.env:/app/.env
|
||||
- ./runtime:/data
|
||||
- ./minio_data:/minio_data:ro
|
||||
- ./keys:/run/secrets/update-keys:ro
|
||||
depends_on:
|
||||
minio:
|
||||
|
||||
@@ -44,12 +44,13 @@ services:
|
||||
environment:
|
||||
SERVER_HOST: 0.0.0.0
|
||||
SERVER_PORT: 8000
|
||||
ENV_FILE_PATH: /app/.env
|
||||
DB_FILE: /data/mini.db
|
||||
SQL_FILE: /app/tables.sql
|
||||
ADMIN_HTML_PATH: /app/admin.html
|
||||
LOCAL_UPLOAD_ROOT: /data/uploads
|
||||
UPLOAD_SPOOL_DIR: /data/upload_spool
|
||||
MINIO_DATA_DIR: /data
|
||||
MINIO_DATA_DIR: /minio_data
|
||||
CRASH_STORAGE_ROOT: /data/crash_storage
|
||||
MANIFEST_PRIVATE_KEY_PATH: /run/secrets/update-keys/manifest_private_key.pem
|
||||
MINIO_ENDPOINT: minio:9000
|
||||
@@ -59,7 +60,9 @@ services:
|
||||
ports:
|
||||
- "${SERVER_PORT:-8000}:8000"
|
||||
volumes:
|
||||
- ./.env:/app/.env
|
||||
- ./runtime:/data
|
||||
- ./minio_data:/minio_data:ro
|
||||
- ./keys:/run/secrets/update-keys:ro
|
||||
depends_on:
|
||||
minio:
|
||||
|
||||
+749
-180
File diff suppressed because it is too large
Load Diff
@@ -105,6 +105,24 @@ def put_file(object_path: str, data: bytes, size: int):
|
||||
return {'storage': 'local', 'path': str(local_path)}
|
||||
|
||||
|
||||
|
||||
def put_file_stream(object_path: str, source, size: int):
|
||||
bucket = MINIO_BUCKET
|
||||
try:
|
||||
source.seek(0)
|
||||
mc.put_object(bucket, object_path, source, length=size)
|
||||
return {'storage': 'minio', 'path': object_path}
|
||||
except Exception as e:
|
||||
print(f"minio put_file_stream error: {e}")
|
||||
local_path = LOCAL_UPLOAD_ROOT / object_path
|
||||
local_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
source.seek(0)
|
||||
with open(local_path, 'wb') as target:
|
||||
shutil.copyfileobj(source, target, length=1024 * 1024)
|
||||
print(f"local fallback stored {local_path}")
|
||||
return {'storage': 'local', 'path': str(local_path)}
|
||||
|
||||
|
||||
def remove_prefix(prefix: str):
|
||||
bucket = MINIO_BUCKET
|
||||
try:
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
param(
|
||||
[string]$Version = "0.1.0",
|
||||
[string]$OutputDir = "$PSScriptRoot/dist/SimCAEServerDockerPackage",
|
||||
[switch]$SkipBuild,
|
||||
[switch]$SkipPull
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$serverDir = $PSScriptRoot
|
||||
$projectRoot = (Resolve-Path (Join-Path $serverDir "..")).Path
|
||||
$imageName = "simcae-update-server:$Version"
|
||||
$minioImage = "minio/minio:RELEASE.2025-04-22T22-12-26Z"
|
||||
$mcImage = "minio/mc:RELEASE.2025-04-16T18-13-26Z"
|
||||
$packageDir = $OutputDir
|
||||
$imagesDir = Join-Path $packageDir "images"
|
||||
$keysDir = Join-Path $packageDir "keys"
|
||||
$tarFile = Join-Path $imagesDir "simcae-server-all-images_$Version.tar"
|
||||
|
||||
function Require-File($path, $message) {
|
||||
if (-not (Test-Path $path)) { throw $message }
|
||||
}
|
||||
|
||||
Require-File (Join-Path $serverDir "Dockerfile") "server/Dockerfile is missing."
|
||||
Require-File (Join-Path $serverDir "docker-compose.image.yml") "server/docker-compose.image.yml is missing."
|
||||
Require-File (Join-Path $serverDir ".env.docker.example") "server/.env.docker.example is missing."
|
||||
Require-File (Join-Path $serverDir "keys/manifest_private_key.pem") "server/keys/manifest_private_key.pem is missing."
|
||||
Require-File (Join-Path $serverDir "keys/manifest_public_key.pem") "server/keys/manifest_public_key.pem is missing."
|
||||
|
||||
if (-not $SkipBuild) {
|
||||
docker build -t $imageName -f (Join-Path $serverDir "Dockerfile") $projectRoot
|
||||
}
|
||||
|
||||
if (-not $SkipPull) {
|
||||
docker pull $minioImage
|
||||
docker pull $mcImage
|
||||
}
|
||||
|
||||
if (Test-Path $packageDir) { Remove-Item $packageDir -Recurse -Force }
|
||||
New-Item $imagesDir,$keysDir -ItemType Directory -Force | Out-Null
|
||||
|
||||
Copy-Item (Join-Path $serverDir "docker-compose.image.yml") (Join-Path $packageDir "docker-compose.yml") -Force
|
||||
Copy-Item (Join-Path $serverDir ".env.docker.example") (Join-Path $packageDir ".env.example") -Force
|
||||
$readmeSource = Get-ChildItem $serverDir -File -Filter "*.md" | Where-Object {
|
||||
$_.Name -like "*Docker*.md"
|
||||
} | Select-Object -First 1
|
||||
if ($readmeSource) {
|
||||
Copy-Item $readmeSource.FullName (Join-Path $packageDir "README.md") -Force
|
||||
}
|
||||
Copy-Item (Join-Path $serverDir "keys/manifest_private_key.pem") (Join-Path $keysDir "manifest_private_key.pem") -Force
|
||||
Copy-Item (Join-Path $serverDir "keys/manifest_public_key.pem") (Join-Path $keysDir "manifest_public_key.pem") -Force
|
||||
|
||||
$quickReadme = @"
|
||||
# SimCAE Server Offline Docker Package
|
||||
|
||||
1. Copy this package to the target server and extract it.
|
||||
2. Run: ./load-images.ps1
|
||||
3. Edit .env and replace tokens, passwords, and SERVER_IP.
|
||||
4. Run: docker compose up -d
|
||||
5. Visit: http://SERVER_IP:8000/
|
||||
|
||||
Important: keys/manifest_private_key.pem is the server signing private key. Keep it secret.
|
||||
"@
|
||||
$readmePath = Join-Path $packageDir "README.md"
|
||||
if (Test-Path $readmePath) {
|
||||
$oldReadme = Get-Content $readmePath -Raw -Encoding UTF8
|
||||
Set-Content $readmePath ($quickReadme + "`n---`n`n" + $oldReadme) -Encoding UTF8
|
||||
} else {
|
||||
Set-Content $readmePath $quickReadme -Encoding UTF8
|
||||
}
|
||||
|
||||
@"
|
||||
`$ErrorActionPreference = "Stop"
|
||||
docker load -i .\images\simcae-server-all-images_$Version.tar
|
||||
if (-not (Test-Path .\.env)) {
|
||||
Copy-Item .\.env.example .\.env
|
||||
Write-Host "Created .env from .env.example. Edit .env before starting services."
|
||||
} else {
|
||||
Write-Host ".env already exists. Keeping existing file."
|
||||
}
|
||||
Write-Host "Next: edit .env, then run: docker compose up -d"
|
||||
"@ | Set-Content (Join-Path $packageDir "load-images.ps1") -Encoding UTF8
|
||||
|
||||
$envExamplePath = Join-Path $packageDir ".env.example"
|
||||
$envText = Get-Content $envExamplePath -Raw -Encoding UTF8
|
||||
$envText = $envText.Replace("SIMCAE_UPDATE_SERVER_IMAGE=simcae-update-server:0.1.0", "SIMCAE_UPDATE_SERVER_IMAGE=$imageName")
|
||||
Set-Content $envExamplePath $envText -Encoding UTF8
|
||||
|
||||
docker save -o $tarFile $imageName $minioImage $mcImage
|
||||
|
||||
Compress-Archive -Path (Join-Path $packageDir "*") -DestinationPath "$packageDir.zip" -CompressionLevel Optimal -Force
|
||||
|
||||
Write-Host "Offline package directory: $packageDir"
|
||||
Write-Host "Offline package zip: $packageDir.zip"
|
||||
Write-Host "Images tar: $tarFile"
|
||||
@@ -105,11 +105,15 @@ mkdir -p "$IMAGES_DIR" "$KEYS_DIR"
|
||||
|
||||
cp "$SCRIPT_DIR/docker-compose.image.yml" "$PACKAGE_DIR/docker-compose.yml"
|
||||
cp "$SCRIPT_DIR/.env.docker.example" "$PACKAGE_DIR/.env.example"
|
||||
cp "$SCRIPT_DIR/keys/manifest_private_key.pem" "$KEYS_DIR/manifest_private_key.pem"
|
||||
cp "$SCRIPT_DIR/keys/manifest_public_key.pem" "$KEYS_DIR/manifest_public_key.pem"
|
||||
|
||||
cat > "$PACKAGE_DIR/README.md" <<'EOF_README'
|
||||
# SimCAE 服务端 Docker 部署包说明
|
||||
|
||||
这个包已经包含服务端运行需要的 Docker 镜像、配置模板、签名密钥和编排文件。你的服务器无论能不能联网,都可以按下面流程部署。
|
||||
这个包用于把 SimCAE 自动升级服务端部署到你的服务器。包里已经包含后端 API、MinIO 对象存储、初始化工具、配置模板、签名密钥和 Docker 编排文件;你的服务器即使不能联网,也可以按本文完成部署。
|
||||
|
||||
如果你只想先跑起来,按“二、最小部署流程”执行即可。后面的配置说明用于解释每个字段是什么意思、哪些必须改、哪些保持默认也能运行。
|
||||
|
||||
## 一、这个包里面有什么
|
||||
|
||||
@@ -122,13 +126,24 @@ SimCAEServerDockerPackage/
|
||||
.env.example 环境变量模板
|
||||
load-images.sh 导入 Docker 镜像并创建 .env 的脚本
|
||||
images/
|
||||
simcae-server-all-images___VERSION__.tar 三个 Docker 镜像:api、minio、minio-init
|
||||
simcae-server-all-images___VERSION__.tar Docker 镜像包,包含 api、minio、minio-init
|
||||
keys/
|
||||
manifest_private_key.pem 服务端 Manifest 签名私钥
|
||||
manifest_public_key.pem 与客户端配套的验签公钥
|
||||
```
|
||||
|
||||
## 二、你在服务器上怎么运行
|
||||
这些文件的关系可以这样理解:
|
||||
|
||||
```text
|
||||
images/*.tar 程序镜像包,相当于安装材料
|
||||
docker-compose.yml 容器部署图纸,说明启动哪些服务、端口怎么映射、目录怎么挂载
|
||||
.env 你的实际配置,第一次运行 load-images.sh 时由 .env.example 生成
|
||||
keys/ 发布版本时用于签名 Manifest,客户端用对应公钥验签
|
||||
runtime/ 启动后自动生成,保存服务端数据库、上传临时文件、崩溃报告等
|
||||
minio_data/ 启动后自动生成,保存升级包文件
|
||||
```
|
||||
|
||||
## 二、最小部署流程
|
||||
|
||||
先把 `SimCAEServerDockerPackage.tar.gz` 拷贝到要部署的 Ubuntu 服务器上,然后执行:
|
||||
|
||||
@@ -151,9 +166,7 @@ keys/
|
||||
|
||||
后面所有 `docker compose` 命令都要在这个目录执行,因为 `docker-compose.yml` 和 `.env` 都在这里。
|
||||
|
||||
## 三、导入镜像并生成 .env
|
||||
|
||||
在 `SimCAEServerDockerPackage` 目录执行:
|
||||
继续在 `SimCAEServerDockerPackage` 目录执行:
|
||||
|
||||
```bash
|
||||
bash ./load-images.sh
|
||||
@@ -164,71 +177,41 @@ bash ./load-images.sh
|
||||
```text
|
||||
1. docker load 导入 images/simcae-server-all-images___VERSION__.tar 里的镜像
|
||||
2. 如果当前目录没有 .env,就从 .env.example 复制一份 .env
|
||||
3. 自动创建 runtime/、minio_data/ 等运行目录,并尽量修正目录权限
|
||||
```
|
||||
|
||||
## 四、修改 .env
|
||||
|
||||
继续在 `SimCAEServerDockerPackage` 目录执行:
|
||||
然后修改 `.env`:
|
||||
|
||||
```bash
|
||||
nano .env
|
||||
```
|
||||
|
||||
`.env.example` 里已经填好一组可直接试跑的默认 token 和 MinIO 账号。你通常只需要先改服务器地址:
|
||||
最少只需要把 `MINIO_PUBLIC_ENDPOINT` 改成 Windows 客户端能访问到的服务器地址:
|
||||
|
||||
```text
|
||||
MINIO_PUBLIC_ENDPOINT=http://你的服务器IP:9000
|
||||
```
|
||||
|
||||
正式部署时,建议同时修改这些默认值,避免所有环境共用同一套公开示例密码:
|
||||
|
||||
```text
|
||||
CLIENT_API_TOKEN=客户端 API token,对应客户端 app_config.json 的 client_token
|
||||
ADMIN_TOKEN=后台管理员 token,网页登录时填这个值
|
||||
CRASH_REPORT_TOKEN=崩溃上传 token
|
||||
CRASH_SYMBOL_TOKEN=符号上传 token
|
||||
MINIO_ACCESS_KEY=MinIO 用户名
|
||||
MINIO_SECRET_KEY=MinIO 密码
|
||||
```
|
||||
|
||||
如果你在网页里点击“更改令牌”,新令牌只会在当前服务进程中立即生效。为了让服务重启后仍然使用新令牌,请同步修改 `.env` 里的 `ADMIN_TOKEN`,然后执行 `docker compose restart api`。
|
||||
|
||||
`MINIO_PUBLIC_ENDPOINT` 必须是 Windows 客户端能访问到的地址。比如服务器 IP 是 `192.168.229.128`,就填:
|
||||
例如服务器 IP 是 `192.168.229.128`:
|
||||
|
||||
```text
|
||||
MINIO_PUBLIC_ENDPOINT=http://192.168.229.128:9000
|
||||
```
|
||||
|
||||
## 五、启动服务
|
||||
|
||||
确认你仍然在 `SimCAEServerDockerPackage` 目录:
|
||||
|
||||
```bash
|
||||
pwd
|
||||
```
|
||||
|
||||
然后启动:
|
||||
启动服务:
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
如果提示 `docker: 'compose' is not a docker command`,说明服务器没有安装 Docker Compose plugin,需要先安装它。
|
||||
|
||||
## 六、查看状态和日志
|
||||
|
||||
这些命令也都在 `SimCAEServerDockerPackage` 目录执行:
|
||||
查看状态和后端日志:
|
||||
|
||||
```bash
|
||||
docker compose ps
|
||||
docker compose logs -f api
|
||||
```
|
||||
|
||||
正常情况下可以看到 `api`、`minio` 处于 running/healthy 状态。
|
||||
|
||||
## 七、访问地址
|
||||
|
||||
把下面的 `你的服务器IP` 换成真实服务器 IP:
|
||||
浏览器访问:
|
||||
|
||||
```text
|
||||
后台/API: http://你的服务器IP:8000/
|
||||
@@ -243,9 +226,228 @@ MinIO 控制台: http://你的服务器IP:9001/
|
||||
9001 MinIO 控制台,可选
|
||||
```
|
||||
|
||||
## 八、重要提醒
|
||||
## 三、.env 配置怎么填
|
||||
|
||||
`.env.example` 里已经给了一组能直接试跑的默认值。下面按重要程度说明。
|
||||
|
||||
### 必须确认或修改
|
||||
|
||||
| 字段 | 是否必填 | 默认能否直接用 | 怎么填 |
|
||||
| --- | --- | --- | --- |
|
||||
| `MINIO_PUBLIC_ENDPOINT` | 必填 | 不能直接用于正式环境 | 改成 Windows 客户端能访问到的 MinIO 地址,格式是 `http://服务器IP:9000`。客户端会用这个地址下载升级文件。 |
|
||||
| `SERVER_PORT` | 必填 | 可以 | 后台/API 端口,默认 `8000`。如果服务器 8000 被占用,可以改成其他端口。 |
|
||||
| `RELEASE_MAIN_EXECUTABLE` | 必填 | SimCAE 默认可以 | 发布包里主程序的相对路径。当前 SimCAE 发布根目录下主程序是 `bin/SimCAE.exe`,所以默认是这个。 |
|
||||
| `CLIENT_API_TOKEN` | 必填 | 可以 | 客户端访问服务端 API 的令牌。必须和客户端 `config/app_config.json` 里的 `client_token` 完全一致。 |
|
||||
| `ADMIN_TOKEN` | 必填 | 可以 | 管理后台登录令牌。网页登录时输入这个值。网页里“更改管理员令牌”成功后,会写回当前目录的 `.env`。 |
|
||||
| `MINIO_ACCESS_KEY` | 必填 | 可以 | MinIO 用户名。默认可试跑,正式环境建议改。 |
|
||||
| `MINIO_SECRET_KEY` | 必填 | 可以 | MinIO 密码。默认可试跑,正式环境建议改。 |
|
||||
|
||||
### 通常不用改
|
||||
|
||||
| 字段 | 作用 | 默认值说明 |
|
||||
| --- | --- | --- |
|
||||
| `SIMCAE_UPDATE_SERVER_IMAGE` | API 镜像名称 | 打包脚本会自动写成当前版本,例如 `simcae-update-server:__VERSION__`。 |
|
||||
| `APP_UID` / `APP_GID` | API 容器写入 `runtime/` 时使用的用户 ID | `load-images.sh` 会尽量自动改成当前服务器用户。遇到权限问题时再检查。 |
|
||||
| `SERVICE_TITLE` | 管理后台标题 | 默认 `SimCAE Update Service`。 |
|
||||
| `CORS_ALLOW_ORIGINS` | 跨域来源 | 内网部署保持 `*` 即可。 |
|
||||
| `TARGET_PLATFORM` / `TARGET_ARCH` | 发布包目标平台 | 当前客户端是 Windows x64,默认 `windows` / `x64`。 |
|
||||
| `SIGNING_KEY_ID` | Manifest 签名密钥编号 | 默认 `manifest-key-v1`。只有更换签名体系时才需要改。 |
|
||||
| `MINIO_API_PORT` | MinIO 文件下载端口 | 默认 `9000`。客户端下载升级文件要能访问这个端口。 |
|
||||
| `MINIO_CONSOLE_PORT` | MinIO 控制台端口 | 默认 `9001`。不需要控制台时可以不开放到外部。 |
|
||||
| `MINIO_BUCKET` | MinIO 存储桶名 | 默认 `updates`。 |
|
||||
| `SIGN_EXPIRE_MIN` | 升级文件下载链接有效期 | 默认 `60` 分钟。 |
|
||||
| `MINIO_CONNECT_TIMEOUT_SEC` / `MINIO_READ_TIMEOUT_SEC` / `MINIO_RETRY_TOTAL` / `MINIO_HEALTH_TIMEOUT_SEC` | MinIO 连接超时与重试 | 默认适合内网部署。 |
|
||||
|
||||
### 发布保护参数
|
||||
|
||||
这些字段用于防止上传超大目录导致服务器磁盘、内存压力过大。默认一般不用改。
|
||||
|
||||
| 字段 | 作用 | 默认值 |
|
||||
| --- | --- | --- |
|
||||
| `PUBLISH_MAX_REQUEST_MB` | 单次发布请求最大大小,单位 MB | `4096` |
|
||||
| `PUBLISH_MAX_FILES` | 单次发布最多文件数 | `20000` |
|
||||
| `PUBLISH_MAX_FIELDS` | 表单字段数上限,通常要大于文件数 | `20100` |
|
||||
| `UPLOAD_SPACE_RESERVE_MB` | 上传时额外保留的磁盘空间,单位 MB | `256` |
|
||||
|
||||
如果正式发布目录超过 4GB,可以在确认服务器磁盘空间足够后调大 `PUBLISH_MAX_REQUEST_MB`。如果页面提示空间不足,优先清理旧版本、扩容磁盘,或把服务端部署到更大的数据盘。
|
||||
|
||||
### 崩溃报告接口参数
|
||||
|
||||
| 字段 | 是否必填 | 默认能否直接用 | 怎么填 |
|
||||
| --- | --- | --- | --- |
|
||||
| `CRASH_SERVICE_VERSION` | 必填 | 可以 | 崩溃报告接口版本,默认 `1.0.0`。 |
|
||||
| `CRASH_REPORT_TOKEN` | 必填 | 可以 | 客户端上传崩溃报告时使用的令牌。正式环境建议改。 |
|
||||
| `CRASH_SYMBOL_TOKEN` | 必填 | 可以 | 上传符号文件时使用的令牌。正式环境建议改。 |
|
||||
| `CRASH_ADMIN_TOKEN` | 可不填 | 可以 | 崩溃报告管理令牌。不填时使用 `ADMIN_TOKEN`。 |
|
||||
| `CRASH_METADATA_MAX_KB` | 必填 | 可以 | 崩溃报告 metadata 最大大小。 |
|
||||
| `CRASH_MINIDUMP_MAX_MB` | 必填 | 可以 | minidump 最大大小。 |
|
||||
| `CRASH_ATTACHMENTS_MAX_MB` | 必填 | 可以 | 附件最大大小。 |
|
||||
| `CRASH_REQUEST_MAX_MB` | 必填 | 可以 | 崩溃报告完整请求最大大小。 |
|
||||
| `CRASH_SYMBOLS_MAX_MB` | 必填 | 可以 | 符号文件最大大小。 |
|
||||
|
||||
## 四、客户端配置要同步哪些值
|
||||
|
||||
客户端 `config/app_config.json` 至少要和服务端保持这两个值一致:
|
||||
|
||||
```json
|
||||
{
|
||||
"api_base_url": "http://你的服务器IP:8000",
|
||||
"client_token": "和服务端 CLIENT_API_TOKEN 一样"
|
||||
}
|
||||
```
|
||||
|
||||
如果服务端 `.env` 里保持默认:
|
||||
|
||||
```text
|
||||
CLIENT_API_TOKEN=SimCAEClientToken2026
|
||||
```
|
||||
|
||||
客户端就填:
|
||||
|
||||
```json
|
||||
"client_token": "SimCAEClientToken2026"
|
||||
```
|
||||
|
||||
`api_base_url` 是后端 API 地址,走 `SERVER_PORT`,不是 MinIO 地址。
|
||||
|
||||
## 五、发布新版本
|
||||
|
||||
进入后台后,“发布新版本”支持两种方式:
|
||||
|
||||
```text
|
||||
1. 选择软件发布根目录,例如 SimCAE 目录,目录内应包含 bin/SimCAE.exe
|
||||
2. 上传压缩发布包,支持 zip、tar.gz、tgz、tar.bz2、tbz2、rar
|
||||
```
|
||||
|
||||
压缩发布包上传到服务器后,服务端会先解压,再校验是否包含 `.env` 中 `RELEASE_MAIN_EXECUTABLE` 指定的主程序路径。当前默认是:
|
||||
|
||||
```text
|
||||
RELEASE_MAIN_EXECUTABLE=bin/SimCAE.exe
|
||||
```
|
||||
|
||||
`.rar` 需要服务器镜像内有 rar 解压工具。当前 Docker 镜像已内置 `bsdtar`;如果某些 rar 变体仍然解压失败,请改用 zip/tar.gz/tar.bz2,或在服务器镜像中补充 `unrar`/`7z`。
|
||||
|
||||
## 六、常用命令
|
||||
|
||||
确认你仍然在 `SimCAEServerDockerPackage` 目录:
|
||||
|
||||
```bash
|
||||
pwd
|
||||
```
|
||||
|
||||
启动:
|
||||
|
||||
```bash
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
查看状态:
|
||||
|
||||
```bash
|
||||
docker compose ps
|
||||
```
|
||||
|
||||
查看后端日志:
|
||||
|
||||
```bash
|
||||
docker compose logs -f api
|
||||
```
|
||||
|
||||
查看所有容器日志:
|
||||
|
||||
```bash
|
||||
docker compose logs -f
|
||||
```
|
||||
|
||||
重启后端:
|
||||
|
||||
```bash
|
||||
docker compose restart api
|
||||
```
|
||||
|
||||
停止服务:
|
||||
|
||||
```bash
|
||||
docker compose down
|
||||
```
|
||||
|
||||
如果提示 `docker: 'compose' is not a docker command`,说明服务器没有安装 Docker Compose plugin,需要先安装它。
|
||||
|
||||
## 七、数据、备份和迁移
|
||||
|
||||
运行后会生成这些目录或文件:
|
||||
|
||||
```text
|
||||
.env 当前服务器实际配置
|
||||
runtime/ 服务端数据库、上传临时目录、崩溃报告等
|
||||
minio_data/ MinIO 对象数据,也就是上传后的升级文件
|
||||
keys/ Manifest 签名密钥
|
||||
```
|
||||
|
||||
备份或迁移正式环境时,重点备份:
|
||||
|
||||
```text
|
||||
.env
|
||||
runtime/
|
||||
minio_data/
|
||||
keys/
|
||||
docker-compose.yml
|
||||
```
|
||||
|
||||
不要只备份容器。容器可以由镜像重新创建,真正重要的数据在上面这些挂载目录里。
|
||||
|
||||
## 八、常见问题
|
||||
|
||||
### 启动后看不到后端日志
|
||||
|
||||
`docker compose up -d` 是后台启动,不会持续打印日志。用下面命令看后端日志:
|
||||
|
||||
```bash
|
||||
docker compose logs -f api
|
||||
```
|
||||
|
||||
### API 容器反复重启,提示 Permission denied: '/data/uploads'
|
||||
|
||||
这是 `runtime/` 目录权限不对。进入 `SimCAEServerDockerPackage` 目录后执行:
|
||||
|
||||
```bash
|
||||
docker compose down
|
||||
mkdir -p runtime/uploads runtime/upload_spool runtime/crash_storage
|
||||
sudo chown -R $(id -u):$(id -g) runtime
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
### 网页能打开,但客户端提示令牌校验失败
|
||||
|
||||
检查客户端 `config/app_config.json`:
|
||||
|
||||
```json
|
||||
"client_token": "..."
|
||||
```
|
||||
|
||||
必须和服务端 `.env`:
|
||||
|
||||
```text
|
||||
CLIENT_API_TOKEN=...
|
||||
```
|
||||
|
||||
完全一致。
|
||||
|
||||
### 客户端能连 API,但下载升级文件失败
|
||||
|
||||
检查 `.env`:
|
||||
|
||||
```text
|
||||
MINIO_PUBLIC_ENDPOINT=http://你的服务器IP:9000
|
||||
```
|
||||
|
||||
这个地址必须从 Windows 客户端能访问。还要确认服务器防火墙放行了 `9000` 端口。
|
||||
|
||||
## 九、安全提醒
|
||||
|
||||
`keys/manifest_private_key.pem` 是服务端签 Manifest 的私钥,必须保护好。客户端 SDK 里的 `manifest_public_key.pem` 必须和这个私钥配套,否则客户端会 Manifest 验签失败。
|
||||
|
||||
默认 token 和默认 MinIO 密码可以直接试跑。正式部署建议改掉,避免多个环境共用同一套公开示例值。
|
||||
EOF_README
|
||||
|
||||
python3 - "$PACKAGE_DIR/README.md" "$VERSION" <<'PYREADME'
|
||||
@@ -264,10 +466,27 @@ set -euo pipefail
|
||||
docker load -i ./images/simcae-server-all-images_$VERSION.tar
|
||||
if [[ ! -f .env ]]; then
|
||||
cp .env.example .env
|
||||
sed -i "s/^APP_UID=.*/APP_UID=\$(id -u)/" .env
|
||||
sed -i "s/^APP_GID=.*/APP_GID=\$(id -g)/" .env
|
||||
echo "Created .env from .env.example. Edit .env before starting services."
|
||||
else
|
||||
echo ".env already exists. Keeping existing file."
|
||||
fi
|
||||
|
||||
APP_UID_VALUE="\$(grep -E '^APP_UID=' .env | tail -n 1 | cut -d= -f2-)"
|
||||
APP_GID_VALUE="\$(grep -E '^APP_GID=' .env | tail -n 1 | cut -d= -f2-)"
|
||||
APP_UID_VALUE="\${APP_UID_VALUE:-\$(id -u)}"
|
||||
APP_GID_VALUE="\${APP_GID_VALUE:-\$(id -g)}"
|
||||
|
||||
mkdir -p ./runtime/uploads ./runtime/upload_spool ./runtime/crash_storage ./minio_data
|
||||
|
||||
if [[ -w ./runtime ]]; then
|
||||
chown -R "\$APP_UID_VALUE:\$APP_GID_VALUE" ./runtime 2>/dev/null || true
|
||||
else
|
||||
echo "Warning: ./runtime is not writable by the current user."
|
||||
echo "Run: sudo chown -R \$APP_UID_VALUE:\$APP_GID_VALUE ./runtime"
|
||||
fi
|
||||
|
||||
echo "Next: edit .env, then run: docker compose up -d"
|
||||
EOF
|
||||
chmod +x "$PACKAGE_DIR/load-images.sh"
|
||||
|
||||
Reference in New Issue
Block a user