Total Pageviews

Sunday 21 August 2016

使用Packer创建Digital Ocean的镜像

1. 什么是Packer

Packer没听说过,可能你听说过Vagrant;如果Vagrant都没听说过,那么请原谅我说这真是稍微有点out了(如果你知道DevOps这个词的话)。
Packer和Vagrant都出自HashiCorp这个公司,这个公司实在是太性感了,以至于我还专门写过一些介(ruǎn)绍(wén):http://slides.com/binliu/docker-and-hashicorp#/ 
除了本文要说的Packer之外,HashiCorp的大杀器还包括:
  • Serf:一个简单的去中心化的集群管理软件;
  • Consul:跨DataCenter的服务发现、配置管理和编配软件;
  • Terraform:一个高抽象度、消除基础设施物理差异,来对基础设施进行构建、变更和版本化的工具;
  • VAULT:用于保存密码、token等机密信息的存储服务;
  • Atlas:通过一种工作流,完成公司内部从开发到发布的流程支撑基础工具。
那么言归正传,什么是Packer呢?按照官方介绍:
Packer is a tool for creating identical machine images for multiple platforms from a single source configuration.
也就是说,Packer是一款创建(OS)镜像的工具,它以代码为表现形式,并支持多种本地和云平台,比如支持VirtualBox的OVF和VMware的VMDK镜像,以及EC2、DigitalOcean、OpenStack、Google Compute Engine等主流云主机,甚至支持构建Docker镜像。
Packer的目的不是取代现有的配置管理工具,比如Chef或者Puppet等,而是可以和这些工具配合使用,沿用公司历史资产。
Packer的项目主页: https://packer.io/ 

2. 为什么用Packer

首先,那就是基础设施代码化,即Infrastructure as Code。因为我们都是程序员,喜欢代码,喜欢命令行,我们喜欢在Shell执行命令,看结果在屏幕上流动那种感觉。
其次,有利于实现 Immutable Infrastructure ,即不可变基础设施,这一部分灵感来自于函数式编程,不可变带来的好处是不会发生状态污染,也就是说,环境之间的差异被消除,出了问题,很容易知道是自己代码的问题,还是OS等基础设施软件的问题。
Packer还能提高部署速度。在云计算之前,我们要想启动一台机器老费劲了,可能得从购买CPU、硬盘开始,攒成机器,装上OS,再装软件,把代码拷贝进去,再启动;有了云计算技术,前几步我们都可以省了;而使用Packer的话,只要你的程序不需要更新,所有步骤都可以省了。启动服务,约等于从镜像启动一台主机这么简单、快速。
Packer还能在一定程度上简化、方便在vendor之间进行迁移(备份),使用混合环境。比如,你可以在Digital Ocean上构架staging环境,而生产环境跑在AWS上,开发则使用桌面虚拟机技术,比如VirtualBox等。
面向测试。你知道么,基础设施也是可以测试的,像单元测试一样,比如像下面这样:

# http://serverspec.org/resource_types.html#port
describe port(80) do
  it { should be_listening.on('127.0.0.1').with('tcp') }
end

# http://serverspec.org/resource_types.html#docker_image
describe docker_image('busybox:latest') do
  it { should exist }
end

3. Packer示例

下面我们就来看一下简单的使用方式。
首先要安装Packer,这里就不多说了,可参看官方的 安装说明 ,基本上就是下载、修改权限就行了,因为是Go编写的工具,都是直接可运行文件。
首先,我们需要创建一个JSON格式的模板(Template)文件,用来描述要构建的镜像信息。这里我们以在Digital Ocean上为例,来看一下如何构建一个镜像(实际上会保存为一个snapshot)。

{

  "variables": {
    "do_api_token": "{{env `DIGITALOCEAN_API_TOKEN`}}"
  },

  "builders": [{
    "type": "digitalocean",
    "api_token": "{{user `do_api_token`}}",
    "droplet_name": "as",
    "image": "centos-7-0-x64",
    "size": "512mb",
    "region": "sfo1"
  }],

  "provisioners": [{
    "type": "shell",
    "inline": [
      "sleep 30",
      "sudo yum update -y",
      "sudo yum install -y http://nginx.org/packages/centos/7/noarch/RPMS/nginx-release-centos-7-0.el7.ngx.noarch.rpm",
      "sudo yum install -y nginx"
    ]
  }]

}
配置文件很简单,从名字上能看出大概每一行都在干什么。
provisioners指的是如何进行安装、配置,这里我们简单地使用shell的方式安装了nginx而已。
进行构建也很简单,只需要运行packer build digitalocean.json即可。
运行结果如下:
如果构建成功,会输出上图下面那部分内容,包括了Creating snapshot: packer-xxxx等信息。
这时候,我们也可以在Digital Ocean控制台上看到刚创建的镜像。
有了此镜像,我们就可以随意创建任意数量的云主机出来了,从而保证了运行环境的统一。这也是基础设施代码化和不可变基础设施的一项基本条件。
当然这个例子很简单,Packer也是HashiCorp众多优秀开源工具之一,也是其工具链上的一环。我们还可以将构建工作放到他们的服务Atlas( https://atlas.hashicorp.com/ )上进行,这样我们就可以将漫长的构建过程从本地分离出来,类似CI服务,当我们更新模板文件后,可以通过诸如 vagrant push、git push甚至其它CI 等命令启动远程构建活动。
此外,构建的镜像也可以保存到Atlas里并进行版本化,以方便 Terraform( https://terraform.io/ )等工具使用。

4. 我们该如何使用Packer?

云计算的出现,不只是把服务器从硬件搬到虚拟机那么简单,同时带来的是软件设计思想、开发流程和生命周期管理的变化。材料不同,加工方式也对应有变化。
现在的开源软件,除了基础设施,包括OS、容器、以及中间件等,还包括很多开发工具,甚至git-flow这样的方法论。流程的变化已经是不得不面对的现实,选择合适的技术、工具,并正确的使用,显得越来越重要。
Packer就是随着这种发展而出现的一种工具。我们既可以单独使用,也可以配合其他工具在自己的流程中使用。
HashiCorp做Packer是有目的的,这也是其工具链上的一个重要组成部分,HashiCorp的大本营是Atlas,我们可以以此为枢纽,将Vagrant,Packer,Terraform等工具运用到该流程的各个部分。下面的图来自官网介绍。
在此图中,HashiCorp想的是使用Vagrant开发,在本地通过vagrant push触发Packer进行镜像(包括应用程序代码)构建,之后Terraform使用构建结果(artifacts )进行物理部署,基础设施(其实这里的基础设施已经包括应用程序了)部署之后,Consul开始对集群的监控工作。
个人认为此流程只能说理想,思路很不错,但是有其缺点,尤其是在国内,离实用化还有一定距离。
首先,我觉得Vagrant不应该出现在其中(或者说地位不应该这么重要),而应该通过git或者CI等来完成build的触发工作。应该更积极的开放出整个流程的一部分功能给第三方;
其次,国内云服务的public API完善程度太低,这个不多说了。 软件吞噬世界,API连接一切;
最后,对Docker的支持给人一种hotfix的感觉。Packer构建Docker镜像,也只是简单的export机制,丢失了历史信息;如何在云上高效、透明的运行容器,也缺乏一些方向性的支持。Docker是个产品,也是一整套生态环境,HashCorp应该更多的去拥抱其他开源项目,而不要太过于迷信 If a sufficient tool does not exist, we step in to build it.
from http://ju.outofmemory.cn/entry/195420