【爬蟲】將 Scrapy 部署到 k8s
一. 概述
因為學習了 docker
和 k8s
,不管什麼項目都想使用容器化部署😬,一個最主要的原因是,使用容器化部署是真的方便😎。上一篇文章 【爬蟲】從零開始使用 Scrapy 介紹了如何使用 scrapy
,如果需要啟動或者定時運行 scrapy
項目可以部署如下兩個組件:
scrapyd
:它本質上就是幫我們執行了scrapy crawl spidername
這個命令來啟動scrapy
項目。spiderkeeper
:它是scrapy
項目的可視化管理工具。
scrapyd
源碼地址://github.com/scrapy/scrapyd
spiderkeeper
源碼地址://github.com/DormyMo/SpiderKeeper
如果我們要將 scrapy
項目部署到 k8s
,那麼就需要將 scrapyd
和 spiderkeeper
部署到 k8s
上面,這篇文章將通過如下內容進行介紹:
- 自定義
scrapyd
的鏡像並上傳到docker hub
- 自定義
spiderkeeper
的鏡像並上傳到docker hub
- 部署
scrapyd
到k8s
- 部署
spiderkeeper
到k8s
- 項目驗證是否部署成功
- 總結
環境說明
作業系統:Windows 10
安裝的組件:
- Docker Desktop :在
windows
系統中運行docker
,便於在本地構建和推送鏡像 - minikube :在
windows
系統中運行本地k8s
環境,和其他k8s
集群使用方式是一樣的,這裡為了方便測試驗證
二. 自定義 scrapyd
的鏡像
如果要自定義 scrapyd
的鏡像,我們需要知道 scrapyd
在伺服器上面是怎樣安裝的,查閱官方文檔
scrapyd
官方文檔://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 //mirrors.aliyun.com/pypi/simple -r requirements.txt
EXPOSE 6800
CMD scrapyd
scrapyd.conf
文件是 scrapyd
的配置文件,在 Unix
系統中會在 /etc/scrapyd/scrapyd.conf
文件中讀取配置,官方文檔的說明如下圖:
因為 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 的安裝地址://github.com/DormyMo/SpiderKeeper
根據官方文檔可以知道 spiderkeeper 的安裝方式為 pip install spiderkeeper
,所以 Dockerfile 文件內容如下:
FROM python:3.7
WORKDIR /home/spiderkeeper
RUN pip install spiderkeeper
EXPOSE 5000
ENV SERVER //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 發現有相關的版本,如下圖所示:
所以如果要解決這個問題,我們需要修改 spiderkeeper
依賴包的版本,給項目的作者提交了升級依賴的 PR
,但是作者並沒有合併,這種情況下我打算自己將升級依賴後的 spiderkeeper
推送到 pypi
官網,查閱了一些資料實現了這個方法,後面會寫一篇文章介紹如何推送自己的 python
包到 pypi
官網,下面就是我自己推送的 spiderkeeper-new
:
下面就是使用自己定義的 spiderkeeper-new
來構建鏡像,Dockerfile
的內容如下:
FROM python:3.7
WORKDIR /home/db
RUN pip install -i //pypi.org/simple/ SpiderKeeper-new
EXPOSE 5000
ENV SERVER //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: //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
,登錄成功後如下圖所示:
點擊 Create Project
,創建一個 test 項目:
在 scrapy 項目中使用 scrapyd-deploy --build-egg output.egg
生成部署文件並上傳:
七. 總結
本文詳細描述了如何將 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 源碼地址://github.com/Gerapy/Gerapy