管理 Amazon 的 EC2 实例

The most amazing achievement of the computer software industry is its continuing cancellation of the steady and staggering gains made by the computer hardware industry.

— Henry Petroski

如果你觉得你的电脑近年来变得比较慢,这可能是正确的。 对于大多数应用程序而言,你已不必将所有的计算能力(computing power) 全部挤进你办公桌下的一个米色盒子里。 为了解决这个问题,计算能力已经成为一种可以在网上购买的商品。

亚马逊不只是卖书了:他们也卖首饰、摩托车、叶鼓风机,以及对我们当前目的有用的计算能力。 你可以用信用卡签约使用 Amazon Web Services,并根据你的需要创建众多的服务器实例, 每个服务器基于小时计费。如果你只是想试水,可以运行一个免费最长一年的微型实例。 如果你正在寻找将你的一部分基础设施迁移到公共云的方案,这是一个不错的实验方式。

本处方将向你展示一个使用 Puppet 创建并自动供应一个 EC2 实例的简单方法。 尽管还可以使用更强大的方式实现,包括使用 MCollective,但作为教学目的, 我们将只做最低限度的必要的工作:让一个实例运行起来并应用 Puppet 配置清单。 一旦你获得了基本思路,你就可以以此作为基础加入你自己的改良和改进。

准备工作

你需要一个 Amazon Web ServicesAWS)账号。如果还没有,请到 http://aws-portal.amazon.com/gp/aws/developer/subscription/index.html?productCode=AmazonEC2 注册。

你需要 AWS 访问的 key ID,这个秘密访问 Key 对应于你的 AWS 账号。你可以在这个页面找到它: http://aws-portal.amazon.com/gp/aws/developer/account/index.html?action=access-key

你还需要访问 EC2 实例的 SSH 密钥对。为此,你需要如下步骤:

  1. https://console.aws.amazon.com/ec2/home 登录 AWS 管理控制台。

  2. 选择 Amazon EC2 标签,在导航部分的标题 Network & Security 上单击 Key Pairs

  3. 单击 Create key pair,当提示出现后下载 keypair 文件。将此文件保存到一个安全的地方, 并使用如下命令为它设置模式为 0600 的权限:

    # chmod 600 bitfield.pem
    

操作步骤

  1. 创建 fog 模块:

    # mkdir /etc/puppet/modules/fog
    # mkdir /etc/puppet/modules/fog/manifests
    # mkdir /etc/puppet/modules/fog/files
    
  2. 使用如下内容创建 /etc/puppet/modules/fog/manifests/init.pp 文件:

    class fog {
        package { "fog":
            ensure   => installed,
            provider => gem,
        }
    
        file { "/usr/local/etc/fog_credentials":
            source => "puppet:///modules/fog/fog_credentials",
        }
    
        file { "/usr/local/bin/boot-ec2":
            source => "puppet:///modules/fog/boot-ec2.rb",
            mode   => "755",
        }
    
        file { "/usr/local/bin/bootstrap-ec2":
            source => "puppet:///modules/fog/bootstrap-ec2.sh",
            mode   => "755",
        }
    }
    
  3. 使用如下内容创建 /etc/puppet/modules/fog/files/boot-ec2.rb 文件 (修改 :private_key_path 参数指向你自己的 AWS 私钥文件):

    #!/usr/bin/ruby
    require 'rubygems'
    require 'fog'
    
    HOSTNAME = 'devbox'
    @server = ''
    Fog.credentials_path = '/usr/local/etc/fog_credentials'
    
    def command( cmdline )
        puts "Running command: #{cmdline}"
        res = @server.ssh( "sudo #{cmdline}" )[0]
        puts res.stdout
        puts res.stderr
    end
    
    def create()
        puts "Bootstrapping instance..."
        connection = Fog::Compute.new( { :provider => 'AWS' } )
        @server = connection.servers.bootstrap( :key_name =>
                                                'bitfield',
                                                :private_key_path =>
                                                '~/bitfield.pem',
                                                :username => 'ubuntu')
        @server.wait_for { ready? }
        @server.reload
        puts "Instance name: #{@server.dns_name}"
        puts "Setting hostname..."
        @server.ssh( "sudo hostname #{HOSTNAME}" )
    end
    
    def copy_bootstrap_files()
        puts "Copying bootstrap files..."
        @server.scp( "puppet.tar.gz", "/tmp" )
        @server.scp( "/usr/local/bin/bootstrap-ec2", "/tmp" )
    end
    
    def bootstrap()
        puts "Bootstrapping..."
        command( "sudo sh /tmp/bootstrap-ec2" )
    end
    
    create()
    copy_bootstrap_files()
    bootstrap()
    
  4. 使用如下内容创建 /etc/puppet/modules/fog/files/bootstrap-ec2.sh 文件:

    #!/bin/bash
    apt-get update
    apt-get -y install puppet
    apt-get -y install git-core
    cd /root
    tar xzf /tmp/puppet.tar.gz
    puppet --modulepath=/root/puppet/modules \
      /root/puppet/manifests/site.pp
    
  5. 使用如下内容创建 /etc/puppet/modules/fog/files/fog_credentials 文件 (使用你自己的 AWS 凭证替换相应的值):

    :default:
      :aws_access_key_id: AKIAI5RGMC3QRPO3AJWR
      :aws_secret_access_key: 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
    
  6. 添加如下的节点声明,此节点将会应用 EC2 实例:

    node devbox {
        file { "/etc/motd":
            content => "Puppet power!\n",
        }
    }
    
  7. 添加如下代码到一个节点:

    include fog
    
  8. 运行 Puppet:

    # puppet agent --test
    info: Retrieving plugin
    info: Caching catalog for cookbook.bitfieldconsulting.com
    info: Applying configuration version '1313160844'
    
    notice: /Stage[main]/Fog/Package[fog]/ensure: ensure changed
    'purged' to 'present'
    
    notice: /Stage[main]/Fog/File[/usr/local/bin/bootstrap-ec2]/
    ensure: defined content as '{md5}5bc2ffb3b5aa94b33b17d419625ecbab'
    
    notice: /Stage[main]/Fog/File[/usr/local/bin/boot-ec2]/ensure:
    defined content as '{md5}dadc835c6e52c89cb928d60db7677713'
    
    notice: /Stage[main]/Fog/File[/usr/local/etc/fog_credentials]/
    ensure: defined content as '{md5}3b140aedac170bbfcc2837077e03bb93'
    
    notice: Finished catalog run in 1.67 seconds
    
  9. 在你的工作目录中,为分发 EC2 实例创建一个 Puppet 的 tar 包。 最简单的方法是对你现有的 Puppet 仓库(对于 git 的裸仓库需要先检出)执行 tar 命令:

    # cd /etc
    # tar czf /tmp/puppet.tar.gz --exclude .git puppet
    # cd -
    # mv /tmp/puppet.tar.gz .
    
  10. 运行 boot-ec2 脚本:

    # boot-ec2
    Bootstrapping instance...
    Instance name: ec2-107-20-59-174.compute-1.amazonaws.com
    Setting hostname...
    Copying bootstrap files...
    Bootstrapping...
    Running command: sudo sh /tmp/bootstrap.sh
    sudo: unable to resolve host devbox
    sudo: unable to resolve host devbox
    ...
    notice: //Node[devbox]/File[/etc/motd]/content: defined content as
    'unknown checksum'
    
  11. 登录到该实例检查你的配置清单已被正确应用:

    # ssh -i bitfield.pem [email protected]
    Puppet power!
    ubuntu@devbox:~$
    
  12. 你已经得到了一个由 Puppet 管理控制的云服务器! 如果想要创建十个实例,运行此脚本十次即可。 不要忘记使用完毕之后,要在 AWS 管理控制台关闭这些实例(按使用时间付费的哦!)。

工作原理

Fog 是一个用于管理云资源的 Ruby 库,包括 EC2 和其他一些供应商(如 Rackspace)。 尽管你可以使用 Amazon 自己提供的 ec2-tools 脚本启动和管理 EC2 实例, 但使用 Fog 可以轻而易举地将你的实例迁移到另一个供应商, 而且还不需要你为运行 ec2-tools 而安装 Java 以及其他依赖的软件。 对于创建 EC2 基础设施的这两种方法来说,我可以自信的说我更喜欢用 Fog, 尽管事实上它几乎没有文档(而 Amazon 却有很多)。

在 boot-ec2 脚本中,我们用自己的凭证使用 Fog 创建了一个新的 EC2 实例, 并为其传输了一份 Puppet 配置清单的拷贝。 然后我们复制 bootstrap-ec2 脚本,它用于安装 Puppet 以及应用程序的配置清单。

对于本例而言,配置清单相当简单:

file { "/etc/motd":
    content => "Puppet power!\n",
}

你可以轻松地修改它,比如,与你的生产应用服务器同名。 这对于快速部署位于物理负载平衡器之后的大量应用程序服务器来说是一个好方法, 例如,处理突然飙升的需求。另外,你也可以使用 EC2 实例作为测试服务器或临时服务器 (这完全取决于你自己的需求)。

更多用法

除了你的信用卡强加给你的限制之外,此处的脚本没有对你能部署的 EC2 实例数量做任何限制。 所以你可以尝试修改此处所示的脚本,启用一个由命令行参数设置的实例数量。

你或许想要创建不同类型的实例,例如:Web 服务器、人工队列服务器(queue worker servers)等。 你可以修改启动脚本,携带一个参数指定要启动的实例类型。

此处显示的脚本有一个重要的限制,就是它以 tar 包形式提供了一个包含你的 Puppet 配置清单快照的实例。 显然,当你在 Puppetmaster 上修改你的 Puppet 配置清单后,EC2 实例不受影响,即更改不会被应用到 EC2 实例。 基于简单的目的,本处方中的例子仅仅使用 Puppet 构建了初始的服务器,它没有运行 Puppet 守护进程也没与 Puppetmaster 服务器联系。

这对于短生存期或仅为指定目的而运行的 EC2 实例往往还是不错的。 如果你需要运行长生存期的服务器,或者需要通过 Puppet 更新 EC2 实例服务器, 就应该修改脚本使实例能与你的 Puppetmaster 服务器取得联系。 要解决的是证书签名问题,例如你可以对证书进行预签名并伴随 bootstrap 脚本一同部署到 EC2 实例。 另外一种方法是,在脚本中通过 SSH 或 MCollective 登录 Puppetmaster 服务器并对实例的证书请求进行签名。 这两种证书签名的机制或简单或复杂,随你选择。

你可能还想使用其他的云服务提供商,例如 Rackspace 或 Linode。 为此,你需要对脚本做轻微地修改。 请参考 Fog 文档获取相关的详细信息,网址为 http://fog.io

注记

你也可以使用 Puppet 新的云供应商扩展(Cloud Provisioner extension)来管理 EC2 实例; 要获取相关的详细信息请参考 Puppet Labs 的 http://docs.puppetlabs.com/guides/cloud_pack_getting_started.html 页面。

参见本书