# 从裸机到 Kubernetes

> 原文： [http://highscalability.com/blog/2019/4/8/from-bare-metal-to-kubernetes.html](http://highscalability.com/blog/2019/4/8/from-bare-metal-to-kubernetes.html)

![](img/6a1d9f7a6234c97845d7e14fa51b4df5.png)

*这是位于旧金山的零售服装公司和众筹平台 [Betabrand](https://www.betabrand.com) 的首席工程师 [Hugues Alary](https://www.linkedin.com/in/huguesalary/?locale=en_US) 的特邀帖子。 本文最初在此处发表[。](https://boxunix.com/post/bare_metal_to_kube/)*

*   [早期基础架构](#_early_infrastructure)
    *   [VPS](#_vps)
    *   [机架空间](#_rackspace)
    *   [OVH](#_ovh)
*   [硬件基础结构](#_hardware_infrastructure)
    *   [可伸缩性和可维护性问题](#_the_scalability_and_maintainability_issue)
    *   [扩展开发流程](#_scaling_development_processes)
*   [Docker](#_the_advent_ofdocker) 的出现
*   [调速器](#_kubernetes)
    *   [学习 Kubernetes](#_learning_kubernetes)
    *   [正式迁移](#_officially_migrating)
    *   [开发/分阶段环境](#_the_developmentstaging_environments)
    *   [在](#_a_year_after)之后一年

如何将 [Betabrand](https://www.betabrand.com) 的裸机基础架构迁移到托管在 Google Container Engine 上的 Kubernetes 集群，从而解决了许多工程问题-从硬件故障到生产服务的可伸缩性不足，复杂的配置管理和高度异构的开发 -生产阶段环境-使我们能够实现可靠，可用和可扩展的基础架构。

这篇文章将引导您了解 Betabrand 从 2011 年到 2018 年遇到的许多基础架构变更和挑战。

* * *

## 早期基础设施

### VPS

在我工作的 7 年中，Betabrand 的基础架构发生了许多次变化。

在 2011 年，即我们的 CTO 雇用我的那一年，该网站托管在具有 Plesk 界面且没有 root 访问权限的共享服务器上（当然）。 每封新闻通讯（最多发送给数百人）都会使该网站屈服并使其爬行，有时甚至完全无响应。

我的第一笔生意就是寻找替代品，并将网站转移到自己的专用服务器上。

### 机架空间

经过几天的在线研究，我们在 Rackspace 上安装了 VPS-8GB RAM，320GO 磁盘，4 个虚拟 CPU，150Mbps 带宽。 再过几天，我们就生活在由……1 台服务器组成的新基础架构上； 运行带有 Memcached 提示的典型 Linux，Apache，PHP，MySQL 堆栈。

毫不奇怪，此基础架构很快就过时了。

它不仅没有扩展，而且更重要的是，它的每个部分都是单点故障。 阿帕奇下来？ 网站关闭。 Rackspace 实例关闭了吗？ 网站关闭。 MySQL 崩溃了……您明白了。

它的另一方面是它的成本。

我们的平均每月账单迅速攀升至 1,000 美元以上。 对于一台机器和我们当时产生的低流量来说，这是很昂贵的价格。

在运行了该堆栈几年后，即 2013 年中，我决定是时候让我们的网站更具可扩展性，冗余性和成本效益了。

我估计，我们至少需要 3 台服务器才能使我们的网站有些冗余，这在 Rackspace 上每年高达$ 14400。 作为一家非常小的初创公司，我们无法证明基础设施账单的“高价”； 我一直在寻找。

最便宜的选择最终导致我们的堆栈在裸机服务器上运行。

### OVH

我过去曾在 OVH 工作过，一直都很满意（尽管在线上有不同的评论）。 我估计在 OVH 上运行 3 台服务器每年将达到 3240 美元，几乎比 Rackspace 便宜 5 倍。

OVH 不仅更便宜，而且其服务器的功能也比 Rackspace 的服务器强 4 倍：32GB RAM，8 个 CPU，SSD 和无限带宽。

最重要的是，他们刚刚在北美开设了一个新的数据中心。

几周后，Betabrand.com 被托管在加拿大博哈努瓦的 OVH。

## 硬件基础架构

在 2013 年至 2017 年之间，我们的硬件基础架构经历了一些架构更改。

到 2017 年底，无论是在软件还是在硬件方面，我们的堆栈都大大超过了以往。

Betabrand.com 在 17 台裸机上运行：

*   2 台负责 SSL 卸载的 HAProxy 机器配置为热备用

*   在我们的 Web 服务器的热备份负载平衡中配置了 2 个清漆缓存计算机

*   5 台运行 Apache 和 PHP-FPM 的计算机

*   2 个 Redis 服务器，每个服务器运行 2 个独立的 Redis 实例。 1 个实例用于某些应用程序缓存，1 个实例用于我们的 PHP 会话

*   3 台配置为 master-master 的 MariaDB 服务器，但以 master-slave 方式使用

*   3 个 Glusterd 服务器为我们所有的静态资产服务

否则，每台机器都将运行一个或多个进程，例如 keepalived，Ganglia，Munin，logstash，exim，备份管理器，有监督的，sshd，fail2ban，prerender，rabbitmq 和 docker。

但是，尽管此基础架构非常便宜，冗余且没有单点故障，但它仍不可扩展，并且维护起来也非常困难。

### 可伸缩性和可维护性问题

现在，管理服务器“舰队”需要编写一组 Ansible 脚本并进行维护，尽管 Ansible 是一款了不起的软件，但这绝非易事。

即使会尽最大努力使您达到目标，Ansible 也不保证您的系统状态。

例如，在由异构 OS 组成的服务器机群（例如 debian 8 和 debian 9）上运行 Ansible 脚本，将使所有计算机的状态都接近您定义的状态，但是最终可能会出现差异。 第一个是您在 Debian 8 和 Debian 9 上运行，但是在某些服务器和其他服务器上，软件版本和配置也不同。

> 我经常搜索 Ansible 替代品，但从未发现更好。
> 
> 我看了看 Puppet，但发现它的学习曲线太陡峭了，从阅读别人的食谱中，*似乎*感到惊讶，因为它们做相同事情的方法太多了。 有些人可能认为这是灵活性，我认为这是复杂性。
> 
> SaltStack 引起了我的注意，但也发现很难学习。 尽管他们进行了广泛而深入的文档编制，但他们的命名选择（矿井，矿井，盐等）从未对我产生影响； 在复杂性方面，它似乎遭受了与 Puppet 相同的问题。
> 
> Nix 软件包管理器和 NixOS 听起来很棒，除了我对学习全新的操作系统感到不舒服（我已经使用 Debian 多年了），并担心尽管选择了巨大的软件包，但最终我仍需要软件包 可用，这将成为新的维护对象。
> 
> 这些是我查看过的仅有的 3 个工具，但我敢肯定还有很多其他工具我可能从未听说过。

然而，编写 Ansible 脚本并进行维护并不是我们唯一的问题； 增加容量是另一个。

对于裸机，无法即时添加和删除容量。 您需要提前计划好您的需求：购买一台机器-通常租用至少 1 个月-等待其准备就绪-可能需要 2 分钟至 3 天的时间-安装其基本操作系统， 安装 Ansible 的依赖项（主要是 python 和一些其他软件包），然后最后对它运行 Ansible 脚本。

对我们来说，整个过程是完全不切实际的，通常发生的事情是，我们会为预期的峰值负载增加容量，但之后再也不会删除它，这反过来又增加了我们的成本。

但是，值得注意的是，即使基础架构中未使用的容量类似于在烧钱，但在裸机上的成本仍然比在云上便宜得多。 另一方面，使用裸机服务器带来的工程难题只是将成本从纯粹的材料成本转移到了管理成本。

在我们的裸机设置容量计划中，服务器管理和 Ansible 脚本只是冰山一角。

### 扩展开发流程

在 2017 年初，虽然我们的基础架构有所发展，但我们的团队也有所发展。

我们又雇用了 7 名工程师，使我们的团队由 9 人组成，其技能组从后端到前端遍及各个领域，并具有不同的资历水平。

即使在一个只有 9 人的小型团队中，也要保持生产效率并限制部署到生产中的错误数量，就可以确保简单，易于设置和易于使用的开发，分期和生产三联产品。

将您的开发环境设置为新员工，无需花费数小时，也无需升级或重新创建它。

此外，应该存在公司范围内可访问的登台环境，该环境应与您的产品的 99％（如果不是 100％）匹配。

不幸的是，在我们的硬件基础架构中，达到这种和谐的三重奏是不可能的。

### 开发环境

首先，我们工程团队的每个人都使用 MacBook Pro，这是一个问题，因为我们的堆栈基于 Linux。

但是，要求所有人切换到 Linux 并可能更改他们宝贵的工作流程并不是一个理想的选择。 这意味着最好的解决方案是提供一个与开发人员的机器偏好无关的开发环境。

我只能看到两个明显的选择：

提供一个可以运行多个虚拟机的 Vagrant 堆栈（实际上更可能是 17 个计算机运行我们的整个堆栈），或者重新使用已经编写的 ansible 脚本，然后对我们的本地 macbook 运行它们。

在调查了 Vagrant 之后，我觉得使用虚拟机会严重阻碍性能，这是不值得的。 我决定（不管是好是坏）走 Ansible 路线（事后看来，这可能不是最好的决定）。

我们将在生产，登台和开发中使用相同的 Ansible 脚本集。 当然，我们的开发堆栈虽然接近生产，但并不是 100％匹配。

这足够好一段时间了。 但是，这种失配会在以后（例如，我们的开发和生产 MySQL 版本未统一）时引起问题。 一些在开发人员上运行的查询不会在生产环境中使用。

#### 暂存环境

其次，在不同的软件（mac os 与 debian）上运行开发和生产环境意味着我们绝对需要一个暂存环境。

不仅是由于版本不匹配导致的潜在错误，还因为我们需要一种在发布之前与外部成员共享新功能的方法。

我再次有多种选择：

*   购买 17 台服务器并对它们运行 ansible。 但是，这会使我们的成本增加一倍，并且我们试图节省资金。

*   在一个可以从外部访问的独特的 linux 服务器上设置我们的整个堆栈。 更便宜的解决方案，但再次没有提供我们生产系统的精确副本。

我决定实施节省成本的解决方案。

暂存环境的早期版本涉及 3 个独立的 linux 服务器，每个服务器运行整个堆栈。 然后，开发人员会在整个房间（或聊天室）大喊大叫，“接管 dev1”，“有人在使用 dev3 吗？”，“ dev2 关闭了：/”。

总体而言，我们的开发，分阶段和生产设置远非最佳：它可以完成工作； 但绝对需要改进。

## Docker 的出现

2013 年，Dotcloud 发布了 Docker。

Docker 的 Betabrand 用例立即显而易见。 我将其视为简化我们的开发和登台环境的解决方案。 通过摆脱烦人的脚本（好吧，差不多；稍后再讲）。

这些脚本现在仅用于生产。

当时，该团队的一个主要痛点是争夺我们的三台物理登台服务器：dev1，dev2 和 dev3；而另一台则是服务器。 对我来说，维护这 3 台服务器是一个很大的麻烦。

在观察了 docker 几个月后，我决定在 2014 年 4 月试用它。

在其中一个登台服务器上安装 docker 之后，我创建了一个包含整个堆栈（haproxy，清漆，redis，apache 等）的 docker 映像，然后在接下来的几个月中编写了一个工具（`sailor`），使我们可以创建 ，销毁和管理可通过单独的唯一 URL 访问的无限数量的登台环境。

> 值得一提的是，当时 docker-compose 还不存在； 而且将整个堆栈放入一个 docker 映像中当然是一个很大的禁忌，但这在这里并不重要。

从那时起，团队不再竞争访问登台服务器。 任何人都可以使用 Sailor 从 Docker 映像创建一个完全配置的新登台容器。 我也不再需要维护服务器； 更好的是，我关闭并取消了其中的 2 个。

但是，我们的开发环境仍在 macos（当时为“ Mac OS X”）上运行，并使用 Ansible 脚本。

然后，在 2016 年左右的某个时候发布了 docker-machine。

Docker machine 是一种工具，可在您选择的任何堆栈上部署 docker 守护进程：virtualbox，aws，gce，bare-metal，azure（由您命名），docker-machine 可以完成； 在一个命令行中。

我将其视为轻松，快速地将基于 ansible 的开发环境迁移到基于 docker 的机会。 我修改了`sailor`以使用 docker-machine 作为其后端。

设置开发环境现在只需创建一个新的 docker-machine，然后传递一个标志供水手使用即可。

至此，我们的开发阶段流程已大大简化； 至少从开发人员的角度来看：每当我需要将我们的堆栈中的任何软件升级到较新版本或更改配置时，都无需修改我的 ansible 脚本，而是要求所有团队来运行它们，然后自己在所有 3 个设备上运行它们 登台服务器； 我现在可以简单地推送一个新的 docker 映像。

具有讽刺意味的是，我最终需要虚拟机（故意避免使用）在我们的 macbook 上运行 docker。 从一开始，使用无业游民而不是 Ansible 是一个更好的选择。 后视总是 20/20。

将 docker 用于我们的开发和登台系统为 Betabrand.com 现在运行的更好的解决方案铺平了道路。

## 州长

由于 Betabrand 主要是一个电子商务平台，因此黑色星期五每年越来越多地出现在我们的网站上。

令我们惊讶的是，自 2013 年以来，该网站已处理了越来越多的负载，而没有发生任何重大灾难，但是它确实需要提前一个月的准备：尽可能地增加容量，负载测试和优化我们的结帐代码路径。

但是，在为 2016 年黑色星期五做准备之后，很明显基础架构无法在 2017 年黑色星期五进行扩展。 我担心在负载下该网站将无法访问。

幸运的是，在 2015 年的某个时候，Kubernetes 1.0 的发布引起了我的注意。

就像在 docker 中看到一个明显的用例一样，我知道 k8s 是解决许多问题所需要的。 首先，它最终将允许我们运行几乎与*相同的 dev-staging-production 环境。 而且，还将解决我们的可伸缩性问题。*

我还评估了另外两个解决方案，即 Nomad 和 Docker Swarm，但 Kubernetes 似乎是最有前途的。

对于 2017 年黑色星期五，我着手将整个基础架构迁移到 k8s。

> 尽管我考虑了这一点，但我很快排除了将我们当前的 OVH 裸机服务器用于 k8s 节点的问题，因为这将与我摆脱 Ansible 而不是处理硬件服务器所带来的所有问题的目标背道而驰。 此外，在我开始调查 Kubernetes 之后不久，Google 便发布了他们的托管 Kubernetes（GKE）产品，我很快就选择了它。

### 学习 Kubernetes

迁移到 k8 首先需要通过阅读在线文档来深入了解其架构和概念。

最重要的是了解容器，容器，部署和服务以及它们如何组合在一起。 然后依次执行 ConfigMaps，Secrets，Daemonsets，StatefulSets，Volumes，PersistentVolumes 和 PersistentVolumeClaims。

其他概念也很重要，尽管使集群前进的必要性较低。

一旦吸收了这些概念，第二个也是最困难的一步就是将我们的裸机架构转换为一组 YAML 清单。

从一开始，我就打算只有一套清单用于创建所有三个开发，登台和生产环境。 我很快就遇到了需要参数化我的 YAML 清单的问题，而 Kubernetes 并不能立即使用它。 这是 Helm <sup>[ [1](#_footnotedef_1 "View footnote.") ]</sup> 派上用场的地方。

> Helm 网站上的*：Helm 帮助您管理 Kubernetes 应用程序-Helm Charts 帮助您定义，安装和升级最复杂的 Kubernetes 应用程序。*

Helm 将自己定位为 Kubernetes 的程序包管理器，但我最初只是将其用于模板功能。 现在，我也开始欣赏它的软件包管理器方面，并用它来安装 Grafana <sup>[ [2](#_footnotedef_2 "View footnote.") ]</sup> 和 Prometheus <sup>[ [3](#_footnotedef_3 "View footnote.") ]</sup> 。

经过一番汗水和几滴眼泪，我们的基础架构现在被整齐地组织为 1 个 Helm 程序包，17 个部署，9 个 ConfigMap，5 个 PersistentVolumeClaims，5 个秘密，18 个服务，1 个 StatefulSet，2 个 StorageClasses，22 个容器映像。

剩下的就是迁移到这个新的基础架构并关闭所有硬件服务器。

### 正式迁移

2017 年 10 月 5 日是夜晚。

扣动扳机非常容易，而且顺利进行。

我创建了一个新的 GKE 集群，运行`helm install betabrand --name production`，将我们的 MySQL 数据库导入到 Google Cloud SQL 中，然后，实际上花了大约 2 个小时，我们才生活在 Clouds 中。

迁移很简单，就是。

当然，最有用的是在 Google GKE 中创建多个集群的能力：在迁移产品之前，我能够通过多次测试迁移进行排练，记下成功启动所需的每个步骤。

Betabrand 的黑色星期五 2017 年非常成功，我们遇到的一些技术问题与迁移无关。

### 开发/分期环境

我们的开发机器通过 Minikube <sup>[ [4](#_footnotedef_4 "View footnote.") ]</sup> 运行 Kubernetes 集群。

相同的 YAML 清单用于创建本地开发环境或“类似生产”的环境。

在生产环境中运行的所有内容，也在开发环境中运行。 两种环境之间的唯一区别是，我们的开发环境与本地 MySQL 数据库对话，而生产与 Google Cloud SQL 对话。

创建登台环境与创建新的生产集群完全相同：所需要做的只是克隆生产数据库实例（只需单击几下或一个命令行），然后通过`--set database`将登台集群指向该数据库。 `helm`中的]参数。

### 一年后

从我们将基础架构移至 Kubernetes 至今已经一年零两个月了，我再也高兴不起来了。

Kubernetes 在生产中一直坚如磐石，我们还没有遇到过停机的情况。

预计 2018 年黑色星期五会有大量流量，我们能够在几分钟内创建生产服务的精确副本并进行大量负载测试。 这些负载测试显示特定的代码路径性能非常差，只能显示大量流量，并允许我们在黑色星期五之前修复它们。

不出所料，2018 年黑色星期五给 Betabrand.com 带来了比以往更多的访问量，但 k8s 兑现了承诺，而 Horizo​​ntalPodAutoscaler 等功能与 GKE 的节点自动缩放功能相结合，使我们的网站能够毫无问题地吸收峰值负载。

K8 与 GKE 相结合，为我们提供了使我们的基础架构可靠，可用，可伸缩和可维护所需的工具。

* * *

[1](#_footnoteref_1). [https://helm.sh/](https://helm.sh/)[2](#_footnoteref_2). [https://grafana.com/](https://grafana.com/)[3](#_footnoteref_3). [https://prometheus.io/](https://prometheus.io/)[4](#_footnoteref_4). [https://github.com/kubernetes/minikube](https://github.com/kubernetes/minikube)

雨果，好帖子！ 真的很脆，没有花哨/不必要的术语。

我很好奇看到您每月帐单的比较-OVH 裸机与 GCP K8S

I too am curious to see a comparison of your monthly bill - OVH bare-metall vs GCP K8S...😉

您认为这对这家公司来说太过分了吗？ 我一直都很喜欢 Kube，不是因为业务需要，而是因为人们喜欢高科技。 IDK，只是想一想

为什么不使用不同的名称空间进行测试和暂存，而不是创建不同的集群？