vfarcic/cloud-provisioning(https://github.com/vfarcic/cloud-provisioning)代码库已经有了我们将要使用的Packer和Terraform的配置。它们位于目录terraform/do:
第一步是使用Packer创建一个快照。要做到这一点,需要将DigitalOcean API令牌设置为环境变量DIGITALOCEAN_API_TOKEN。这与我们在环境变量DIGITALOCEAN_ ACCESS_TOKEN中设置的令牌相同。不幸的是,Docker Machine和Packer有着不同的命名标准:
请使用实际的令牌来替换[...]。
我们将从同一个快照来实例化所有的Swarm节点。它将基于Ubuntu并安装最新的Docker Engine。
我们将要构建的镜像的JSON定义在文件terraform/do/packer-ubuntu-docker.json(https://github.com/vfarcic/cloud-provisioning/blob/master/terraform/do/packer-ubuntu-docker.json):
该配置包括两部分:builders和provisioners:
builders部分定义了Packer构建快照需要的所有信息。provisioners部分描述了为builders创建的机器安装和配置软件的命令。builders是唯一需要的部分。
builders负责为不同的平台创建机器并从其生成镜像。例如,EC2、VMWare、VirtualBox等都有单独的builders。默认情况下,Packer附带大多数builders,还可以扩展添加新的builders。
现在使用的builders部分如下:
每种类型的builder都有可以使用的特定参数。我们指定该类型为digitalocean。更多信息请参考DigitalOcean Builder页面(https://www.packer.io/ docs/builders/digitalocean.html)。
请注意,当使用digitalocean类型时,必须提供令牌。可以通过api_token字段来指定。但是,还有另外的办法。如果没有指定该字段,Packer将尝试从环境变量DIGITALOCEAN_API_TOKEN中获取值。因为我们已经设置了环境变量,所以不需要在Packer内部重复指定令牌。此外,令牌应该是保密的。
将其放入配置中会有暴露的风险。区域很关键,因为快照只能在一个区域内创建。如果想要在多个区域共享同一台机器,那么每个区域都需要指定为一个单独的builder。
我们将镜像设置为ubuntu-16-04-x64。以此为基础创建自己的镜像文件。快照的大小与我们将要创建的droplets大小没有直接关系,所以没有必要设置的很大。我们将其设置为1 GB。
默认情况下,DigitalOcean只启用公开网络,因此我们将private_networking定义为true。稍后,我们将设置Swarm通信,使其只能通过私有网络访问。
snapshot_name字段是我们给这个快照指定的名字。由于没有覆盖现有快照的选项,所以名字必须是唯一的,因此我们在名字中添加了时间戳。
更多信息请参考DigitalOcean Builder页面(https://www.packer.io/docs/ builders/digItalocean.html)。
第二部分是provisioners。它包含了所有的provisioners,在将机器转换成快照之前,Packer使用provisioner在运行的机器中安装和配置软件。
现在可以使用大多数provisioner类型。如果你阅读过《微服务运维实战(第一卷)》(https://www.amazon.com/dp/B01BJ4V66M),那么你应该知道我提倡使用Ansible作为provisioner。这里也应该使用它吗?大多数情况下,当构建镜像只是运行Docker容器时,我会选择简单的shell。将Ansible更改为shell的原因在于目的不同,运行live server时使用provisioner,而不是在创建镜像时。
与Shell不同,Ansible(以及其他大多数provisioners)是幂等的(idempotent)。它们验证实际状态并执行一个或另一个操作,这取决于对期望的状态应该做什么。这是一种很好的方法,因为我们可以运行任意多次Ansible,并总能得到相同的结果。例如,如果我们指定要使用JDK 8,那么Ansible会将SSH插入目标服务器,发现JDK不存在并安装它。下一次运行它时,它会发现JDK已经存在并且什么都不做。这种方法允许我们尽可能频繁地运行Ansible playbook,并且结果总是JDK被安装了。如果试图使用Shell脚本来完成相同的任务,那么我们需要编写冗长的if/else语句。如果JDK已经安装,就什么都不做;如果没有安装,就安装JDK;如果已经安装,但是版本不正确,就升级JDK;等等。
那为什么不使用Packer呢?答案很简单。我们不需要幂等,因为只在创建镜像时运行一次。我们不会在运行的实例中使用它。你还记得宠物和牛的讨论吗?虚拟机将从一个已经拥有我们需要的一切的镜像中被实例化。如果虚拟机的状态发生变化,则将终止它并创建一个新的。如果需要升级或安装额外的软件,则不会在运行的实例中做这些事情,而是创建一个新的镜像,销毁正在运行的实例,并基于更新的镜像实例化一个新的。
幂等性是我们使用Ansible的唯一原因吗?当然不是!当我们需要定义复杂的服务器设置时,它是一个非常方便的工具。然而,在我们的例子中,设置很简单。我们需要Docker Engine,仅此而已。几乎所有的东西都会在容器中运行。编写一些Shell命令来安装Docker比定义Ansible playbook更容易和更快。(www.xing528.com)
安装Ansible可能需要与安装Docker相同数量的命令。
长话短说,我们将使用shell作为建造AMI的provisioner。
现在使用的provisioners部分如下:
shell类型后面跟着一组命令。它们与我们在Ubuntu上安装Docker所用到的命令相同(https://docs.docker.com/engine/installation/linux/ubuntulinux/)。
现在已经大致了解了Packer的配置是如何工作的,下面可以继续并构建一个镜像:
现在运行packer-ubuntu-docker.json的packer构建,并将机器可读的输出发送给packer-ubuntu-docker.log文件。机器可读的输出允许我们轻松解析它并检索刚刚创建的快照ID。输出的最后部分如下:
除了确认构建成功之外,输出的相关部分是行id,sfo2:21373017。它包含基于镜像实例化虚拟机所需的快照ID。如果需要从其他服务器获取ID,则可能想要将packer-ubuntu-docker.log存储在代码库中。
图13-2描述了执行的流程。
图13-2 Packer过程的流程图
现在,使用基于构建的快照的虚拟机,我们已经做好了创建一个Swarm集群的准备。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。