【爬蟲】將 Scrapy 部署到 k8s

blogwd發表於2022-01-12

一. 概述

因為學習了 dockerk8s ,不管什麼專案都想使用容器化部署?,一個最主要的原因是,使用容器化部署是真的方便?。上一篇文章 【爬蟲】從零開始使用 Scrapy 介紹瞭如何使用 scrapy,如果需要啟動或者定時執行 scrapy 專案可以部署如下兩個元件:

  • scrapyd:它本質上就是幫我們執行了 scrapy crawl spidername 這個命令來啟動 scrapy 專案。
  • spiderkeeper:它是 scrapy 專案的視覺化管理工具。

scrapyd 原始碼地址:https://github.com/scrapy/scrapyd

spiderkeeper 原始碼地址:https://github.com/DormyMo/SpiderKeeper

如果我們要將 scrapy 專案部署到 k8s,那麼就需要將 scrapydspiderkeeper 部署到 k8s 上面,這篇文章將通過如下內容進行介紹:

  1. 自定義 scrapyd 的映象並上傳到 docker hub
  2. 自定義 spiderkeeper 的映象並上傳到 docker hub
  3. 部署 scrapydk8s
  4. 部署 spiderkeeperk8s
  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

要部署 scrapydk8s 只需要定義一個 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

要部署 spiderkeeperk8s 只需要建立一個 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

六. 專案驗證

通過前面的步驟已經將 scrapydspiderkeeper 部署到 k8s 叢集了,我們可以通過如下方式暴露服務:

  • ingress (推薦)
  • 設定 servicetypeNodePort
  • 使用 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 官網。如果你對 dockerk8s 比較瞭解,其他的就沒有什麼難點了,其中有一點值得說明一下,這裡是將 scrapydspiderkeeper 分開部署的,通過它們之間通過 servicename 進行通訊,k8sservice 提供了負載均衡的能力,所以當有大量 scrapy 專案需要部署的時候,你可能認為通過增加 scrapyd 的副本數就可以了,但是預設情況下 spiderkeeper 使用的資料庫是 sqlite,儲存的資料儲存在容器內部無法共享,就會導致一個問題,在 spiderkeeper 中無法看到所有的 scrapy 專案,只能看到它連線的那個 scrapyd 中的專案,為了解決這個問題,你可以使用 mysql 作為 spiderkeeper 的外部資料庫,這樣應該可以實現資料共享,具體實現就不在這裡介紹了。

還有一個管理 scrapy 專案的工具,叫做 Gerapy ,也可以瞭解一下,如果有空可以寫一篇檔案介紹一下在 k8s 中的使用流程。

Gerapy 原始碼地址:https://github.com/Gerapy/Gerapy

相關文章