# 15.3 Scrapyd 对接 Docker

我们使用了 Scrapyd-Client 成功将 Scrapy 项目部署到 Scrapyd 运行，前提是需要提前在服务器上安装好 Scrapyd 并运行 Scrapyd 服务，而这个过程比较麻烦。如果同时将一个 Scrapy 项目部署到 100 台服务器上，我们需要手动配置每台服务器的 Python 环境，更改 Scrapyd 配置吗？如果这些服务器的 Python 环境是不同版本，同时还运行其他的项目，而版本冲突又会造成不必要的麻烦。

所以，我们需要解决一个痛点，那就是 Python 环境配置问题和版本冲突解决问题。如果我们将 Scrapyd 直接打包成一个 Docker 镜像，那么在服务器上只需要执行 Docker 命令就可以启动 Scrapyd 服务，这样就不用再关心 Python 环境问题，也不需要担心版本冲突问题。

接下来，我们就将 Scrapyd 打包制作成一个 Docker 镜像。

### 1. 准备工作

请确保本机已经正确安装好了 Docker，如没有安装可以参考第 1 章的安装说明。

### 2. 对接 Docker

接下来我们首先新建一个项目，然后新建一个 scrapyd.conf，即 Scrapyd 的配置文件，内容如下：

```ini
[scrapyd]
eggs_dir    = eggs
logs_dir    = logs
items_dir   =
jobs_to_keep = 5
dbs_dir     = dbs
max_proc    = 0
max_proc_per_cpu = 10
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
```

在这里实际上是修改自官方文档的配置文件：[https://scrapyd.readthedocs.io/en/stable/config.html#example-configuration-file](https://scrapyd.readthedocs.io/en/stable/config.html#example-configuration-file)，其中修改的地方有两个：
* max_proc_per_cpu = 10，原本是 4，即 CPU 单核最多运行 4 个 Scrapy 任务，也就是说 1 核的主机最多同时只能运行 4 个 Scrapy 任务，在这里设置上限为 10，也可以自行设置。
* bind_address = 0.0.0.0，原本是 127.0.0.1，不能公开访问，在这里修改为 0.0.0.0 即可解除此限制。

接下来新建一个 requirements.txt ，将一些 Scrapy 项目常用的库都列进去，内容如下：

```
requests
selenium
aiohttp
beautifulsoup4
pyquery
pymysql
redis
pymongo
flask
django
scrapy
scrapyd
scrapyd-client
scrapy-redis
scrapy-splash
```

如果我们运行的 Scrapy 项目还有其他的库需要用到可以自行添加到此文件中。

最后我们新建一个 Dockerfile，内容如下：

```Dockerfile
FROM python:3.6
ADD . /code
WORKDIR /code
COPY ./scrapyd.conf /etc/scrapyd/
EXPOSE 6800
RUN pip3 install -r requirements.txt
CMD scrapyd
```

第一行 FROM 是指在 python:3.6 这个镜像上构建，也就是说在构建时就已经有了 Python 3.6 的环境。

第二行 ADD 是将本地的代码放置到虚拟容器中，它有两个参数，第一个参数是 . ，即代表本地当前路径，/code 代表虚拟容器中的路径，也就是将本地项目所有内容放置到虚拟容器的 /code 目录下。

第三行 WORKDIR 是指定工作目录，在这里将刚才我们添加的代码路径设成工作路径，在这个路径下的目录结构和我们当前本地目录结构是相同的，所以可以直接执行库安装命令等。

第四行 COPY 是将当前目录下的 scrapyd.conf 文件拷贝到虚拟容器的 /etc/scrapyd/ 目录下，Scrapyd 在运行的时候会默认读取这个配置。

第五行 EXPOSE 是声明运行时容器提供服务端口，注意这里只是一个声明，在运行时不一定就会在此端口开启服务。这样的声明一是告诉使用者这个镜像服务的运行端口，以方便配置映射。另一个用处则是在运行时使用随机端口映射时，会自动随机映射 EXPOSE 的端口。

第六行 RUN 是执行某些命令，一般做一些环境准备工作，由于 Docker 虚拟容器内只有 Python3 环境，而没有我们所需要的一些 Python 库，所以在这里我们运行此命令来在虚拟容器中安装相应的 Python 库，这样项目部署到 Scrapyd 中便可以正常运行了。

第七行 CMD 是容器启动命令，在容器运行时，会直接执行此命令，在这里我们直接用 scrapyd 来启动 Scrapyd 服务。

到现在基本的工作就完成了，运行如下命令进行构建：

```
docker build -t scrapyd:latest .
```

构建成功后即可运行测试：

```
docker run -d -p 6800:6800 scrapyd
```

运行之后我们打开：[http://localhost:6800](http://localhost:6800) 即可观察到 Scrapyd 服务，如图 15-2 所示：

![](./assets/15-2.png)

图 15-2 Scrapyd 主页

这样我们就完成了 Scrapyd Docker 镜像的构建并成功运行了。

然后我们可以将此镜像上传到 Docker Hub，例如我的 Docker Hub 用户名为 germey，新建了一个名为 scrapyd 的项目，首先可以打一个标签：

```
docker tag scrapyd:latest germey/scrapyd:latest
```

这里请自行替换成你的项目名称。

然后 Push 即可：

```
docker push germey/scrapyd:latest
```

之后我们在其他主机运行此命令即可启动 Scrapyd 服务：

```
docker run -d -p 6800:6800 germey/scrapyd
```

执行命令后会发现 Scrapyd 就可以成功在其他服务器上运行了。

### 3. 结语

这样我们就利用 Docker 解决了 Python 环境的问题，在后一节我们再解决一个批量部署 Docker 的问题就可以解决批量部署问题了。