把采集服务装进 Docker:从裸机脚本到可交付镜像的工程实践

[复制链接]
发表于 昨天 10:21 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
采集服务在裸机上跑了半年,没出过大事——直到换服务器那天:Python 版本对不上、cron 任务忘配、字体缺了导致报表乱码,迁移花了一整天。迁完我就把服务容器化了:换情况从「一天」变成「一条命令」。这篇记录容器化过程中的实践和坑。
第一步:写 Dockerfile
  1. FROM python:3.12-slim
  2. WORKDIR /app
  3. COPY requirements.txt .
  4. RUN pip install --no-cache-dir -r requirements.txt
  5. COPY app/ ./app/
  6. RUN useradd -r -u 1001 collector \
  7.     && chown -R collector:collector /app
  8. USER collector
  9. CMD ["python", "-m", "app.collect"]
复制代码
三个细节:slim 底子镜像(够用、体积小)、依赖先于代码拷贝(代码改动不会让依赖层缓存失效)、非 root 运行(安全惯例,数据目次权限一并处理)。
requirements.txt 记得锁版本(requests==2.32.3 这种),否则某天上游更新,镜像构建直接炸——裸机上踩的「依赖漂移」,容器化后并不会自动消失。
第二步:状态外置(最重要的一条)

容器的原则是「可抛弃、可重建」——所以 SQLite 文件、日志、任何有状态的东西,都不能留在容器里:
  1. # docker-compose.yml
  2. services:
  3.   collector:
  4.     build: .
  5.     env_file: .env
  6.     volumes:
  7.       - ./data:/app/data        # serp.db、logs 全在这里
  8.     restart: unless-stopped
复制代码
./data 挂到宿主机上,docker compose down 重建容器,数据纹丝不动。反过来说:如果你发现有文件必须留在容器里才能工作,那是个 bug,迟早会在重建时丢数据。
第三步:调度方式的选择

采集任务大多是「定时批量 + 偶然长跑」,调度有三种姿势:
方式做法适合容器内 cron镜像里装 cron/守护不推荐:日志和退出码都难管宿主机 cron + 一次性容器docker compose run --rm collector批量任务首选常驻 worker服务自己带调度循环需要常驻并发/队列时我用的第二种,宿主机 crontab 就一行:
  1. 0 6 * * * cd /srv/collector && docker compose run --rm collector >> run.log 2>&1
复制代码
每次跑一个干净容器,跑完即退,退出码就是成败——这比在容器里养一个 cron 守护进程干净得多。
第四步:密钥从情况进,不进镜像
  1. # .env(不进 git)
  2. SERPBASE_API_KEY=xxx
复制代码
  1.     env_file: .env
复制代码
两个禁忌:别用 ENV/ARG 把 Key 写进 Dockerfile(docker history 能看到镜像层里的值);别把 .env 打进镜像(.dockerignore 里加一行)。
第五步:日志与健康检查

日志:让程序输出到 stdout,宿主机同一收:
  1.     logging:
  2.       driver: json-file
  3.       options:
  4.         max-size: "10m"
  5.         max-file: "3"
复制代码
不配上限的话,json-file 日志能把磁盘悄悄吃满——之前磁盘篇讲的坑,容器里换个情势再来一遍。
健康检查:别只测「进程活着」,要测「能力还在」——比如最近一次成功采集的时间:
  1.     healthcheck:
  2.       test: ["CMD", "python", "-c",
  3.              "import app.health, sys; sys.exit(0 if app.health.fresh(240) else 1)"]
  4.       interval: 5m
  5.       retries: 3
复制代码
踩坑记录

坑 1:数据留在容器里。 重建容器数据全没。volume 挂载是第一条纪律。
坑 2:时区不对。 容器默认 UTC:日志时间是 UTC、datetime.today() 是 UTC——本地跑没问题、容器里跑出来的「本日」差 8 小时。要么同一按 UTC 思考(存储层推荐),要么显式设 TZ 情况变量,别稀里糊涂。
坑 3:密钥进了镜像层。 ARG API_KEY + ENV API_KEY=$API_KEY 的写法,docker history 一览无余。密钥只交运行时情况。
坑 4:依赖没锁版本。 镜像构建某天突然失败,因为上游发了新版本。requirements.txt 固定到详细版本。
坑 5:root 跑容器。 数据文件权限全归 root,宿主机上想改都费劲。非 root + 目次 chown。
坑 6:迁移完忘了 crontab。 容器化解决了代码和情况,但「谁在几点触发」还是宿主机的事——迁移清单里加上 cron 这一项。
工程清单


  • slim 镜像 + 依赖锁版本 + 非 root
  • 状态全部外置(volume),容器可随时重建
  • 批量任务用「宿主机 cron + run --rm」,别在容器里养 cron
  • 密钥交运行时 env,.dockerignore 清除 .env
  • 日志 stdout + 大小上限;healthcheck 测真实能力
  • 时区显式声明(UTC 或 TZ),迁移清单含 cron
容器化的价值不在「时髦」,而在把「情况」变成「代码」:过去散落在服务器上的 Python 版本、依赖、字体、cron,现在都在 Dockerfile 和 compose 里,可审查、可重建、可迁移。对一个人的采集项目来说,这是性价比很高的一次工程化。
接口的鉴权方式(Key 走情况变量)在 SerpBase 官方文档 有阐明,配合容器化时注意别让密钥进镜像。你们的采集服务跑在裸机还是容器里?迁移时踩过什么坑?评论区聊聊。

免责声明:如果侵犯了您的权益,请联系站长及时删除侵权内容,谢谢合作!qidao123.com:ToB企服之家,中国第一个企服评测及软件市场,开放入驻,技术点评得现金.
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表