Segment:使用Docker、ECS和Terraform重建基础设施

本文讲的是Segment:使用Docker、ECS和Terraform重建基础设施,【编者的话】本文转帖Segment公司CTO以及联合创始人Calvin French-Owen发表的文章。Segment公司采用独立的AWS账户进行真正意义上的隔离,采用Docker和ECS运行服务,并采用Terraform配置脚本进行整合并为服务描述添加Datadog供应商获得免费的监控告警信息。

Segment 于 2012年 在旧金山成立,一开始就因其整合数据的能力倍受关注,去年6月,Segment 把自己的服务拓展到移动领域,发布了允许开发者将数据一键分送给多家数据分析服务提供商的 SDK(包含 iOS 和 Android 版)。对于用户,尤其是开发者来说,Segment 能让他们在接入不同数据追踪服务中节省不少时间,以前要对提供者给定的 API 逐个进行配置,而 Segment 搭建的底层系统,让用户只进行简单地开关切换。接入基于 SOAP XML 协议 API 相比 REST 更为复杂,而 Segment 能对此进行有利整合,开发者们也可以从 API 中解放出来去专注产品打磨。本文翻译自其官方博客。

在Segment早期,我们的基础设施是拼装的,我们通过AWS的用户界面提供实例,有一个由从未使用的AMI组成的组件,以及通过三种不同方式实现的配置。

随着公司业务开始腾飞,我们的工程师团队开始扩充,架构也开始日益复杂,但是生产环境的相关工作仍然局限于我们少数这些知道神秘陷阱的人。我们一直在逐步改善过程,但我们需要给我们的基础设施更深层次的改革以保持快速发展。

因此,几个月前,我们坐下来问自己:“如果我们今天设计,那么基础设施设置会是什么样子?

在10周的过程后,我们完全重新设计了基础设施,我们撤下了几乎每一个实例和旧的配置,将我们的服务移到Docker容器中运行,并且切换为使用全新的AWS账号。

我们花了很多时间考虑如何使生产环境设置变得可审计、简单并且易用,同时仍然不失可扩展的弹性。

下面就是我们的解决方案。

独立的AWS账户

我们切换到了完全独立的AWS账户,而不是使用Region或者Tag来分离不同的预生产环境和生产环境实例,我们需要确保提供的脚本不会影响当前运行的服务,并且使用全新的账户意味着我们将从一张白纸开始。


运维账户提供了跳转和集中登录服务,团队中的每个人都有一个AWS IAM账户。

其它环境拥有一系列IAM角色来进行切换,这意味着只能有一个登录点来管理账户,也只有一个地方限制访问。

举个例子来说,Alice也许可以访问上图中的所有三个环境,Bob只能访问开发环境(哪怕他删除了生产环境中的负载均衡器),但是他们都是通过同一个运维账户登录的。

作为对于复杂的IAM设置限制访问的替代,我们只是简单地通过环境来锁定用户并且通过角色来分组,从界面上使用每一个账户就像切换当前的活跃角色一样方便。


我们可以免费获得真正意义上的隔离,无需额外配置,而不是担心预生产环境沙盒会不安全或者会改动生产环境数据库。

分享配置代码带来的额外好处就是我们的预生产环境事实上将会成为生产环境的一个镜像,配置中仅有的区别只有实例大小和日期数目。

最后,我们也可以跨账户合并账单。我们使用相同的发票来支付月付账单,可以看到一个按照环境来分割的详细分解后的费用。

Docker和ECS

一旦我们设置好了账户,接下来就是轮到如何设计服务真正运行了,为此,我们转向了DockerEC2容器服务(ECS)

截止今天为止,我们大部分的服务都运行在Docker容器里,包括我们的API和数据流管道。容器每秒钟都会接收数千次请求,每月处理500亿条事件。

Docker的最大好处就是可以一定程度上授权团队从无到有构建服务,我们不再有一组复杂的配置脚本或AMIs——我们只需交给生产集群一个镜像然后运行即可。不会再有有状态的实例了,我们可以保证预生产环境和生产环境运行的是一模一样的代码。

配置完我们的服务如何运行在容器里后,我们选择了ECS作为调度器。

在一个较高的水平,ECS负责在生产环境中实际运行我们的容器。ECS关注服务的调度,即将服务放置在单独的主机上运行,并且在当连接到ELB时确保零宕机重载服务。ECS甚至可以通过AZs调度提供更好的可用性,如果某个容器挂了,ECS会确保在集群中重新调度一个新的实例。

切换到ECS极大地简化了运行服务的工作,从而不需要担心Upstart工作或者配置实例。添加Dockerfile、设置任务定义以及将其和集群关联都是非常容易的。

在我们的设置中,Docker镜像通过CI(持续集成)来构建,然后再推送到Docker Hub。当一个服务启动时,会从Dokcer Hub上拉取镜像,接着ECS就可以跨机器调度了。


我们将服务集群按照它们的关注领域和负载profile(比如针对API、CDN、APP等的不同的集群)分组,拥有分离的集群意味着更好的可见性以及针对每一个集群都可以决定如何使用不同的实例类型(因为ECS没有实例关联的概念)。

每一个服务都有一个特定的任务定义,指出了运行在哪一个版本的容器里、运行多少实例以及选择哪一个集群。
在运行过程中,服务通过ELB注册它自身,使用健康检查来确认容器是否准备好运行。我们在ELB中指向一个本地的Route53条目,这样服务借助于DNS可以互相通信和简单地引用。

设置非常的棒,因为我们不需要任何服务发现,本地的DNS就完成了所有的记账工作。

ECS可以运行所有的服务,我们从ELB获得了免费的CloudWatch监控指标,这比起在启动阶段就不得不通过一个中央认证授权中心注册服务要简单多了,并且最大的好处还是在于我们不需要亲自处理服务状态冲突了。

Terraform模板化

Docker和ECS描述了如何运行我们的每一个服务,而Terraform就像胶水一样把它们整合在了一起。在高级别上,它是一组配置脚本,可以创建和更新我们的基础设施。你可以认为它像一个建造中的CloudFormation版本,但不会让你想要戳你的眼睛。

Terraform不是运行一组服务来维护状态,而是只通过一组脚本来描述集群,配置脚本在本地运行(将来也是这样,借助于持续集成)并且提交给Git,所以我们拥有了关于生产环境基础设施实际运行的持续记录。

这里就是一个我们Terraform模块设置Bastion节点的样本,该样本创建了所有的安全组、实例和AMIs,这样我们就可以很容易地为将来的环境设置跳跃点。

// Use the Ubuntu AMI
module "ami" {
    source = "github.com/terraform-community-modules/tf_aws_ubuntu_ami/ebs"
    region = "us-west-2"
    distribution = "trusty"
    instance_type = "${var.instance_type}"
}

// Set up a security group to the bastion
resource "aws_security_group" "bastion" {
    name = "bastion"
    description = "Allows ssh from the world"
    vpc_id = "${var.vpc_id}"

    ingress {
        from_port = 22
        to_port   = 22
        protocol  = "tcp"
        cidr_blocks = ["0.0.0.0/0"]
    }

    egress {
        from_port = 0
        to_port = 0
        protocol = "-1"
        cidr_blocks = ["0.0.0.0/0"]
    }

    tags {
        Name = "bastion"
    }
}

// Add our instance description
resource "aws_instance" "bastion" {
    ami = "${module.ami.ami_id}"
    source_dest_check = false
    instance_type = "${var.instance_type}"
    subnet_id = "${var.subnet_id}"
    key_name = "${var.key_name}"
    security_groups = ["${aws_security_group.bastion.id}"]
    tags  {
        Name = "bastion-01"
        Environment = "${var.environment}"
    }
}

// Setup our elastic ip
resource "aws_eip" "bastion" {
    instance = "${aws_instance.bastion.id}"
    vpc = true
}   

我们在预生产环境和生产环境中都使用相同的模块来设置我们各自的Bastion节点,我们唯一需要换掉的是IAM keys,我们准备好了。

改变这些也丝毫没有痛苦,不需要拆了已有的整个基础设施,Terraform只在需要更新的地方更新。

当我们需要修改ELB Draining超时60秒时,只需要在Terraform apply后跟随一个简单的find/replace操作,这样两分钟后我们就会拥有一个对于我们所有的ELB都是完全调整了的生产环境设置。

Terraform是可复制的、可审计的并且自注释的,没有任何黑箱。

我们将所有的配置都放在一个中央的基础设施Repo,其可以非常容易发现一个服务是如何设置的。

我们还没有完全拿到圣杯。我们想要转换更多的Terraform配置来利用模块的优势,这样可以合并单个文件,减少共享样本的数量。

一路上我们发现了一些关于.tfstate的陷阱,Terraform总是一开始读取现有的基础设施,然后当状态变得不同步时就会抱怨,我们通过将.tfstate提交到Repo的方式终止了这种情况,然后在有任何改变之后再推送回去,但是我们正在调研Atlas,或者通过持续集成来解决这个问题。

移动到Datadog

通过这一点,我们有了我们的基础设施,我们的供应和我们的隔离。剩下的最后一件事是度量和监控,用以追踪生产环境中运行的一切东西。

在我们的新的环境中,我们已经将所有的度量和监控切换到了Datadog上,这是非常奇妙的。


我们一直非常满意Datadog的界面、API以及其与AWS的完全集成,但从工具中获得最多的还是来自于一些关键的设置。

我们做的第一件事是将AWS与Cloudtrail集成,这个给出了一个居高临下鸟瞰的视角来观察我们的每一个环境如何演化的,因为我们要与ECS集成,Datadog feed每次都会在任务定义更新的时候更新,所以我们最终得到了免费部署的通知。寻找Feed是出奇的快,而且很容易追溯到上一次的服务部署或重新调度。

接下来,我们确保添加Datadog-agent作为基础AMI的容器(Datadog/Docker-dd-agent),它不仅可以从主机(CPU、内存等)收集度量指标,还可以作为Statsd指标库。每个服务收集自定义的基于查询、延迟和错误的度量指标,这样我们可以在Datadog里探查指标和发送告警。我们的Go工具箱(很快就会开源)自动收集Ticker的pprof输出并且发送,所以我们可以监控内存和协程(Goroutines)。

更酷的是,Datadog-agent可以在环境中跨主机将实例利用率可视化,所以我们可以得到一个高层次的实例或集群概述,也许会有下面的一些议题:


另外,我的队友Vince创建了“Terraform provider for Datadog”,所以我们完全可以针对生产配置编写告警脚本。我们的告警将会记录下来并且与生产环境运行的系统保持同步。

resource "datadog_monitor_metric" "app.internal_errors" {
    name = "App Internal Errors"
    message = "App Internal Error Alerts"

    metric = "app.5xx"
    time_aggr = "avg"
    time_window = "last_5m"
    space_aggr = "avg"
    operator = ">"

    warning {
        threshold = 10
        notify = "@slack-team-infra"
    }

    critical {
        threshold = 50
        notify = "@slack-team-infra @pagerduty"
    }
}   

按照惯例,我们指定了两个告警级别:Waring和Critical。Waring级别可以让任何在线的用户知道有什么东西看起来可疑,并针对任何潜在的问题提前做好预案。Critical级别的告警被保留为“唤醒你在深夜的问题”亦即一个严重的系统故障。

更重要的是,一旦我们过渡到Terraform模块并为我们的服务描述添加Datadog供应商,接着所有的服务最终都会免费获得告警信息,数据将直接由我们的内部工具箱和Cloudwatch度量指标来驱动处理。

让Docker运行的美好时光

一旦我们有了上述所有的这些组件,切换的这一天终于来临了。

我们首先在新的生产环境和遗留环境之间设置一个VPC的对等连接——允许我们在它们之间集群化数据库和复制。

接下来我们在新的生产环境中预热ELBs,确保它们可以处理负载。亚马逊没有提供ELBs的自动调整排列功能,所以我们不得不咨询亚马逊来提前准备(或者缓慢扩展自身)来处理增加的负载。

从那里开始,这只是一个使用加权Route53路由从老环境到新环境稳步增加流量的问题,持续监控,一切都看起来不错。

今天,我们的API像蜂群一样辛勤工作,每秒处理成千上万的请求,并且完全运行在Docker容器里。

但是我们还没有完成,我们仍然在微调我们的服务创建方式,并减少样板,这样团队里的任何人都可以非常容易地构建具有适当的监控和告警功能的服务,并且我们想改进与容器工作相关的工具,因为服务不再与实例关联了。

我们还计划为这个项目留意有前途的技术。Convox团队正在围绕AWS基础设施构建很棒的工具。虽然我们喜欢ECS的简单以及集成特性,但是KubernetesMesosphereNomad和 Fleet看起来也都是非常酷的资源调度系统,看看它们都是如何打开市场局面的将是令人兴奋的,我们会一直跟踪它们,看看有什么可以采用借鉴的。

在所有这些业务流程的变化后,我们比以往更强烈的认为应将我们的基础设施外包给AWS。他们已经通过将大量核心服务产品化改变了游戏规则,同时保持一个非常有竞争力的价格点。这一点带来了一种新的类型的创业公司,它们可以高效地构建产品,廉价同时花费更少的时间进行维护,我们看好在AWS的生态系统上构建工具。

原文链接:Segment: Rebuilding Our Infrastructure With Docker, ECS, And Terraform (翻译:胡震)

原文发布时间为:2015-10-26

本文作者:国会山上的猫TuxHu 

本文来自合作伙伴DockerOne,了解相关信息可以关注DockerOne。

原文标题:Segment:使用Docker、ECS和Terraform重建基础设施

时间: 2024-09-15 20:52:01

Segment:使用Docker、ECS和Terraform重建基础设施的相关文章

当Terraform遇上ECS(一)——DataSource篇

背景 越来越多的公司已经熟知并运用"基础设施即代码"来构建和维护自己的云基础设施.目前也有许多的自动化构建工具协助用户通过脚本进行云资源的部署和生命周期的管理,如:Terraform.Ansible.Chef等.但是,在实施过程中,都遇到了如何获取镜像id.可用区.实例类型id,如何跟自己的脚本相结合而备受困扰? 请首先检查一下您的构建脚本,是否有imageId=centos_6u8_64_40G_cloudinit_20161115.vhd.instanceType=ecs.s2.l

云上DevOps-CodePipeline,Packer和Terraform集成实践探索

1.简介         DevOps越来越火,各种产品层出不穷,技术人员如果不谈谈这个词,就会显得很落伍了,在这种形势下,阿里云也推出了自己的DevOps公共云产品CodePipeline,本文并不想介绍已经铺天盖地的DevOps概念,而是结合阿里云的产品CodePipeline和开源工具Packer,Terraform来实践一种全新云上的DevOps方案,从构建代码,创建自定义镜像,然后基于包含新应用的镜像来创建运行应用的整个基础设施,包括ECS,VPC网络,安全组等等,然后发布应用,从无到

巧用Terraform和Packer开源工具完成云上自动运维

2017年在线技术分会--运维/DevOps在线技术峰会上,来自阿里云的黎山分享了利用开源DevOps工具完成云上的自动运维的实践.她首先通过对5个应用场景的分析引出了"自动化能自动化的一切"的理念.然后介绍了使用Terraform和Packer开源工具完成云上自动运维的具体实现过程.最后对多工具组合案例进行了分享.   以下内容根据直播视频整理而成.   云计算的特点是开箱即用,可以随时扩缩容,不用考虑硬件的损坏问题,而且有丰富的云平台和云产品供选择. 应用场景分析 应用1 某应用1

解读基础设施即代码

现代软件开发对基础设施的管理提出了更苛刻的要求.产品要适应瞬息万变的市场,要求基础设施要有更快的响应速度.而持续交付和DevOps的推行要求产品团队对部署和运维要有更高的自主性.技术的快速进步和演化,也使得基础设施的配置不得不频繁变化.在这种快速变化的过程中,要求基础设施既要灵活,也要安全.可靠. 而传统的基础设施运维管理具有以下几个问题. 被动响应. 产品团队获取服务器资源采用的是申请制,中间存在若干审批过程,以及需要等待运维团队实施,响应不及时. 自动化缺乏串联.虽然有一定的自动化,但不能做

8 个你可能不知道的 Docker 知识

本文讲的是8 个你可能不知道的 Docker 知识,[编者的话]在过去的一年内,Docker 技术已经逐渐走向成熟,并且推动了大型初创公司例如 Twitter 和 Airbnb 的发展,甚至在银行.连锁超市.甚至 NASA 的数据中心都赢得了一席之地.本文介绍了一些基本的Docker知识,比如Docker可以做什么.Docker的文件系统. 自从上世纪 90 年代硬件虚拟化被主流的技术广泛普及之后,对数据中心而言,发生的最大的变革莫过于容器和容器管理工具,例如:Docker.在过去的一年内,Do

CodePicnic的Docker Swarm之路

本文讲的是CodePicnic的Docker Swarm之路[编者的话]本文描述了CodePicnic发展过程中的遇到的问题,使用的工具,以及选择的理由. 在CodePicnic,Docker很早就成了基础设施的核心部分.从0.11版本开始,我们不但看到了Docker的成长,更看到了一整个相关生态的建立. 与此同时,CodePicnic也在发展,我们有了不同于其他基于容器平台的特性.这也导致我们开始考虑在可扩展并且控制成本的前提下,(使之成为)一个稳定且高效的平台. 我们的应用负责以一种简单高效

摩尔定律都二变三了 硬件基础设施还有救吗

前几天收拾房间的时候,笔者从杂物间里搜出来一个壁挂钟.没错,就是晚上会发出"滴答.滴答"声的老式壁挂钟,相信70后或80后对这种老古董还记忆犹新,多少个夜晚就是这有节奏的钟摆声陪着我们入眠.但在这个电子设备消灭一切机械设备的时代,大部分人家里早就没有了这美妙的"滴答"声,可能甚至连电子壁挂钟也没有了,一台手机搞定一切. 在另一个维度的世界,"Tick-Tock, Tick-Tock"也像钟摆声一样维持着电子世界的秩序,不管是PC.服务器还是数据中

《Docker生产环境实践指南》——1.4 可预期的情况

1.4 可预期的情况 在生产环境中运行Docker容器困难不小,但还是能实现的.每天都有越来越多公司开始在生产环境中运行Docker.如同所有的基础设施一样,我们建议以小规模入手,然后渐进式地完成迁移. 为什么在生产环境中运行Docker如此困难Docker对生产环境有很多要求:安全可靠的部署.健康检查.最小或零停机时间.从失败中恢复的能力(回滚).一个集中存储日志的方式.一种分析或调试应用的方式,以及一种聚合监控参数的方式.类似Docker这样的新技术虽然使用起来非常有趣,但还需要时间来完善.

Puppet发布Blueshift项目中专门针对Docker的特性

于Ubuntu Xenial Puppet代理程序包,另一个基于简化版的Alpine. Blueshift演示了异构软件管理问题的解决方案,使用Puppet作为新软件栈的统一管理方式.Blueshift包含Puppet社区中关于如何集成Consul.CoreOS和Mesos等技术的信息.Blueshift还包含Puppet的内部工程. Puppet还提供了如何在Docker中使用Puppet的例子.目前,这些例子展示了如何在VMware Photon OS.Red Hat CentOS Atom