带有Packer和Puppet的不可变服务器

最近,我越来越喜欢不可变服务器的概念,同时使Zapier的基础架构自动化 。 这个概念很简单:永远不要在活动服务器上进行服务器升级或更改,而只是使用应用的更新来构建新服务器,而丢弃旧服务器。 您基本上可以在基础结构级别上获得不变性的所有好处,而且您不必担心配置漂移。 甚至更好的是,我不必再担心,尽管进行了广泛的测试,但有人还是会推动人为改变的伪装清单,使我们的前端Web服务器崩溃(确保我们可以回滚更改并进行恢复,但是仍然存在少量潜在中断)担心)。

显然,您需要一些好的工具来实现这一目标。 最近与Packer的一些鬼混让我整理了一个到目前为止令我有些满意的设置。

节点

在我们的基础架构项目中,我们有一个nodes.yaml,用于定义节点名称及其所属的AWS安全组。 这非常简单,可用于多种其他工具(例如vagrant )。

elasticsearch: 
  group: logging

zookeeper:
  group: zookeeper

redis:
  group: redis
  size: m2.2xlarge

Rakefile

我们将此节点.yaml文件与rake一起使用,以生成打包程序模板以构建新的AMI。 这使我不必管理大量的打包程序模板,因为它们大多具有相同的功能。

require 'erb'
require 'yaml'

namespace :packer do
  task :generate do 
    current_dir = File.dirname(__FILE__)
    nodes = YAML.load_file( "#{current_dir}/nodes.yml")
    nodes.each_key do |node_name|
      include ERB::Util
      
      template = File.read("#{current_dir}/packs/template.json.erb")
      erb = ERB.new(template)
      File.open("#{current_dir}/packs/#{node_name}.json", "w") do |f|
        f.write(erb.result(binding))
      end
    end
  end
end

它与简单的erb模板结合使用,该模板将节点名简单地注入其中。

{
  "builders": [{
    "type": "amazon-ebs",
    "region": "us-east-1",
    "source_ami": "ami-10314d79",
    "instance_type": "t1.micro",
    "ssh_username": "ubuntu",
    "ami_name": "<%= node_name %> {{.CreateTime}}",
    "security_group_id": "packer"
  }],
  "provisioners": [{
    "type": "shell",
    "script": "packs/install_puppet.sh"
  }, {
    "type": "shell", 
    "inline": [
      "sudo apt-get upgrade -y",
      "sudo sed -i /etc/puppet/puppet.conf -e \"s/nodename/<%= node_name %>-$(hostname)/\"",
      "sudo puppet agent --test || true"
    ]
  }]

这将为每个节点生成一个打包程序模板

  • 在us-east-1中创建一个AMI
  • 使用Ubuntu Server 13.04 AMI开始
  • 将安全组设置为EC2中的打包程序。 我们创建此文件,并允许其访问puppetmaster的安全组。 否则,打包程序将创建一个随机的临时安全组,该组将无权访问任何其他组(如果至少遵循最佳实践)!
  • 安装木偶
  • 运行一次木偶以配置系统

我们也永远不会启用人偶代理(默认情况下不启动),以便它从不轮询更新。 我们还可以在完成后从服务器中删除木偶,以免AMI进入。

剧本

Packer具有使用户能够指定要运行的Shell命令和Shell文件的出色功能。 这对于引导程序是很好的,但对于执行更适合puppet的配置管理级别来说却不是那么好。 因此,我们的打包程序模板调用了一个shell脚本,以确保我们不使用过时的ruby linux发行版将其默认设置为安装木偶。 在安装过程中,它还会指定人偶主服务器名称(如果您使用VPC而不是EC2 classic,则不需要此名称,因为您只需将内部dns“人偶”分配给人偶主服务器即可)。

sleep 30,
wget http://apt.puppetlabs.com/puppetlabs-release-raring.deb
sudo dpkg -i puppetlabs-release-precise.deb
sudo apt-get update
sudo apt-get remove ruby1.8 -y
sudo apt-get install ruby1.9.3 puppet -y

sudo su -c 'echo """[main]
logdir=/var/log/puppet
vardir=/var/lib/puppet
ssldir=/var/lib/puppet/ssl
rundir=/var/run/puppet
factpath=$vardir/lib/facter
templatedir=$confdir/templates


[agent]
server = ip-10-xxx-xx-xx.ec2.internal
report = true
certname=nodename""" >> /etc/puppet/puppet.conf'

建立它

现在,我们需要做的就是为packer build packs/redis.json构建一个新的AMI,运行packer build packs/redis.json并开始繁荣! 创建,配置,映像和终止服务器。 现在,只需在jenkins中设置一些作业即可根据某些触发器生成这些作业,那么您就可以使不可变的基础架构实现自动化又迈了一步。

打扫干净

当然,您生成的每个AMI每天都会花费您一分钱或类似的费用。 这可能看起来很小,但是一旦每个AMI进行了100次修订,就会花钱! 因此,作为最后一步,我整理了一个简单的fabfile脚本来清理旧图像。 事实证明这很简单,因为我们在AMI名称中包含了unix时间戳。

import os

import boto
from fabric.api import task


class Images(object):
    def __init__(self, **kwargs):
        self.conn = boto.connect_ec2(**kwargs)
    
    def get_ami_for_name(self, name):
        (keys, AMIs) = self.get_amis_sorted_by_date(name)
        return AMIs[0]

    def get_amis_sorted_by_date(self, name):
        amis = self.conn.get_all_images(filters={'name': '{}*'.format(name)})

        AMIs = {}
        for ami in amis:
            (name, creation_date) = ami.name.split(' ')
            AMIs[creation_date] = ami
            
        # remove old ones!
        keys = AMIs.keys()
        keys.sort()
        keys.reverse()

        return (keys, AMIs)

    def remove_old_images(self, name):
        (keys, AMIs) = self.get_amis_sorted_by_date(name)

        while len(keys) > 1:
            key = keys.pop()
            print("deregistering {}".format(key))
            AMIs[key].deregister(delete_snapshot=True)



@task
def cleanup_old_amis(name):
    '''
    Usage: cleanup_old_amis:name={{ami-name}}
    '''
    images = Images(
        aws_access_key_id=os.environ['AWS_ACCESS_KEY_ID'], 
        aws_secret_access_key=os.environ['AWS_SECRET_ACCESS_KEY']
    )
    images.remove_old_images(name)

将其设置为生成AMI的jenkins作业的构建后作业,您始终要确保只有最新的作业。 您可能还可以对此进行调整,以保留最后5个AMI,以便进行归档。

下一步是什么?

我承认我对这个概念还是有点新鲜。 理想情况下,我会很乐意将我们的基础架构调整到每个月(或每周!)服务器都可以使用新副本进行回收的地步。 诸如Web服务器或队列之类的瞬态服务器可以很容易地工作。 使用数据存储,这可能会更加棘手,因为您需要一种有效的策略来启动主实例的副本,将副本升级为主实例并淘汰旧的主实例。

最后的挑战是确定允许什么级别的可变性。 部署显然很好,因为它们不需要调整服务器配置,但是添加/删除用户又如何呢? 我们是采用全有还是全无的方法,还是允许在无需完全重建服务器的情况下更新SSH公钥之类的小细节?


翻译自: https://www.javacodegeeks.com/2013/07/immutable-servers-with-packer-and-puppet.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值