ow
This commit is contained in:
1 parent
53184877cd
commit
479762b57e
5 files changed
+457
-1
No files matched your search
@@ -0,0 +1,42 @@
|
||||
# 复制为 .env 后按需修改:cp .env.example .env
|
||||
# .env 会被 docker compose 自动读取,不要提交到公开仓库
|
||||
|
||||
# ============ 鉴权(三选一,推荐第 1 种) ============
|
||||
# 生成 token:openssl rand -hex 24 或 python -c "import secrets;print(secrets.token_urlsafe(32))"
|
||||
|
||||
# 1) 多 token(推荐):名称:token,名称2:token2
|
||||
# 每个调用方发一把,吊销时只删对应的那一段,不影响别人。
|
||||
# 日志里会打印调用方名称,方便排查是谁在调。
|
||||
API_TOKENS=frontend:c419f1c903ac03c4f4329f21a8f49af57118fc1bce6660f2,win-service:3444df79189bbf16e872d109c5d56bc7684e24645c39b416
|
||||
|
||||
# 2) 旧版单密钥(兼容保留,不推荐):所有调用方共用一把
|
||||
# API_KEY=
|
||||
|
||||
# 3) 短期 token(可选):设置后启用 POST /api/v1/auth/token
|
||||
# 调用方用 client_secret 换有效期 TOKEN_TTL 秒的签名 token,
|
||||
# 适合前端——页面里不硬编码长期密钥,只持有短时 token。
|
||||
# CLIENT_ID=default
|
||||
# CLIENT_SECRET=
|
||||
# TOKEN_TTL=3600
|
||||
|
||||
# ============ 跨域 ============
|
||||
# 允许跨域的前端来源,逗号分隔。浏览器里的 Vue/React 页面调这个接口必须配。
|
||||
# * = 允许所有来源(方便开发,但任何网页都能读结果,生产环境务必收紧)
|
||||
# 例:CORS_ORIGINS=http://10.1.1.163:5173,http://10.1.1.163:8080
|
||||
# 后端到后端调用(curl / requests / 其他容器)不受此项影响。
|
||||
CORS_ORIGINS=*
|
||||
|
||||
# ============ 基础镜像源 ============
|
||||
# 默认国内公共源(fnOS 自带加速源需授权,常 401)。
|
||||
# 备选:
|
||||
# BASE_IMAGE=docker.1ms.run/library/python:3.11-slim
|
||||
# BASE_IMAGE=mirror.ccs.tencentyun.com/library/python:3.11-slim
|
||||
# 离线导入基础镜像(docker load)后改用本地 tag:
|
||||
# BASE_IMAGE=python:3.11-slim
|
||||
# BASE_IMAGE=docker.m.daocloud.io/library/python:3.11-slim
|
||||
|
||||
# —— 以下一般不用改,低配吃紧时再动 ——
|
||||
# MAX_SIDE=960
|
||||
# DET_LIMIT_SIDE_LEN=736
|
||||
# MAX_DIMENSION=6000
|
||||
# MAX_IMAGE_BYTES=5242880
|
||||
@@ -0,0 +1,276 @@
|
||||
# Windows 操作 NAS Docker · 命令手册
|
||||
|
||||
针对本项目的实际环境整理(身份证识别 API 部署在飞牛 fnOS)。
|
||||
|
||||
## 本机参数
|
||||
|
||||
| 项 | 值 |
|
||||
|---|---|
|
||||
| NAS IP | `10.1.1.163` |
|
||||
| 项目目录 | `/vol1/1000/Docker/idcard-api` |
|
||||
| compose 项目名 | `icd`(镜像名 `icd-idcard-api`) |
|
||||
| 容器名 | `idcard-api` |
|
||||
| 服务端口 | `8000`(容器内 8000 映射到宿主机 8000) |
|
||||
| 宿主机用户 | `owen`(**不在 docker 组,docker 命令都要 `sudo`**) |
|
||||
|
||||
---
|
||||
|
||||
## 一、三个操作平面(最容易搞错的地方)
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────┐
|
||||
│ ① Windows PowerShell(你的电脑) │
|
||||
│ 能做:curl.exe 测接口、WinSCP 传文件 │
|
||||
│ 不能:任何 docker 命令 │
|
||||
│ 提示符:PS C:\Users\Administrator> │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ ② NAS 宿主机(SSH 连进去) │
|
||||
│ 能做:docker / docker compose / sudo / 文件操作 │
|
||||
│ 登录:ssh owen@10.1.1.163 │
|
||||
│ 提示符:owen@youjiala:/$ │
|
||||
├─────────────────────────────────────────────┤
|
||||
│ ③ 容器内部(fnOS Docker 界面「终端」按钮) │
|
||||
│ 能做:容器内的 ls / grep / cat / env │
|
||||
│ 不能:docker 命令(容器里没装 docker CLI) │
|
||||
│ 提示符:root@c5bbd0b03ba1:/# │
|
||||
└─────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**判断口诀**:命令里有 `docker` 或要动 NAS 上的文件 → 平面 ②;只是想试试接口通不通 → 平面 ①;想偷懒看容器里某个文件 → 平面 ③(但别在里面敲 docker)。
|
||||
|
||||
---
|
||||
|
||||
## 二、快速判断表
|
||||
|
||||
| 你要做的事 | 在哪里执行 | 需要登录吗 |
|
||||
|---|---|---|
|
||||
| 测接口通不通(curl) | Windows PowerShell | ❌ 不需要 |
|
||||
| 上传/覆盖代码文件 | Windows(WinSCP / 资源管理器) | ❌ 不需要(SFTP) |
|
||||
| `docker ps` / `docker logs` | NAS 宿主机 | ✅ `ssh owen@10.1.1.163` |
|
||||
| `docker compose build/up` | NAS 宿主机 | ✅ SSH |
|
||||
| 看镜像创建时间 | NAS 宿主机 | ✅ SSH |
|
||||
| 改 `.env` | WinSCP 或 SSH 均可 | 视习惯 |
|
||||
| 查看容器内 `main.py` | NAS 宿主机 `docker exec` | ✅ SSH |
|
||||
| 快速瞄一眼容器内文件 | fnOS Docker 界面「终端」 | ❌ 界面点开即可 |
|
||||
| 加 docker 组免 sudo | NAS 宿主机 | ✅ SSH |
|
||||
|
||||
---
|
||||
|
||||
## 三、Windows 连接方式
|
||||
|
||||
### SSH 登录宿主机
|
||||
|
||||
```powershell
|
||||
ssh owen@10.1.1.163
|
||||
# 首次会问 yes/no,输 yes,然后输 owen 的密码
|
||||
# 退出:exit
|
||||
```
|
||||
|
||||
看到提示符 `owen@youjiala:/$` 就说明进去了。
|
||||
|
||||
### 传文件(WinSCP / FileZilla)
|
||||
|
||||
- 协议:`SFTP`
|
||||
- 主机:`10.1.1.163`,端口 `22`
|
||||
- 用户:`owen`
|
||||
- 目标目录:`/vol1/1000/Docker/idcard-api`
|
||||
|
||||
或者在 fnOS 网页的「我的文件 → Docker → idcard-api」里直接上传。
|
||||
|
||||
### 一次性免 sudo(推荐做一次)
|
||||
|
||||
```bash
|
||||
sudo usermod -aG docker $USER
|
||||
newgrp docker # 当前会话立即生效,不用退出重登
|
||||
```
|
||||
|
||||
之后所有 docker 命令都不用加 `sudo` 了。本文档仍按**带 sudo** 写,两种都能用。
|
||||
|
||||
---
|
||||
|
||||
## 四、命令速查
|
||||
|
||||
### 1. 测试接口(Windows PowerShell)
|
||||
|
||||
> ⚠️ PowerShell 里 `curl` 是 `Invoke-WebRequest` 的别名,**必须写 `curl.exe`**。
|
||||
|
||||
```powershell
|
||||
# 健康检查
|
||||
curl.exe -s http://10.1.1.163:8000/api/v1/idcard/health
|
||||
|
||||
# 根路径(服务信息 + 端点清单)
|
||||
curl.exe -s http://10.1.1.163:8000/
|
||||
|
||||
# 识别(带 token)
|
||||
curl.exe -X POST http://10.1.1.163:8000/api/v1/idcard/recognize ^
|
||||
-H "Authorization: Bearer 你的token" ^
|
||||
-F "file=@C:/path/idcard.jpg"
|
||||
|
||||
# 识别(旧版 X-API-Key 头)
|
||||
curl.exe -X POST http://10.1.1.163:8000/api/v1/idcard/recognize ^
|
||||
-H "X-API-Key: 你的key" ^
|
||||
-F "file=@C:/path/idcard.jpg"
|
||||
|
||||
# 反向验证:不带 token 应该 401
|
||||
curl.exe -X POST http://10.1.1.163:8000/api/v1/idcard/recognize ^
|
||||
-F "file=@C:/path/idcard.jpg"
|
||||
```
|
||||
|
||||
> `^` 是 CMD 的续行符。PowerShell 用反引号 `` ` ``,或者直接写成一行。
|
||||
|
||||
### 2. 首次部署(SSH)
|
||||
|
||||
```bash
|
||||
# ① 建目录(WinSCP 已传过文件可跳过)
|
||||
mkdir -p /vol1/1000/Docker/idcard-api
|
||||
cd /vol1/1000/Docker/idcard-api
|
||||
|
||||
# ② 确认文件都在
|
||||
ls -la
|
||||
|
||||
# ③ 配 .env(必须有 .env,.env.example 不生效)
|
||||
cp .env.example .env
|
||||
vi .env # 或 WinSCP 直接编辑
|
||||
|
||||
# ④ 检查 compose 解析结果
|
||||
sudo docker compose -p icd config | grep -A2 API_TOKENS
|
||||
|
||||
# ⑤ 首次构建(会装 numpy/onnxruntime,3-5 分钟)
|
||||
sudo docker compose -p icd up -d --build
|
||||
|
||||
# ⑥ 跟踪日志
|
||||
sudo docker logs -f idcard-api
|
||||
```
|
||||
|
||||
### 3. 日常更新代码(SSH)
|
||||
|
||||
```bash
|
||||
cd /vol1/1000/Docker/idcard-api
|
||||
sudo docker compose -p icd up -d --build # 增量构建,10-30 秒
|
||||
```
|
||||
|
||||
或者用项目自带脚本(会校验镜像里的代码真的更新了):
|
||||
|
||||
```bash
|
||||
bash /vol1/1000/Docker/idcard-api/deploy.sh
|
||||
```
|
||||
|
||||
**只改了 `.env` 或 `docker-compose.yml`**(不需要 build):
|
||||
|
||||
```bash
|
||||
sudo docker compose -p icd up -d
|
||||
```
|
||||
|
||||
**怀疑缓存坏了**(全量重建,3-5 分钟):
|
||||
|
||||
```bash
|
||||
sudo docker compose -p icd build --no-cache
|
||||
sudo docker compose -p icd up -d --force-recreate
|
||||
```
|
||||
|
||||
### 4. 排查"改了代码没生效"
|
||||
|
||||
这是本项目最容易踩的坑:**fnOS 的「重新部署」只重建容器,不重建镜像**。
|
||||
|
||||
```bash
|
||||
# ① 容器里的代码是新版吗?0=旧代码,≥1=新代码
|
||||
sudo docker exec idcard-api grep -c auth_enabled /app/app/main.py
|
||||
|
||||
# ② 镜像什么时候建的?
|
||||
sudo docker images --format "{{.Repository}}:{{.Tag}} {{.ID}} 创建于 {{.CreatedSince}}" | grep -i idcard
|
||||
|
||||
# ③ compose 项目真实工作目录(和你上传的目录一致吗?)
|
||||
sudo docker inspect idcard-api --format '{{index .Config.Labels "com.docker.compose.project.working_dir"}}'
|
||||
|
||||
# ④ 环境变量注入情况
|
||||
sudo docker exec idcard-api env | grep -E "API_TOKENS|API_KEY|CLIENT_SECRET"
|
||||
|
||||
# ⑤ 容器状态与端口
|
||||
sudo docker ps --filter name=idcard-api
|
||||
```
|
||||
|
||||
### 5. 日常运维(SSH)
|
||||
|
||||
```bash
|
||||
# 实时日志
|
||||
sudo docker logs -f idcard-api
|
||||
|
||||
# 最近 50 行
|
||||
sudo docker logs --tail 50 idcard-api
|
||||
|
||||
# 过滤调用记录(看谁在调、耗时多少)
|
||||
sudo docker logs --tail 100 idcard-api | grep "recognize by="
|
||||
|
||||
# 内存占用(关键:1C2G 机器要盯这个)
|
||||
sudo docker stats --no-stream idcard-api
|
||||
|
||||
# 重启(不重新读 .env,改配置请用 up -d)
|
||||
sudo docker restart idcard-api
|
||||
|
||||
# 停掉并删除容器 + 镜像
|
||||
sudo docker compose -p icd down --rmi local
|
||||
|
||||
# 进容器内部 shell(在宿主机执行)
|
||||
sudo docker exec -it idcard-api bash
|
||||
```
|
||||
|
||||
### 6. 容器内部(fnOS 界面「终端」里执行)
|
||||
|
||||
```bash
|
||||
grep -c auth_enabled /app/app/main.py # 代码版本
|
||||
ls -l --time-style=long-iso /app/app/ # 文件时间
|
||||
echo $API_TOKENS # 环境变量
|
||||
```
|
||||
|
||||
> 这里**不能**跑 `docker` 命令。要跑 docker,回宿主机 SSH。
|
||||
|
||||
---
|
||||
|
||||
## 五、完整流程:从改代码到生效
|
||||
|
||||
```bash
|
||||
# ① Windows:改本地文件(WorkBuddy 生成)
|
||||
|
||||
# ② Windows:WinSCP 上传到 /vol1/1000/Docker/idcard-api
|
||||
# 注意保持目录结构:app/、Dockerfile、docker-compose.yml 等
|
||||
|
||||
# ③ SSH 登录 NAS
|
||||
ssh owen@10.1.1.163
|
||||
|
||||
# ④ 构建并启动
|
||||
cd /vol1/1000/Docker/idcard-api
|
||||
sudo docker compose -p icd up -d --build
|
||||
|
||||
# ⑤ 校验镜像里的代码真的换了(关键!别跳过)
|
||||
sudo docker exec idcard-api grep -c 你的新特征字符串 /app/app/main.py
|
||||
|
||||
# ⑥ 退出 SSH,回 Windows 测接口
|
||||
exit
|
||||
```
|
||||
|
||||
```powershell
|
||||
curl.exe -s http://10.1.1.163:8000/api/v1/idcard/health
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 六、错误对照表(本对话踩过的坑)
|
||||
|
||||
| 报错 | 在哪发生 | 原因 | 解决 |
|
||||
|---|---|---|---|
|
||||
| `docker: command not found` | 容器内部 | 在容器里跑 docker 命令 | 回宿主机 SSH,或去掉 `docker exec` 前缀用容器内路径 |
|
||||
| `permission denied ... docker.sock` | 宿主机 | 用户不在 docker 组 | 命令前加 `sudo`,或 `usermod -aG docker` |
|
||||
| `401 Unauthorized ... docker.fnnas.com` | 宿主机 build | fnOS 加速源不授权,且会覆盖 daemon.json | Dockerfile 用 `ARG BASE_IMAGE=国内仓库全路径`,绕开 daemon 配置 |
|
||||
| `could not find ... dockerfile` | 宿主机 build | Dockerfile 首行 `# syntax=` 触发前端镜像拉取 | 删掉该行 |
|
||||
| health 返回缺字段 / 行为没变化 | Windows 测接口 | 镜像没重建,跑的还是旧镜像 | 必须 `up -d --build`,不能只「重新部署」 |
|
||||
| `.env` 改了不生效 | 宿主机 | ①文件叫 `.env.example` ②只 `restart` 了 | 创建真正的 `.env`,然后 `up -d`(不是 restart) |
|
||||
| `curl: 无法将...识别为 cmdlet` | Windows | `curl` 是 PowerShell 别名 | 用 `curl.exe` |
|
||||
| `\r: command not found` | 宿主机 | Windows CRLF 换行 | `sed -i 's/\r$//' 脚本名.sh` |
|
||||
| 识别返回空,前端提示"未识别到信息" | C# 调用方 | 401 被静默吞掉(没检查状态码) | C# 加鉴权头 + 检查 `IsSuccessStatusCode` |
|
||||
|
||||
---
|
||||
|
||||
## 七、两条铁律
|
||||
|
||||
1. **改代码必须 build**。`docker compose up -d`(不带 `--build`)在镜像已存在时不会重新构建,只重建容器。代码改动一点都进不去。
|
||||
2. **`-p icd` 不能省**。项目名不是目录名,不带这个参数会创建新项目,容器和镜像都对不上。
|
||||
+60
-1
@@ -130,10 +130,38 @@ docker stats idcard-api # 看内存峰值是
|
||||
### 第 5 步:接入调用方
|
||||
|
||||
- **同 NAS 上的其他 Docker 容器**:把调用方容器加入 `idcard-api_idcard-api` 网络(或在调用方 compose 里加 `external_links` / 同一自定义网络),地址写 `http://idcard-api:8000`;图省事直接用 `http://飞牛IP:8000`。
|
||||
- **局域网其他设备**:`http://飞牛IP:8000`,带 `X-API-Key` 头。
|
||||
- **局域网其他设备**:`http://飞牛IP:8000`,带 `Authorization: Bearer <token>` 头。
|
||||
- **要域名 + HTTPS**:用 fnOS 自带的反向代理/远程访问把域名指到 `127.0.0.1:8000`,不要在路由器上映射公网端口直连。
|
||||
- **ARM 机型(aarch64)**:python:3.11-slim 和 opencv-headless 有 ARM 版,但 onnxruntime 需 ≥1.19 才有完善的 ARM wheel,先在 NAS上 `docker compose build` 试;若 onnxruntime 装不上,只能换 x86 机型或用云侧部署。
|
||||
|
||||
### 第 6 步:以后更新代码怎么发(重要)
|
||||
|
||||
**fnOS 的「重新部署 / 重建容器」只会 recreate 容器,不会 rebuild 镜像**——environment 变了会把新变量注进新容器,但代码改动完全不会进去。所以改完代码必须显式 build。
|
||||
|
||||
```bash
|
||||
cd /vol1/1000/Docker/idcard-api # 换成你的实际目录
|
||||
sudo docker compose -p icd up -d --build
|
||||
```
|
||||
|
||||
> `-p icd` 不能省:镜像名 `icd-idcard-api` 说明 compose 项目名是 `icd`,不带这个参数会建成另一个项目,跟现有容器对不上。宿主机用户如果不在 docker 组,命令前都要 `sudo`(或执行一次 `sudo usermod -aG docker $USER && newgrp docker`)。
|
||||
|
||||
| 你改了什么 | 命令 | 耗时 |
|
||||
|---|---|---|
|
||||
| `app/*.py` | `up -d --build` | 10–30 秒 |
|
||||
| `requirements.txt` | `up -d --build`(pip 层失效重跑) | 1–3 分钟 |
|
||||
| `.env` / `docker-compose.yml` | `up -d`(自动 recreate,无需 build) | 秒级 |
|
||||
| 怀疑缓存脏 / 要刷基础镜像 | `build --no-cache` + `up -d --force-recreate` | 3–5 分钟 |
|
||||
|
||||
**`--no-cache` 不是日常操作**:Docker 的层缓存按内容哈希失效,`COPY app ./app` 依赖代码内容,代码一变这一层和后续层必然重跑,前面的 apt/pip 层照常命中缓存。
|
||||
|
||||
也可以直接用 `deploy.sh`(已随项目提供),它会增量构建、等就绪、校验镜像内代码真的更新了,失败自动降级全量重建:
|
||||
|
||||
```bash
|
||||
bash /vol1/1000/Docker/idcard-api/deploy.sh
|
||||
```
|
||||
|
||||
> 如果脚本报 `\r: command not found`,是 Windows 换行符问题,执行 `sed -i 's/\r$//' deploy.sh` 修一下。
|
||||
|
||||
## 调用
|
||||
|
||||
```bash
|
||||
@@ -175,6 +203,37 @@ curl -X POST http://127.0.0.1:8000/api/v1/idcard/recognize/base64 \
|
||||
|
||||
Python 示例见 `client_example.py`。
|
||||
|
||||
### C# / .NET 调用示例(server-to-server)
|
||||
|
||||
要点三个:**必须带鉴权头**、**必须检查 HTTP 状态码**(否则 401 会被当成"未识别到"静默吞掉)、**超时要给足**(低端 NAS 首张要加载模型 10–20 秒)。
|
||||
|
||||
```csharp
|
||||
// 配置里加一项 IdCardOcrToken,与服务端 .env 的 API_TOKENS 对应
|
||||
string token = ServiceSettingsPolicy.GetIdCardOcrToken(service);
|
||||
|
||||
using var request = new HttpRequestMessage(HttpMethod.Post, apiUrl);
|
||||
if (!string.IsNullOrWhiteSpace(token))
|
||||
{
|
||||
// 新版服务(推荐):标准 Bearer 头
|
||||
request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
|
||||
// 或旧版服务(仅设置了 API_KEY):改用下面这行
|
||||
// request.Headers.TryAddWithoutValidation("X-API-Key", token);
|
||||
}
|
||||
request.Content = form;
|
||||
|
||||
using var response = client.SendAsync(request).GetAwaiter().GetResult();
|
||||
|
||||
// 关键:先判状态码,别让 401/413/422 掉进 JSON 解析分支变成"静默失败"
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
string body = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
|
||||
Console.WriteLine($"[UploadIdCardFile] OCR HTTP {(int)response.StatusCode}: {body}");
|
||||
return data; // 前端提示"未识别到信息",后端日志里有真实原因
|
||||
}
|
||||
```
|
||||
|
||||
`HttpClient` 建议用 `IHttpClientFactory` 或静态单例,不要每次 `new`——高频调用会耗尽 socket。
|
||||
|
||||
## 鉴权(Token 验证)
|
||||
|
||||
支持三种方式,全部用**标准库实现**(HMAC-SHA256),不引入 PyJWT 等依赖,对 1C/2G 无额外开销。
|
||||
|
||||
@@ -99,6 +99,17 @@ def _parse_tokens() -> dict:
|
||||
|
||||
_TOKEN_MAP = _parse_tokens()
|
||||
|
||||
# 弱口令提醒:示例占位符(REPLACE_ME_*)或过短的 token 不该出现在正式环境。
|
||||
# 只告警不阻止启动,避免影响联调;换成真随机串后这条日志自动消失。
|
||||
_weak_clients = sorted(
|
||||
{name for tok, name in _TOKEN_MAP.items() if "REPLACE_ME" in tok.upper() or len(tok) < 12}
|
||||
)
|
||||
if _weak_clients:
|
||||
log.warning(
|
||||
"token 过弱或仍是示例占位符,请尽快更换:%s(生成:openssl rand -hex 24)",
|
||||
", ".join(_weak_clients),
|
||||
)
|
||||
|
||||
_engine = None
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
#!/usr/bin/env bash
|
||||
# ------------------------------------------------------------------
|
||||
# fnOS 一键更新部署
|
||||
#
|
||||
# 用法(在 NAS 宿主机):
|
||||
# bash /vol1/1000/Docker/idcard-api/deploy.sh
|
||||
#
|
||||
# 逻辑:增量构建(只重跑失效层,通常 10-30s)→ 等就绪 → 校验镜像内代码
|
||||
# 是否真的更新了 → 打印 health。校验失败自动降级为 --no-cache 全量重建。
|
||||
# ------------------------------------------------------------------
|
||||
set -uo pipefail
|
||||
|
||||
# 切到脚本所在目录,避免路径写死
|
||||
cd "$(dirname "$0")" || exit 1
|
||||
|
||||
PROJECT_NAME="icd" # compose 项目名(镜像名 icd-idcard-api 的前缀)
|
||||
SERVICE="idcard-api" # container_name
|
||||
PORT=8000
|
||||
MARKER="auth_enabled" # 用它能判断镜像里是新代码
|
||||
|
||||
echo "==> 目录: $(pwd)"
|
||||
|
||||
# ---------- 1. 增量构建 + 启动 ----------
|
||||
echo "==> 1/4 构建并启动(增量,通常 10-30 秒)"
|
||||
if ! sudo docker compose -p "$PROJECT_NAME" up -d --build; then
|
||||
echo "!! 构建失败。常见原因:基础镜像源 401,检查 Dockerfile 的 BASE_IMAGE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ---------- 2. 等服务就绪 ----------
|
||||
echo "==> 2/4 等待服务就绪"
|
||||
ready=0
|
||||
for _ in $(seq 1 30); do
|
||||
if curl -sf "http://127.0.0.1:$PORT/api/v1/idcard/health" >/dev/null 2>&1; then
|
||||
ready=1
|
||||
break
|
||||
fi
|
||||
sleep 2
|
||||
done
|
||||
if [ "$ready" -ne 1 ]; then
|
||||
echo "!! 服务 60 秒内未就绪,看日志:sudo docker logs --tail 50 $SERVICE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ---------- 3. 校验镜像内代码是否真的更新 ----------
|
||||
echo "==> 3/4 校验容器内代码版本"
|
||||
count=$(sudo docker exec "$SERVICE" grep -c "$MARKER" /app/app/main.py 2>/dev/null || echo 0)
|
||||
if [ "${count:-0}" -lt 1 ]; then
|
||||
echo "!! 容器内仍是旧代码,降级为 --no-cache 全量重建(需要几分钟)"
|
||||
sudo docker compose -p "$PROJECT_NAME" build --no-cache || exit 1
|
||||
sudo docker compose -p "$PROJECT_NAME" up -d --force-recreate || exit 1
|
||||
count=$(sudo docker exec "$SERVICE" grep -c "$MARKER" /app/app/main.py 2>/dev/null || echo 0)
|
||||
if [ "${count:-0}" -lt 1 ]; then
|
||||
echo "!! 全量重建后代码仍是旧的。检查 compose 项目目录是否就是本目录:"
|
||||
sudo docker inspect "$SERVICE" --format '{{index .Config.Labels "com.docker.compose.project.working_dir"}}'
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
echo " 容器内代码已更新(匹配 $count 处)"
|
||||
|
||||
# ---------- 4. 健康检查 ----------
|
||||
echo "==> 4/4 健康检查"
|
||||
curl -s "http://127.0.0.1:$PORT/api/v1/idcard/health"
|
||||
echo
|
||||
echo
|
||||
echo "部署完成。"
|
||||
echo " 看日志:sudo docker logs -f $SERVICE"
|
||||
echo " 看内存:sudo docker stats --no-stream $SERVICE"
|
||||
Reference in new issue
Block a user