使用Docker Swarm搭建分散式爬蟲叢集

青南發表於2018-10-14

在爬蟲開發過程中,你肯定遇到過需要把爬蟲部署在多個伺服器上面的情況。此時你是怎麼操作的呢?逐一SSH登入每個伺服器,使用git拉下程式碼,然後執行?程式碼修改了,於是又要一個伺服器一個伺服器登入上去依次更新?

有時候爬蟲只需要在一個伺服器上面執行,有時候需要在200個伺服器上面執行。你是怎麼快速切換的呢?一個伺服器一個伺服器登入上去開關?或者聰明一點,在Redis裡面設定一個可以修改的標記,只有標記對應的伺服器上面的爬蟲執行?

A爬蟲已經在所有伺服器上面部署了,現在又做了一個B爬蟲,你是不是又得依次登入每個伺服器再一次部署?

如果你確實是這麼做的,那麼你應該後悔沒有早一點看到這篇文章。看完本文以後,你能夠做到:

  • 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基礎再來看本文。

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 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節點。執行下面一條命令。

docker swarm init
複製程式碼

執行完成以後,可以看到的返回結果下圖所示。

使用Docker Swarm搭建分散式爬蟲叢集

這個返回結果中,給出了一條命令:

docker swarm join --token SWMTKN-1-0hqsajb64iynkg8ocp8uruktii5esuo4qiaxmqw2pddnkls9av-dfj7nf1x3vr5qcj4cqiusu4pv 45.77.138.242:2377
複製程式碼

這條命令需要在每一個從節點(Slave)中執行。現在先把這個命令記錄下來。

初始化完成以後,得到一個只有1臺伺服器的Docker 叢集。執行如下命令:

docker node ls
複製程式碼

可以看到當前這個叢集的狀態,如下圖所示。

使用Docker Swarm搭建分散式爬蟲叢集

建立私有源(可選)

建立私有源並不是一個必需的操作。之所以需要私有源,是因為專案的Docker映象可能會涉及到公司機密,不能上傳到DockerHub這種公共平臺。如果你的映象可以公開上傳DockerHub,或者你已經有一個可以用的私有映象源,那麼你可以直接使用它們,跳過本小節和下一小節。

私有源本身也是一個Docker的映象,先將拉取下來:

docker pull registry:latest
複製程式碼

如下圖所示。

使用Docker Swarm搭建分散式爬蟲叢集

現在啟動私有源:

docker run -d -p 8003:5000 --name registry -v /tmp/registry:/tmp/registry docker.io/registry:latest
複製程式碼

如下圖所示。

使用Docker Swarm搭建分散式爬蟲叢集

在啟動命令中,設定了對外開放的埠為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
複製程式碼

如下圖所示。

使用Docker Swarm搭建分散式爬蟲叢集

重啟完成以後,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
複製程式碼

如下圖所示。

使用Docker Swarm搭建分散式爬蟲叢集

等待指令碼執行完成以後,你就可以從Slave-1和Slave-2的SSH上面登出了。以後也不需要再進來了。

回到Master伺服器,執行下面的命令,來確認現在叢集已經有3個節點了:

docker node ls
複製程式碼

看到現在叢集中已經有3個節點了。如下圖所示。

使用Docker Swarm搭建分散式爬蟲叢集

到止為止,最複雜最麻煩的過程已經結束了。剩下的就是體驗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 Swarm搭建分散式爬蟲叢集

上傳映象到私有源

映象構建完成以後,需要把它上傳到私有源。此時需要執行命令:

docker push localhost:8003/spider:0.01
複製程式碼

如下圖所示。

使用Docker Swarm搭建分散式爬蟲叢集

大家記住這個構建和上傳的命令,以後每一次更新程式碼,都需要使用這兩條命令。

建立服務

Docker Swarm上面執行的是一個一個的服務,因此需要使用docker service命令建立服務。

docker service create --name spider --network host 45.77.138.242:8003/spider:0.01
複製程式碼

這個命令建立了一個名為spider的服務。預設執行1個容器。執行情況如下圖所示。

使用Docker Swarm搭建分散式爬蟲叢集

當然也可以一建立就用很多容器來執行,此時只需要新增一個--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
複製程式碼

如下圖所示。

使用Docker Swarm搭建分散式爬蟲叢集

檢視節點Log

根據上圖執行結果,可以看到這個執行中的容器的ID為rusps0ofwids,那麼執行下面的命令動態檢視Log:

docker service logs -f 容器ID
複製程式碼

此時就會持續跟蹤這一個容器的Log。如下圖所示。

使用Docker Swarm搭建分散式爬蟲叢集

橫向擴充套件

現在,只有1臺伺服器執行了一個容器,我想使用3臺伺服器執行這個爬蟲,那麼我需要執行一條命令即可:

docker service scale spider=3
複製程式碼

執行效果如下圖所示。

使用Docker Swarm搭建分散式爬蟲叢集

此時,再一次檢視爬蟲的執行情況,可以發現三臺機器上面會各自執行一個容器。如下圖所示。

使用Docker Swarm搭建分散式爬蟲叢集

現在,我們登入slave-1機器上,看看是不是真的有一個任務在執行。如下圖所示。

使用Docker Swarm搭建分散式爬蟲叢集

可以看到確實有一個容器在上面執行著。這是Docker Swarm自動分配過來的。

現在我們使用下面的命令強行把slave-1上面的Docker給關了,再來看看效果。

systemctl stop docker
複製程式碼

回到master伺服器,再次檢視爬蟲的執行效果,如下圖所示。

使用Docker Swarm搭建分散式爬蟲叢集

可以看到,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 Swarm搭建分散式爬蟲叢集

更新爬蟲

如果你的程式碼做了修改。那麼你需要更新爬蟲。

先修改程式碼,重新構建,重新提交新的映象到私有源中。如下圖所示。

使用Docker Swarm搭建分散式爬蟲叢集

接下來需要更新服務中的映象。更新映象有兩種做法。一種是先把所有爬蟲關閉,再更新。

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做更多事情

本文使用的是一個模擬爬蟲的例子,但是顯然,任何可以批量執行的程式都能夠用Docker Swarm來執行,無論你用Redis還是Celery來通訊,無論你是否需要通訊,只要能批量執行,就能用Docker Swarm。

在同一個Swarm叢集裡面,可以執行多個不同的服務,各個服務之間互不影響。真正做到了搭建一次Docker Swarm叢集,然後就再也不用管了,以後的所有操作你都只需要在Manager節點所在的這個伺服器上面執行。

廣告時間

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

本書讀者交流群也已經開通,掃碼新增公眾號,回覆:讀者交流 即可獲得加群方式。

使用Docker Swarm搭建分散式爬蟲叢集

相關文章