From 9f2eb00eacc178b39eed5fbdf025d3e2d2adbf3a Mon Sep 17 00:00:00 2001 From: BXY0414 <1079823339@qq.com> Date: Tue, 24 Mar 2026 17:59:32 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4docker=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DOCKER_PREFECT_USAGE.md | 276 +++++++++++++++++++++------------------- Dockerfile | 4 +- docker-compose.yaml | 50 ++++---- 3 files changed, 170 insertions(+), 160 deletions(-) diff --git a/DOCKER_PREFECT_USAGE.md b/DOCKER_PREFECT_USAGE.md index 1856e59..80f51ca 100644 --- a/DOCKER_PREFECT_USAGE.md +++ b/DOCKER_PREFECT_USAGE.md @@ -1,13 +1,16 @@ # Docker + Prefect 使用说明 -当前方案包含两条定时任务: +当前方案是: + +- 使用 [prefect.yaml](/Users/idss/YXT_Project/gmv-analytics/prefect.yaml) 管理 deployment +- 使用 Docker 容器运行 Prefect worker +- 由 Prefect Server 统一调度 + +当前有两条调度: - `08:00` 执行数据统计并写入飞书多维表格 - `09:00` 推送结果到飞书群 -调度配置写在 [prefect.yaml](/Users/idss/YXT_Project/gmv-analytics/prefect.yaml) 中。 -运行容器的职责是启动 Prefect worker,不再使用 `--serve` 作为主方案。 - ## 1. 创建 Docker 镜像 在项目目录执行: @@ -17,44 +20,24 @@ cd /Users/idss/YXT_Project/gmv-analytics docker build -t gmv-analytics-prefect:0.1.0 . ``` -镜像内容来自: +镜像构建特点: -- [Dockerfile](/Users/idss/YXT_Project/gmv-analytics/Dockerfile) -- [docker-entrypoint.sh](/Users/idss/YXT_Project/gmv-analytics/docker-entrypoint.sh) - -容器启动后会: - -- 加载 `.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 -``` +- 基础镜像:`python:3.12-slim-bookworm` +- 使用 `uv` 安装依赖 +- 使用清华 `apt` 和 `PyPI` 源 +- 依赖来源:[pyproject.toml](/Users/idss/YXT_Project/gmv-analytics/pyproject.toml) ## 2. 启动 Docker 容器 -### 方式 A:直接用 `docker run` +推荐使用 Compose。 -```bash -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 -``` +项目里的 [docker-compose.yaml](/Users/idss/YXT_Project/gmv-analytics/docker-compose.yaml) 已经配置了: -停止容器: - -```bash -docker stop prefect-gmv-worker -docker rm prefect-gmv-worker -``` - -### 方式 B:用 `docker compose` - -项目里已经有 [docker-compose.yaml](/Users/idss/YXT_Project/gmv-analytics/docker-compose.yaml)。 +- `PREFECT_API_URL` +- `host.docker.internal` +- `PROJECT_MAPPING_FILE` +- `uv_cache` 持久化卷 +- CPU / 内存资源限制 启动: @@ -63,78 +46,86 @@ cd /Users/idss/YXT_Project/gmv-analytics docker compose up -d --build ``` -开启热加载监听: - -```bash -cd /Users/idss/YXT_Project/gmv-analytics -docker compose watch -``` - 停止: ```bash docker compose down ``` -热加载规则是: +查看运行状态: -- 修改 `.py`、`.env`、Excel 映射表等项目内容: - - 自动同步到容器 - - 并自动重启服务 -- 修改 `Dockerfile`、`pyproject.toml`、`supervisord.conf`、`docker-compose.yaml`、`requirements-docker.txt`: - - 自动触发 rebuild +```bash +docker ps +``` -## 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 cd /Users/idss/YXT_Project/gmv-analytics prefect deploy --all ``` -这会向 `.env` 中的 `PREFECT_API_URL` 注册两个 deployment: +### 方式 B:在容器里执行 -- `gmv-daily-data-sync-8am` -- `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,可以在宿主机启动一个: +如果宿主机没有 `prefect` 命令,可以直接在容器里执行: ```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 -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) +## 5. 自动执行是怎么发生的 -如果你走的是 Docker worker 方案: +完整流程如下: -1. 容器常驻运行 `prefect worker start --pool "gmv-analytics-pool" --type process` -2. Prefect Server 到点触发 deployment -3. worker 从 `gmv-analytics-pool` 拉起执行 +1. `prefect deploy --all` 把 [prefect.yaml](/Users/idss/YXT_Project/gmv-analytics/prefect.yaml) 注册到 Prefect Server +2. Prefect Server 根据 cron 触发: + - `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 -建议: - -- 正式环境优先用 `prefect.yaml + prefect deploy --all` -- Docker 容器只负责提供 worker 执行环境 - -## 5. 单次手动执行 +## 6. 单次手动执行 只跑数据同步: @@ -160,101 +151,124 @@ python /Users/idss/YXT_Project/gmv-analytics/prefect_gmv_scheduler.py --mode all docker run --rm \ --env-file /Users/idss/YXT_Project/gmv-analytics/.env \ -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 \ python prefect_gmv_scheduler.py --mode sync ``` -## 6. Docker 中的日志 +## 7. Docker 中的日志 -现在日志分成两层: +现在日志分成三层: -### 6.1 容器标准输出日志 +### 7.1 容器标准输出日志 -这是你最先看到的日志来源。 - -如果用 `docker run`: +查看 worker 容器日志: ```bash docker logs -f prefect-gmv-worker ``` -如果用 `docker compose`: +或者: ```bash cd /Users/idss/YXT_Project/gmv-analytics 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/gmv_sync.log` +- 目录:`/app/logs` +- 文件:`/app/logs/gmv_sync.log` -进入容器查看: +查看方式: ```bash docker exec -it prefect-gmv-worker sh 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 -docker exec -it prefect-gmv-worker sh -tail -f /app/logs/gmv_sync.log +docker exec -it prefect-gmv-worker sh -lc 'cd /app && prefect deploy --all' ``` -### 6.3 日志级别 +### 8.2 `httpx.ConnectError: All connection attempts failed` -默认是 `INFO`。 -如果要看更细的调试日志,在 `.env` 里加: +说明容器里访问不到 `PREFECT_API_URL`。 +常见原因: + +- `.env` 里的 `PREFECT_API_URL` 写成了 `localhost` +- 容器里访问不到宿主机 Prefect API + +当前 compose 已经加了: + +```yaml +extra_hosts: + - "host.docker.internal:host-gateway" +``` + +所以更推荐把 `.env` 里的 `PREFECT_API_URL` 配成类似: ```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. 构建镜像 -2. 准备好 `.env` -3. 启动 Prefect API -4. 启动 worker -5. 执行: +2. 准备 `.env` +3. 启动 worker 容器 ```bash cd /Users/idss/YXT_Project/gmv-analytics -prefect deploy --all -``` - -如果你要的是“容器里运行 worker,由 Prefect Server 统一调度”,直接: - -```bash docker compose up -d --build ``` -然后在能连到 Prefect API 的环境里执行: +4. 在能连到 `PREFECT_API_URL` 的环境里注册 deployment ```bash -cd /Users/idss/YXT_Project/gmv-analytics -prefect deploy --all +docker exec -it prefect-gmv-worker sh -lc 'cd /app && prefect deploy --all' ``` + +5. 到 Prefect UI 检查: + - deployment 是否已注册 + - work pool 是否是 `gmv-analytics-pool` + - schedule 是否正确 diff --git a/Dockerfile b/Dockerfile index 054f037..8036338 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,10 +4,12 @@ FROM python:3.12-slim-bookworm COPY --from=uv /uv /bin/uv +ARG UV_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple + ENV PYTHONUNBUFFERED=1 \ PYTHONDONTWRITEBYTECODE=1 \ UV_SYSTEM_PYTHON=1 \ - UV_INDEX_URL="https://pypi.tuna.tsinghua.edu.cn/simple" \ + UV_INDEX_URL=${UV_INDEX_URL} \ TZ=Asia/Shanghai \ PYTHONPATH="/app:${PYTHONPATH}" diff --git a/docker-compose.yaml b/docker-compose.yaml index 4521af2..8a462be 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -3,37 +3,31 @@ services: build: context: . dockerfile: Dockerfile + args: + - UV_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple image: gmv-analytics-prefect:0.1.0 container_name: prefect-gmv-worker restart: unless-stopped env_file: - .env environment: - PROJECT_MAPPING_FILE: /app/店铺映射表.xlsx - develop: - watch: - - action: sync+restart - path: . - target: /app - ignore: - - .git/ - - .venv/ - - __pycache__/ - - .pytest_cache/ - - logs/ - - "*.pyc" - - "Dockerfile" - - "docker-compose.yaml" - - "pyproject.toml" - - "supervisord.conf" - - "requirements-docker.txt" - - action: rebuild - path: Dockerfile - - action: rebuild - path: docker-compose.yaml - - action: rebuild - path: pyproject.toml - - action: rebuild - path: supervisord.conf - - action: rebuild - path: requirements-docker.txt + - PYTHONUNBUFFERED=1 + - PROJECT_MAPPING_FILE=/app/店铺映射表.xlsx + - PREFECT_API_URL=${PREFECT_API_URL:-http://host.docker.internal:4200/api} + extra_hosts: + - "host.docker.internal:host-gateway" + volumes: + - .:/app + - ./logs:/app/logs + - uv_cache:/root/.cache/uv + deploy: + resources: + limits: + cpus: "2.0" + memory: 4G + reservations: + cpus: "0.5" + memory: 512M + +volumes: + uv_cache: