277 lines
9.5 KiB
Markdown
277 lines
9.5 KiB
Markdown
# 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` 不能省**。项目名不是目录名,不带这个参数会创建新项目,容器和镜像都对不上。
|