使用Docker Swarm搭建分佈式爬蟲集羣

在爬蟲開發過程當中,你確定遇到過須要把爬蟲部署在多個服務器上面的狀況。此時你是怎麼操做的呢?逐一SSH登陸每一個服務器,使用git拉下代碼,而後運行?代碼修改了,因而又要一個服務器一個服務器登陸上去依次更新?html

有時候爬蟲只須要在一個服務器上面運行,有時候須要在200個服務器上面運行。你是怎麼快速切換的呢?一個服務器一個服務器登陸上去開關?或者聰明一點,在Redis裏面設置一個能夠修改的標記,只有標記對應的服務器上面的爬蟲運行?node

A爬蟲已經在全部服務器上面部署了,如今又作了一個B爬蟲,你是否是又得依次登陸每一個服務器再一次部署?python

若是你確實是這麼作的,那麼你應該後悔沒有早一點看到這篇文章。看完本文之後,你可以作到:linux

  • 2分鐘內把一個新爬蟲部署到50臺服務器上:
docker build -t localhost:8003/spider:0.01 .
docker push localhost:8002/spider:0.01
docker 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.02
docker service update --image 45.77.138.242:8003/spider:0.02 spider
複製代碼

這篇文章不會教你怎麼使用Docker,因此請肯定你有一些Docker基礎再來看本文。git

Docker Swarm是什麼

Docker Swarm是Docker自帶的一個集羣管理模塊。他可以實現Docker集羣的建立和管理。redis

環境搭建

本文將會使用3臺Ubuntu 18.04的服務器來進行演示。這三臺服務器安排以下:docker

  • Master:45.77.138.242
  • Slave-1:199.247.30.74
  • Slave-2:95.179.143.21

Docker Swarm是基於Docker的模塊,因此首先要在3臺服務器上安裝Docker。安裝完成Docker之後,全部的操做都在Docker中完成。shell

在Master上安裝Docker

經過依次執行下面的命令,在Master服務器上安裝Dockerjson

apt-get update
apt-get install -y apt-transport-https ca-certificates curl software-properties-common
curl -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 update
apt-get install -y docker-ce
複製代碼

建立Manager節點

一個Docker Swarm集羣須要Manager節點。如今初始化Master服務器,做爲集羣的Manager節點。運行下面一條命令。ubuntu

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服務器來講,只須要作三件事情:

  1. 安裝Docker
  2. 加入集羣
  3. 信任源

今後之後,剩下的事情所有交給Docker Swarm本身管理,你不再用SSH登陸這個服務器了。

爲了簡化操做,能夠寫一個shell腳原本批量運行。在Slave-1和Slave-2服務器下建立一個init.sh文件,其內容以下。

apt-get update
apt-get install -y apt-transport-https ca-certificates curl software-properties-common
curl -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 update
apt-get install -y docker-ce
echo '{ "insecure-registries":["45.77.138.242:8003"] }' >> /etc/docker/daemon.json
systemctl 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.6
label mantainer='contact@kingname.info'

user root
ENV PYTHONUNBUFFERED=0
ENV PYTHONIOENCODING=utf-8

run python3 -m pip install redis

copy spider.py spider.py
cmd 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=0
docker service update --image 45.77.138.242:8003/spider:0.02 spider
docker 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節點所在的這個服務器上面運行。

廣告時間

本文是多種部署分佈式爬蟲方法中的一種,其餘方法,能夠參閱個人新書《Python爬蟲開發 從入門到實戰》。現已在京東、噹噹、亞馬遜上架。

本書讀者交流羣也已經開通,掃碼添加公衆號,回覆:讀者交流 便可得到加羣方式。

相關文章
相關標籤/搜索