写了 300000 行基础设施代码,我学到了这五条经验
    Saturday, December 8, 2018
    9:54 AM

    |

    | | —- |

    | Tags: #微信 |

    写了 300000 行基础设施代码,我学到了这五条经验
    Yevgeniy Brikman CSDN
    O 卢 击
    本文为作者 Yevgeniy Brikman 分享了他在 Gruntwork 工作时创建并维护一个超过 30 万行基础设施代码的库(https://gruntwork.io/infrastructure-as-code-library/)时学到的五条经验。
    , -prototype -  this. fitøS .  , , this.  var it—index (activeln&x •

    写了 300000 行基础设施代码,我学到了这五条经验 - 图3
    DevOps 仍在石器时代**

    尽管业界充斥着大量尖端的词汇——Kubernetes、微服务、服务网格、不可改变的架构、大数据、数据湖等等,但现实是,在真正构建基础设施时,你完全感觉不到任何现代化。
    在我看来,DevOps 就像是这样:
    计算机生成了可选文字:
    计算机生成了可选文字:
    计算机生成了可选文字:
    计算机生成了可选文字:
    建立生产级别的基础设施很难、压力很大、而且很花时间。非常耗时间。
    下面是我对于基础设施项目的时间估计,来自几百家与我们合作过的公司的经验数据:
    Managed service  Distributed system (stateless)  Distributed system (stateful)  Entire cloud architecture  Examples  ECS, ELB, RDS, ElastiCache  nginx, Node.js app, Rails app  Elasticsearch, Kafka, MongoDB  Apps, DBS, CI/CD, monitoring, etc.  Time estimate  2  2 —4 months  6 — 24 months
    写了 300000 行基础设施代码,我学到了这五条经验 - 图9
    第一条:生产级基础设施的检查列表
    DevOps 项目永远比你预想的时间长。为什么呢?
    第一个原因就是:剪牛鬃。(https://seths.blog/2005/03/dont_shave_that/。简单来说,“剪牛鬃”指的是完成一项任务所需的一系列动作中的最后一步,比如:今天我需要给车打蜡,但洗车的水龙头坏了,得去五金店买个新的,但五金店在桥对面,但我没有通行证又不想交过桥费……不过我可以借邻居的通行证,但我儿子借了他的靠垫,要不先还给他靠垫他是不会借给我通行证的……但靠垫上的一个小东西掉了,我需要一些牛鬃毛才能修好……于是第二天你就去剪牛鬃了,这样你才能去给车打蜡。)下面这张来自美剧《马尔科姆的一家》的动图很好地说明了这一点:
    计算机生成了可选文字:
    第二个原因就是,打造生产级基础设施(即你的公司可以依赖的基础设施)涉及大量的小细节。绝大多数开发者都不知道这些细节,所以在估算项目时,你通常会漏掉很多重要且耗时间的细节问题。
    为了避免这个问题,每次在构建新的基础设施时,应当使用下面的检查列表:
    The Production-Crade Infrastructure Checklist  www.gruntwork.io  Task  Install  Configure  Provision  Deploy  Security  Monitoring  Logs  Backup and  restore  Networking  High  availability  Scalability  Performance  Cost  optimization  Documentation  Tests  Maintenance  Description  Install the software binaries and all dependencies.  Configure the software at runtime: e.g., configure port settings, file paths, users, leaders,  followers, replication, etc.  Provision the infrastructure: e.g., EC2 Instances, load balancers, network topology, security  groups, IAM permissions, etc.  Deploy the service on top of the infrastructure. Roll out updates with no downtime: e.g.,  blue-green, rolling, canary deployments.  Encryption in transit (TLS) and on disk, authentication, authorization, secrets management,  server hardening.  Availability metrics, business metrics, app metrics, server, metrics, events, Observability,  tracing, alerting.  Rotate logs on disk. Aggregate log data to a central location.  Make backups of DBS, caches, and other data on a scheduled basis. Replicate to separate  region/account.  VPCs, subnets, static and dynamic IPs, service discovery, service mesh, firewalls, DNS, SSH  access, VPN access.  Withstand outages of individual processes, EC2 Instances, services, Availability Zones, and  regions.  Scale up and down in response to load. Scale horizontally (more servers) and/or vertically  (bigger servers).  Optimize CPU, memory, disk, network, GPI-I and usage. Query tuning. Benchmarking, load  testing, profiling.  Pick proper instance types, use spot and reserved instances, use auto scaling, nuke unused  resources  Document your code, architecture, and practices. Create playbooks to respond to incidents.  Write automated tests for your infrastructure code. Run tests after every commit and nightly.  Update the software. Update tools (e.g., Terraform, packer). Update to latest best practices.  Add new features. Fix bugs. Install security patches.  Example tools  Bash, Chef, Ansible, puppet  Bash, Chef, Ansible, Puppet  Terraform, CloudFormation  Scripts, Orchestration tools (ECS,  K8S, Nomad)  ACM, EBS Volumes, Cognito, Vault,  Cis  CloudWatch, DataDog, New Relic,  Honeycomb  CloudWatch Logs, ELK, Sumo  Logic, Papertrail  RDS, Elasticache, ec2-snapper,  Lambda  ElPs, ENIs, vpcs, NACLs, SGs,  Route 53, OpenVPN  Multi AZ, multi-region, replication,  ASGs, ELBs  ASGs, replication, sharding,  caching, divide and conquer  Dynatrace, valgrind, VisualVM, ab,  Jmeter  ASGs, spot instances, reserved  instances  READMEs, wikis, Slack  Terratest  Human beings, Gruntwork  commercial support.
    并不是每个基础设施都需要列表中的每一项,但应当认真检查每一项,找出哪些你应当实现,哪些应当忽略,以及原因。
    写了 300000 行基础设施代码,我学到了这五条经验 - 图12
    第二条:工具集**
    2018 年我们在 Gruntwork 用来构建和管理基础设施的主要工具有:
    Docker  Cluster  Container  Container  Container  Container  Container  Container  VM  Server  VM  Server  Networking, Load Balancers, Databases, Users, Permissions, etc  VM  Server  VM  Server  VM  Server  docker  Packer  Terraform

    1. Terraform:我们使用 Terraform 来管理所有基本的基础设施,包括网络、负载均衡器、用户、权限和所有服务器。
    1. Packer:我们使用Packer来定义并构建服务器上运行的虚拟机的映像。
    1. Docker:我们的一些服务器组成集群,在集群上我们通过Docker容器运行应用程序。我们使用的主要Docker集群工具是Kubernetes、ECS和Fargate。

    所有这些工具都很有用,但这并不是重点。真正的重点是,仅有工具本身是不够的。你还需要改变团队的行为模式。
    具体来说,如果你的团队不习惯使用那些工具,或者没有足够的时间学习那些工具,那么即使世界上最好的工具也无法为你的团队提供一丝一毫帮助。因此,主要的经验是:以代码的方式使用基础设施(infrastructure as code)是一项重要的投入。一定的前期投入是不可避免的,只有这样才能让它运转起来,但如果正确地投入了时间和精力,长期来看你会获得巨大的收益。
    写了 300000 行基础设施代码,我学到了这五条经验 - 图14
    第三条:大型模块是有害的
    以代码方式使用基础设施(infrstructure as code)的新手们经常会把所有基础设施的所有环境(dev、stage、prod等)都放在一个文件中,或者放在一组文件中但作为一个单元来部署。这是个很糟糕的习惯。
    下面是几条缺陷:

    1. 速度慢。如果所有基础设施都在一个地方定义,那么运行任何命令都会花很长时间。我们遇到过许多公司中,terraform plan 需要花五六分钟时间!
    1. 不安全。如果所有基础设施都在同一个地方管理,那么做任何修改都需要拥有访问一切的权限。也就是说,每个用户都必须是管理员,这同样是个非常糟糕的想法。
    1. 高风险。把所有鸡蛋放在一个篮子里,那么任何地方出错都会破坏一切。可能你只想对dev里的前端app做一点微小改动,但一个输入错误或运行错误的命令,就可能会删掉生产数据库。、
    1. 难理解。同一个地方的代码越多,别人就越难看懂。如果所有代码都在同一个地方,那么你无法理解的部分早晚会坑你。
    1. 难测试。基础设施的代码很难测试,大量基础设施的代码几乎不可能测试。我们稍后会讨论着一点。
    1. 难审查。一些命令(如terraform plan)的输出结果变得毫无意义,因为根本没人会查看几千条plan的输出。而且,进一步会让代码审查变得毫无意义:

    I Am Devloper  @iamdevloper  10 lines of code = 10 issues.  500 lines of code =
    简单来说,你应当将代码写成小型、独立、可重用、可组合的模块。这也不是什么新观点或有争议的观点了。你肯定已经听过上千次了,只不过是在不同的领域:
    “只做一件事并把它做好。”——Unix 的哲学
    “函数的第一条规则就是它们应当很小。第二条规则就是它们应该比第一条更小。”——《代码整洁之道》
    写了 300000 行基础设施代码,我学到了这五条经验 - 图16
    第四条:没有自动化测试的基础设施无法使用
    如果你的基础设施代码没有自动化测试,那就没办法使用。只不过你还没意识到罢了。虽然这么说,但测试基础设施代码非常困难。你没有真正的“localhost”可以使用(例如,你不能把 AWS 上的 VPC 部署到自己的笔记本电脑上),也没有真正的“单元测试”(例如,你没办法把 Terraform 的代码与“外界”隔离开来,因为 Terraform 的功能就是要与外部交流)。
    因此,要想恰当地测试你的基础设施代码,通常都要将其部署到一个真实的环境,运行真实的基础设施,验证它能实现你想要的功能,最后全部拆毁(这种风格的测试可以参见 Terratest(https://blog.gruntwork.io/open-sourcing-terratest-a-swiss-army-knife-for-testing-infrastructure-code-5d883336fcd5),这是个开源库,包含了一些用来测试 Terraform、Packer 和 Docker 代码的工具,支持 AWS、GCP 和 Kubernetes API,可以在本地执行命令,也可以通过 SSH 在远程服务器上执行命令,还有去多其他功能)。这意味着,在基础设施测试中,一些术语的定义需要稍作修改:
    Entire  stack  Multiple  modules  Individual  modules  Tests  Integration Tests  Unit Tests

    • 单元测试:部署并测试一种类型的基础设施中的一个或几个紧密相关的模块(例如,测试一个数据库中的模块)。
    • 集成测试:部署并测试来自不同类型的基础设施中的多个模块,验证它们能正确地合作(例如,测试某个数据库的模块和某个Web服务的模块)。
    • 端到端(e2e)测试:部署并测试整个架构。

    注意图示是个金字塔,也就是说,里面有很多单元测试,几个集成测试,和非常少的 e2e 测试。为什么?因为每种测试的执行时间如下:
    30 -120+  minutes  5 - 60  minutes  1-20  minutes  Tests  Integration Tests  Unit Tests
    基础设施的测试非常慢,特别是在进入金字塔顶端之后,所以应当尽可能多地在金字塔底层抓出 Bug。也就是说:

    1. 构建小型、简单、独立的模块(还记得第三条吗?)并为之编写许多单元测试,确保它们能正确工作。
    2. 将小型、简单、测试过的模块组合成更复杂的基础设施,并通过几个集成测试和 e2e 测试进行测试。

    写了 300000 行基础设施代码,我学到了这五条经验 - 图19
    第五条:发布过程
    现在我们总结一下。从今以后,构建和管理基础设施的过程应当如下:

    1. 仔细阅读“生产级基础设施检查列表”确保构建的方向正确。
    1. 使用工具实现通过代码方式使用基础设施,如 Terraform、Packer、Docker 等。确保团队有足够的时间掌握这些工具(参见“DevOps资源”(https://gruntwork.io/devops-resources/))。
    1. 写代码时要写成小型、独立、可组合的模块(或使用 Infrastructure as Code Library(https://gruntwork.io/infrastructure-as-code-library/)中提供的现成的模块)。
    1. 使用 Terratest 为模块编写自动化测试。
    1. 提交拉取请求,让别人审查代码。
    1. 发布代码的新版本。
    1. 将新版本的代码从一个环境提升到下一个环境。
      0 、

    链接:https://blog.gruntwork.io/5-lessons-learned-from-writing-over-300-000-lines-of-infrastructure-code-36ba7fadeac1
    作者:Yevgeniy Brikman,Gruntwork联合创始人,著有《Hello, Startup》和《Terraform: Up & Running》。
    译者:弯月,责编:屠敏
    【完】