01-必备软件的安装与故障排除
附录A 必备软件的安装与故障排除
A.1 必备软件的安装
本书使用了庞大的虚拟服务器系统演示现实中多服务器部署环境下的Scrapy使用。我们使用了行业标准工具——Vagrant和Docker,来搭建该系统。由于本书严重依赖于网站内容和布局,如果我们使用不可控的网站,那么我们的例子将会在几个月的时间之后无法使用。Vagrant和Docker为我们提供了一个独立的环境,在这里我们的示例无论现在还是以后都能正常运行。作为附带的好处,我们不会访问任何远程服务器,因此就不会对任何网站管理者造成不便。即使我们破坏了某些东西,造成示例无法工作,也可以使用两个命令: vagrant destroy 和 vagrant up --no-parallel ,销毁并重建系统,继续运行。
在开始之前,我需要说明一下,该基础架构是专门为本书读者的需求定制的。尤其是有关Docker的部分,普遍共识是每个Docker容器应当是只运行单一进程的微服务。我们并没有这么做。我们的很多Docker容器都比较重,我们可以使用 vagrant ssh 连接它们并执行各种操作。尤其是我们的开发机看起来一点也不像微服务。这是我们去往该隔离系统的用户友好的网关,我们将其视为功能齐全的Linux机器。如果我们不使用这种方式改变规则,就必须使用大量的Vagrant和Docker命令,更加深入地排查故障,在这种情况下本书将很快变为Vagrant/Docker书籍。我希望Docker爱好者能够原谅我们,并且每位读者能够享受到Vagrant和Docker带给我们的方便和益处。
本书中的容器不适用于生产环境。
我们不可能测试每个软件/硬件的配置。假设某些地方无法工作,如果可以的话,请修复它并在GitHub中向我们发送一个Pull Request。如果你不知道如何修复,那么请在GitHub上搜索相关issue,如果不存在的话请打开一个新的issue。
A.2 系统
本节用于参考。你可以先跳过本节内容,当想要更好地理解本书系统的构成方式时,可以返回来阅读本节。我们在相关章节中重复了本节中的部分信息。
我们使用Vagrant构建了如下系统(见图A.1)。

在图A.1中,每个方框表示一台服务器,主机名是其标题的第一部分( dev 、 Web 、 es 等)。标题的第二部分是其使用的Docker镜像( scrapybook/dev 、 scrapybook/web 、 scrapybook/es 等)。下面是运行在该服务器上的软件的简要描述。线段表示不同服务器之间的链接,其协议写在线段旁边。Docker所提供的隔离的一部分是不允许超出显式声明的连接。也就是说,比如你想在Spark服务器上使用1234端口监听某些东西,除非你在Vagrant文件中添加相关声明暴露该端口,否则没有人能连接到该端口。请记住这一点,以避免在其他服务器中安装自定义软件时出现问题。
在大部分章节中,我们只会使用到两个机器: dev 和 web 。 vagrant ssh 可以让我们连接到开发机中。我们可以从这里使用主机名很轻松地访问其他机器( mysql 、 web 等)。我们可以通过执行如 ping web 的操作来确认能否访问web机器。我们在每章中使用并解释了很多命令。第9章演示了如何推送数据到不同的数据库。第11章使用了3个运行Scrapyd的Docker容器(实际上与开发机相同,以减少下载大小),这些机器的主机名分别是 scrapyd1-3 。我们还使用了一个主机名为 spark 的服务器,用于运行Apache Spark以及FTP服务。可以使用 vagrant ssh spark 连接该服务器,并运行Spark任务。
可以在GitHub顶级目录的 Vagrantfile 中找到该系统的描述。当输入 vagrant up --no-parallel 时,系统将开始构建。这将会花费几分钟时间,尤其是在第一次构建时,我们将会在后面的FAQ中了解到更详细的介绍。可以看到,本书代码是挂载在 ~/book 目录当中的。任何时候我们在宿主机修改其中的内容时,变更都会自动传播。这样我们就可以使用文本编辑器或IDE修改文件,并且可以在开发机中快速查看变化了。
最后,一些监听端口被转发到我们的宿主机中,并暴露了相关的服务。比如,你可以使用一个简单的Web浏览器来访问它们。如果你已经在计算机中使用了其中某个端口,那么会产生冲突,导致系统构建无法成功。我们将会在后面的FAQ中告知你如何解决这种情况。表A.1是转发的端口列表。
| 机器和服务 | 从开发机访问的地址 | 从你的(宿主)机访问的地址 |
| :----- | :----- | :----- | :----- | :----- |
| Web—eb服务器 | http://web:9312 | http://localhost:9312 |
| dev—scrapyd | http://dev:6800 | http://localhost:6800 |
| scrapyd1—scrapyd | http://scrapyd1:6800 | http://localhost:6801 |
| scrapyd2—scrapyd | http://scrapyd2:6800 | http://localhost:6802 |
| scrapyd3—scrapyd | http://scrapyd3:6800 | http://localhost:6803 |
| es—Elasticsearch API | http://es:9200 | http://localhost:9200 |
| spark—FTP | ftp://spark:21 & 30000-9 | ftp://localhost:21 & 30000-9 |
| Redis—Redis API | redis://redis:6379 | redis://localhost:6379 |
| MySQL - MySQL数据库 | mysql://mysql:3306 | mysql://localhost:3306 |
部分机器的 ssh 也是暴露的,Vagrant负责为我们重定向并转发这些端口,以避免冲突。我们所需要做的就是运行 vagrant ssh <hostname> 来访问想要连接的机器。
A.3 安装概述
我们所需安装的必要软件如下:
- Vagrant;
- git;
- VirtualBox(Windows或Mac主机)或Docker(Linux主机)。
在Windows中,可能还需要启用 git ssh 客户端。你可以访问它们的网站,并遵照它们对你所使用的平台描述的步骤操作。在下面几节中,我们将尝试提供逐步指引方案,目前来说这些方法是有效的,不过它们肯定会在未来某个时间失效,因此也请随时关注其官方文档。
A.4 在Linux上安装
我们之所以首先介绍如何在Linux上安装系统是因为它是最简单的。我将以Ubuntu 14.04.3 LTS (Trusty Tahr)进行演示,不过该过程在其他分发版本中也会十分相似,当然分发版本越不常见,你就越能了解如何填补其中的差距。为了安装Vagrant,需要访问Vagrant的网站: <a class="my_markdown" href="['https://www.vagrant.com/']">https://www.vagrant.com/</a> ,并浏览其下载页。右键单击 Debian package, 64-bit version 。复制链接地址,如图A.2所示。

我们将使用终端安装Vagrant,因为这是最通用的方式,尽管可以在Ubuntu上通过几下单击达成相同目的。为了打开终端,需要单击屏幕左上角的Ubuntu图标来打开 Dash 。另一种方案是,按下 Windows 按键。然后输入 terminal ,并单击 Terminal 图标以打开它。
我们输入 wget ,并粘贴从Vagrant页面中得到的链接。几秒后,将会下载一个 .deb 文件。输入 sudo dpkg -I <name of the .deb file you just downloaded> 以安装文件。到这里为止,Vagrant已经被安装好了。
安装 git 只需要在终端中输入如下两行命令。
$ sudo apt-get update
$ sudo apt-get install git
现在,让我们来安装Docker。我们将按照 https://docs.docker. com/engine/ installation/ubuntulinux/ 的指南进行安装。在终端中,输入如下命令。
$ sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80
--recv-keys 58118E89F3A912897C070ADBF76221572C52609D
$ echo "deb https://apt.dockerproject.org/repo ubuntu-trusty main" | sudo
tee /etc/apt/sources.list.d/docker.list
$ sudo apt-get update
$ sudo apt-get install docker-engine
$ sudo usermod -aG docker $(whoami)
我们登出并再重新登录以应用分组变化,此时,应该可以没有问题地使用 docker ps 命令了。现在,我们可以下载本书的代码,并享受本书内容。
$ git clone https://github.com/scalingexcellence/scrapybook.git
$ cd scrapybook
$ vagrant up --no-parallel
A.5 在Windows或Mac上安装
Windows和Mac环境中的安装过程是相似的,因此我们将一起介绍这两种环境下的安装,并凸显它们之间的区别。
A.5.1 安装Vagrant
为了安装Vagrant,我们需要访问Vagrant的网站: <a class="my_markdown" href="['https://www.%20vagrantup.com/']">https://www. vagrantup.com/</a> ,并浏览其下载页。选择自己的操作系统,并使用安装向导进行安装,如图A.3所示。

几次单击之后,Vagrant将会安装好。要想访问它,需要打开命令行或终端。
A.5.2 如何访问终端
在Windows中,可以按下Ctrl + Esc 或Win 键打开应用菜单,并搜索 cmd 。而在Mac中,可以按下Cmd + Space,并搜索 terminal 。上述访问方式如图A.4所示。

无论哪种情况,我们都得到了一个控制台窗口,当我们输入 vagrant 时,将会打印出一些说明。这就是我们现在所需要做的所有事情。
A.5.3 安装VirtualBox和Git
为了简化该步骤,我们将安装Docker Toolbox,在其中已经包含了Git和VirtualBox。如果我们使用Google搜索docker toolbox install,可以找到 <a class="my_markdown" href="['https://www.docker.com/%20docker-toolbox']">https://www.docker.com/ docker-toolbox</a> ,在这里可以下载适用于我们操作系统的版本。安装过程像Vagrant一样简单,如图A.5所示。

A.5.4 确保VirtualBox支持64位镜像
安装好Docker Toolbox之后,可以在Windows桌面或Mac的启动器(按下F4打开)中找到VirtualBox的图标。尽早检查VirtualBox是否支持64位镜像非常重要,检查过程如图A.6所示。

打开VirtualBox,单击 New 按钮来创建一个新的虚拟机。查看版本下拉菜单,检查其中的选项,然后单击 Cancel 。我们现在还不需要真正创建一个虚拟机。
如果下拉菜单中包含64位镜像,那么我们可以跳过本节接下来的部分。
如果下拉菜单中没有包含64位镜像,或者当我们尝试运行一个64位虚拟机时得到类似 VT-x/AMD-V hardware acceleration is notavailable on your system 的错误信息的话,我们可能就有一些麻烦了。
这意味着VirtualBox无法检测到我们电脑中的VT-x或AMD-V扩展。如果我们的硬件过旧,那么这种情况是合理且符合预期的。但是如果是新硬件,那么很可能是由于这些扩展在BIOS中被禁用了。如果我们使用的是Windows系统(很大可能),一个简单的方式是通过名为SecurAble的工具进行检查,该工具可以从 <a class="my_markdown" href="['https://www.grc.com/%20securable.htm']">https://www.grc.com/ securable.htm</a> 中下载。如果 Hardware Virtualization 为红色且提示为 No 的话,就意味着我们的CPU不支持必要的虚拟扩展。在这种情况下,我们将无法运行Vagrant/Docker,不过我们仍然可以安装Scrapy,并且使用在线网站( scrapybook.s3. amazonaws.com )作为源来运行这些示例。我们可以从第4章中的爬虫开始使用,该爬虫是可以直接拿来使用的,并且是针对在线网站构建的。
如果 Hardware Virtualization 为绿色,我们很可能可以从BIOS中启用该扩展。使用Google搜索你的电脑机型,以及如何变更BIOS中关于VT-x或AMD-V的设置。通常情况下,我们可以在重启时按下某个按键以访问BIOS。在这里,我们需要进入安全相关的菜单,然后启用 Virtualization Technology (VTx) 或其他类似写法的选项。重启过后,我们将能够从该计算机运行64位的虚拟机。
A.5.5 在Windows中启用ssh客户端
如果我们使用的是Mac,将不需要本步,可以直接跳到下一节中。如果我们使用的是Windows,则没有提供给我们默认的 ssh 客户端。幸运的是,Git(我们刚才安装的)有一个 ssh 客户端,我们可以通过添加Windows Path的方式激活它,如图A.7所示。

默认情况下, ssh 的二进制文件位于 C:\Program Files\Git\usr\bin 中(图A.7所示的1区域)。我们需要添加 C:\Program Files\Git\usr\bin 和 C:\Program Files\Git\bi``n 到路径当中。为了实现该目的,我们需要将它们复制到记事本中,并在每个路径前添加;来连接它们(如图A.7所示的3区域)。最终结果如下所示:
;C:\Program Files\Git\bin;C:\Program Files\Git\usr\bin
现在,按下Ctrl + Esc 或Win按键,打开开始菜单,然后找到 Computer(计算机) 选项。右键单击它(图A.7所示的4区域),并选择 Properties(属性) 。在弹出的窗口中,选择 Advanced System Settings(高级系统设置) 。然后,单击 Environment Variables(环境变量) 。这里是我们用于编辑 Path 的表单。单击 Path 以编辑它。在 Edit User Variable(编辑用户变量) 对话框中,我们在结尾处粘贴在记事本中连接的两个新路径。应当小心不要意外覆盖追加路径;之前的任何值。然后单击几次 OK(确定) ,退出所有对话框,此刻必备软件已经全部安装完毕。
A.5.6 下载本书代码并创建系统
现在,我们已经拥有了一个功能齐全的Vagrant系统,接下来打开一个新的控制台/终端/命令行(我们已经在前面见过如何打开),输入如下命令,享受本书所带来的乐趣。
$ git clone https://github.com/scalingexcellence/scrapybook.git
$ cd scrapybook
$ vagrant up --no-parallel
A.6 系统创建与操作FAQ
接下来是你在首次使用Scrapy工作时可能遇到的问题的解决方案。
A.6.1 我应该下载什么以及需要花费多少时间
当我们运行 vagrant up --no-parallel 之后,就没有那么多的可见度了。所经过的时间与我们的下载速度及网络连接质量密切相关。图A.8所示为当网络连接能力达到每秒下载5MB(38Mbit/s)内容时的期望时间。

如果我们使用的是Linux环境,或是Docker已经被安装好,那么前三步就不是必要的,这样可以为我们节省4分钟的时间以及450MB的下载量。
请注意,上述所有步骤只与用于下载全部内容的 vagrant up --no-parallel 命令的第一次运行相关。后续运行在通常情况下只会花费不到10秒的时间。
A.6.2 如果Vagrant无法响应应该怎么办
可能会有很多原因导致Vagrant无法响应,我们所需要做的就是按下Ctrl + C两次从中退出。然后再次尝试 vagrant up --no-parallel ,此时应当能够恢复。我们可能需要这样做几次,这取决于网络连接的速度和质量。如果打开 Windows Task Manager(Windows任务管理器) 或Mac的 Activity Monitor(活动监视器) ,可以更清晰地看到Vagrant正在做什么,如图A.9所示。

在下载期间或之后不超过60秒的短暂无法响应是可以预期的,因为此时软件正在进行安装。而更长时间的无法响应则很有可能意味着出现了某些问题。
当我们中断后再恢复时, vagrant up --no-parallel 可能会执行失败,并返回类似下面所述的错误信息。
Vagrant cannot forward the specified ports on this VM... The forwarded
port to 21 is already in use on the host machine.
这同样是一个临时性的问题。如果我们再次运行 vagrant up --no-parallel ,则应该能够成功恢复。
假设我们见到了如下的失败信息。
... Command: "docker" "ps" "-a" "-q" "--no-trunc"
Stderr: bash: line 2: docker: command not found
如果发生该情况,请按照下一个问题所显示的方法关闭并恢复虚拟机。
A.6.3 如何快速关闭/恢复虚拟机
当使用虚拟机时,最快的关闭方式是进入节能状态,具体来说就是打开VirtualBox,选择虚拟机,按下Ctrl+ V 或 Cmd + V,或右键单击菜单并选择 Save State( 保存状态 ) ,如图A.10所示。

我们可以通过运行 vagrant up --no-parallel 恢复虚拟机。开发和Spark服务器的 ~/book 目录都应该可以正常工作。
A.6.4 如何完全重置虚拟机
如果我们想要变更核心数量、内存大小或虚拟机的端口映射,则需要进行完全重置。为了达到该目的,我们仍然需要按照前一个答案的步骤操作,不过现在要选择的是 Power Off(关闭电源) ,或者按下Ctrl + F或 Cmd + F。我们也能通过编程方式完成此事,其执行语句是 vagrant global-status --prune 。我们可以找到名为“docker-provider”的虚拟主机的ID(比如95d1234),然后使用 vagrant halt 停止它,比如 vagrant halt 957d887 。
然后,可以使用 vagrant up --no-parallel 重启系统。不过很遗憾的是,开发和Spark机器很可能已经清空了其 ~/book 目录。要想解决该问题,可以运行 vagrant destroy -f dev spark ,然后重新运行 vagrant up --no-parallel 。这将解决此类问题。
A.6.5 如何调整虚拟机大小
我们可能想要改变虚拟机的大小,比如将使用的内存从2GB调整为1GB,将使用的8核调整为4核。我们可以通过编辑 Vagrantfile.dockerhost 的 vb.memory 及 vb.cpus 设置来进行调整。然后,按照上一个答案的流程完全重置虚拟机。
A.6.6 如何解决端口冲突
有时,在主机上运行的一些服务可能占用了该系统需要的端口。首先,请注意如果我们打开了这两个机器的 Vagrantfile ,请移除其中所有的 forwarded_port 语句,按照后面讲到的方法重置,此时仍然能够运行本书中的示例。我们可能刚好不太容易检查宿主机上这些端口运行的服务(通常通过Web浏览器)。
也就是说,我们可以通过重新映射冲突端口的方式更适当地解决冲突。让我们使用Web服务器9312端口的冲突作为示例。根据我们运行的是原生Linux还是虚拟机,过程会有些许不同。
Linux环境使用原生Docker
该问题将表现为如下所示的错误信息。
Stderr: Error: Cannot start container a22f...: failed to create
endpoint web on network bridge: Error starting userland proxy: listen
tcp 0.0.0.0:9312: bind: address already in use
打开Dockerfile,编辑Web服务器中 forwarded_port 语句的 host 值。之后,使用 vagrant destroy web 销毁Web服务器,并通过 vagrant up web 重启,如果问题发生在初始化加载阶段,则使用 vagrant up --no-parallel 恢复加载。
Windows或Mac环境使用虚拟机
此时,我们会得到不同的错误信息。
Vagrant cannot forward the specified ports on this VM, since they
would collide... The forwarded port to 9312 is already in use
on the host machine...
为了修复该问题,我们需要打开 Vagrantfile.dockerhost ,移除已有的包含端口号的行。然后在下面添加自定义端口转发语句,比如: config.vm.network “forwarded_port”, guest: 9312, host: 9316 。此时将会修改为使用9316端口。接下来,按照“如何完全重置虚拟机”这一问题的答案流程重置虚拟机,一切又都会正常工作了。
A.6.7 如何隐藏在公司代理背后工作
有一些简单代理和TLS拦截代理。简单代理需要我们在请求到达互联网之前,转发到代理服务器上。它们可能需要权限验证,也可能不需要,不过无论哪种情况,我们需要使用的信息就是URL,该URL可以从我们的IT部门获取到。它大概形如 http://user:[email protected]:8080/ 。如果我们使用的是Linux,而不是虚拟机,很可能已经完全正确配置,不再需要进一步的调整。不过如果我们使用的是虚拟机,则需要使代理服务器在Vagrant、Docker provider VM、Ubuntu的APT下载以及Docker服务自身都应当可用。所有这些操作都已经在 Vagrantfile.dockerhost 中进行了处理,我们只需要移除定义 proxy_url 行的注释,并正确设置其值即可。
假设遇到了如下的SSL相关的问题。
SSL certificate problem: unable to get local issuer certificate
...
If you'd like to turn off curl's verification of the certificate, use
the -k (or --insecure) option.
无论是Vagrant还是部署的Docker,我们都很可能需要处理TLS拦截代理的问题。这种代理旨在以一种“中间人”的角色监控所有安全和不安全流量。它们代表我们执行https请求,在必要时验证证书;而我们执行到它们的https连接,验证它们的证书。我们的IT部门很可能会提供给我们一个证书,通常情况下是 .crt 文件的形式。我们将该文件的副本放到本书主目录下( Vagrantfile 所在的目录)。接下来,按照前面例子设置 proxy_url ,然后更进一步取消掉定义 crt_filename 变量所在行的注释,将其值设置为我们的证书文件的名称。
A.6.8 如何连接Docker provider虚拟机
如果我们处于Linux环境中,并且没有使用虚拟机,那么我们的机器已经是Docker provider,此时无需做任何事情。如果我们使用的是虚拟机,那么可以通过运行 vagrant global-status --prune 得到Docker provider的ID,然后找到名为 docker-provider 的机器。我们可以在Linux或Mac环境中,使用别名的方式对其实现自动化。
$ alias provider_id="vagrant global-status --prune | grep 'docker-
provider' | awk '{print \$1}'"
我们可以使用 vagrant ssh <provider id> ,或者在已设置别名的情况下使用 vagrant ssh $(provider_id) 来连接Docker provider。在这里是Ubuntu Trusty 64位虚拟机。
A.6.9 每个服务器使用了多少CPU/内存
如果我们使用了原生Docker,或者按照前一个答案描述的方法连接到了provider,那么可以通过 docker stats ,看到每台独立Docker容器所消耗的资源,如下所示。
$ docker ps --format "{{.Names}}" | xargs docker stats
图A.11所示为运行第11章代码时的示例输出,此时是Scrapyd从Web服务器集中下载的时间。

A.6.10 如何查看Docker容器镜像的大小
如果我们使用了原生Docker,或者按照之前答案中看到的方法连接到了provider,那么可以使用如下命令查看Docker镜像大小。
$ docker images
本书的容器都是基于一个镜像,每个变体上安装的其他软件都很少。因此,我们看到的GB级的大小是虚拟大小,而不是真实占用的磁盘空间。如果我们想要查看镜像的构建层次以及个体大小,可以为很长的 dockviz 命令创建一个别名,然后按照如下所示进行使用。
$ alias dockviz="docker run --rm -v /var/run/docker.sock:/var/run/docker.
sock nate/dockviz"
$ dockviz images -t
A.6.11 当Vagrant无法响应时,如何重置系统
即使最终处于一个连Vagrant也无法重置的混乱状态,我们也可以对系统进行完全重置。我们可以在不重置虚拟主机的情况下做到这一点,当然这种方式需要花费一些时间来完成。我们所需要做的就是连接到docker provider机器,强行停止所有容器,移除它们的镜像,然后重启Docker。具体命令如下所示。
$ docker stop $(docker ps -a -q)
$ docker rm $(docker ps -a -q)
$ sudo service docker restart
也可以使用如下命令。
$ docker rmi $(docker images -a | grep "<none>" | awk "{print $3}")
我们使用这种方式移除了下载的所有Docker层内容,这就意味着下一次执行 vagrant up --no-parallel 时将会花费一些时间用于下载。
A.7 有一个无法解决的问题,怎么办
我们可以随时使用VirtualBox以及从osboxes.org( <a class="my_markdown" href="['http://www.osboxes.org/ubuntu/']">http://www.osboxes.org/ubuntu/</a> )下载得到的Ubuntu 14.04.3(Trusty Tahr)镜像,按照Linux的安装过程操作。代码将会完全运行在虚拟机里。我们唯一会忽略的事情是端口转发和同步文件夹,这意味着要么我们手动设置它们,要么在虚拟机中进行开发。
本书中的容器不适用于生产环境。
如果下拉菜单中包含64位镜像,那么我们可以跳过本节接下来的部分。