ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Crawlab Docker单节点部署指南:爬虫管理平台搭建与避坑

Crawlab Docker单节点部署指南:爬虫管理平台搭建与避坑 前阵子要帮团队把零散的爬虫脚本集中管起来调度靠crontab、日志靠print的日子实在撑不住了我就把目光放到了crawlab这个开源爬虫管理平台上。当时最直接的需求就是先用最省事的方式把平台跑起来能创建任务、能看日志、能配定时调度后续真要加机器了再往分布式扩。所以最终方案很简单就是crawlab通过docker单节点部署先把一套简单爬虫完整跑通。这篇记录就是当时整个部署过程的复盘包含完整的docker-compose配置、爬虫接入步骤、调度设置和一堆排坑经验适合刚接触爬虫平台、想快速用docker把crawlab跑起来的人参考。1. 为什么选择crawlab docker 单节点部署爬虫1.1 爬虫管理平台的痛点大多数爬虫团队在早期都是一个人一台电脑写脚本挂crontab跑完看输出文件。脚本少的时候没毛病但一旦超过十几个任务问题就很明显有的脚本挂了没人知道有的任务跑重复了数据乱掉日志散落各台机器上很难回溯。更头疼的是新同学接手项目时光搞清楚哪个脚本对应哪个任务是哪套逻辑就得花掉大半天。我当时的需求其实很明确要有一个地方能统一创建爬虫任务能看到每个任务跑了多少次、成功多少条、失败多少条最好还能定时触发不用我手动敲命令。crawlab提供的正是这些东西——它本身是一个爬虫管理平台包含任务的创建、调度、日志查看、结果统计、节点管理等功能。虽然不是唯一选择但它的部署方式对容器化很友好后台界面也清爽适合快速上手。1.2 单节点部署为什么够用很多教程一上来就给你讲master-worker分布式架构。实际对于个人或小团队来说单节点部署完全够用而且能省掉大量不必要的麻烦。单节点模式下调度和执行都跑在同一台机器上说白了就是crawlab把主控和干活的人合并成一个角色。为什么够用因为爬虫任务的瓶颈往往不在调度而在目标网站的网络响应速度和本机带宽。你单机并发开个几十个任务只要代码里没有失控的循环或者阻塞轻轻松松。分布式带来的收益是在任务量上百、节点分布各地、需要精细化流量调度时才会明显体现。初期没必要为这种假设买单。再说单节点部署在docker下还有个额外好处整体资源消耗可控占用内存也就几个容器叠加的量级普通8G内存的开发机完全跑得动。我现在这个部署方案MongoDB加Redis加crawlab主容器稳定占用大概在2GB上下加上系统本身8G内存机器依然很宽裕。1.3 docker部署方式的选择理由crawlab的部署方式不止一种可以用二进制安装包也可以跑在k8s上。但对绝大多数人来说docker-compose是最短路径。二进制安装要处理一堆依赖比如MongoDB、Redis、SeaweedFS版本不对就得折腾半天。而docker-compose把crawlab及其依赖的服务全部写成声明式配置一键拉镜像一键启动坏了还能一键删掉重来。这里有个很重要的思路不要抱着“我要会docker才用docker”的心态。docker-compose最核心的价值其实就是环境隔离和可重复性机器A上能跑机器B上就能跑因为我方的运行环境都固化在镜像里了不需要在宿主机安装各种依赖库。这也是我推荐单节点部署时坚持用docker而不是本机直接装crawlab的原因——后面哪怕你要迁移服务器只要把compose文件和挂载目录拷过去就能恢复原状。2. 环境准备与前置条件2.1 硬件与系统要求先说硬件别一上来就想着要几核几G的服务器。因为crawlab本身是Java写的后端加上MongoDB这类数据库内存是关键指标。我的建议是至少4GB内存推荐8GB。CPU的话2核起步普通任务解析页面够用。磁盘就看你要存多少抓取数据默认docker模块镜像加容器启动后大概占8GB左右后续抓取数据多了自然涨。操作系统方面Linux、macOS、Windows都能部署。Linux下我用的是Ubuntu 20.04最顺手。Windows下借助Docker Desktop也能跑但要注意文件路径映射和虚拟化支持问题后面我在故障排查部分会细说。较老版本的Docker Toolbox在Windows上跑compose文件可能会遇到目录挂载兼容问题遇到就升级到Docker Desktop别在Toolbox上浪费时间。2.2 安装Docker与docker-compose这一步骤假设你从来没装过docker。Linux下我习惯用官方源直接装# Ubuntu / Debian 系 sudo apt update sudo apt install -y docker.io docker-compose-v2 sudo systemctl enable --now docker如果你用的是Windows或macOS直接去Docker官网下载Docker Desktop安装包装上之后把Docker Engine跑起来就行。需要注意的一点是Windows下如果Docker Desktop启动报错提示虚拟化未开启要去BIOS里打开虚拟化功能同时在Windows功能里勾选“适用于Linux的Windows子系统”和“虚拟机平台”因为Docker Desktop底层依赖WSL 2的后端。装好后验证环境执行下面的命令docker version docker compose version只要两个命令都能输出版本信息就说明环境OK。现在新版docker自带compose插件老版本的docker-compose命令也能用但字段解析和网络配置略有差异。建议统一用docker compose不带横杠这个新命令下面所有的操作都基于这个语法避免读者在两种命令间来回踩坑。2.3 验证Docker环境是否可用环境装好不等于万事大吉我习惯先跑一个hello-world容器确认整个链路是通的docker run --rm hello-world这一步别看简单它能暴露很多问题。比如在Linux下你可能会遇到permission denied while trying to connect to the Docker daemon socket这是当前用户没加到docker组导致的。解决办法sudo usermod -aG docker $USER # 重新登录终端生效还有网络层面的问题镜像拉取慢或者超时通常就是网络环境导致的。国内推荐在docker配置里加镜像加速地址具体路径是/etc/docker/daemon.json加好之后重启docker服务sudo systemctl restart docker这一步做好之后后续拉crawlab镜像能省掉大量等待时间值得在部署前就处理掉。3. crawlab单节点部署实操3.1 获取并调整docker-compose.ymlcrawlab官方仓库里其实就带了docker-compose的示例文件。不过我更建议自己写一份因为官方示例有些配置偏多单节点部署不需要那么多服务。先看下我用到的完整compose配置services: master: image: crawlab/crawlab:latest container_name: crawlab_master environment: CRAWLAB_SERVER_MASTER: Y CRAWLAB_MONGO_URI: mongodb://mongo:27017/crawlab CRAWLAB_REDIS_ADDRESS: redis:6379 CRAWLAB_FS_EP: http://seadrive:8081 ports: - 8080:8080 volumes: - ./crawlab_data:/data/crawlab depends_on: - mongo - redis - seadrive restart: unless-stopped mongo: image: mongo:5.0 container_name: crawlab_mongo volumes: - ./crawlab_data/mongo:/data/db restart: unless-stopped redis: image: redis:7.0 container_name: crawlab_redis restart: unless-stopped seadrive: image: crawlab/seaweedfs:latest container_name: crawlab_seadrive environment: SEADRIVE_MASTER_SERVER: seadrive:8888 SEADRIVE_FS_SERVER: seadrive:8081 ports: - 8888:8888 - 8081:8081 volumes: - ./crawlab_data/seaweedfs:/data restart: unless-stopped解释一下这个配置里的几个关键点。首先master是crawlab主服务environment里指给了它依赖的MongoDB、Redis和文件服务的地址注意这里地址用的是容器内的服务名mongo、redis、seadrive而不是localhost因为docker compose内部有自动DNS解析。然后CRAWLAB_SERVER_MASTER: Y代表让这个节点同时充当调度节点单节点部署时这一项必须为Y否则平台无法分配任务。文件存储用SeaweedFS它是crawlab存储爬虫日志和上传文件的关键组件。单节点部署时有人会想省掉它我在实际测试中发现没有SeaweedFS的话日志模块会一直报错爬虫任务虽然能跑但看不到实时输出所以还是建议带上。3.2 启动服务与初始化检查配置文件放好后直接在目录下执行启动命令docker compose up -d执行完以后先用docker compose ps看看所有容器的状态。我遇到最常见的情况是mongo容器一直在restart原因大多是数据目录权限问题。此时看下容器日志docker logs crawlab_mongo --tail 100如果日志里提示无法写入/data/db直接给本机的数据目录加权限sudo chown -R 1000:1000 ./crawlab_data/mongo所有容器都进入Up状态后可以确认下主服务的日志是否正常初始化。这里有个经验第一次启动crawlab时它会自动执行数据库初始化脚本创建索引和默认管理员账号所以启动初期日志里会有大量建表操作等个一两分钟再访问后台不要一看日志还没输出完就去重启容器。3.3 登录后台与基础配置初始化完成后浏览器访问http://localhost:8080看到登录页就说明部署成功了。默认账号是admin密码也是admin登录进去第一件事就是修改密码这个不用我说你也该知道为什么。进入系统后建议先去“节点管理”页面看一眼正常情况下应该能看到一个节点处于在线状态。如果节点列表是空的多半是master容器的CRAWLAB_REDIS_ADDRESS配置不对导致注册信息没有写进Redis。这个问题在后面的故障排查部分我会详细展开。另外在“设置”页面可以配置站点基础信息、爬虫文件存储方式单节点部署保持默认就行。到这一步crawlab本身已经能用了。很多人到这里就以为大功告成实际上还没真正验证过爬虫能不能在平台上跑起来下一节就带你走一遍创建爬虫的完整流程。4. 在crawlab中创建并调度一个简单爬虫4.1 编写一个合规的轻量爬虫脚本先声明一下日常爬虫开发一定以合规为前提。我演示用的是一个公开测试站点的列表页抓取遵循robots.txt不对目标站点造成压力也不涉及验证码绕过或逆向破解这类灰色操作。用Python写一个最简单的requests脚本import requests from bs4 import BeautifulSoup def crawl(): url https://quotes.toscrape.com/ headers {User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)} resp requests.get(url, headersheaders, timeout10) resp.raise_for_status() soup BeautifulSoup(resp.text, html.parser) quotes soup.select(div.quote) result [] for item in quotes: text item.select_one(span.text).get_text() author item.select_one(small.author).get_text() result.append({text: text, author: author}) return result if __name__ __main__: data crawl() print(f抓取成功共 {len(data)} 条数据) for d in data[:3]: print(d) # 实际写入数据库或文件的代码这里省略避免引入额外依赖写爬虫时控制抓取频率很重要。我习惯在请求之间加一个time.sleep(random.uniform(1, 2))既减轻对方服务器压力也能降低被限流的概率。真正的生产级代码还应该加上异常重试、数据去重这些逻辑但作为入门演示这个脚本已经足够。4.2 在crawlab中创建爬虫项目并上传进入crawlab后台点击“爬虫”菜单新建爬虫。这里有几个字段值得注意爬虫名称随意但最好和业务关联比如quotes_demo爬虫类型选择“自定义”因为我们是自己写的Python脚本执行命令填python main.py这是crawlab在节点上实际执行的命令文件上传把main.py文件传到对应目录。上传完成后crawlab会自动把文件同步到SeaweedFS。也就是说哪怕你之后在另一台机器上添加worker节点这个文件也会自动分发过去这就是用平台管理爬虫相比手动拷贝脚本的明显优势。创建好后点击“运行”按钮可以看到任务状态从Pending变成Running最后变成Finished。点进任务详情日志里会出现刚才print输出的内容。日志这一能力在调试阶段特别重要以前脚本挂在某台云主机上报错信息根本看不到现在全部集中在平台里排查问题效率提升明显。4.3 配置定时调度与抓取结果查看crawlab支持用cron表达式配置定时任务。在爬虫详情页的“定时任务”标签里新建一个调度规则。比如我想每5分钟跑一次cron表达式就是*/5 * * * *提醒一句演示站点的数据量就那几页频繁抓取没有意义这里只是为了演示调度能力。正式业务中你应根据目标站点的更新频率设置合理的抓取时间别把人家站点抓挂了。关于抓取结果的存储crawlab本身不做数据存储真正存哪里由你的爬虫代码决定。最简单的做法是把抓到的数据写进平台自带的MongoDB之后用MongoDB Compass查看。我在演示脚本中刻意没写存储逻辑因为存储方案太依赖业务场景有人用MySQL有人用ES还有人直接写文件。平台负责的是任务管理、调度和文件分发数据怎么落库由你决定这个分层要搞清楚。5. 常见问题与排查技巧实录5.1 容器启动失败或频繁重启这是新人遇到最多的一个问题。首先是端口被占用8080端口被其他服务占了会导致master容器起不来改掉compose文件里ports映射的宿主机端口就行比如改成8081:8080。其次是mongo和redis的依赖顺序问题理论上depends_on已经保证了先后启动但实际中mongo初始化需要一点时间crawlab连不上会一直重试这个在日志里看到连接错误是正常的等上几十秒再看。还有一个细节默认配置里restart: unless-stopped如果中间手动改了配置文件导致容器起不来它会不停重启刷日志。此时先停掉服务docker compose stop docker compose rm -f # 修改文件后重新启动 docker compose up -d不要抱着“改一下配置让容器自己恢复”的侥幸心理compose容器启动失败后不会自动加载新配置必须重建容器。5.2 爬虫任务一直是Pending任务提交后一直停留在Pending状态大概率是节点没有正常上报。这一类问题先查节点管理页面的在线状态如果节点显示离线去master容器里看日志docker logs crawlab_master --tail 50常见原因有两个。一个是CRAWLAB_REDIS_ADDRESS配置错误导致节点心跳信息写不进Redis。另一个是master容器和node服务之间的时间不同步这个比较隐蔽因为docker容器默认时区未必一致跨时区场景下容易出现心跳超时。解决办法是给master容器加时间挂载volumes: - /etc/localtime:/etc/localtime:ro做完之后重启容器Pending问题基本能解决。5.3 抓取结果看不到任务跑起来了状态也显示Finished但日志里啥也没有或者在MongoDB里找不到数据。如果日志完全没有输出优先怀疑两点一是脚本本身print的数据没被平台捕获这通常是因为crawlab执行命令时用的是非交互式shell而你的脚本里用了input()之类交互函数卡死在等待输入二是SeaweedFS存储异常日志文件写入失败。第一种情况很好排查把脚本里所有交互逻辑去掉确保能纯后台执行。第二种情况需要看seadrive容器日志docker logs crawlab_seadrive --tail 50常见的是文件目录没有写权限执行chmod -R 777 ./crawlab_data/seaweedfs放权就行。日志里出现failed to save file这类关键字基本都是SeaweedFS存储目录问题或磁盘空间过小。5.4 镜像拉取缓慢自带加速配置我已经在前面提到了。如果配置了加速还是慢还有一个简单粗暴的办法在一台网络状况好的机器上先把镜像pull下来然后docker save导出tar包再拷贝到目标机器上docker load导入。这个办法在云服务器和本地开发机之间迁移时特别实用不依赖网络速度。再补充一个版本匹配的点crawlab的镜像tag有很多种latest会追踪最新版但实际使用时我发现某些依赖容易因为版本升级出现兼容问题。如果你追求稳定建议锁定一个具体版本比如crawlab/crawlab:v0.6.0版本号从官方Release页面找不要一直追latest。5.5 资源占用过高怎么处理crawlab全家桶里内存大头是MongoDB默认配置下它会占很多内存但其实很多是缓存不一定是问题。如果你机器内存只有4GB我建议对MongoDB做一下限制mongo: image: mongo:5.0 command: mongod --wiredTigerCacheSizeGB 0.5wiredTigerCacheSizeGB限制的是MongoDB的WiredTiger缓存大小我设成0.5表示最多用512MB做缓存内存压力立刻缓解。Redis也可以加--maxmemory 256mb参数但单节点部署场景下Redis基本不占多少内存不调也行。还有一个容易被忽略的点docker日志文件会无限增长container日志文件动辄几个G磁盘满的时候crawlab页面会直接白屏。给docker配置日志轮转很有必要在daemon.json里加上{ log-driver: json-file, log-opts: { max-size: 10m, max-file: 3 } }重启docker生效这个配置能保证单个容器日志到达上限后自动切割不会把磁盘写爆。6. 参数调优建议与个人体会6.1 调整Mongo和Redis内存限制如果宿主机的内存比较紧张除了上面说的限制MongoDB缓存之外还可以给JVM限一下堆内存。crawlab主服务是Java应用默认JVM会占用宿主机四分之一的物理内存在4GB机器上就是1GB。一般任务量不大时1GB也够但如果你同时跑几十个任务JVM内存不够会频繁GC表现为页面卡顿、任务调度延迟明显。官方提供了JAVA_OPTS环境变量我调成这样environment: JAVA_OPTS: -Xms512m -Xmx1g-Xms是初始堆大小-Xmx是最大堆大小。尽量不要超过2G否则在4GB机器上会和MongoDB抢内存系统开始频繁swap体验比内存不够还难受。6.2 升级到master-worker多节点扩展的思路单节点部署验证通过后很多人会想以后任务多了怎么扩我的建议是先把单节点的配置固化下来备份compose文件和crawlab_data目录等到确实有需要再考虑在另一台机器上部署worker节点。Worker节点的部署和master非常相似区别就两处一是CRAWLAB_SERVER_MASTER设成N二是CRAWLAB_MONGO_URI和CRAWLAB_REDIS_ADDRESS要指向master所在机器的局域网IP不能再写容器内部的服务名。因为worker是独立容器它要通过网络连接master的MongoDB和Redis。environment: CRAWLAB_SERVER_MASTER: N CRAWLAB_MONGO_URI: mongodb://192.168.1.10:27017/crawlab CRAWLAB_REDIS_ADDRESS: 192.168.1.10:6379有一点要提前说清楚worker节点通常不需要单独挂SeaweedFS文件分发是由master节点完成的worker只需要在启动时从master拉取爬虫文件。所以worker的compose文件比master精简很多。6.3 写在最后的几点体会整个流程走下来我最大的体会是crawlab解决的不是“怎么写爬虫”的问题而是“怎么管理爬虫”的问题。脚本本身还是原来那些Python代码但有了统一的调度后台、日志中心和文件分发能力之后团队协作的方式完全不一样了。踩过几次坑之后我建议每个用docker部署crawlab的读者都养成一个习惯任何配置改动之前先备份compose文件和挂载目录。docker好处是环境可复制坏处是你根本不会记得当初是怎么调整到这个状态的不备份就真的找不回来了。好在目录不大一个tar打包即可tar -czf crawlab_backup_$(date %Y%m%d).tar.gz docker-compose.yml crawlab_data/这个备份文件在你某天误删容器、改坏配置时会变成救命稻草。另外一个小技巧想分享给新手crawlab后台的“日志”页面在调试阶段显示的内容可能不够实时我通常直接看容器标准输出docker logs crawlab_master -f很多报错在网页上看不到但容器日志里一定会留下痕迹。等把平台玩熟了再转回网页日志也不迟。这一套部署下来我也越来越觉得工具的选型往往不是比谁功能多而是比谁让你最省心。对于中小规模爬虫任务crawlab配合docker单节点确实是当前平衡成本和效率最好的方式之一。
返回列表