调整docker配置
This commit is contained in:
+145
-131
@@ -1,13 +1,16 @@
|
|||||||
# Docker + Prefect 使用说明
|
# Docker + Prefect 使用说明
|
||||||
|
|
||||||
当前方案包含两条定时任务:
|
当前方案是:
|
||||||
|
|
||||||
|
- 使用 [prefect.yaml](/Users/idss/YXT_Project/gmv-analytics/prefect.yaml) 管理 deployment
|
||||||
|
- 使用 Docker 容器运行 Prefect worker
|
||||||
|
- 由 Prefect Server 统一调度
|
||||||
|
|
||||||
|
当前有两条调度:
|
||||||
|
|
||||||
- `08:00` 执行数据统计并写入飞书多维表格
|
- `08:00` 执行数据统计并写入飞书多维表格
|
||||||
- `09:00` 推送结果到飞书群
|
- `09:00` 推送结果到飞书群
|
||||||
|
|
||||||
调度配置写在 [prefect.yaml](/Users/idss/YXT_Project/gmv-analytics/prefect.yaml) 中。
|
|
||||||
运行容器的职责是启动 Prefect worker,不再使用 `--serve` 作为主方案。
|
|
||||||
|
|
||||||
## 1. 创建 Docker 镜像
|
## 1. 创建 Docker 镜像
|
||||||
|
|
||||||
在项目目录执行:
|
在项目目录执行:
|
||||||
@@ -17,44 +20,24 @@ cd /Users/idss/YXT_Project/gmv-analytics
|
|||||||
docker build -t gmv-analytics-prefect:0.1.0 .
|
docker build -t gmv-analytics-prefect:0.1.0 .
|
||||||
```
|
```
|
||||||
|
|
||||||
镜像内容来自:
|
镜像构建特点:
|
||||||
|
|
||||||
- [Dockerfile](/Users/idss/YXT_Project/gmv-analytics/Dockerfile)
|
- 基础镜像:`python:3.12-slim-bookworm`
|
||||||
- [docker-entrypoint.sh](/Users/idss/YXT_Project/gmv-analytics/docker-entrypoint.sh)
|
- 使用 `uv` 安装依赖
|
||||||
|
- 使用清华 `apt` 和 `PyPI` 源
|
||||||
容器启动后会:
|
- 依赖来源:[pyproject.toml](/Users/idss/YXT_Project/gmv-analytics/pyproject.toml)
|
||||||
|
|
||||||
- 加载 `.env`
|
|
||||||
- 自动把 `PROJECT_MAPPING_FILE` 修正为容器内的 `/app/店铺映射表.xlsx`
|
|
||||||
- 默认执行 `supervisord`
|
|
||||||
- 再由 [supervisord.conf](/Users/idss/YXT_Project/gmv-analytics/supervisord.conf) 启动:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
prefect worker start --pool "gmv-analytics-pool" --type process
|
|
||||||
```
|
|
||||||
|
|
||||||
## 2. 启动 Docker 容器
|
## 2. 启动 Docker 容器
|
||||||
|
|
||||||
### 方式 A:直接用 `docker run`
|
推荐使用 Compose。
|
||||||
|
|
||||||
```bash
|
项目里的 [docker-compose.yaml](/Users/idss/YXT_Project/gmv-analytics/docker-compose.yaml) 已经配置了:
|
||||||
docker run -d \
|
|
||||||
--name prefect-gmv-worker \
|
|
||||||
--env-file /Users/idss/YXT_Project/gmv-analytics/.env \
|
|
||||||
-e PROJECT_MAPPING_FILE=/app/店铺映射表.xlsx \
|
|
||||||
gmv-analytics-prefect:0.1.0
|
|
||||||
```
|
|
||||||
|
|
||||||
停止容器:
|
- `PREFECT_API_URL`
|
||||||
|
- `host.docker.internal`
|
||||||
```bash
|
- `PROJECT_MAPPING_FILE`
|
||||||
docker stop prefect-gmv-worker
|
- `uv_cache` 持久化卷
|
||||||
docker rm prefect-gmv-worker
|
- CPU / 内存资源限制
|
||||||
```
|
|
||||||
|
|
||||||
### 方式 B:用 `docker compose`
|
|
||||||
|
|
||||||
项目里已经有 [docker-compose.yaml](/Users/idss/YXT_Project/gmv-analytics/docker-compose.yaml)。
|
|
||||||
|
|
||||||
启动:
|
启动:
|
||||||
|
|
||||||
@@ -63,78 +46,86 @@ cd /Users/idss/YXT_Project/gmv-analytics
|
|||||||
docker compose up -d --build
|
docker compose up -d --build
|
||||||
```
|
```
|
||||||
|
|
||||||
开启热加载监听:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
cd /Users/idss/YXT_Project/gmv-analytics
|
|
||||||
docker compose watch
|
|
||||||
```
|
|
||||||
|
|
||||||
停止:
|
停止:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker compose down
|
docker compose down
|
||||||
```
|
```
|
||||||
|
|
||||||
热加载规则是:
|
查看运行状态:
|
||||||
|
|
||||||
- 修改 `.py`、`.env`、Excel 映射表等项目内容:
|
```bash
|
||||||
- 自动同步到容器
|
docker ps
|
||||||
- 并自动重启服务
|
```
|
||||||
- 修改 `Dockerfile`、`pyproject.toml`、`supervisord.conf`、`docker-compose.yaml`、`requirements-docker.txt`:
|
|
||||||
- 自动触发 rebuild
|
|
||||||
|
|
||||||
## 3. 注册 Prefect 调度
|
当前容器名是:
|
||||||
|
|
||||||
推荐方式是使用 [prefect.yaml](/Users/idss/YXT_Project/gmv-analytics/prefect.yaml) 注册 deployment:
|
```bash
|
||||||
|
prefect-gmv-worker
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. 容器启动后会做什么
|
||||||
|
|
||||||
|
容器启动后:
|
||||||
|
|
||||||
|
1. 加载 `.env`
|
||||||
|
2. 自动修正:
|
||||||
|
- `PROJECT_MAPPING_FILE=/app/店铺映射表.xlsx`
|
||||||
|
3. 启动 `supervisord`
|
||||||
|
4. 再由 [supervisord.conf](/Users/idss/YXT_Project/gmv-analytics/supervisord.conf) 启动:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
prefect worker start --pool "gmv-analytics-pool" --type process
|
||||||
|
```
|
||||||
|
|
||||||
|
也就是说,这个容器的职责不是直接跑 flow,而是作为 Prefect worker 等待调度。
|
||||||
|
|
||||||
|
## 4. 注册 Prefect 调度
|
||||||
|
|
||||||
|
调度定义在 [prefect.yaml](/Users/idss/YXT_Project/gmv-analytics/prefect.yaml)。
|
||||||
|
|
||||||
|
当前 work pool 是:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gmv-analytics-pool
|
||||||
|
```
|
||||||
|
|
||||||
|
注册 deployment 的方式:
|
||||||
|
|
||||||
|
### 方式 A:在本机或服务器上直接执行
|
||||||
|
|
||||||
|
前提是当前环境里有 `prefect` CLI,并且能访问 `PREFECT_API_URL`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd /Users/idss/YXT_Project/gmv-analytics
|
cd /Users/idss/YXT_Project/gmv-analytics
|
||||||
prefect deploy --all
|
prefect deploy --all
|
||||||
```
|
```
|
||||||
|
|
||||||
这会向 `.env` 中的 `PREFECT_API_URL` 注册两个 deployment:
|
### 方式 B:在容器里执行
|
||||||
|
|
||||||
- `gmv-daily-data-sync-8am`
|
如果宿主机没有 `prefect` 命令,可以直接在容器里执行:
|
||||||
- `gmv-daily-notify-9am`
|
|
||||||
|
|
||||||
前提条件:
|
|
||||||
|
|
||||||
- `.env` 中已经配置好 `PREFECT_API_URL`
|
|
||||||
- Prefect API 服务可访问
|
|
||||||
- 已经有可用的 work pool
|
|
||||||
当前 [prefect.yaml](/Users/idss/YXT_Project/gmv-analytics/prefect.yaml) 默认使用:
|
|
||||||
`gmv-analytics-pool`
|
|
||||||
|
|
||||||
如果还没有 worker,可以在宿主机启动一个:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
prefect worker start --pool gmv-analytics-pool --type process
|
docker exec -it prefect-gmv-worker sh -lc 'cd /app && prefect deploy --all'
|
||||||
```
|
```
|
||||||
|
|
||||||
## 4. 自动执行是怎么发生的
|
注意:
|
||||||
|
|
||||||
如果你走的是 `prefect deploy --all` 方案:
|
- 这条命令要求容器里的 `PREFECT_API_URL` 可访问
|
||||||
|
- 如果你看到 `ConnectError`,通常是 `.env` 里的 `PREFECT_API_URL` 地址在容器里不可达
|
||||||
|
|
||||||
1. `prefect.yaml` 注册两个 deployment
|
## 5. 自动执行是怎么发生的
|
||||||
2. Prefect Server/Cloud 按 cron 触发:
|
|
||||||
- `08:00`:`gmv-daily-data-sync-8am`
|
|
||||||
- `09:00`:`gmv-daily-notify-9am`
|
|
||||||
3. Prefect worker 拉起执行
|
|
||||||
4. 代码入口在 [prefect_gmv_scheduler.py](/Users/idss/YXT_Project/gmv-analytics/prefect_gmv_scheduler.py)
|
|
||||||
|
|
||||||
如果你走的是 Docker worker 方案:
|
完整流程如下:
|
||||||
|
|
||||||
1. 容器常驻运行 `prefect worker start --pool "gmv-analytics-pool" --type process`
|
1. `prefect deploy --all` 把 [prefect.yaml](/Users/idss/YXT_Project/gmv-analytics/prefect.yaml) 注册到 Prefect Server
|
||||||
2. Prefect Server 到点触发 deployment
|
2. Prefect Server 根据 cron 触发:
|
||||||
3. worker 从 `gmv-analytics-pool` 拉起执行
|
- `gmv-daily-data-sync-8am`
|
||||||
|
- `gmv-daily-notify-9am`
|
||||||
|
3. `prefect-gmv-worker` 容器里的 worker 从 `gmv-analytics-pool` 拉取任务
|
||||||
|
4. worker 执行 [prefect_gmv_scheduler.py](/Users/idss/YXT_Project/gmv-analytics/prefect_gmv_scheduler.py) 里的 flow
|
||||||
|
|
||||||
建议:
|
## 6. 单次手动执行
|
||||||
|
|
||||||
- 正式环境优先用 `prefect.yaml + prefect deploy --all`
|
|
||||||
- Docker 容器只负责提供 worker 执行环境
|
|
||||||
|
|
||||||
## 5. 单次手动执行
|
|
||||||
|
|
||||||
只跑数据同步:
|
只跑数据同步:
|
||||||
|
|
||||||
@@ -160,101 +151,124 @@ python /Users/idss/YXT_Project/gmv-analytics/prefect_gmv_scheduler.py --mode all
|
|||||||
docker run --rm \
|
docker run --rm \
|
||||||
--env-file /Users/idss/YXT_Project/gmv-analytics/.env \
|
--env-file /Users/idss/YXT_Project/gmv-analytics/.env \
|
||||||
-e PROJECT_MAPPING_FILE=/app/店铺映射表.xlsx \
|
-e PROJECT_MAPPING_FILE=/app/店铺映射表.xlsx \
|
||||||
|
-e PREFECT_API_URL=http://host.docker.internal:4200/api \
|
||||||
|
--add-host host.docker.internal:host-gateway \
|
||||||
gmv-analytics-prefect:0.1.0 \
|
gmv-analytics-prefect:0.1.0 \
|
||||||
python prefect_gmv_scheduler.py --mode sync
|
python prefect_gmv_scheduler.py --mode sync
|
||||||
```
|
```
|
||||||
|
|
||||||
## 6. Docker 中的日志
|
## 7. Docker 中的日志
|
||||||
|
|
||||||
现在日志分成两层:
|
现在日志分成三层:
|
||||||
|
|
||||||
### 6.1 容器标准输出日志
|
### 7.1 容器标准输出日志
|
||||||
|
|
||||||
这是你最先看到的日志来源。
|
查看 worker 容器日志:
|
||||||
|
|
||||||
如果用 `docker run`:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker logs -f prefect-gmv-worker
|
docker logs -f prefect-gmv-worker
|
||||||
```
|
```
|
||||||
|
|
||||||
如果用 `docker compose`:
|
或者:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd /Users/idss/YXT_Project/gmv-analytics
|
cd /Users/idss/YXT_Project/gmv-analytics
|
||||||
docker compose logs -f
|
docker compose logs -f
|
||||||
```
|
```
|
||||||
|
|
||||||
这些日志包含:
|
这里通常能看到:
|
||||||
|
|
||||||
- Prefect flow 启动/完成
|
- worker 启动日志
|
||||||
- 每天数据同步流程
|
- Prefect 调度执行日志
|
||||||
- 飞书接口日志
|
- Python 进程报错堆栈
|
||||||
- 错误堆栈
|
|
||||||
|
|
||||||
### 6.2 容器内本地文件日志
|
### 7.2 容器内本地文件日志
|
||||||
|
|
||||||
项目已经接了统一日志模块 [logging_config.py](/Users/idss/YXT_Project/gmv-analytics/logging_config.py),所以日志还会写入容器内文件:
|
业务日志还会写到容器内文件:
|
||||||
|
|
||||||
- 默认目录:`/app/logs`
|
- 目录:`/app/logs`
|
||||||
- 默认文件:`/app/logs/gmv_sync.log`
|
- 文件:`/app/logs/gmv_sync.log`
|
||||||
|
|
||||||
进入容器查看:
|
查看方式:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker exec -it prefect-gmv-worker sh
|
docker exec -it prefect-gmv-worker sh
|
||||||
tail -f /app/logs/gmv_sync.log
|
tail -f /app/logs/gmv_sync.log
|
||||||
```
|
```
|
||||||
|
|
||||||
如果是 compose:
|
worker 自己的 supervisor 日志也会在:
|
||||||
|
|
||||||
|
- `/app/logs/prefect_worker.out.log`
|
||||||
|
- `/app/logs/prefect_worker.err.log`
|
||||||
|
|
||||||
|
### 7.3 Prefect UI 日志
|
||||||
|
|
||||||
|
现在业务日志已经接入 Prefect run logger,所以在 Prefect UI 的 `Logs` 面板里也能看到:
|
||||||
|
|
||||||
|
- 数据同步开始/结束
|
||||||
|
- 每天处理日期
|
||||||
|
- 查询销售额/退款额
|
||||||
|
- 匹配目标表
|
||||||
|
- GMV 计算
|
||||||
|
- 飞书推送
|
||||||
|
|
||||||
|
如果 UI 没看到新日志,通常说明:
|
||||||
|
|
||||||
|
- worker 还没重启到最新代码
|
||||||
|
- 或本次 run 还是旧 deployment / 旧镜像执行的
|
||||||
|
|
||||||
|
## 8. 常见问题
|
||||||
|
|
||||||
|
### 8.1 `prefect: command not found`
|
||||||
|
|
||||||
|
说明宿主机没有安装 Prefect CLI。
|
||||||
|
可改为在容器里执行:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
docker exec -it prefect-gmv-worker sh
|
docker exec -it prefect-gmv-worker sh -lc 'cd /app && prefect deploy --all'
|
||||||
tail -f /app/logs/gmv_sync.log
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### 6.3 日志级别
|
### 8.2 `httpx.ConnectError: All connection attempts failed`
|
||||||
|
|
||||||
默认是 `INFO`。
|
说明容器里访问不到 `PREFECT_API_URL`。
|
||||||
如果要看更细的调试日志,在 `.env` 里加:
|
常见原因:
|
||||||
|
|
||||||
|
- `.env` 里的 `PREFECT_API_URL` 写成了 `localhost`
|
||||||
|
- 容器里访问不到宿主机 Prefect API
|
||||||
|
|
||||||
|
当前 compose 已经加了:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
extra_hosts:
|
||||||
|
- "host.docker.internal:host-gateway"
|
||||||
|
```
|
||||||
|
|
||||||
|
所以更推荐把 `.env` 里的 `PREFECT_API_URL` 配成类似:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
LOG_LEVEL=DEBUG
|
PREFECT_API_URL=http://host.docker.internal:4200/api
|
||||||
```
|
```
|
||||||
|
|
||||||
可选日志配置还有:
|
## 9. 最推荐的执行方式
|
||||||
|
|
||||||
```bash
|
如果你要的是“服务器上长期稳定自动执行”,建议按这个顺序:
|
||||||
LOG_DIR=/app/logs
|
|
||||||
LOG_FILE_NAME=gmv_sync.log
|
|
||||||
LOG_MAX_BYTES=10485760
|
|
||||||
LOG_BACKUP_COUNT=7
|
|
||||||
```
|
|
||||||
|
|
||||||
## 7. 现在最推荐的执行方式
|
|
||||||
|
|
||||||
如果你要的是“长期稳定自动执行”,建议这样:
|
|
||||||
|
|
||||||
1. 构建镜像
|
1. 构建镜像
|
||||||
2. 准备好 `.env`
|
2. 准备 `.env`
|
||||||
3. 启动 Prefect API
|
3. 启动 worker 容器
|
||||||
4. 启动 worker
|
|
||||||
5. 执行:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd /Users/idss/YXT_Project/gmv-analytics
|
cd /Users/idss/YXT_Project/gmv-analytics
|
||||||
prefect deploy --all
|
|
||||||
```
|
|
||||||
|
|
||||||
如果你要的是“容器里运行 worker,由 Prefect Server 统一调度”,直接:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
docker compose up -d --build
|
docker compose up -d --build
|
||||||
```
|
```
|
||||||
|
|
||||||
然后在能连到 Prefect API 的环境里执行:
|
4. 在能连到 `PREFECT_API_URL` 的环境里注册 deployment
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd /Users/idss/YXT_Project/gmv-analytics
|
docker exec -it prefect-gmv-worker sh -lc 'cd /app && prefect deploy --all'
|
||||||
prefect deploy --all
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
5. 到 Prefect UI 检查:
|
||||||
|
- deployment 是否已注册
|
||||||
|
- work pool 是否是 `gmv-analytics-pool`
|
||||||
|
- schedule 是否正确
|
||||||
|
|||||||
+3
-1
@@ -4,10 +4,12 @@ FROM python:3.12-slim-bookworm
|
|||||||
|
|
||||||
COPY --from=uv /uv /bin/uv
|
COPY --from=uv /uv /bin/uv
|
||||||
|
|
||||||
|
ARG UV_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple
|
||||||
|
|
||||||
ENV PYTHONUNBUFFERED=1 \
|
ENV PYTHONUNBUFFERED=1 \
|
||||||
PYTHONDONTWRITEBYTECODE=1 \
|
PYTHONDONTWRITEBYTECODE=1 \
|
||||||
UV_SYSTEM_PYTHON=1 \
|
UV_SYSTEM_PYTHON=1 \
|
||||||
UV_INDEX_URL="https://pypi.tuna.tsinghua.edu.cn/simple" \
|
UV_INDEX_URL=${UV_INDEX_URL} \
|
||||||
TZ=Asia/Shanghai \
|
TZ=Asia/Shanghai \
|
||||||
PYTHONPATH="/app:${PYTHONPATH}"
|
PYTHONPATH="/app:${PYTHONPATH}"
|
||||||
|
|
||||||
|
|||||||
+22
-28
@@ -3,37 +3,31 @@ services:
|
|||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
dockerfile: Dockerfile
|
dockerfile: Dockerfile
|
||||||
|
args:
|
||||||
|
- UV_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple
|
||||||
image: gmv-analytics-prefect:0.1.0
|
image: gmv-analytics-prefect:0.1.0
|
||||||
container_name: prefect-gmv-worker
|
container_name: prefect-gmv-worker
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
env_file:
|
env_file:
|
||||||
- .env
|
- .env
|
||||||
environment:
|
environment:
|
||||||
PROJECT_MAPPING_FILE: /app/店铺映射表.xlsx
|
- PYTHONUNBUFFERED=1
|
||||||
develop:
|
- PROJECT_MAPPING_FILE=/app/店铺映射表.xlsx
|
||||||
watch:
|
- PREFECT_API_URL=${PREFECT_API_URL:-http://host.docker.internal:4200/api}
|
||||||
- action: sync+restart
|
extra_hosts:
|
||||||
path: .
|
- "host.docker.internal:host-gateway"
|
||||||
target: /app
|
volumes:
|
||||||
ignore:
|
- .:/app
|
||||||
- .git/
|
- ./logs:/app/logs
|
||||||
- .venv/
|
- uv_cache:/root/.cache/uv
|
||||||
- __pycache__/
|
deploy:
|
||||||
- .pytest_cache/
|
resources:
|
||||||
- logs/
|
limits:
|
||||||
- "*.pyc"
|
cpus: "2.0"
|
||||||
- "Dockerfile"
|
memory: 4G
|
||||||
- "docker-compose.yaml"
|
reservations:
|
||||||
- "pyproject.toml"
|
cpus: "0.5"
|
||||||
- "supervisord.conf"
|
memory: 512M
|
||||||
- "requirements-docker.txt"
|
|
||||||
- action: rebuild
|
volumes:
|
||||||
path: Dockerfile
|
uv_cache:
|
||||||
- action: rebuild
|
|
||||||
path: docker-compose.yaml
|
|
||||||
- action: rebuild
|
|
||||||
path: pyproject.toml
|
|
||||||
- action: rebuild
|
|
||||||
path: supervisord.conf
|
|
||||||
- action: rebuild
|
|
||||||
path: requirements-docker.txt
|
|
||||||
|
|||||||
Reference in New Issue
Block a user