使用Docker Swarm搭建分布式爬蟲集群
https://mp.weixin.qq.com/s?__biz=MzIxMjE5MTE1Nw==&mid=2653195618&idx=2&sn=b7e992da6bd1b24fae8a285fbbe1bd38&chksm=8c99ffb8bbee76ae2b6fc5f265fb586edc8ce8e8d67eb0389b5b247c4cde2a063c0d7d9e432b&scene=0&key=b2ddfae992804f5474c3b20abb75e2a5469a814cac9cbb914d843e7b76e1ea6752c8b6fd32fe01dceca2fe2e898436d5691b7190eb90cdca1a9dcd325dbb621675cc529c2992bf58e8def79d5a644a71&ascene=1&uin=MjgwMTEwNDQxNg%3D%3D&devicetype=Windows-QQBrowser&version=6103000b&lang=zh_CN&pass_ticket=rxCIkuKX8bC9GUfoiX05Q%2B8W%2FnX7p%2B9TdnJOkqoSw4N06LIjjrXo0dqYU5hVSkAz
本文轉載自公眾號 未聞Code
在爬蟲開發過程中,你肯定遇到過需要把爬蟲部署在多個服務器上面的情況。此時你是怎麽操作的呢?逐一SSH登錄每個服務器,使用git拉下代碼,然後運行?代碼修改了,於是又要一個服務器一個服務器登錄上去依次更新?
有時候爬蟲只需要在一個服務器上面運行,有時候需要在200個服務器上面運行。你是怎麽快速切換的呢?一個服務器一個服務器登錄上去開關?或者聰明一點,在Redis裏面設置一個可以修改的標記,只有標記對應的服務器上面的爬蟲運行?
A爬蟲已經在所有服務器上面部署了,現在又做了一個B爬蟲,你是不是又得依次登錄每個服務器再一次部署?
如果你確實是這麽做的,那麽你應該後悔沒有早一點看到這篇文章。看完本文以後,你能夠做到:
-
2分鐘內把一個新爬蟲部署到50臺服務器上:
docker build -t localhost:8003/spider:0.01 .docker push localhost:8002/spider:0.01docker service create --name spider --replicas 50 --network host 45.77.138.242:8003/spider:0.01
-
30秒內把爬蟲從50臺服務器擴展到500臺服務器:
docker service scale spider=500
-
30秒內批量關閉所有服務器上的爬蟲:
docker service scale spider=0
-
1分鐘內批量更新所有機器上的爬蟲:
docker build -t localhost:8003/spider:0.02 .docker push localhost:8003/spider:0.02docker service update --image 45.77.138.242:8003/spider:0.02 spider
這篇文章不會教你怎麽使用Docker,所以請確定你有一些Docker基礎再來看本文。
Docker Swarm是什麽
Docker Swarm是Docker自帶的一個集群管理模塊。他能夠實現Docker集群的創建和管理。
環境搭建
本文將會使用3臺Ubuntu 18.04的服務器來進行演示。這三臺服務器安排如下:
-
Master:45.77.138.242
-
Slave-1:199.247.30.74
-
Slave-2:95.179.143.21
Docker Swarm是基於Docker的模塊,所以首先要在3臺服務器上安裝Docker。安裝完成Docker以後,所有的操作都在Docker中完成。
在Master上安裝Docker
通過依次執行下面的命令,在Master服務器上安裝Docker
apt-get updateapt-get install -y apt-transport-https ca-certificates curl software-properties-commoncurl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable"apt-get updateapt-get install -y docker-ce
創建Manager節點
一個Docker Swarm集群需要Manager節點。現在初始化Master服務器,作為集群的Manager節點。運行下面一條命令。
docker swarm init
運行完成以後,可以看到的返回結果下圖所示。
這個返回結果中,給出了一條命令:
docker swarm join --token SWMTKN-1-0hqsajb64iynkg8ocp8uruktii5esuo4qiaxmqw2pddnkls9av-dfj7nf1x3vr5qcj4cqiusu4pv 45.77.138.242:2377
這條命令需要在每一個從節點(Slave)中執行。現在先把這個命令記錄下來。
初始化完成以後,得到一個只有1臺服務器的Docker 集群。執行如下命令:
docker node ls
可以看到當前這個集群的狀態,如下圖所示。
創建私有源(可選)
創建私有源並不是一個必需的操作。之所以需要私有源,是因為項目的Docker鏡像可能會涉及到公司機密,不能上傳到DockerHub這種公共平臺。如果你的鏡像可以公開上傳DockerHub,或者你已經有一個可以用的私有鏡像源,那麽你可以直接使用它們,跳過本小節和下一小節。
私有源本身也是一個Docker的鏡像,先將拉取下來:
docker pull registry:latest
如下圖所示。
現在啟動私有源:
docker run -d -p 8003:5000 --name registry -v /tmp/registry:/tmp/registry docker.io/registry:latest
如下圖所示。
在啟動命令中,設置了對外開放的端口為8003端口,所以私有源的地址為:45.77.138.242:8003
提示: 這樣搭建的私有源是HTTP方式,並且沒有權限驗證機制,所以如果對公網開放,你需要再使用防火墻做一下IP白名單,從而保證數據的安全。
允許docker使用可信任的http私有源(可選)
如果你使用上面一個小節的命令搭建了自己的私有源,由於Docker默認是不允許使用HTTP方式的私有源的,因此你需要配置Docker,讓Docker信任它。
使用下面命令配置Docker:
echo ‘{ "insecure-registries":["45.77.138.242:8003"] }‘ >> /etc/docker/daemon.json
然後使用下面這個命令重啟docker。
systemctl restart docker
如下圖所示。
重啟完成以後,Manager節點就配置好了。
創建子節點初始化腳本
對於Slave服務器來說,只需要做三件事情:
-
安裝Docker
-
加入集群
-
信任源
從此以後,剩下的事情全部交給Docker Swarm自己管理,你再也不用SSH登錄這個服務器了。
為了簡化操作,可以寫一個shell腳本來批量運行。在Slave-1和Slave-2服務器下創建一個init.sh
文件,其內容如下。
apt-get updateapt-get install -y apt-transport-https ca-certificates curl software-properties-commoncurl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu bionic stable"apt-get updateapt-get install -y docker-ceecho ‘{ "insecure-registries":["45.77.138.242:8003"] }‘ >> /etc/docker/daemon.jsonsystemctl restart docker docker swarm join --token SWMTKN-1-0hqsajb64iynkg8ocp8uruktii5esuo4qiaxmqw2pddnkls9av-dfj7nf1x3vr5qcj4cqiusu4pv 45.77.138.242:2377
把這個文件設置為可自行文件,並運行:
chmod +x init.sh./init.sh
如下圖所示。
等待腳本運行完成以後,你就可以從Slave-1和Slave-2的SSH上面登出了。以後也不需要再進來了。
回到Master服務器,執行下面的命令,來確認現在集群已經有3個節點了:
docker node ls
看到現在集群中已經有3個節點了。如下圖所示。
到止為止,最復雜最麻煩的過程已經結束了。剩下的就是體驗Docker Swarm帶來的便利了。
創建測試程序
搭建測試Redis
由於這裏需要模擬一個分布式爬蟲的運行效果,所以先使用Docker搭建一個臨時的Redis服務:
在Master服務器上執行以下命令:
docker run -d --name redis -p 7891:6379 redis --requirepass "KingnameISHandSome8877"
這個Redis對外使用7891
端口,密碼為KingnameISHandSome8877
,IP就是Master服務器的IP地址。
編寫測試程序
編寫一個簡單的Python程序:
-
import time
-
import redis
-
-
-
client = redis.Redis(host=‘45.77.138.242‘, port=‘7891‘, password=‘KingnameISHandSome8877‘)
-
-
while True:
-
data = client.lpop(‘example:swarm:spider‘)
-
if not data:
-
break
-
print(f‘我現在獲取的數據為:{data.decode()}‘)
-
time.sleep(10)
這個Python每10秒鐘從Redis中讀取一個數,並打印出來。
編寫Dockerfile
編寫Dockerfile,基於Python3.6的鏡像創建我們自己的鏡像:
from python:3.6label mantainer=‘[email protected]‘user rootENV PYTHONUNBUFFERED=0ENV PYTHONIOENCODING=utf-8run python3 -m pip install rediscopy spider.py spider.pycmd python3 spider.py
構建鏡像
編寫完成Dockerfile以後,執行下面的命令,開始構建我們自己的鏡像:
docker build -t localhost:8003/spider:0.01 .
這裏需要特別註意,由於我們要把這個鏡像上傳到私有源供Slave服務器上面的從節點下載,所以鏡像的命名方式需要滿足localhost:8003/自定義名字:版本號
這樣的格式。其中的自定義名字
和版本號
可以根據實際情況進行修改。在本文的例子中,我由於要模擬一個爬蟲的程序,所以給它取名為spider,由於是第1次構建,所以版本號用的是0.01。
整個過程如下圖所示。
上傳鏡像到私有源
鏡像構建完成以後,需要把它上傳到私有源。此時需要執行命令:
docker push localhost:8003/spider:0.01
如下圖所示。
大家記住這個構建和上傳的命令,以後每一次更新代碼,都需要使用這兩條命令。
創建服務
Docker Swarm上面運行的是一個一個的服務,因此需要使用docker service命令創建服務。
docker service create --name spider --network host 45.77.138.242:8003/spider:0.01
這個命令創建了一個名為spider
的服務。默認運行1個容器。運行情況如下圖所示。
當然也可以一創建就用很多容器來運行,此時只需要添加一個--replicas
參數即可。例如一創建服務就使用50個容器運行:
docker service create --name spider --replicas 50 --network host 45.77.138.242:8003/spider:0.01
但是一般一開始的代碼可能會有不少bug,所以建議先使用1個容器來運行,觀察日誌,發現沒有問題以後再進行擴展。
回到默認1個容器的情況下,這個容器可能在目前三臺機器在的任何一臺上面。通過執行下面的命令來觀察這一個默認的容器運行情況:
docker service ps spider
如下圖所示。
查看節點Log
根據上圖執行結果,可以看到這個運行中的容器的ID為rusps0ofwids
,那麽執行下面的命令動態查看Log:
docker service logs -f 容器ID
此時就會持續跟蹤這一個容器的Log。如下圖所示。
橫向擴展
現在,只有1臺服務器運行了一個容器,我想使用3臺服務器運行這個爬蟲,那麽我需要執行一條命令即可:
docker service scale spider=3
運行效果如下圖所示。
此時,再一次查看爬蟲的運行情況,可以發現三臺機器上面會各自運行一個容器。如下圖所示。
現在,我們登錄slave-1機器上,看看是不是真的有一個任務在運行。如下圖所示。
可以看到確實有一個容器在上面運行著。這是Docker Swarm自動分配過來的。
現在我們使用下面的命令強行把slave-1上面的Docker給關了,再來看看效果。
systemctl stop docker
回到master服務器,再次查看爬蟲的運行效果,如下圖所示。
可以看到,Docker Swarm探測到Slave-1掉線以後,他就會自動重新找個機器啟動任務,保證始終有3個任務在運行。在這一次的例子中,Docker Swarm自動在master機器上啟動了2個spider容器。
如果機器性能比較好,甚至可以在3每臺機器上面多運行幾個容器:
docker service scale spider=10
此時,就會啟動10個容器來運行這些爬蟲。這10個爬蟲之間互相隔離。
如果想讓所有爬蟲全部停止怎麽辦?非常簡單,一條命令:
docker service scale spider=0
這樣所有爬蟲就會全部停止。
同時查看多個容器的日誌
如果想同時看所有容器怎麽辦呢?可以使用如下命令查看所有容器的最新的20行日誌:
docker service ps robot | grep Running | awk ‘{print $1}‘ | xargs -i docker service logs --tail 20 {}
這樣,日誌就會按順序顯示出來了。如下圖所示。
更新爬蟲
如果你的代碼做了修改。那麽你需要更新爬蟲。
先修改代碼,重新構建,重新提交新的鏡像到私有源中。如下圖所示。
接下來需要更新服務中的鏡像。更新鏡像有兩種做法。一種是先把所有爬蟲關閉,再更新。
docker service scale spider=0docker service update --image 45.77.138.242:8003/spider:0.02 spiderdocker service scale spider=3
第二種是直接執行更新命令。
docker service update --image 45.77.138.242:8003/spider:0.02 spider
他們的區別在於,直接執行更新命令時,正在運行的容器會一個一個更新。
運行效果如下圖所示。
你可以用Docker Swarm做更多事情
本文使用的是一個模擬爬蟲的例子,但是顯然,任何可以批量運行的程序都能夠用Docker Swarm來運行,無論你用Redis還是Celery來通信,無論你是否需要通信,只要能批量運行,就能用Docker Swarm。
在同一個Swarm集群裏面,可以運行多個不同的服務,各個服務之間互不影響。真正做到了搭建一次Docker Swarm集群,然後就再也不用管了,以後的所有操作你都只需要在Manager節點所在的這個服務器上面運行。
使用Docker Swarm搭建分布式爬蟲集群