【爬虫】将 Scrapy 部署到 k8s

一. 概述

因为学习了 docker 和 k8s ,不管什么项目都想使用容器化部署😬,一个最主要的原因是,使用容器化部署是真的方便😎。上一篇文章 【爬虫】从零开始使用 Scrapy 介绍了如何使用 scrapy,如果需要启动或者定时运行 scrapy 项目可以部署如下两个组件:

  • scrapyd:它本质上就是帮我们执行了 scrapy crawl spidername 这个命令来启动 scrapy 项目。
  • spiderkeeper:它是 scrapy 项目的可视化管理工具。

scrapyd 源码地址:https://github.com/scrapy/scrapyd

spiderkeeper 源码地址:https://github.com/DormyMo/SpiderKeeper

如果我们要将 scrapy 项目部署到 k8s,那么就需要将 scrapyd 和 spiderkeeper 部署到 k8s 上面,这篇文章将通过如下内容进行介绍:

  1. 自定义 scrapyd 的镜像并上传到 docker hub
  2. 自定义 spiderkeeper 的镜像并上传到 docker hub
  3. 部署 scrapyd 到 k8s
  4. 部署 spiderkeeper 到 k8s
  5. 项目验证是否部署成功
  6. 总结

环境说明

操作系统:Windows 10

安装的组件:

  • Docker Desktop :在 windows 系统中运行 docker,便于在本地构建和推送镜像
  • minikube :在 windows 系统中运行本地 k8s 环境,和其他 k8s 集群使用方式是一样的,这里为了方便测试验证

二. 自定义 scrapyd 的镜像

如果要自定义 scrapyd 的镜像,我们需要知道 scrapyd 在服务器上面是怎样安装的,查阅官方文档

scrapyd 官方文档:https://scrapyd.readthedocs.io/en/stable/install.html

这里我们构建 scrapyd 的镜像需要定义三个文件:

  • Dockerfile :构建镜像的文件
  • scrapyd.conf :scrapyd 的配置文件
  • requirements.txt :python 的依赖包管理文件

Dockerfile 文件内容如下:

FROM python:3.7
COPY scrapyd.conf /etc/scrapyd/scrapyd.conf
COPY requirements.txt requirements.txt
RUN pip install --upgrade pip && pip install -i https://mirrors.aliyun.com/pypi/simple -r requirements.txt
EXPOSE 6800
CMD scrapyd

scrapyd.conf 文件是 scrapyd 的配置文件,在 Unix 系统中会在 /etc/scrapyd/scrapyd.conf 文件中读取配置,官方文档的说明如下图:

image-20220111193421089

因为 scrapyd.conf 文件中的 bind_address 的值默认为 127.0.0.1 ,它只能在本机访问,如果部署到 docker 容器中,则只能在容器内部访问,所以我们需要修改 scrapyd.conf 文件中的 bind_address 的值为 0.0.0.0,以便外部服务能够访问 scrapyd,修改后的 scrapyd.conf 文件内容如下:

[scrapyd]
eggs_dir    = eggs
logs_dir    = logs
items_dir   =
jobs_to_keep = 5
dbs_dir     = dbs
max_proc    = 0
max_proc_per_cpu = 4
finished_to_keep = 100
poll_interval = 5.0
bind_address = 0.0.0.0
http_port   = 6800
debug       = off
runner      = scrapyd.runner
application = scrapyd.app.application
launcher    = scrapyd.launcher.Launcher
webroot     = scrapyd.website.Root

[services]
schedule.json     = scrapyd.webservice.Schedule
cancel.json       = scrapyd.webservice.Cancel
addversion.json   = scrapyd.webservice.AddVersion
listprojects.json = scrapyd.webservice.ListProjects
listversions.json = scrapyd.webservice.ListVersions
listspiders.json  = scrapyd.webservice.ListSpiders
delproject.json   = scrapyd.webservice.DeleteProject
delversion.json   = scrapyd.webservice.DeleteVersion
listjobs.json     = scrapyd.webservice.ListJobs
daemonstatus.json = scrapyd.webservice.DaemonStatus

由于我们的 scrapy 项目是在 scrapyd 容器中运行,而我们上传到 scrapyd 中的是 scrapy 项目的源码,如果要正确的运行 scrapy 项目,需要在 scrapyd 的容器中安装相关的依赖,这里将相关的依赖定义在 requirements.txt 文件中, requirements.txt 文件中的内容如下:

scrapyd~=1.2.1
beautifulsoup4~=4.10.0
requests~=2.26.0
chardet~=3.0.4
lxml~=4.7.1
pymongo==3.5.1

如果你的 scrapy 项目有其他依赖,那么需要在 requirements.txt 文件中添加相关依赖,并重新构建 scrapyd 的镜像。

定义好上面的三个文件之后,在 Dockerfile 文件所在的位置执行下面的命令构建 scrapyd 的镜像:

docker build -t scrapyd .

构建完成镜像后,可以通过下面的命令查看镜像:

docker images |grep scrapyd

如果需要推送镜像到远程仓库需要给镜像打上标签,使用如下命令 Usage: docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]:

docker tag scrapyd wangedison98/scrapyd

使用如下命令推送镜像到远程仓库,这里根据需要推送到你自己的 docker hub 仓库:

docker push wangedison98/scrapyd

三. 自定义 spiderkeeper 的镜像

自定义 spiderkeeper 的镜像和构建 scrapyd 的 镜像一样,首先需要知道 spiderkeeper 在服务器上面是怎样安装的,查阅官方文档:

spiderkeeper 的安装地址:https://github.com/DormyMo/SpiderKeeper

根据官方文档可以知道 spiderkeeper 的安装方式为 pip install spiderkeeper,所以 Dockerfile 文件内容如下:

FROM python:3.7
WORKDIR /home/spiderkeeper

RUN pip install spiderkeeper
EXPOSE 5000

ENV SERVER http://localhost:6800
ENV USERNAME admin
ENV PASSWORD admin

CMD ["sh", "-c", "spiderkeeper --username=$USERNAME --password=$PASSWORD --server=$SERVER"]

使用如下命令构建 spiderkeeper 的镜像:

docker build -t spiderkeeper .

发现构建过程中报出如下错误:

ERROR: Could not find a version that satisfies the requirement MarkupSafe==1.0 (from spiderkeeper) 
ERROR: No matching distribution found for MarkupSafe==1.0

从报错的内容可以知道无法下载 MarkupSafe==1.0 的依赖包,去到 pypi 官网搜索 MarkupSafe 发现有相关的版本,如下图所示:

image-20220112110301230

所以如果要解决这个问题,我们需要修改 spiderkeeper 依赖包的版本,给项目的作者提交了升级依赖的 PR,但是作者并没有合并,这种情况下我打算自己将升级依赖后的 spiderkeeper 推送到 pypi 官网,查阅了一些资料实现了这个方法,后面会写一篇文章介绍如何推送自己的 python 包到 pypi 官网,下面就是我自己推送的 spiderkeeper-new:

image-20220112111014913

下面就是使用自己定义的 spiderkeeper-new 来构建镜像,Dockerfile 的内容如下:

FROM python:3.7
WORKDIR /home/db

RUN pip install -i https://pypi.org/simple/ SpiderKeeper-new
EXPOSE 5000

ENV SERVER http://localhost:6800
ENV USERNAME admin
ENV PASSWORD admin

CMD ["sh", "-c", "spiderkeeper --username=$USERNAME --password=$PASSWORD --server=$SERVER"]

在 Dockerfile 文件所在位置,再次使用如下命令构建 spiderkeeper 镜像:

docker build -t spiderkeeper .

构建完成后可以使用如下命令查看 spiderkeeper 镜像:

docker images |grep spiderkeeper

如果需要推送镜像到远程仓库需要给镜像打上标签,使用如下命令 Usage: docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]:

docker tag spiderkeeper wangedison98/spiderkeeper

使用如下命令推送镜像到远程仓库,这里根据需要推送到你自己的 docker hub 仓库:

docker push wangedison98/spiderkeeper

四. 部署 scrapyd 到 k8s

要部署 scrapyd 到 k8s 只需要定义一个 deployment.yaml 文件,文件的内容如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: scrapyd
  namespace: default
  labels:
    app: scrapyd
spec:
  replicas: 1
  selector:
    matchLabels:
      app: scrapyd
  template:
    metadata:
      labels:
        app: scrapyd
    spec:
      containers:
        - name: scrapyd
          image: wangedison98/scrapyd:latest
          imagePullPolicy: Always
          env:
            - name: TZ
              value: Asia/Shanghai
            - name: NAMESPACE
              value: default
          ports:
            - containerPort: 6800
              name: http-port

---
apiVersion: v1
kind: Service
metadata:
  name: scrapyd
  namespace: default
  labels:
    app: scrapyd
spec:
  ports:
    - name: port
      port: 80
      protocol: TCP
      targetPort: 6800
    - name: port2
      port: 6800
      protocol: TCP
      targetPort: 6800
  selector:
    app: scrapyd
  type: ClusterIP

在 k8s 中执行下面的命令即可部署 scrapyd:

kubectl apply -f deployment.yaml

五. 部署 spiderkeeper 到 k8s

要部署 spiderkeeper 到 k8s 只需要创建一个 deployment.yaml 文件,文件内容如下:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: spiderkeeper
  namespace: default
  labels:
    app: spiderkeeper
spec:
  replicas: 1
  selector:
    matchLabels:
      app: spiderkeeper
  template:
    metadata:
      labels:
        app: spiderkeeper
    spec:
      containers:
        - name: spiderkeeper
          image: wangedison98/spiderkeeper:latest
          imagePullPolicy: Always
          env:
            - name: TZ
              value: Asia/Shanghai
            - name: NAMESPACE
              value: default
            - name: SERVER
              value: http://scrapyd:6800
            - name: USERNAME
              value: admin
            - name: PASSWORD
              value: admin
          ports:
            - containerPort: 5000
              name: http-port

---
apiVersion: v1
kind: Service
metadata:
  name: spiderkeeper
  namespace: default
  labels:
    app: spiderkeeper
spec:
  ports:
    - name: port
      port: 80
      protocol: TCP
      targetPort: 5000
    - name: port2
      port: 5000
      protocol: TCP
      targetPort: 5000
  selector:
    app: spiderkeeper
  type: ClusterIP

在 k8s 中执行下面的命令即可部署 spiderkeeper :

kubectl apply -f deployment.yaml

六. 项目验证

通过前面的步骤已经将 scrapyd 和 spiderkeeper 部署到 k8s 集群了,我们可以通过如下方式暴露服务:

  • ingress (推荐)
  • 设置 service 的 type 为 NodePort
  • 使用 kubectl port-forward TYPE/NAME 临时暴露服务

因为我这里使用的是 minikube 所以,可以使用 minikube service [flags] SERVICE [options] 临时暴露服务,使用如下命令:

minikube service spiderkeeper

之后就可以根据返回的地址和端口访问 spiderkeeper 服务,默认的用户名和密码为:admin,登录成功后如下图所示:

image-20220112144129276

点击 Create Project,创建一个 test 项目:

image-20220112144415955

在 scrapy 项目中使用 scrapyd-deploy --build-egg output.egg 生成部署文件并上传:

image-20220112144757134

七. 总结

本文详细描述了如何将 scrapy 项目部署到 k8s 集群,其中遇到的难点就是官方给出的 spiderkeeper 无法成功构建镜像,所以通过自己下载源码,升级相关依赖,推送了一个新的 spiderkeeper 用来构建镜像,这里没有介绍相关流程,下一篇文件将会讲解如何实现推送 python 包到 pypi 官网。如果你对 docker 和 k8s 比较了解,其他的就没有什么难点了,其中有一点值得说明一下,这里是将 scrapyd 和 spiderkeeper 分开部署的,通过它们之间通过 servicename 进行通信,k8s 的 service 提供了负载均衡的能力,所以当有大量 scrapy 项目需要部署的时候,你可能认为通过增加 scrapyd 的副本数就可以了,但是默认情况下 spiderkeeper 使用的数据库是 sqlite,存储的数据保存在容器内部无法共享,就会导致一个问题,在 spiderkeeper 中无法看到所有的 scrapy 项目,只能看到它连接的那个 scrapyd 中的项目,为了解决这个问题,你可以使用 mysql 作为 spiderkeeper 的外部数据库,这样应该可以实现数据共享,具体实现就不在这里介绍了。

还有一个管理 scrapy 项目的工具,叫做 Gerapy ,也可以了解一下,如果有空可以写一篇文件介绍一下在 k8s 中的使用流程。

Gerapy 源码地址:https://github.com/Gerapy/Gerapy

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容