精通-Openstack-第三版-全-

精通 Openstack 第三版(全)

原文:annas-archive.org/md5/2a88c2973d2d6ce43abf497882295bd4

译者:飞龙

协议:CC BY-NC-SA 4.0

前言

欢迎阅读掌握 OpenStack,这是Mastering系列的第三版,将为您提供关于基于 OpenStack 部署和运行私有云基础设施的最新更新和前沿技术。由于 OpenStack 生态系统的复杂性以及不同版本之间的快速发展,组织在采用 OpenStack 时常常面临挑战。本书将通过对每个核心组件采取迭代方式,帮助您克服这些挑战,为生产就绪的私有云设计做好准备。在每一章中,本书从最常用的最佳实践中汲取灵感,用于部署和管理基础设施。这包括利用基础设施即代码、CI/CD 以及 DevSecOps 范式。由于本书将涉及新的 OpenStack 服务和高级概念,自动化将成为您成功部署它们的守护天使。本书同样适用于新的 OpenStack 用户,因为它会逐步介绍核心组件,并通过容器部署它们。虽然不要求具备深入的容器化技术知识,但建议有基本了解。最重要的是,本书专注于生产质量和受多行业启发的最流行部署。OpenStack 世界提供了大量的服务和部署选项。本书旨在帮助您理解如何从头开始构建和设计一个符合组织需求的私有云架构。在本版的最后,本书将揭示云市场中的一项新趋势:混合云。OpenStack 扮演着私有云的角色,并与 AWS 环境结合,构建混合云架构。在本书的结尾,将探索更多机会,展示如何在不同云服务提供商之间运行大规模环境,其中 OpenStack 作为私有云解决方案非常合适。

本书的读者

本书面向具备 OpenStack 生态系统基本理解以及云计算和虚拟化概念的云架构师和管理员。本书对拥有公共云工作经验的企业顾问和云开发人员也非常有用。建议读者熟悉 Linux 命令行并具备容器化和网络拓扑的基本知识,以便顺利阅读本书的大部分内容。

本书内容概述

第一章重新审视 OpenStack——设计考虑,总结了 OpenStack 主要架构服务的最新特性。本章介绍了 Antelope 及后续版本中每个核心组件的最新更新。初步的逻辑和物理设计模型将被草拟并作为后续章节的架构参考。

第二章正确启动 OpenStack 设置 – 正确的方法(DevSecOps),首先介绍了 DevOps 概念,并融合了安全方面的内容。本章探讨了 DevSecOps 如何帮助以最敏捷且安全的方式管理、部署和自动化大规模的 OpenStack 私有云基础设施。本章介绍了 Kolla Ansible 项目,它将用于基于容器部署不同的 OpenStack 云基础设施组件。

第三章OpenStack 控制平面 – 共享服务,重点介绍了设计用于在云控制节点中运行的常见 OpenStack 服务。本章深入探讨了最新 OpenStack 更新中引入的控制平面内容,包括核心服务 API、消息传递和数据库服务。基于容器部署,本章将更深入地探讨 Kolla Ansible 仓库中与 OpenStack 控制平面相关的不同组件。

第四章OpenStack 计算 – 计算能力和规格,更深入地回顾了 OpenStack 计算 Nova 服务。调度和 Placement 服务将被介绍,包括执行资源分配以在计算节点中运行实例的高级方法。本章通过涵盖可用区、主机聚合和单元等概念,探讨了大规模 OpenStack 部署的最新计算设计更新。大部分内容将专注于学习 OpenStack 中针对容器化技术的孵化项目。Zun 和 Magnum 将作为其他服务一样,通过基础设施即代码的方式进行部署。

第五章OpenStack 存储 – 块存储、对象存储和文件共享,探索了最新 OpenStack 版本中的不同存储选项,从 Antelope 版本开始。本章揭示了与 Cinder 块存储服务的不同后端集成,如 NFS 和 Ceph。块存储调度的更多更新被详细突出显示。对于 Manila 和 Swift,将给出简洁的更新概述。所涉及的存储服务将通过使用 Kolla Ansible 仓库的部署模型进行集成。

第六章OpenStack 网络 – 连接性和管理服务选项,更深入地解释了 OpenStack 中的 Neutron 网络服务。本章介绍了大规模部署的网络架构的新布局。Neutron 插件将与最新 OpenStack 版本更新一起进行探索,包括 Open vSwitch 和 OVN。路由将被讨论,并展示如何通过利用 Neutron 插件在后台实现。额外的服务,如新版本的负载均衡服务(代号 Octavia),将在本章中进行演示。

第七章运行高可用云 – 满足 SLA,介绍了在每个 OpenStack 控制平面层中增加可用性和可扩展性的不同技术和设计模式。本章探讨了在 Neutron 中实现路由冗余的不同方式。它还超越了基础设施层,专门介绍了一个自动化的方法,通过一个名为 Masakari 的新兴 OpenStack 服务来管理实例的可用性。

第八章监控与日志记录 – 主动修复,展示了一个集中式解决方案,用于在大型 OpenStack 云环境中运行复杂的监控系统。本章介绍了 Prometheus,作为所有 OpenStack 监控指标的单一监控界面。它还探讨了使用 Grafana 在一个系统中可视化和集中化指标的简单方法。对 OpenStack 中 Ceilometer 遥测服务的简要更新也有涉及。本章揭示了一种强大且自动化的方式,通过 OpenSearch 来消化和可视化大量 OpenStack 日志。

第九章基础设施基准测试 – 评估资源容量与优化,介绍了针对 OpenStack 性能和资源优化的更高级别的操作任务。本章讨论了如何通过使用 Rally 工具进行基准测试来评估云基础设施的核心服务和限制。它还通过启用跟踪 OpenStack 不同调用的工具(名为 OSProfiler),将性能优化提升到了新层次。章节还重点介绍了 OpenStack 项目中新加入的一项资源优化工具,名为 Watcher。

第十章OpenStack 混合云 – 设计模式,建议了实施、部署和集成 OpenStack 的新方法,超越了私有云模型。本章讨论了采用混合云模型的趋势,并介绍了针对多个用例的混合云设计模式。我们探讨了基于 OpenStack 的公共云和私有云之间的结合。

第十一章混合云超大规模用例 – 扩展 Kubernetes 工作负载,以混合云的工作负载扩展为主题,结束本书的内容。章节深入讨论了如何在私有 OpenStack 云和 AWS 公共云环境之间扩展工作负载。通过引入双容器和微服务的概念来实现混合云模型,本章演示了如何在私有和公共云之间运行基于 Kubernetes 的工作负载,并介绍了一款名为 Juju 的流行 Canonical 工具,用于跨云管理和调度工作负载。

要充分利用本书

书中涉及的软硬件 操作系统/硬件要求

| OpenStack(Antelope 或更高版本)、AWS 账户、Python、YAML、JSON、Ansible、Kolla、Jenkins、Docker、Kubernetes、Ceph、Canonical Juju、KubeFed | Linux(Ubuntu 22.04)、Vagrant 2.4.1 或更高版本 | 测试环境(1 主机)

  • 2 个 CPU 或更多

  • 8 GB 内存或更多

  • 50 GB 磁盘空间或更多

每个主机的最小开发/生产环境(至少 2 台机器):

  • 2 个 CPU

  • 8 GB 内存

  • 100 GB 磁盘空间或更多

|

如果你使用的是本书的数字版,我们建议你自己键入代码或从本书的 GitHub 仓库访问代码(下节会提供链接)。这样可以帮助你避免因复制和粘贴代码而产生的潜在错误。

下载示例代码文件

你可以从 GitHub 下载本书的示例代码文件,地址为 。如果代码有更新,它将在 GitHub 仓库中更新。

我们还提供了其他代码包,来自我们丰富的书籍和视频目录,访问 github.com/PacktPublishing/。快来看看!

重要提示

从本书的创作到出版,OpenStack 经历了几次重要的版本更新。因此,本书某些部分提到的代码可能需要进行调整才能正常工作。每一章的相关设置或故障排除步骤,以及更新后的代码文件,都将包含在上述 GitHub 仓库中。

使用的约定

本书中使用了许多文本约定。

文本中的代码:表示文本中的代码字、数据库表名、文件夹名称、文件名、文件扩展名、路径名、虚拟网址、用户输入和 Twitter 账号。以下是一个示例:“在 /kolla-ansible/etc/kolla/ globals.yml 文件中,将 enable_magnum 设置为 yes 将启用 Magnum API 服务。”

代码块设置如下:

…
[magnum:children]
control
[magnum-api:children]
magnum
[magnum-conductor:children]
magnum
…

当我们希望特别指出代码块中的某个部分时,相关行或项目将以粗体显示:

"provider_summaries": {
        "ad54422c-b345-5v44-ba23-00cad76e376a": {
            "resources": {
                "DISK_GB": {
                    "used": 0,
                    "capacity": 2000
                }
            },
            "traits": ["SRG_SHARES_STORE"],

任何命令行输入或输出都以如下方式书写:

# openstack allocation candidate list --resource VCPU=4,
MEMORY_MB=2048,DISK_GB=500GB --required   HW_CPU_X86_SVM

粗体:表示新术语、重要单词或你在屏幕上看到的单词。例如,菜单或对话框中的单词会以 粗体 显示。以下是一个示例:“在 Jenkins 仪表盘上,通过指向 管理 Jenkins 并点击 配置系统 来配置已安装的 Anchore 插件。”

提示或重要说明

显示为这样。

联系我们

我们始终欢迎您的反馈。

一般反馈:如果你对本书的任何部分有疑问,请发送邮件至 customercare@packtpub.com,并在邮件主题中提及书名。

勘误:尽管我们已尽一切努力确保内容的准确性,但错误总是难免。如果你在本书中发现错误,我们将不胜感激。如果你发现了问题,请访问 www.packtpub.com/support/errata 并填写表单。

盗版:如果你在互联网上遇到我们的作品的任何非法副本,请提供该位置地址或网站名称。请通过电子邮件 copyright@packt.com 联系我们并附上相关材料的链接。

如果你有兴趣成为作者:如果你在某个领域有专业知识,并且有兴趣撰写或为书籍做出贡献,请访问 authors.packtpub.com

分享你的想法

一旦你阅读了 Mastering OpenStack,我们很想听听你的想法!请 点击这里直接进入亚马逊评论页面 并分享你的反馈。

你的评价对我们和技术社区非常重要,它将帮助我们确保提供优质的内容。

下载本书的免费 PDF 版本

感谢你购买本书!

你喜欢随时随地阅读,但又不能随身携带纸质书籍吗?

你的电子书购买是否与你选择的设备不兼容?

不用担心,现在购买每本 Packt 图书时,你都可以免费获得该图书的无 DRM PDF 版本。

随时随地,在任何设备上阅读。直接从你最喜欢的技术书籍中搜索、复制并粘贴代码到你的应用程序中。

优惠不仅仅是这些,你还可以获得独家折扣、新闻通讯以及每天发送到你邮箱的精彩免费内容。

按照以下简单步骤获取这些福利:

  1. 扫描二维码或访问以下链接

img

packt.link/free-ebook/9781835468913

  1. 提交你的购买证明

  2. 就是这样!我们会将免费的 PDF 文件和其他福利直接发送到你的邮箱。

第一部分:OpenStack 生态系统架构设计

本书的第一部分将介绍 OpenStack 的最新更新,包括 Antelope 版本和后续发布的内容。这将重点介绍任何新增功能和为部署私有云环境所需的变更。该部分将回顾设计稳健架构并实现最稳定操作能力所需的所有核心组件,其中将包括控制平面和数据平面所需的所有服务,并提供不同的配置选项。书籍的第一部分是后续章节的基础,因为它将讨论通过基础设施即代码(Infrastructure as Code)和 DevSecOps 风格部署不同 OpenStack 服务的方法。

本部分包含以下章节:

  • 第一章重新审视 OpenStack – 设计考虑事项

  • 第二章启动 OpenStack 设置 – 正确的方式 (DevSecOps)

  • 第三章OpenStack 控制平面 – 共享服务

  • 第四章OpenStack 计算 – 计算能力与规格

  • 第五章OpenStack 存储 – 块存储、对象存储和文件共享

  • 第六章OpenStack 网络 – 连接性与托管服务选项

第一章:1

重访 OpenStack – 设计考虑因素

“我发现你必须回顾过去的事物,并从新的角度看待它们。”

  • 约翰·科尔特兰

自从精通 OpenStack系列的上一个版本发布以来,OpenStack 社区一直保持着势头,围绕其生态系统不断增长和创新。在撰写本版本时,OpenStack 设计经历了不同周期的改进,通过引入新项目并与现有系统提供无缝集成,以应对组织需求和定制功能。自 2010 年首次发布的Austin版本以来,创新不断为公司开辟了新的机会,并迅速采用稳定的私有云设置,以在市场中保持领先地位。大公司和中型企业在加入 OpenStack 的演变过程中,感受到了处理可扩展基础设施的挑战。如今,在本版的第一页正在书写之际,14 年和 28 个版本已经穿越了不同的 OpenStack 发布,从最初的Austin版本到最新的Dalmatian版本。这是一个回到字母表开头的完整循环。许多经验和见解已经揭示出来,推动了 OpenStack 社区的发展,使其成为全球领先的开源云平台。

数据显示 OpenStack 已经成功地被中型和大型企业广泛采用。根据 2022 年 11 月在 OpenStack 博客上发布的年度OpenStack 用户调查结果,报告称,超过 4000 万个核心正在生产环境中运行,支持 OpenStack 的 300 个部署。

OpenInfra 社区在加强 OpenStack 软件最稳定版本方面做出了巨大贡献。从 2023 年 3 月发布的Antelope版本开始,到最近的 2024 年 10 月发布的Dalmatian版本,组织们迅速完成了升级,值得庆幸的是,这是一个比以往任何时候都更稳定可靠的版本。这一巨大成就的秘诀在于,社区已经改变了稳定 OpenStack 基础服务(包括计算、存储和网络服务)的工作方式,极大地提高了每个服务发布测试的频率,从而避免了可能的漏洞和潜在的安全问题,这些问题可能会在生产环境部署时引发故障。从故事的另一面来看,通过分析每个 OpenStack 版本的图谱,你可能会注意到一些扩展项目的出现和消失。社区贡献者做得对,摒弃了那些不稳定的特性,以免影响 OpenStack 私有部署的成熟度。今天,发布的版本暴露了基本服务,并在稳定的上游增加了更多的项目和功能。这个故事的另一个亮点是,OpenStack 生态系统始终领先一步,及时采用市场技术的新趋势,包括容器化、无服务器架构、大数据分析等。

今天,无论是开始新的 OpenStack 探险,还是翻开新的一页来进行更新,都能带来巨大的成本节约,相比传统的虚拟化替代方案,提供更高的 IT 灵活性,并在最小的担忧下实现高效的超大规模解决方案。

OpenStack 最先进的文档和资源现在比以往任何时候都更容易在互联网上找到。设计和部署一个完整的 OpenStack 环境有许多不同的选择。另一方面,关于不同设计和运行完整生态系统的选择之间的矛盾,即便对于有经验的管理员、架构师和开发者来说,也是一个挑战。这可以用选择太多反而太少来形容!OpenStack 的采用一直是一个挑战,从设计阶段到部署和运维阶段。正如前面所说,你可以想到很多原因,但最主要的原因是,这款软件功能如此多样,容易让人感到不知所措!

本书将通过逐步的方式,带你了解 OpenStack 生态系统的更新部分,并通过分步实施的方式,设计、部署和运营一个可扩展的 OpenStack 环境,满足你的需求和要求。

为了解决 OpenStack 生态系统复杂性带来的挑战,并让新手能够享受这一云计算旅程,我们将在第一章中定义一个私有云采用策略的愿景。如果没有一个精心设计的基础知识框架,将很难在生产阶段开始时做出有关如何支持生产集群的决策。正如商业管理实践专家罗伯特·沃特曼所说,“战略是必要的,因为未来 是不可预测的。”

对于像 OpenStack 生态系统这样的复杂系统,设置正确的资源是必要的,因为我们无法做到 100% 准确预测。OpenStack 设计时具有更大的灵活性和松耦合架构。这样,关键在于我们如何利用这些元素做出容量决策,考虑短期和长期的增长及可用性目标,并根据我们在短期和长期内打算应用的现有资源来响应新的工作负载。

我们的 OpenStack 之旅将在本版本中继续,涵盖以下主题:

  • 回顾并突出展示 OpenStack 核心生态系统的最新更新

  • 解密基于最新发布版本的逻辑架构,特别是从 Antelope 发布版开始引入的内容

  • 起草初步的物理设计,以确保后续阶段的无缝部署

  • 通过容量规划为大规模 OpenStack 环境做准备,作为我们云策略的一部分

OpenStack – 无数创新

当谈到 OpenStack 软件产品时,理解创新的最新状态可能会让人感到困惑。自 14 年前诞生以来,这个开源项目的崛起具有独特性。通过不同的版本,OpenStack 社区一直在根据持续的技术趋势不断开发私有云解决方案可以提供的功能。当 Kubernetes(容器编排技术)首次公开发布时,随后的 OpenStack 版本迅速 dedicating 了一个周期,加入了 OpenStack 生态系统中的服务,以便开箱即用地支持容器管理。OpenStack 成功的故事之一无疑是它始终保持领先一步的愿景。OpenStack 仍然是全球第四大开源社区的原因非常明确:对其主要核心服务的信任。自 OpenStack 诞生之日起,中大型企业便不断投资并持续贡献代码,以增强其核心服务。正如我们稍后会看到的,计算、网络、身份、镜像和存储服务被视为 OpenStack 生态系统中最基础和核心的组件。在每一个新版本中,都会对这些服务进行更多的增强和广泛的开发,使它们更加生动。这样做吸引了更多的贡献者,使得这些服务更加活跃,能够承载更多的工作负载,满足更多的需求,并且帮助企业解锁更具敏捷性和灵活性的基础设施。早期,更多的大型企业如 IBM、Red Hat、HP、Rackspace、eBay 等加入了云计算时代,他们的目标和项目各不相同,包括引入新功能、插件、修复 Bug 等等。一些贡献者基于 OpenStack 构建了自己的专用私有云平台,并继续为开源世界贡献代码,形成了双赢局面。

OpenStack 新颖性的另一个关键方面是其快速扩展能力,涵盖了与公共大型云服务提供商(如 Amazon Web Services (AWS)、Microsoft AzureGoogle Cloud Platform (GCP))类似的更广泛的服务。OpenStack 生态系统从传统的 基础设施即服务 (IaaS) 开始,逐步推出了托管服务,并提供 平台即服务 (PaaS) 以及 软件即服务 (SaaS) 模型。通过快速浏览 OpenStack 的增长速度,我们可能会发现其核心服务已经达到了成熟的水平,可以解锁大量创新功能和解决方案的门扉。在这些服务的基础上,可以提供更多的 PaaS 环境,如数据库、大数据、容器服务等。

OpenStack 增长成功的另一面是软件本身的特性。自开发初期以来,OpenStack 软件大部分是用 Python 编写的,旨在提供丰富的应用程序编程接口API)。这是一项改变游戏规则的创新,几乎在任何地方都能够实现自动化。因此,每个贡献者可以利用自己的专业领域,利用 API 设计的特性,顺利地将新功能集成到软件生态系统中。

OpenStack 的 API 在采用混合云方法中具有重要意义。正如我们在第十一章《混合云超大规模用例——扩展 Kubernetes 工作负载》中所看到的,OpenStack 提供了弹性计算云EC2)API,这是与 AWS 世界兼容的 API。

OpenStack 生态系统的创新和持续增长无疑是一个成功的故事,这得益于社区的一致性,最重要的是,OpenStack 凭借模块化设计自然发展。如今,构建一个 OpenStack 私有云已经可以用于一个或多个目的,它可以为公共托管工作负载、托管数据库、大数据、高性能计算(HPC),甚至多个优化的容器化环境提供 Web 应用程序,满足快速应用开发的需求。最重要的是,了解核心和最新服务的更新是开启云计算之旅的必备钥匙。

OpenStack 的构建模块——控制平面

OpenStack 项目的启动是为了解决 IaaS 范式问题。通过采用按需付费模式,底层资源,包括计算、网络和存储,作为池子被按需安全地暴露并根据用户需求进行预留。在 OpenStack 生态系统的发展过程中(在其他文献中被称为云操作系统),更多的开源项目加入了新兴的云软件生命周期,扩展了其功能。正如前面所提到的,这种项目开发的秘诀在于自然的 API 设计,它始终促进了服务之间的通信。大量的服务可能会让新手困惑,不知道生态系统中的基本部分如何工作,从而启用为定制需求和要求设计的良好架构。接下来的章节将逐步介绍 OpenStack 的核心服务,作为开始。了解这些服务中的每一个至关重要,因为每个 OpenStack 版本都会引入新的项目或服务,并依赖于它们。战略性地掌握核心组件及其功能,将使您更容易部署未来的私有云设置,从而以更少的时间和精力扩展其能力。下表展示了接下来章节将要讨论的核心服务:

服务 代号 描述
计算 Nova 管理 虚拟机VM)生命周期
网络 Neutron 管理每个项目的网络环境
身份 Keystone 提供身份验证与授权信息服务
块存储 Cinder 管理 VM 磁盘和快照生命周期
对象存储 Swift 可访问的 REST API 存储,用于存储图像、媒体文件等对象数据类型
镜像 Glance 管理 VM 镜像生命周期
仪表盘 Horizon OpenStack 前端 Web 界面
文件共享 Manila 管理跨共享文件系统的项目
调度 放置 帮助跟踪提供商的资源库存和使用情况
遥测 Ceilometer 提供资源跟踪和计费的数据收集服务
报警 Aodh 基于收集的指标和配置的规则触发动作和报警

表格 1.1 – OpenStack 核心服务

重要说明

仍然可以在没有对象存储和仪表盘的情况下部署 OpenStack 环境。某些发行版默认启用了这两项服务。例如,启动一个虚拟机不一定需要对象存储。此外,OpenStack 命令行界面CLI)支持每个安装的所有操作,并且可以无需 OpenStack 仪表盘进行指令。

Keystone – 身份验证与授权服务

关键字 身份验证授权 是此身份服务的主要功能。Keystone 是 OpenStack 生态系统控制平面的一部分。

安全性从最早的版本开始被引入,并且深入研究 OpenStack 中的 AAA身份验证、授权、计费)服务成为了必需。每一个联系 OpenStack 服务的请求都必须由 Keystone 验证(通过身份 API)。API 响应将返回一个身份验证令牌,用于访问请求的服务(API 调用)。

在这个阶段,Keystone 工作流可能看起来比我们想象的简单。另一方面,当我们扩展数百个主机以在短时间内处理成千上万的请求时,我们应考虑如何确保 Keystone 作为关键服务能够完全正常运行。这将在后面的章节中讨论。

从旧版 OpenStack 版本到最新稳定版,在身份服务中的主要变化是 API 的版本。以前,在安装身份服务时,可以继续使用版本 2;从 Grizzly 版本开始,推出了版本 3,并且可以安装。今天,身份 API 版本 2 已被弃用,取而代之的是更新的版本。我们将考虑版本 3 及以上(截至本书撰写时,版本 3.14 是 Ussuri OpenStack 版本中的最新版本)。

那么身份 API 能提供什么呢?如前所述,所有 OpenStack 服务之间的通信设计都是通过 API 实现的(稍后,我们将简单介绍如何通过 API 与非 OpenStack 服务进行交互)。考虑到一个失败的简单身份验证请求可能会从最终用户的角度反映出服务故障。一个好的做法是,在首次排查故障时,确保 Keystone 请求没有问题,特别是在服务请求失败时。尽管本书的前几个版本没有深入探讨 Keystone 工作流,但我们将在 第三章 中以更详细的方式重新审视它,*OpenStack 控制平面 - * 共享服务

Nova – 计算服务

Austin,OpenStack 的第一个版本,推出了 Nova 项目的第一个版本,用于启动实例,并开始通过丰富的 API 处理计算管理。与前述的身份服务不同,Nova 在不同版本中不断发展,增加了更多惊人的功能,但相较于其他核心服务,它的复杂性也有所提高。Nova 服务的设计自 Grizzly 版本以来变化不大。另一方面,仍然需要反复讨论构成 OpenStack 生态系统中计算服务引擎的不同 Nova 组件。

重要提示

在最新的 OpenStack 版本中,Nova 带来了许多新功能,详细内容请参见 第四章OpenStack 计算 - 计算能力 与规格

nova-api 服务与用户 API 调用进行交互,管理计算实例。它通过消息总线与计算服务的其他组件进行通信。

nova-scheduler 服务监听来自消息总线的新实例请求。该服务的任务是为新实例选择最佳计算节点。

nova-compute 服务是负责启动和终止虚拟机的进程。该服务运行在计算节点上,并通过消息总线监听新的请求。

nova-conductor 服务处理计算节点的数据库访问请求,以限制攻击者通过被妥协的主机对数据库的访问风险。

Placement – 调度服务

每当涉及到新的系统改进或逻辑添加时,OpenStack 社区会创建、移动或部署不同的服务或组件来实现这一目标。自 Newton 版本以来,OpenStack 生态系统的一个重要更新是引入了 Placement API 服务。在此版本之前,用户在识别不同资源提供者(如计算、网络和存储分配池)上的计数器时遇到困难。正是在这里,专门为此创建一个独立的服务,进而通过与其他服务(如 Nova)的良好连接的 API 来跟踪这些资源提供者并监控其使用情况,就显得尤为重要。Placement 服务主要作为资源清单进行工作。不仅如此,最重要的改进还使得过滤过程(通过 nova-scheduler )更加精细。在一些其他术语中,你可能会看到 预过滤 这个词作为对新 Placement 服务的引用。此步骤是在处理调度器之前,根据一些可配置的规格和特性,启动过滤过程以准备可用的计算节点。Placement 服务将在 第四章OpenStack 计算 – 计算容量 与规格 中演示。

Glance – 镜像服务

要通过 Nova 服务在 OpenStack 中启动一个实例,成功完成虚拟机配置需要一个实例镜像。Glance 是一个核心服务,它不仅处理实例镜像(作为模板源镜像),还处理可以从实例创建的快照。当涉及到 Glance 存储镜像和快照的位置问题时,答案可以在其最新支持的驱动配置中找到。与许多其他 OpenStack 服务一样,可以使用多种存储选项来支持 Glance 的镜像存储。再次提醒,如果我们从短期和长期来看待 OpenStack 基础设施扩展,我们必须考虑 Glance 应该使用哪种后端存储。OpenStack 社区已经开发了最常用的存储后端,无论是在适当的 OpenStack 支持的存储服务中,如 Swift 对象存储Cinder 块存储,还是基于 RADOS 块设备RBD)的第三方扩展,如 Ceph 存储、VMware 存储,甚至是 AWS 简单存储服务S3)存储。

这种多样化的存储后端选项可能增加架构选择的矛盾,但它提出了一个问题:我们从业务和容量角度应该解决哪些需求。例如,Glance 配置允许在相同的配置布局中启用多个存储后端,可以定制指示映像服务使用现有的块存储池来直接附加图像,减少从头开始下载的等待时间。如果 Ceph 基础设施庞大,并且拥有数十个对象存储节点,可以通过将一个 Ceph 存储池专用于生产图像,利用 Glance 与 Ceph 后端之间稳定的驱动程序集成所提供的现有资源来提高其使用效率。

重要提示

在选择任何类型的后端之前,理解您的需求非常重要,因为并非所有后端都支持相同的功能。例如,在 Antelope 版本中,OpenStack Glance 团队在块存储后端 Cinder 中加入了一个新特性——允许扩展运行中的附加卷。Ceph 存储扩展将在 第五章 中详细讨论, OpenStack 存储 – 块存储、对象存储和 文件共享

相反,更多有趣的使用案例将利用 Swift 作为 Glance 快照和模板的存储后端。这可以被认为是一种安全的内部备份场景。进一步说,增加您的 容错能力FT)领域可以跨越公共云服务,比如 AWS S3 后端。

Glance 服务中最令人印象深刻的进展之一是支持的图像格式列表的扩展。Antelope 版本支持至少 11 种格式,包括 RAW、QCOW2、VDI、VHD、ISO、OVA、PLOOP 和 Docker,另外还增加了处理亚马逊公共云兼容性的格式,分别是 AKI、AMI 和 ARI:

图 1.1 – Glance 支持的后端

图 1.1 – Glance 支持的后端

Swift 一直是大型部署中存储 Glance 图像的最优选项之一,下一节将重点介绍这一点。

Swift – 对象存储服务

与 Nova 一起,Swift 在 2010 年推出了首个 OpenStack 版本 Austin。对象存储为解决多个存储挑战的企业提供了巨大价值,区别于传统的持久化存储设计。Swift 本身是一个革命性的服务,尤其在云技术刚刚起步的时期。根据对象存储模型的特点,对象以平面层级结构存储。在特定的 OpenStack 部署中,Swift 的主要用途是进行归档和备份。许多与 OpenStack 生态系统中存储相关的服务,都与 Swift 存储后端兼容,无论是直接存储、备份目的,还是两者兼有。

正如我们将在第五章OpenStack 存储——块、对象和文件共享》中展示的那样,以下是对象存储常见规格的简要回顾:

  • 通过设计避免单点故障SPOF

  • 提供用于常见对象管理的 HTTP REST API

  • 高度可扩展,适用于要求提升性能的工作负载

  • 设计时考虑最终一致性

  • 通过设计实现高可用性,并且可以通过廉价硬件轻松实现水平扩展

现在,让我们来看看下一个存储选项:Cinder 服务。

Cinder —— 块存储服务

OpenStack 生态系统中的另一项存储服务,并被视为核心服务的是名为Cinder的块存储服务。Cinder 被开发用于保持实例卷(虚拟磁盘)的独立生命周期操作。Cinder API 提供了完整的不同卷和快照操作列表,包括创建、删除、附加、分离、扩展、克隆、从卷创建镜像、从镜像创建卷以及从快照创建卷。随着最近的 OpenStack 版本发布,更多的操作功能已经被开发出来,以支持备份、恢复和卷迁移。

Manila —— 共享文件系统服务

文件共享解决方案已经成为企业日益增长的存储选择。在过去十年中,IT 基础设施中无论是本地部署还是云环境,对一个可以提供便捷访问和简单管理的协作中央存储大脑的需求不断增加。自Liberty版本以来,OpenStack 社区抓住了这一机会,推出了Manila 分布式和共享文件系统解决方案。Manila 与 Cinder 有着相同的逻辑工作流,但由于功能有限,它没有被纳入核心 OpenStack 项目。从Kilo版本到最新版本,Manila 已经证明自己是 OpenStack 基础设施中的一个稳定组件,使企业能够访问自助文件共享服务,满足不同资源和客户端的需求。

再次提到,多个存储供应商通过开发更多的驱动程序来支持其存储后端硬件,从而持续推动 Manila 服务的发展。沿用 Cinder 的做法,我们可能会发现 Manila 支持的完整文件共享驱动程序列表,包括 CephFS、LVM、Hadoop HDFS、EMC、IBM 等。完整的支持驱动程序列表可以在 Manila 的 OpenStack 网页上找到:docs.openstack.org/manila/latest/configuration/shared-file-systems/drivers.html。在 Manila 服务的最新版本中,还包括了一些更有趣的更新,如安全性、备份共享集成以及更高的可访问性,这些将在第五章 OpenStack 存储——块存储、对象存储和文件共享中详细讨论。

Neutron——网络服务

如果我们考虑到nova-network仍在使用中,前面的引用可能会有争议!另一方面,自Grizzly版本以来,Neutron项目已经成为 OpenStack 生态系统中的一个更重要的网络即服务NaaS)支柱。这是有道理的,因为社区采取了提供独立网络服务而非嵌入式服务的方法(Nova 计算服务就是一个例子)。从传统的nova-network到 Neutron 的过渡,对于那些希望从旧时代迁移到由 Neutron 主导的新网络时代的公司来说,过程更为艰难。尽管我们将在本书的后续部分继续关注 Neutron,第六章 OpenStack 网络——连接性与托管服务选项中将专门讨论 Neutron 的更多高级功能。

采用 Neutron 的动机非常明显,因为该项目的崛起解决了许多nova-network的局限性,并开放了新的网络能力。与仅提供基础网络功能的nova-network(主要限于与计算服务的交互)相比,Neutron 带来了几个方面和功能,可以总结如下:

  • 项目简化自助服务,用于配置端口、子网、网络和路由器对象

  • 高级网络功能可以在短时间内部署,例如防火墙、虚拟私人网络VPN)和负载均衡器

  • 对复杂网络拓扑的更多支持

  • 第三方网络解决方案集成的多种方式

  • 一个独立的服务使架构支持高可用性HA)变得更简单

  • 针对各种规模部署的高效服务

随着基于 软件定义网络 (SDN) 解决方案的硬件和软件的出现,OpenStack Neutron 团队率先在 SDN 部分提供更多支持,从而开发了 Neutron 驱动程序,以集成一些著名的 SDN 实现,如 OpenContrail 和 VMware NSX。

自 2013 年以来,在每个 OpenStack 版本中,Neutron 项目一直被认为是提交次数和功能开发最多的服务之一。第六章OpenStack 网络 – 连接性和托管服务选项,将深入探讨更多 Neutron 功能,并将这些功能与最新 OpenStack 版本中的 SDN 连接起来。

Ceilometer – 遥测服务

遥测服务是在 OpenStack 生态系统中引入的,出现在 Havana 版本中。代号为 Ceilometer 的遥测服务带着一个明确的使命:记录、收集和监控 OpenStack 基础设施中的资源利用度度量数据。与旧版本的 OpenStack 不同,最新的 Ceilometer 版本仅包含度量数据收集功能,将报警和通知功能交给了另一个名为 Aodh 的专用项目。

Aodh – 警报服务

作为监控服务链的一部分,允许用户根据遥测事件触发自定义通知,已成为监控部署项目资源的必备功能。如 Ceilometer – 遥测服务 部分所述,报警功能已从 Ceilometer 中分离出来,Aodh 专门用于根据配置的规则和设定的阈值触发警报。

重要提示

Ceilometer 旨在将收集到的度量数据发送到其他目的地,包括一个名为 Gnocchi 的非 OpenStack 开源项目。Gnocchi 项目提出了时间序列 数据库即服务 (DBaaS) 这一术语。在这种情况下,不再需要专用的数据库接口来存储和查询度量数据。

Horizon – 仪表盘服务

拥有一个图形用户界面GUI)来操作您的 OpenStack 环境,肯定会让您的管理任务变得更加简便。令人惊讶的是,OpenStack 的首次发布并未带来图形界面支持,无法通过仪表板的几次点击来帮助管理基础设施资源。直到Essex版本,Horizon才诞生,用于支持第一个核心项目的操作,如创建对象容器、操作实例生命周期、管理镜像,以及基本的项目用户管理布局,之前这些用户被称为租户用户。随着更多服务的广泛集成,仪表板需要包含更多控制功能,这一需求逐渐显现。在最新的版本中,我们可能会注意到 Horizon 的使用体验变得更加复杂。Horizon 是基于 Django 框架构建的,支持大多数 OpenStack API,核心服务的大部分资源都可以通过 Horizon 进行操作。另一方面,像自定义网络配置这样的高级操作只能通过 OpenStack CLI 来执行。此外,不要指望 Horizon 会自动包含核心服务之外的其他服务。这并不是限制,而是出于模块化设计的考虑,安装新服务需要增加与之关联的 Horizon 模块,并将其定义为面板。对于运行小型环境的云管理而言,Horizon 配合 CLI 的良好参考足以胜任。谈到更大规模的基础设施,拥有数十个项目和数百个资源的管理,使用 Horizon 可能并不是理想的选择。敏捷思维在大规模环境下要求更多的自动化和脚本支持。在第二章正确启动 OpenStack 设置 - DevSecOps 方法中,我们将详细讨论 OpenStack 设置的自动化,以及如何使用相同的方法管理项目资源中的资源。

非 OpenStack 服务

作为 OpenStack 控制平面的一部分,我们可能会发现,与任何软件架构一样,所有 OpenStack 服务依赖的其他核心组件:高级消息队列协议AMQP)和数据库服务。

传递消息 – AMQP

AMQP,消息队列服务,是构建 OpenStack 生态系统模块化架构设计的另一种重要组件。

对于每个请求命中特定的 OpenStack 服务 API,消息队列服务器将确保在所有参与的组件(进程)之间异步地传递消息,以完成该请求。如果你偏向于使用某一款开源 AMQP 软件,那么在 OpenStack 部署过程中,你可以在设置时简单地指定它进行运行,并与不同的组件进行通信。RabbitMQ、Qpid 和 ZeroMQ 是支持的消息队列解决方案,其中 RabbitMQ 是最常用的。虽然成为 AMQP 操作的专家并不是成功运营 OpenStack 的必备条件,但在处理 OpenStack 中的消息队列时,有几个关键点是需要考虑的。我们将在后续章节中从架构角度了解 OpenStack 服务如何依赖于消息队列,并强调这些服务运行在尽可能高的可用性上的重要性。另一个方面是,对于消息概念的基本了解,对于排查问题将是非常有帮助的。第三章OpenStack 控制平面 – 共享服务,以及 第七章运行高可用云 – 满足 SLA,将依次介绍 AMQP 在 OpenStack 中的内部工作流程,并阐述如何最大化其可用性。

存储状态 – 数据库

另一个基础的 OpenStack 控制平面服务是数据库。与 AMQP 服务类似,每个 OpenStack 服务都需要数据库连接来存储其不同的状态。OpenStack 生态系统中的数据库定义了持久存储,所有服务在每个请求时都可以查询和更新它。数据库这一话题从架构角度来看一直是一个热点话题,主要是由于安全问题。如前所述,在Nova – 计算服务部分,由于学习曲线的影响,存在减少对数据库或在不同主机上运行的服务的不安全访问的趋势,这些服务可能会带来安全风险。数据库敏感性话题的另一面,类似于 AMQP 服务,是可用性困境。除了故障的风险,OpenStack 架构师和管理员还需要在数据库开始增长时重新审视传统数据库异常问题:性能。第三章OpenStack 控制平面 – 共享服务,以及 第七章运行高可用云 – 满足 SLA,将介绍如何确保大型 OpenStack 部署中数据库的健康启动。第九章基准测试基础设施 – 评估资源容量和优化,将揭示数据库基准测试例行程序背后的动机,以提升性能状态。

其他服务

最新的 OpenStack 发布版展示了 OpenStack 对用户的良好意图,不仅提供了非常稳定的核心服务,还增加了其他服务,帮助用户部署和运营 OpenStack 私有云基础设施。与较旧的版本相比,一些孵化项目处于间歇模式,决定是否采用其中一些项目来集成到现有部署中会存在不安全因素。来自不同项目倡议的不同见解在最新的 OpenStack 发布版中塑造了更自信的软件,这些软件已准备好在您的云环境中支持更多功能和服务。一些额外的稳定服务按不同 OpenStack 周期发布的集成顺序列出在下表中:

服务 发布 描述
Heat Havana 基于 OpenStack 提供的 IaaS 扩展的编排 PaaS。Heat 将云资源抽象成代码——也称为领域特定语言DSL)。当云操作员利用代码模板的力量来自动化任务、减少人为错误并提高资源管理的敏捷性时,Heat 便发挥作用。Heat 使用Heat 编排模板HOTs),支持 YAML 或 JSON 格式,允许用户通过代码定义运行工作负载所需的整个基础设施。
Trove Icehouse DBaaS 允许用户自动化提供关系型和非关系型可扩展数据库,且数据库任务(如打补丁、维护和备份)通过提供的自动化进行最小化管理。
Sahara Juno(在 Icehouse 中孵化) 弹性数据处理即服务EDPaaS)提供了一种在 OpenStack 上编排结构化和非结构化数据处理与分析软件及基础设施的方式,如 Hadoop 和 Spark 集群。
Ironic Kilo 裸金属即服务BMaaS)允许用户直接在物理机上提供基础设施,因此不涉及虚拟化层。
Murano Kilo 应用即服务AaaS)使开发人员能够加速应用程序的部署,并将其发布到一个可以浏览并准备以自动化方式部署的应用程序目录中。
Designate Liberty DNS 即服务DNSaaS)处理域名服务DNS)条目,如 DNS 记录和区域。
Barbican Liberty 秘密管理即服务SMaaS)旨在集中存储不同类型的秘密,如密码、密钥和证书,以便其他 OpenStack 服务能够以安全的方式使用。
Zaqar Liberty 消息即服务MSaaS)允许用户提供和管理多租户消息和通知队列。
Magnum Liberty 容器即服务CaaS)通过支持的容器编排引擎COE)如 Docker Swarm、Kubernetes 和 Mesos 来编排一组容器。
Octavia Liberty 作为服务的负载均衡器LBaaS)提供了负载均衡功能。Octavia 可被视为一个企业级负载均衡解决方案。与 Neutron LBaaS 驱动程序相比,这项服务已经变得更加易于使用,成为了一个吸引人的功能。

表 1.2 – 其他 OpenStack 服务

在回顾了核心和孵化中的 OpenStack 服务后,我们现在可以逐一浏览不同的功能需求,这些需求将构建出私有云可以提供的服务。

构建动机

在构建未来的 OpenStack 环境之前,必须确保商业目标与 OpenStack 解决方案的结果相一致。正如我们在前面章节中简要提到的,随着 OpenStack 词汇表的最新更新,你可能会感到新开发的服务和功能令人应接不暇。显然,OpenStack 的新形象比以往更加稳健,拥有众多服务即一切XaaS)的机会。众多选择可能会阻碍架构师和运维人员,如果从设计草图的第一天起,商业目标没有明确,便无法启动一个合适的 OpenStack 基础设施建设。像 AWS、Azure 或 GCP 等现有的大型公有云提供商一样,OpenStack 部署应被视为一种长期投资。期望在运营和成本节约方面的效果,只能在后期阶段显现出来。如果从一开始就正确使用 OpenStack,具备战略眼光至关重要。成百上千的企业已转向在其环境中使用 OpenStack,但并非所有企业都取得了成功,许多企业很快就放弃了它。因此,理解你的业务将适用于哪个使用案例,能够确保 OpenStack 之旅的安全起步。

自 2010 年以来,OpenStack 的使用呈现出多样化的面貌,企业们投资于 OpenStack 生态系统,跟随其里程碑的演进并采纳它。14 年后,我们可以看到大量的部署案例,OpenStack 以其辉煌的成功历史闪耀着光辉。接下来的章节将广泛列出一些常见的实施使用案例。

应用开发加速器

现代软件开发生命周期SDLC)通过增强发布阶段并自动化整个链条,从简单的代码提交到不同类型的测试,朝着更加成熟的方向发展。尽管持续集成/持续交付CI/CD)方法和工具在云时代兴起之前就出现了,但交付一个经过充分测试的软件产品面临着一个新挑战:资源限制。尽管限制这一措辞并不完全描述这个挑战,但从开发者的角度来看,这意味着没有可用的资源来继续或执行特定的单元、冒烟或集成测试。如果企业不允许产品在没有为测试提供与生产环境完全相同的环境的情况下上线,那么预生产环境在所有阶段的验证将更加具有挑战性。资源仪表化和虚拟化解决了这一问题,但仅仅是部分解决。由于缺乏自动化和操作引擎,整个链条仍然无法节省成本并减少市场时间TTM)。这就是 OpenStack 为几百家企业所做的工作:通过在多租户的 OpenStack 环境中运行他们的 CI/CD 流水线,加速产品发布。

云应用启用器

如果你计划提供大多数开发者梦寐以求的功能(从零开始开发!),那么你来对地方了。无论开发的应用程序是一个网页宠物商店、在线预订助手,还是航班预订引擎,都可以通过例如 Heat 这样的工具,在合适的基础设施中快速、干净地封装应用程序。由于应用程序将在 HOT 文件中定义为代码,你无需担心应用程序配置的一致性以及如果模板中声明了自动扩展的话,它的可扩展性问题。由于 OpenStack 服务将处理所有的自动化开销,应用程序所有者可以专注于应用程序业务的下一个层级,寻找更多改进的空间,而不是浪费精力在资源管理和运营开销上。

使用 OpenStack 的另一个特点,特别是在Kilo版本的调查中,是云就绪应用的趋势。OpenStack 通过多种方式加速应用程序的发布过程。随着容器技术的采用增加,OpenStack 已经包括了容器服务,以通过 OpenStack Magnum 服务支持一些著名的容器编排引擎,如 Docker Swarm 和 Kubernetes。在Kilo版本的用户调查中,76%的用户表示对 OpenStack 和容器化结合的兴趣。一个广为人知的 OpenStack 大规模环境示例是 CERN。基于 OpenStack,CERN 运行着超过 300,000 个核心,其中很大一部分是 Kubernetes 工作负载(超过 500 个集群),这些都在 Magnum 空间内运行。

重要提示

有关 OpenStack 调查的更多详细信息,请参见www.openstack.org/user-survey/2022-user-survey-report

Murano 应用目录服务是另一个 OpenStack 服务,它可以快速基于容器发布应用。

HPC 支持者

在 OpenStack 的背景下混合使用HPC术语可能会让人感到困惑。最终,OpenStack 并不直接访问硬件以配置计算能力和提升硬件性能。另一方面,它使得你可以设计商品化硬件,以便在遇到更多计算、存储和网络需求时实现横向扩展。在 HPC 的背景下,主要关注的是增强底层硬件容量,而云计算将确保多租户能够以最优化的方式访问资源。

令人惊讶的是,在 OpenStack 的早期阶段,当时只有 Nova 和 Swift 存在时,美国国家航空航天局NASA)和 Rackspace 是首批启动 HPC 运行的 OpenStack 生产环境的发起者。此后,更多的研究机构开始采用 OpenStack 生态系统,为研究人员和科学家大规模提供计算和存储,但同样,选择硬件布局并进行提前规划仍然是必需的,才能真正感受到 OpenStack 通过虚拟化基础设施、裸金属或两者结合所带来的附加价值。OpenStack 支持 HPC 环境部署的所有编排方法。

网络功能虚拟化协调者

在电信行业,只有少数企业在早期意识到虚拟化网络服务的机会。按照服务器虚拟化经验的相同步骤,企业开始投资于将其边缘网络服务运行在标准机器上的新趋势,并以虚拟机的形式向消费者提供路由器、代理、负载均衡器和防火墙等功能。这成为了快速响应网络变化和功能需求的重要资产。网络功能虚拟化NFV)在很大程度上依赖于可以在商品化硬件和虚拟环境中运行的计算能力,而在传统方式中,每个网络功能必须依赖物理设备来运行。在 OpenStack 的背景下,NFV 只需要一个计算服务来暴露不同的功能。根据Kilo 用户调查,超过 12%的组织在网络和电信行业中使用 OpenStack。随着电信行业采用 OpenStack 来实现这一目的,Nova 将成为你的助手,但它会从计算资源和部署位置的战略角度来帮助实现这一目标。

大数据促进者

大众汽车(Volkswagen AG)和宝马(BMW)分享了他们使用 OpenStack 进行大数据和分析的反馈,结果是生态系统的宝贵支持,协同所有不同的服务和资源来完成一些大数据分析任务。在 Juno 版本发布之前以及 Sahara – EDPaaS – 项目的发布之前,大数据资源可以通过 HOTs 快速编排来配置一个集群。Sahara 的发布旨在简化以更细粒度、更即插即用的方式部署此类资源,考虑到数据处理框架的类型、版本、集群的规模、所需拓扑等。通过使用 OpenStack 服务的一些高级功能(例如存储和网络),思考大数据的范围可以更广阔。公司们继续表现出对通过利用 OpenStack 大数据服务自动化他们 提取-转换-加载ETL)管道的兴趣。如果你认为你的业务依赖于某个 Hadoop 提供商,例如,确保性能是底层硬件的关键规格,Nova 会使用这些硬件。

私有云服务提供商

私有云环境可能是你第一次阅读旧版本 OpenStack 文档时理解其定义的主要动机。作为私有云将限制在你组织的边界内提供给最终用户的服务,或者从技术角度讲,在防火墙 后面

私有云 这个术语可能涵盖了之前提到的所有使用案例。唯一的区别是,之前的 OpenStack 实现可以保持在你的边界内隔离,或者根据需求提供服务。

公有云服务提供商

上市!为什么不呢?早在 2000 年代初期,亚马逊内部推出了一个私有弹性计算云,以便为开发者和用户提供基础设施敏捷性,支持运行巨大的在线电子商务网站和其他销售全球数百万商品的服务。简单队列服务SQS)作为第一个云服务发布并对外开放,随后是 S3,紧接着是 EC2 服务。这个想法最初源于名为 S3 的对象存储和 EC2 服务。最初,NASA 和 Rackspace 启动并大力贡献了软件代码,创建了一个最初用于弹性计算和对象存储能力的私有云软件。这就是 Nova 和 Swift 诞生的背景。第一次发布吸引了寻求创新的先行公司,这些公司开始为新的开源项目做出贡献,并很快在 XaaS 产品的市场模型上积累了更多经验。Rackspace 最初推出了其公共云版本,提供计算和对象存储服务。随后,许多其他公司采用了由 OpenStack 支持的公共云,如 Open Telekom Cloud、Cleura、VEXXHOST 等。最近,感觉全世界都在使用 OpenStack,伴随着#RunOnOpenStack的标签。随着 OpenStack 在全球大品牌中的广泛应用,OpenStack 社区提出了OpenStack 公共云护照的概念。其背后的理念是,通过在全球不同地区和位置提供 OpenStack 服务,作为一个主要的公共云提供商。该计划确保了不同 OpenStack 公共云提供商之间的大规模合作枢纽,使用户能够在全球超过 60 个可用区AZs)之间自由漫游。openstack.org网站不断更新可以通过 OpenStack 公共云市场页面筛选的公共云位置:www.openstack.org/marketpla ce/public-clouds/

拼凑碎片

无论未来的 OpenStack 部署从哪个用例开始,掌握其生态系统的艺术是进一步研究任何设计和架构选项之前至关重要的一步。OpenStack 包含超过 100 万行 Python 代码!此时不需要担心如何学习代码的工作原理:更重要的是采取逆向工程的方法:理解生态系统的相互作用。仅仅理解核心服务之间的相互关系,就能为你打开设计艺术的大门。基础知识掌握得当,基础组件将为进一步的学习打开更多的门。所以,到目前为止,我们回顾了 OpenStack 每个版本中存在的核心服务,并简要扫描了孵化项目,特别是在最新的版本中。接下来,我们将选择一个常见的工作流程,展示生成虚拟机的不同步骤和部分。这个工作流程将展示不同的 OpenStack 核心服务如何交互,并涉及几乎所有组件。

重要提示

不同的资源和文档中,列出哪些服务算作核心服务可能有所不同。遥测、调度和仪表盘服务可能被视为可选服务。目前的假设是基于现实世界中的部署,从旅程开始就利用这些服务。

第一轮演示展示了不同 OpenStack 核心服务的构建模块,包括计算、镜像、身份验证、块存储、监控、调度、仪表盘和网络服务:

图 1.2 – 高级服务交互生成实例工作流程

图 1.2 – 高级服务交互生成实例工作流程

在跳入生成过程的详细展示之前,注意了解主要模块是非常重要的,正如前面的图所示。通过提供 Horizon 仪表盘或通过 CLI(同样通过 API),首先会触发身份验证过程,通过登录凭证挑战用户请求,该过程由身份服务 Keystone 处理。一旦验证通过(将为整个会话和后续请求提供身份验证令牌),请求将到达 Nova API,继续下一步。Nova 将与以下服务进行交互,这些服务被视为必需,以成功生成实例:

  • 镜像服务 Glance 查询启动实例所需的镜像。

  • 网络服务 Neutron 获取网络资源。

  • 块存储服务 Cinder 分配存储卷。

  • 调度服务 Placement 分配可用的计算提供者资源。

请注意,整个交互链通过每个组件的 API 进行传递。对于每个组件间的请求,核心数据库将被查询以进行读取和对象更新。根据实例的创建,一个新的虚拟机实例记录将在实例中创建,并在后续步骤中与其他服务进行参考。根据实例请求,Nova 还将与队列消息服务进行交互——例如,请求启动实例(对于 Nova 计算进程)。

在此工作流中,任何 API 端点、调度、影像、身份验证以及共享组件,如数据库和队列服务,都视为 OpenStack 控制平面的一部分。

重要提示

控制平面和数据平面是复杂系统架构中概念性分离的方式。术语将在 第三章 中更详细地定义,OpenStack 控制平面 – 共享服务

现在,让我们放大并以更细致的视角来探讨工作流,以便构建完整的生成实例的图景。如本章前部分所示,每个 OpenStack 服务包括多个子组件,它们共同工作以服务特定的请求。显然,每个服务中都存在 API 部分。记住,它是 OpenStack 生态系统中每个模块的门户。每个暴露的 API 服务(提供基于 HTTP 的 RESTful API)通过队列消息服务总线与其他组件以及随后与子组件进行通信,如下方工作流图所示:

图 1.3 – 低级服务交互生成实例工作流

图 1.3 – 低级服务交互生成实例工作流

从身份服务开始,Keystone 应该知道架构中可用的服务,以授权任何进一步的交互。Keystone 持有一个服务目录,包含所有不同服务的 API 端点。

前面的图表通过包括不同的组件及其各自的子组件来说明每一步:

  1. 通过使用 Horizon 或 CLI 发起一个 REST API 调用,达到身份服务 Keystone 端点。

  2. Keystone 挑战请求,获取用户凭证(用户名和密码的形式),并通过其 API 验证身份。

  3. 验证后的身份认证会生成一个身份认证令牌(auth 令牌)并返回给请求的用户。该 auth 令牌将被缓存,以供特定用户在后续的 API REST 调用中使用,涉及其他服务之间的交互。

  4. 由于我们的请求是一个计算请求,接下来将达到的站点是计算服务 API,nova-api。同样,请求的形式是一个 REST API,由 Keystone 从其目录中转发。你可以将目录视为一个服务地图,在该地图上,Keystone 通过已注册的端点定位每个服务。在这种情况下,包含 auth 令牌的 REST API 将发送到计算服务端点。

  5. 计算 API,即nova-api子组件,会检查随请求一起到达计算端点的auth令牌。在这一阶段,auth令牌将通过身份服务 Keystone 进行验证。与 Keystone 的这一次二次交互的目的是告知计算 API 请求中的用户拥有哪些权限和角色,以及auth令牌将在多长时间内有效,直到生成新的令牌(此过程被标记为令牌过期时间)。

  6. 一旦验证通过,nova-api将进行第一次数据库交互,创建一个新的虚拟机对象,指定请求中的不同参数。请记住,每个服务都会有自己独立的逻辑数据库来更新不同资源的状态。在当前场景中,Nova 服务拥有自己的数据库模式,用于不同状态更新以及读写操作。

  7. 现在,我们进入 Nova 服务的另一个子组件nova-scheduler的下一次交互,用于指定哪个计算节点将承载新的实例。nova-api子组件将通过通信枢纽——消息队列服务,向调度器发出此类请求。这项操作通过远程过程调用RPC)进行处理,标记为rpc.call,该请求会发布到消息队列中并保持在那里,直到nova-scheduler将其取出。

  8. nova-scheduler子组件负责获取最合适的计算节点来承载新的实例。在我们突出的基础核心设计中,Placement 服务将参与选择最佳计算节点的过程。

  9. nova-scheduler子组件通过查询其计算资源提供者来联系placement-api。请注意,Placement 服务仍被视为一个新服务,作为其他服务的扩展,用于跟踪它们的资源,如计算、IP 池和存储,表现为资源提供者。自Stein版本发布以来,它已从 Nova 生态系统中提取并独立运行。在我们的工作流中,我们可以将 Placement 用作最终选择之前的预过滤阶段。Placement 服务还在 Keystone 目录中公开了自己的端点。因此,它将通过身份服务验证auth令牌,更新令牌头并将其返回给placement-api进程。

  10. 主机的选择是通过 Placement 服务来确定的,该服务查询其自身的库存数据库,在第一次迭代时返回一组计算节点及其相关的特性。

  11. 通过在返回结果中应用placement-api组件的过滤和加权参数,nova-scheduler进程将选出合适的计算节点,并在第二次迭代时通过placement-api获取资源,以供实例使用。

  12. placement-api 组件调整其数据库中的状态记录,nova-scheduler 更新其数据库中虚拟机对象的状态,并添加计算节点 ID 及其主机名,然后以 rpc.cast 形式将消息提交到消息中枢。此消息将被 nova-compute 获取,用于在指定的虚拟化主机 ID 上启动实例。

  13. 为了与下一个子组件 nova-conductor 进行通信,nova-compute 将在消息队列中发布下一个 rpc.call 调用,以启动实例的启动过程,并包括准备细节,如 CPU、磁盘和内存规格。请注意,nova-compute 可以在不同的计算节点中的不同进程实例中运行。只有一个特定的 nova-compute 实例会根据 第 8 步 选择的计算节点发布 rpc.callnova-conductor

  14. 如果我们回顾 nova-conductor 在 Nova 服务架构中的作用,其主要目的是充当 nova-compute 进程和数据库之间的 网关角色,以最小化数据库暴露,从而减少其攻击范围。由于我们的目标是大规模部署 OpenStack,nova-compute 组件将与控制节点(托管主要控制平面服务)分离,并将专门部署在不同的物理虚拟化节点上。如果某个计算节点被攻陷,通过逻辑和物理的分离,当进程与数据库交互时,会使得将安全问题传播到数据库变得更加困难。nova-conductor 组件将直接与 Nova 数据库进行交互,读取实例详细信息,例如计算节点 ID、请求的规格、内存、CPU 和磁盘需求。状态将通过 RPC 发布调用返回到消息队列服务。

  15. nova-compute 组件获取已发布的消息,并随后通过向镜像服务 Glance 发送 RESTful API 请求来访问下一个服务组件:glance-api 进程。该请求包含一个 GET API 请求,用于获取请求的镜像 ID 信息。

  16. Glance 将通过其注册的镜像 URL 提供请求的镜像 ID。但首先,由于我们正在访问生态系统中的另一个服务,Glance 将联系身份服务 Keystone,重新验证 auth 令牌。如果令牌会话尚未过期,Keystone 将验证令牌,并且像 第 5 步 中的 Nova 一样,身份服务将在更新令牌头并将其返回给镜像 API 之前检查用户角色和权限。

  17. Glance 组件被认为比 Nova 简单,因为在此步骤中没有与消息队列的交互。glance-api 组件仅检查 Glance 数据库(运行其专用的数据库模式),获取请求的镜像 ID 的元数据,并以镜像 URL 格式反馈给 nova-compute

  18. nova-compute 组件访问镜像存储,并通过返回的 URL 开始加载提供的镜像。

  19. 接下来,我们需要与之交互的服务是网络服务。nova-compute 组件通过 neutron-server 向 Neutron 服务发送一个 RESTful API 请求。如前所述,Neutron(根据其架构的命名惯例)并不涉及带有 api 后缀的明确子组件名称。neutron-server 子组件是处理所有 API 请求的 API 网关。在执行相同的身份验证周期并假设令牌尚未过期的情况下,neutron-server 会将 API 请求转发给 Keystone,经过验证后更新令牌头部的不同角色和权限,并将其返回给 neutron-server 进程。

  20. neutron-server 组件检查网络项的状态,并根据网络参数的 API 调用分别创建请求的资源。请注意,Neutron 服务会根据请求的不同类型有所不同,因此会根据请求的复杂性暴露不同的工作流。我们将在第六章《OpenStack 网络 – 连接性与管理服务选项》中讨论涉及其他网络控制器、代理和插件的其他工作流场景,例如 Open vSwitch (OVS)。例如,一旦为实例创建了端口,neutron-server 会在消息队列中发布一个 RPC 调用,联系 动态主机配置协议 (DHCP) 代理。neutron-dhcp-agent 进程将调用其相关的 DHCP 驱动程序,通过 dnsmasq 进程重新加载主机的文件条目。一旦实例启动,dnsmasq 就准备好接收实例请求并发送 DHCP 提供以进行最终的实例网络配置。此场景还假定已创建网络和子网,实例将在其中连接,这一点在实例创建请求中已指定。

  21. 一旦获取到新实例请求的网络参数,nova-compute 会访问数据库并更新虚拟机对象的网络状态记录。

  22. 完成实例创建的最后一个服务是与块存储服务进行交互。与之前的服务类似,nova-compute 向 Cinder API 的 cinder-api 子组件发送 RESTful API 请求。

  23. 接着,Cinder API 进程会进入身份服务,Keystone 验证 auth 令牌。如果令牌未过期,Keystone 会返回经验证后的更新令牌头,并附带请求者的角色和权限。

  24. 与 Nova 和 Neutron 一样,Cinder 还拥有更多的子组件,它们会在最终将请求提交给 nova-compute 进程之前,再执行一些额外的步骤。Cinder 通过向消息队列服务发布 RPC 调用,也涉及到自己的调度程序。

  25. cinder-scheduler 子组件会接收请求,并根据请求的卷规格(卷大小和类型)为新卷候选项列出可用资源。请注意,Cinder 还提供了另一个进程 cinder-volume,该进程会在特定存储提供商内启动新的读写请求时与 cinder-scheduler 进行交互。在这种情况下,cinder-volume 会与后端驱动程序方法接口,生成一个候选列表,并将其发布到消息队列,稍后由 cinder-scheduler 子组件取回。

  26. cinder-scheduler 子组件会更新 Cinder 数据库中与其关联的返回元数据的卷 ID 状态。

  27. cinder-api 组件会从 cinder-volume 获取发布的消息,并通过 RESTful 调用响应 nova-compute

  28. nova-compute 组件接收到 API 请求中的已创建卷的元数据。默认情况下,如果未配置其他特定的虚拟化驱动程序,Nova 将执行 libvirt 守护进程,并继续在指定的计算节点上创建实例。

  29. 在实例创建工作流的最后阶段,创建的卷应由 cinder-volume 进程映射。这时,虚拟化驱动程序(在此情况下是 libvirt)会通过触发 mount 操作将卷提供给实例。执行的方式取决于存储提供商和协议,但常见的做法是将卷路径传递给虚拟机监控程序(hypervisor),它会将其挂载为虚拟块设备。

  30. 我们初步工作流的最后一步是将实例指标传输到 Ceilometer 服务。监控已创建实例的状态至关重要。Ceilometer 提供了两种收集实例数据指标的方式:轮询代理通知代理。收集的指标将通过 Ceilometer 流水线转换以进行进一步操作,并准备发布这些数据。最新的版本提供了多种存储发布数据的选择,可以存储在 Ceilometer 数据库中,也可以通过 Ceilometer API、Gnocchi,甚至是简单的文件存储访问。

在为您的私有云草拟首个设计布局之前,深入了解不同核心组件之间的通信至关重要,这将在下一节详细说明。

架构云计算

确定 OpenStack 环境的初始使用案例是云计算旅程成功启动的关键之一。随着功能的广泛增加,尤其是在最新发布中,云管理平台比以往任何时候都更加成熟,但这也可能让人感到压倒。偏离 OpenStack 实现的目的会增加管理复杂性,并可能在缺乏清晰愿景的情况下使业务面临风险。为此,将设计分为不同的迭代将有助于避免被选择的悖论所困扰,并释放出清晰的短期愿景,朝着更长远的目标迈进。作为第一次设计迭代,我们将简单地识别我们的概念性 OpenStack 模型,然后是逻辑架构。一旦草拟完成,我们将进行实际的实施,并汇总一些数据,以反映我们第一次部署的硬件图景。

草拟概念设计

根据最新的启动实例工作流程,我们已经确定了在第一次 OpenStack 实现中应该包含的核心服务。自然地,任何后续扩展我们基础设置的服务,如 PaaS 服务,都将依赖于当前正在建设的、主要构建我们 IaaS 层的服务。在接下来的设计阶段,我们将考虑一个通用的 OpenStack 使用案例,适用于作为私有云的内部使用,支持组织弹性的 IaaS 资源,促进云应用开发,支持数据分析,并帮助处理公共托管工作负载。除了核心服务外,其他成熟的服务也将被纳入本次设计迭代,如下表所示:

云服务 服务角色
计算 – Nova 管理虚拟机生命周期 UI 启用
镜像 – Glance 管理虚拟机镜像文件 UI 启用
对象存储 – Swift 管理持久化存储的对象 UI 启用
块存储 – Cinder 管理虚拟机卷的持久存储 UI 启用
网络 – Neutron 管理 L2 和 L3 网络资源 UI 启用
数据度量 – Ceilometer 收集资源数据度量以供监控 UI 启用
文件共享 – Manila 管理可扩展文件共享系统 UI 启用
身份验证 – Keystone 身份认证与授权
仪表板 – Horizon GUI
调度 – Placement 资源提供者及其特征的预过滤

表 1.3 – 初始 OpenStack 服务

将这些服务总结成一个概念图,将引导我们下一次逻辑设计迭代,并缩小服务在 OpenStack 实现中不同集群角色之间的分布:

图 1.4 – OpenStack 服务交互工作流程

图 1.4 – OpenStack 服务交互工作流程

上述图示展示了我们第一个 OpenStack 架构草图的高层次呈现,包含多个服务,以托管为最终用户提供各种工作负载。我们可以在下一节中通过开发逻辑布局继续进行设计。

草拟逻辑设计

逻辑设计的迭代是一个至关重要的步骤,需要更加关注。在设计的每一层级和每个服务中都会提出更多的头脑风暴点,以制定一个更有信心能够实施的初步草稿。另一个关键考虑是为控制平面和数据平面运行我们的服务时,最小化 HA 设置。这可以通过在后续的迭代中集群控制节点和计算节点来实现。在进行云路线图规划时,必须考虑到增长方面。当你的业务需求被明确后,第一个逻辑设计应与首次探索的需求相匹配。即使是最小化安装的 OpenStack,也能帮助你熟悉其基本的生态系统组件。另一方面,第一个部署时一个重要的考虑因素是考虑增长。正如前面提到的,OpenStack 是以模块化软件架构开发的;在逻辑设计中体现相同的思路,然后在物理设计中遵循这一方法,绝对会让你的云架构大放异彩。请参考以下指南开始:

  • 为 OpenStack 系统在控制平面和数据平面中定义角色

  • 从最小节点数和足够的硬件开始,隔离角色

  • 提前考虑组件服务失败的可能性

  • 使用云运维团队最熟悉的软件,如消息排队和数据库常见服务

在第一次逻辑设计迭代过程中,我们将采取增量方法,首先从以下角色开始:

  • 一对控制节点运行控制平面,包括数据库和消息排队。

  • 一台计算节点运行基于内核虚拟机KVM)的虚拟化层。

  • 将选择使用 MariaDB 引擎的 MySQL 和 RabbitMQ 作为数据库和消息队列服务。大多数 OpenStack 的文档化实现几乎把 MySQL 和 RabbitMQ 当做“宗教”一样使用。

  • HAProxy 和 Pacemaker 将在每个控制节点上运行,用于 HA、负载均衡和集群。数据库 HA 将通过 Galera 多主复制实现。RabbitMQ 实例将以其原生的集群模式运行,基于跨两个云控制主机的队列镜像。

重要说明

第一个逻辑设计不应过于复杂,因为它还不是准备投入生产的最终草稿。第七章高可用云架构 – 满足 SLA 要求,专门详细介绍了未来实施的控制平面和数据平面每一层的内容。

第一个逻辑设计提案可以通过使用先前列出的软件工具以及云控制器和计算角色来起草,如下所示:

图 1.5 – OpenStack 组件部署的高级逻辑设计

图 1.5 – OpenStack 组件部署的高级逻辑设计

一旦完成了不同组件和角色的逻辑设置草案,我们将需要确定 OpenStack 节点的连接方式。

连接点

在逻辑设计阶段的另一个重要方面是在每个 OpenStack 实体的不同角色之间提供一致的网络布局。在 OpenStack 生态系统中连接不同部分的方式多种多样;以下布局演示了一种网络分割方法:

图 1.6 – OpenStack 节点的网络分割

图 1.6 – OpenStack 节点的网络分割

通过网络分割不同类型的网络,将增加安全访问。这种折衷是额外的复杂性,但安全性放在首位。对于这种选择的另一个观点也是性能问题,因为为每种类型的流量专用一个单独的段将显著节省带宽。

前述图表说明了四种网络类型,使用以下约定标记:

  • 外部网络 :连接到外部世界。OpenStack 的 API 可以从公共以及全球组织网络内的私有骨干部分中访问。外部网络将提供路由 IP 地址。这种类型的网络将作为数据平面的一部分,因为它将公开或指示基础设施内实例的流量。通过在此级别前端化网络以负载均衡设备或设备来保持与安全配置相关是至关重要的。

  • 管理网络 :作为控制平面的一部分,这提供了在 OpenStack 环境中所有不同节点之间的互连性。诸如数据库和排队消息服务将被插入到此网络中,以供计算节点访问。管理网络不向外部世界公开任何内容,应视为私有或内部网络(您可能会在其他来源中找到API 网络的命名约定)。

  • 租户网络 :由于用户将需要其虚拟网络,租户网络(在其他来源中称为客户覆盖网络)将专门处理实例流量。这种类型的网络可以附加到网络节点中的 SDN 能力中。第六章OpenStack 网络 – 连接和托管服务选项,将更详细地介绍虚拟覆盖网络的范围。租户网络可以视为数据平面的一部分。

  • 存储网络 :作为数据平面的一部分,存储网络将连接计算和存储集群节点。

重要提示

实例可以使用直接的物理网络,而不是通过 SDN 由 Neutron 提供的虚拟网络,后者会分配浮动 IP 来访问外部世界。这种模型被称为 提供商网络,它将网络和计算连接起来。更多细节将在 第六章 中详细说明, OpenStack 网络 - 连接性与托管服务选项

之前列举不同类型的网络将有助于在长期设置中选择并预留每个主机角色所需的不同端口和网卡。尽管仍然可以将多个网络合并到同一个物理连接中,但底层基础设施的持续扩展将达到物理容量的极限,从而带来瓶颈和网络性能异常等各种问题。提前规划和准备将节省大量的时间和精力,尤其是当网络性能开始出现问题时。如果在下一个迭代中某个网络节点是专用的,例如,控制节点就不需要连接到租户和外部网络。

起草物理设计

下一部分将为我们在前面的逻辑设计中定义的参数赋值。然而,提前理解一些关键概念和实践将节省大量的精力和成本。让我们从容量规划的演示开始。

准备容量规划

容量规划出现在新基础设施项目的每个阶段,无论是在内部托管中还是用于开发简单应用程序。容量规划实践的核心是预测和预测 IT 基础设施在响应业务需求时需要多少资源。在 OpenStack 的背景下,一旦定义了业务需求,容量分析的过程就会缩小到应该存在的特定资源集合。如果你计划托管混合的通用网站托管应用和数据分析工作负载,在硬件规格和运行工作负载的技术方面需要进行一定的规划。选择硬件时,NFV 需要更多的关注,因为它可能会消耗大量性能。

为 OpenStack 案例建立容量规划可以总结如下:

  • 灵活操作:能够在出现故障或负载增加时,通过自动化响应并拉取更多的普遍计算资源。

  • 预计失败:底层资源应该随时准备好被替换,而无需在事件发生时浪费时间进行修复和重新配置。

  • 跟踪增长:在生产过程中,实际可用容量可能会变化。由于我们处于按需模型中,预期的增长不一定是线性的。定期跟踪底层基础设施的使用情况,以绘制云使用情况并更新容量路线图。

另一个被大规模基础设施管理高度认可的关键基础是采纳信息技术基础设施库ITIL)实践。通过反思将运行 OpenStack 云环境的 IT 基础设施,ITIL 方法论无疑会完善一个战略流程,以识别在 ITIL 服务设计框架下的容量管理完整周期。如果您的组织已经实施了 ITIL 实践,可以随时在云旅程中重复使用并应用它们。从云服务提供商CSP)的角度来看,采取一种战术方法来管理底层 IT 基础设施,以满足业务需求和用户需求,并全面控制财务方面,是一个必须具备的能力。

重要提示

ITIL 是一个框架,提供了一套实践和方法论,用于标准化、管理和优化在特定业务中提供的 IT 服务。ITIL 已发展为四个不同版本。所有版本都强调围绕业务服务的共同核心概念,如服务设计支柱,专注于容量管理。

映射土地

作为第一次迭代,理想的做法是深入分析一些参数,以生成一些数据来开始旅程。为了估算我们的硬件和配置,我们可以考虑采用反向方法。与其考虑第一次部署能容纳多少实例,不如从最终用户的角度来看待这个问题:哪些实例规格可以提供用于运行哪些特定工作负载? 实例规格是一组在计算服务中定义的特性模板,包括 vCPU 核心数量、RAM 容量(包括交换空间)和根磁盘(包括临时磁盘大小)。

重要提示

在 OpenStack 中,可以自定义和创建更高级的规格,以部署需要特定工作负载的实例,通过调度 Nova 服务使用一组计算节点,比如支持特定的 CPU 架构或用于高性能计算(HPC)的密集型工作负载。

一种简单的方法是将计算资源分布到一个平均规格模型中,该模型可以运行通用工作负载。作为起点,一个实例规格可能适合测试租户环境,具有几个 vCPU 和 1024 MB 的 RAM 容量。定义基线规格模型将使我们能够通过在下一次迭代中将容量大小加倍,来确定下一个规格。请记住,有无数种方法可以定义规格集,但最重要的是确定起始规格,它将帮助我们在系列中对下一个尺寸进行分类。

根据您的商业需求和工作负载类型,您将更清楚地了解在每个计划投资的计算节点中所需的硬件容量。对于每种实例类型的组合,将资源密度放入计算节点中有助于衡量是否存在任何浪费空间,以便可以在新的实例类型中使用。例如,如果一个计算节点支持 40 个中型和 10 个小型实例,并且仍然有一些空间,可以创建一个新的实例类型,将 1 个 vCPU 和 512MB 的 RAM 添加到计算节点的实例类型目录中。

以下使用案例将考虑一个商业计划,运行具有多种类型通用工作负载的实例,包括实例类型:

实例类型 vCPU 内存 (MB) 磁盘 (GB)
Tiny 1 512 10
Small 1 1024 20
Medium 2 2048 40
Large 4 4096 80

表 1.4 – 实例类型列表

第一个容量规划路线图将假设以 200 个虚拟机作为起点,并且是第一组计算节点。接下来的章节将对不同硬件规格进行估算,包括每个计算节点的 CPU、RAM、存储和网络。

CPU 估算

计算能力的正确计算将显著依赖于硬件所支持的技术和模型。因此,我们将定义一份硬件假设清单,以支持我们的使用案例,内容如下:

  • 每个物理核心的 GHz = 2.6 GHz

  • 物理核心超线程支持 = 使用系数 2

  • 每个虚拟机的 GHz(平均计算单位)= 2 GHz

  • 每个虚拟机的 GHz(最大计算单位)= 16 GHz

  • 英特尔 Xeon E5-2648L v2 核心 CPU = 10

  • 每个服务器的 CPU 插槽数 = 2

  • CPU 过度承诺比率 = 16:1

  • 超额订阅:禁用

  • 超线程:禁用

  • 操作系统开销:20%

重要说明

OpenStack 计算允许对 CPU 和 RAM 资源进行过度承诺。过度承诺的技术旨在通过利用在同一虚拟化宿主机上运行的虚拟机之间共享资源,最大化资源的使用。例如,在虚拟化宿主机中,每 1 个物理 CPU 运行 16 个 vCPU,被称为 16:1 的 CPU 过度承诺。

让我们从虚拟核心数开始:

(虚拟机数量 x 每个虚拟机的 GHz) / 每个核心的 GHz

(200 * 2) / 2.6 = 153.8 46

四舍五入后的估算结果为 154 个 vCPU 核心。

现在,我们来考虑在计算节点上运行操作系统的开销为 20%,如下所示:

154 + ((154 * 20)/100) = 184.4

四舍五入后的估算结果为 185 个 vCPU。

通过将 16:1 的过度承诺比率参数添加到计算节点中,估算实际的物理 CPU 可以按以下方式计算:

185/16 = 11.5625

四舍五入后的估算结果为 12 个 CPU 核心。

作为起点,一个具有 12 个 CPU 核心的计算节点将托管 200 个小型模型实例。

内存估算

为了与前面的 CPU 估算对齐,需要以下假设:

  • 每个实例 1024 MB 的 RAM 用于小规格实例

  • 每个虚拟机最大动态分配 8 GB 的 RAM

  • 支持 2、4、8 和 16 GB 内存条的计算节点

  • 1:1 的内存超额承诺比例

  • 操作系统开销 20%

对于 200 个小规格实例的虚拟机,RAM 估算如下:

200 * 1024 MB = 200 GB

增加 20% 操作系统开销后,我们得到以下结果:

200 + ((200 * 20)/100) = 240 GB

1:1 的超额承诺比例将决定每个计算节点所需的实际 RAM 大小:

240/1 = 240 GB

这将要求我们的计算节点配备 240 GB 的 RAM 来容纳 200 个小规格实例。

重要提示

默认 Nova 计算配置的超额承诺值为 1:1.5。需要注意的是,与 CPU 超额承诺行为不同,如果没有提前规划足够的交换内存空间,内存超额承诺可能会影响实例性能。作为良好的实践,使用 1:1.5 时,交换内存应至少配置为提供的内存的两倍。

存储估算

如同存储一样,物理计算节点应提供足够的存储容量,提供多种选择,例如通过计算节点的物理磁盘或通过附加存储设备为实例提供根磁盘。

考虑到 200 个虚拟机和每个虚拟机 20 GB 根磁盘的小规格实例,一个计算节点应该获得 200 * 40 = 800 GB 的存储。

根据操作系统对磁盘空间的需求以及缓存和交换配置的其他因素,估算大约需要 900 GB 至 1 TB 的存储空间,以为所有实例提供安全的磁盘分配(考虑交换和额外的缓存磁盘操作开销)。

另一个可以考虑的用于更多规格定制的方面是存储类型规格。这个内容在之前的规格目录表中没有提及,但作为容量管理的一部分,当业务更改工作负载的性质范围时,可以添加额外的规格类以扩展该列表,比如高性能存储和 每秒输入/输出操作IOPS)规格。存储设备有各种规格以应对特定的用例和模式;对于需要快速读写的高强度工作负载,应该考虑将固态硬盘SSD)列入硬件清单,并提供一个新定制规格的硬盘,显示 SSD 规格。

网络估算

网络容量规划分为两类:

  • 网络拓扑结构,以及切换和路由层以提供足够的 IP 地址支持基础云层

  • 在基础设施之上运行的实例和覆盖网络功能

第一个支柱要求一个一致的网络布局,能够反映哪个节点将获得私有 IP、公有 IP 或两者。显然,根据网络设计,将节点放在一起的第一步是从给定的私有 IP 池中为每个主机分配私有 IP。根据逻辑草案定义,需要访问外部世界的组件将使用公有 IP。可以通过前端设备或设备(如负载均衡器或路由器)通过 源网络地址转换SNAT)和 目标网络地址转换DNAT)机制授予这些 IP。

第二个支柱捕获了针对 undercloud 资源的网络容量估算的几个因素,主要包括以下假设:

  • 每个实例每个虚拟接口的最低带宽为 50 Mbits/sec

  • 每个实例的浮动 IP 关联

  • 每个 NFV 覆盖功能的浮动 IP 关联——虚拟路由器

  • 10% 的浮动 IP 保留供未来使用

在规划网络时,另一个需要考虑的重要方面是将要在每个计算节点中配置的网络接口。如我们在逻辑架构草案中所讨论的那样,将创建并分配几个网络到每个主机中的每个接口。此架构将涉及 L2 配置切换,通常通过 虚拟局域网VLAN)聚合。一旦基本配置就绪,运行一些基准测试工具是必要的,以收集每个交换机端口和计算主机接口上的带宽容量的几个指标。这将帮助快速获取计算主机与主物理交换机端口之间跳数的网络性能信息。由于物理带宽将在不同的虚拟网络实例接口之间共享,交换机端口和计算节点物理接口的第一个值应是可接受的。

下一个考虑因素是考虑到三条网络接口线缆连接到每个计算节点。连接到租户网络(与专用交换机端口中的 VLAN 关联)的网络接口将通过 10 GB 物理链路连接,服务 200 台虚拟机,每台虚拟机提供 50 MBits/sec 的带宽。

重要提示

L2 特定厂商的网络性能因设备而异。在设计网络分段和 VLAN 配置时,确保测量网络流量和支持的 最大传输单元MTU)大小。

物理网络故障和性能问题应该尽早发现,而不是等到被警报通知。包括完整配置、重置布线和接口在生产环境中运行时听起来并不是最聪明的方法。一个节省成本和提高性能的流行网络技术是网络绑定。绑定支持两种不同模式:主动-备份主动-主动。第一种模式将只保持一个网络接口为活动状态,而其他接口处于备份状态;第二种则涉及链路聚合概念——链路聚合控制协议LACP)——其中流量将在不同接口之间进行负载均衡。

为了避免网络性能瓶颈的意外发生,相同的方法也可以应用于物理交换机。一种常见且知名的技术是多底盘链路聚合MLAG),它可以将多个物理交换机转化为一个逻辑交换机,从而允许冗余并将最佳努力带宽暴露给连接节点的端口。

在没有考虑物理交换所能提供的能力的情况下提升网络节点性能,是无法保证优良体验的。收集各个层次的物理网络容量指标,对于避免遭遇意外性能瓶颈至关重要。

我们初步网络容量规划的第二个支柱是浮动 IP 池。由于 Neutron 将在 OpenStack 生态系统中担任我们的网络主控,我们预计网络节点将与不同的网络资源进行交互,例如实例、虚拟路由器和负载均衡器,而不涉及可能会超出我们初步估算的高级 SDN 配置。浮动 IP 是公开可路由的(公共 IP 通常是从互联网服务提供商ISP)获得的)。来自实例或网络功能资源(如路由器或负载均衡器)的浮动 IP 请求不应失败。因此,我们将按以下方式估算浮动 IP 池:

  • 每个计算节点 200 个实例:200 个浮动 IP

  • 20 个租户

  • 每个租户 10 个路由器:200 个浮动 IP

  • 每个租户 10 个负载均衡器:200 个浮动 IP

为了未来的使用增加 10%,将生成一个 660 个浮动 IP 的池。

混合局域网

之前的容量规划练习考虑了一个针对小型口味的单一计算密度原型。容量规划研究可能涉及多个分布计算密度的原型,这取决于您的战略业务需求。目标布局可以扩展,以支持更多口味,并且可以是异构或同构计算密度形式。nova-scheduler 组件可以进行配置,正如我们在前面一节中强调的那样,使用先进的调度功能,与放置服务协同工作,找到最优的计算节点。相同的 vCPU、RAM 和根磁盘的资源估算可以用于迭代下一个口味,以确定下一组计算节点。我们将在第四章中讨论响应计算请求的过滤机制,OpenStack Compute – 计算容量 和口味

如下图所示,设置未来计算节点最可预测的一种方式是为每个可用计算节点分配一个同质化的口味:

图 1.7 – 按口味和工作负载特征排列的计算节点

图 1.7 – 按口味和工作负载特征排列的计算节点

根据调度配置和放置服务中定义的特征,Nova 请求将到达合适的可用计算节点,以容纳特定的工作负载。此模型布局将根据您的业务需求中定义的工作负载类型对计算节点进行分类,因此计算节点的容量将提前准备,以应对最初预测的需求。

总结

战略思维是做出正确决策的关键,特别是在如何设计像 OpenStack 这样复杂的生态系统时。本章旨在降低入门门槛,帮助您制定符合组织需求的有效计划。采取的方法应该帮助您识别启动云计算之旅的不同阶段。设计一个操作性的 OpenStack 环境没有确切的经验法则,但为每个核心服务制定设计模板并遵循最初收集的需求,肯定能增强您的云计算之旅。本章回顾了在 Antelope 及之后版本中 OpenStack 生态系统的核心服务的最新更新,并考虑了在私有云上线后可以提供的其他项目。从架构角度来看,本章应在下一个阶段重新审视,以便在每个步骤中调整和更新您的设计草稿。由于我们为未来的 OpenStack 云环境采用了迭代和增量的方法,下一章将带您进入从草稿到部署阶段的下一步,并结合最佳实践进行设置过程的优化。

第二章:2

启动 OpenStack 设置 – 正确的方式(DevSecOps)

“困难中蕴藏着机遇。”

——阿尔伯特·爱因斯坦

如前一章节所述,OpenStack 生态系统呈现了各种设计模式,并提供了硬件和工具的选择,用于部署强大的私有云设置。随着 Antelope 版本的发布,核心架构系统没有发生重大变化,但一些部分进行了更新,并增加了一些新功能。这也带来了部署和操作阶段复杂度的增加。好消息是,自 OpenStack 最早的版本以来,社区已经创建了不同的方法,以避免繁琐的 OpenStack 操作体验。这个任务的关键机制是自动化。毫无疑问,如果忽视了自动化的实现,会面临无休止的故障排除风险。像 Puppet、Ansible、Chef 等供应商维护了多个工具,这些工具已在成千上万的生产环境中使用。搭建一个 OpenStack 系统并不是旅程的最终目标,而是部署过程本身。我们将利用自动化和敏捷工具,通过采用 DevOps 路径,将 OpenStack 的运维提升到一个新水平。虽然这听起来是朝着强大部署过程迈出的惊人一步,但如果从部署初期就没有将安全性纳入考虑,这个过程仍然是不完整的。开发和运维基础设施的流程应当重新构思,从 DevOps 的视角转变为 DevSecOps 的视角。

本章介绍了 OpenStack 私有云设置未来部署和运维流程的骨干,涵盖以下主题:

  • 重新审视 OpenStack 部署生命周期背后的 DevOps 哲学

  • 重新思考 DevOps,并引入 DevSecOps 以查看它如何适应我们的旅程

  • 探索将 OpenStack 部署到容器中的现代方法

  • 迭代自动化工具并为部署做好准备

  • 通过持续集成/持续交付(CI/CD)工具运行 OpenStack 部署的第一次迭代

  • 通过代码和持续集成/持续交付(CI/CD)管道为大规模部署做准备

  • 在每个部署步骤中以自动化方式集成安全检查

打破壁垒 – DevOps

DevOps 这个词汇已经出现了将近十年,推动了组织重新思考如何构建内部团队,以实现 DevOps 所承诺的目标。关于 DevOps 的定义随处可见,但它可以简单地总结为一个 打破孤岛 的方法。DevOps 提出了将软件产品的主要贡献者——包括运维人员、测试人员和开发人员——聚集在同一张桌子旁的理念。该运动的目标基于几个原则,激励组织在实践中实施它们——知识和责任共享、尊重、自动化一切、持续监控、接纳失败和设计可重用性。然而,DevOps 从来不是一个工具或软件,而是一组定义过程和工作流的原则,旨在提高公司的生产力。这个运动的亮点可以追溯到最简单的定义—— 打破孤岛。由于运维人员和开发人员不再受隔阂的限制,更多的协作和知识在朝着同一个目标——以最高的质量和效率减少市场上市时间——共享。没有许多工具的存在,将这个理念付诸实践将会更加困难。持续集成CI)和持续交付部署CD)工具就是体现这一理念的重要例子。另一类将更多信任交给机器而非人类的工具是 自动化 的概念。CI/CD 工具将所有手动和常规的构建、测试和部署阶段交给服务器上运行的几个流水线来处理。与此同时,团队可以专注于更有趣、更具商业价值的任务。云时代的崛起带来了另一套巨大的机会,通过自动化加速软件开发周期——基础设施自动化。这是 OpenStack 一些服务(如 Heat)关注的领域之一。将 基础设施即代码IaC)的理念付诸实践,激励 Dev 和 Ops 团队将传统软件开发生命周期中的知识应用到基础设施层面。

不再是 那不是我的事,而是 这也是我的事。真正重要的是专注于在合理的时间内交付商业产品,更快地进入市场,并在与竞争对手的赛跑中不落后。这可以通过以下图示中展示的 DevOps 工具链来总结,用于跨 Dev 和 Ops 阶段的不同软件部署:

图 2.1 – DevOps 工具链

图 2.1 – DevOps 工具链

通过采纳相同的理念,我们将部署我们的 OpenStack 私有云。但在达到这一阶段之前,我们需要承认一个重要的事实——在应用 DevOps 的要求时,并没有放之四海而皆准的法则。组织中的团队结构可能会有所不同,IT 领域可以根据职能分布在多个专门的工作小组中,或者合并为一个团队。在没有重新分配和重构团队结构、寻找主题专家、基于专业知识配备跨职能团队成员等情况下,追求DevOps 幸福可能会让人感到困惑。由于在安全性和合规性方面的空白,一些问题暴露了出障碍。接下来的部分我们将揭示这些问题,然后将 OpenStack 的各个部分拼接起来。

向左转——DevSecOps

DevOps 哲学的十亿美金理念就是将人们聚集在一起——包括运营(Ops)、开发(Devs)以及质量保证QA)等各个领域。组织应该明确指出在所有产品贡献者之间出现的各个“孤岛”。这应该包括安全领域,确保他们能够在敏捷工作方式中得到体现。2021 年 DevSecOps 现状研究(www.securitycompass.com/reports/2021-state-of-devsecops/)由网络安全咨询服务公司Security Compass发布,研究表明,75%的受访者(IT 专业人员和 DevOps 从业者)同意安全性会延缓产品发布流程,从而导致上市时间的增加。这与 DevOps 的初衷背道而驰。过分注重市场速度可能会忽视安全性。这样的牺牲在一些大型企业中引发了一些可怕的统计数据,这些企业在数据泄露或网络安全攻击的数量上出现了增加。将安全性视为反应性而非主动性的问题来处理,每一次安全事件的处理都会带来预算和时间的成本。造成网络安全和 DevOps 处于两个不同“孤岛”的主要原因有几个——开发过程中需要更多的手动安全干预和对工具的了解不足。投资安全是为了遵守标准并获得信任。为了追求市场速度而牺牲安全,最终肯定会导致后续的重大损失。这就引出了下一个需要在 DevOps 与安全之间建立的桥梁,形成一个 DevSecOps 联盟。正如开发和运营已经融合一样,安全性不应再被视为事后的考虑。DevOps 的原则可以被继承,以使安全融合成为可能。这就是为什么 DevSecOps 成为了一种新趋势。想象一下,整个安全压力在各个领域得到缓解,所有部门都指向相同的产品目标,并配备了自动化和更快速的反馈。

我们可以总结出未来 OpenStack 部署的正确方法——在流程的不同阶段加入安全性的 DevOps,如下所示的工具链。

图 2.2 – 将安全性整合到 DevOps 工具链中

图 2.2 – 将安全性整合到 DevOps 工具链中

部署像 OpenStack 私有云这样复杂环境的实现需要采用 DevSecOps 方法,下一节将介绍一些最佳实践。

云安全 – 与 DevSecOps 一起前进

采用 DevOps 实践无疑是保持市场竞争力、提高生产力并带来创新新可能的重要举措。相反,缺乏安全性将使任何产品面临失去信任和失败的风险。因此,必须加强 DevOps 链条,确保安全性和合规性。DevOps 的一个基本方面是自动化和可重用性。在基础设施的背景下,我们面对的不是 宠物 而是 牲畜宠物和牲畜 类比是一种著名的比喻,指的是将本地服务器称为 宠物。如果该宠物服务器发生任何变化、更新或故障,就会引发问题。它们是基础设施中长期存在、不可或缺的部分,需要更多的关怀。另一方面,牲畜 指的是云等大规模按需环境中的服务器。牲畜的故障不应妨碍业务的运行,牲畜可以 立即 被替换。如果我们采用 牲畜 类比,云中的服务器应该被设计成不可更改的。这就是基础设施即代码(IaC)发挥作用的地方。通过一个单一的真实来源和共享管道,安全 部分更容易与 DevOps 流程融合。拥有这一能力后,将安全性从右侧移到左侧变得更加可行。

DevSecOps 与 OpenStack

部署复杂的 OpenStack 生态系统的挑战通过 DevOps 变得更加简易,但作为云服务提供商,不能忽视的是保护运行用户工作负载的第一层。正如我们将在本节的下一部分探讨的那样,从代码部署完整的 OpenStack 环境有多种方法。在开始考虑代码结构之前,强调安全性是至关重要的,以免错失 DevSecOps 的机会。一般来说,任何为应用基础设施设计的代码都有可能存在漏洞。尽管 OpenStack 服务的不同模块在开发时已经考虑到了安全性,但在特定网络架构中配置和参数化的无数种方式都应在每个阶段进行安全性异常测试。在任何工作负载部署到 OpenStack 基础设施上之前,云本身必须做好安全控制,并符合主要标准。

编写云代码

处理 OpenStack 环境时,最大的挑战之一就是如何处理其部署和日常运维。如果你考虑手动部署,即使是一个小型环境,那么很可能你的 OpenStack 管理流程,包括更新,都将面临不可避免的困难。这时,DevSecOps 实践就派上用场了,其基本口号是 IaC。一个一致的方法是将 OpenStack 生态系统视为代码。好消息是,OpenStack 代码会随着每个稳定版本发布,并且一旦配置和定制好,就可以准备好部署了。但在我们掌握技术部署之前,我们应该考虑一些常见的注意事项来开始构建我们的工具链:

  • 将每个 OpenStack 服务映射为每个模块的代码。

  • 定义目标系统来运行具有一个特定角色或多个角色的 OpenStack 服务。例如,定义一个计算角色,并部署 Nova 服务。

  • 草拟每个服务(角色)的初始配置。

  • 将角色视为可重用的代码,可以在不同的目标环境中部署。

  • 确保在角色设置之间集成功能测试阶段。

  • 从一开始就考虑安全规则和工具的集成。将每个指定的工具映射到管道的每个阶段,从编码到发布阶段。

  • 避免 Big Bang 编码实践,并以自动化持续部署的方式实现更小的变更。

  • 准备持续监控以下部署指标:

    • 部署频率:IaC 部署的频率(每日/每周/每月)

    • 变更交付时间:从代码提交时开始到成功部署的时间窗口

    • 变更失败率:导致系统损坏或停机的提交 IaC 变更的总百分比(包括热修复和回滚)

    • 修复平均时间MTTR):从服务中断开始到恢复服务所需的时间

  • 使用基于 trunk 的开发方法来促进代码监控变更,并增加安全性可视化集成。

重要提示

基于 trunk 的软件开发是一种编码实践,允许开发人员定期将变更合并到公共的 trunk 代码库中。基于 trunk 的实践要求更频繁的代码发布,并进行较小的变更。

接下来的部分将介绍用于以 DevSecOps 风格部署 OpenStack 环境的不同工具。

在云端部署

自从 OpenStack 首次发布以来,已经开发了多种部署工具和包装器,帮助 OpenStack 操作员以更增强、更简便的方式设置完全运行的 OpenStack 环境。随着 Chef、Puppet、SaltStack 和 Ansible 等系统管理工具的兴起,OpenStack 社区已经为每个系统管理工具设立了不同的渠道,通过 OpenStack 生态系统的演变开发不同的类和模块。我们选择这些工具中的哪一个,取决于熟悉程度或云操作员的技术要求。在本节中,我们将使用 Ansible 作为系统管理工具。

Ansible 简介

与其他任何系统管理工具一样,Ansible 使用自己的词汇和术语来定义基础设施组件、模块、关系和参数。相反,与其他工具不同,Ansible 拥有简单的架构设置,这使得它成为一种流行的选择,可以总结如下:

  • 它具有处理相互依赖的复杂服务模块的灵活性。

  • 它使用无代理传输机制连接和更新目标系统,无需安装额外的软件包。它仅暴露运行 Ansible 软件的 服务器。

  • 在目标系统上执行的模块安装后会自动清理。

  • 它拥有丰富的核心自动化模块,以扩展更多功能。

  • 用 YAML 编写的基础设施代码被组织在 Ansible playbooks 中。YAML 比其他语言(如 Chef 的 Ruby)更容易学习和掌握。

  • 由于 Ansible 架构的简单性,扩展性比其他需要运行代理的工具更容易实现。

  • 作为一种声明式编程方法,它专注于描述期望状态的输出,而不是深入探讨如何实现这一目标以及必须采取哪些步骤才能达到预期的输出。

在处理复杂的 OpenStack 生态系统时,考虑到其中的所有组件、子组件和参数类型,了解 Ansible 术语的基本概念至关重要:

  • Playbooks:这些由描述在一个或一组主机上运行一系列操作的主要配置文件组成。任务以 YAML 编写,并按照从上到下的顺序执行,以完成全面部署或配置更改。

  • 角色:这些通过收集不同的 Ansible 资源(如任务、变量和模块)来呈现 playbooks 的组织结构,以便在一个或一组主机上部署服务。

  • 模块:这些是特定代码功能单元的抽象表示。模块可以编写和定制,以控制系统资源、文件和服务。Ansible 附带了一些模块,称为模块库(核心模块),可以通过定制的 playbooks 执行。

  • 变量:这些是用于角色和 playbook 中的动态值,用来反映所需的配置。类似于编程语言中的变量,Ansible 变量通过相同的角色或 playbook 使不同的状态在不同环境中传播。

  • 库存:这是目标环境中已管理主机的列表。Ansible 使用 INI 格式的配置文件,定义了已管理目标主机的名称和 IP。可以通过不同的模式在库存文件中声明主机,或通过角色嵌套主机,或通过组合和数字模式指定一系列主机。

CI/CD 系统触发 Ansible 安装并在其库存中定义的目标 OpenStack 节点上运行 playbook,如下图所示:

图 2.3 – 通过 Ansible 管理 OpenStack 环境

图 2.3 – 通过 Ansible 管理 OpenStack 环境

在 OpenStack 生态系统生命周期管理中集成 Ansible 等系统管理工具,带来了对如此复杂生态系统管理和操作方式的重大变革。毫不奇怪,快速迁移到采用私有云设置并最大化其部署灵活性的需求,带来了其他挑战。这引出了 OpenStack 服务之间依赖关系的根本原因。从长远来看,开发新的 OpenStack 版本和将新功能集成到现有环境中,成为私有云操作任务的终极挑战之一。推动大规模升级一直是顺利迁移到新 OpenStack 版本时的障碍,尤其是在生产环境中运行时。这使得升级操作变得非常谨慎,并且如果其中一个或多个依赖项因版本兼容性问题崩溃,可能会让你的服务级别协议SLA)面临风险。尽管测试可以帮助识别此类异常,但每个组件需要提前进行大量的测试,这在资源和人工互动上会非常昂贵。另一个方面的挑战是缺乏回滚机制。回滚一个导致问题的更改必然会导致系统的某些部分或整个系统崩溃,因为你需要等待管理工具重新部署、重启受影响的服务、测试并等待其他依赖服务之间的完全同步,才能重新运行它们。最常见的 OpenStack 部署选项包括裸金属机器或虚拟机,使得此类操作任务更加复杂,需要全面管理机器镜像,并且在隔离环境中进行测试时会增加成本。例如,升级或更新 OpenStack 组件版本时,需要在不同的测试环境中部署所有相互依赖的服务,然后再在生产环境中传播更改。在最新的 OpenStack 版本中,一些组织已经开始尝试使用容器化的方式构建完全容器化的 OpenStack 云。让我们在下一节解锁容器难题,探索 OpenStack 部署和管理的潜在机会。

容器化云计算

容器技术已经存在超过十年,企业开始将工作负载部署到容器中,以便利用资源优化、环境隔离和可移植性。将软件的不同部分运行在轻量级、自包含和独立的容器中,为管理复杂的软件系统带来了更大的灵活性。在隔离模式下运行时,像升级和回滚这样的操作变得更加容易,并且可以更有信心地执行。

通过参考我们的基础设施代码,我们可以看到 OpenStack 软件架构的模块化设计的优势,利用容器技术,每个模块可以在一个独立、无状态的环境中运行。通过查看当前容器趋势,可以找到一系列容器和编排引擎,如 LXC、Docker 和 Kubernetes。OpenStack 社区没有错过容器化技术的早期采用机会,尤其是在容器开始成为现代软件开发标准时。在 Antelope 及后续版本中,我们可以找到多种基于容器的部署方法,这些方法结合了配置管理工具,具体总结如下表:

部署项目 容器 项目 来源
OpenStack-Ansible LXC Ansible docs.openstack.org/openstack-ansible/latest/
Kolla-Ansible Docker Ansible docs.openstack.org/kolla-ansible/latest/
OpenStack-Helm Docker Kubernetes 和 Helm docs.openstack.org/openstack-helm/latest/
Triple-O(目前不再支持) Docker Ansible docs.openstack.org/tripleo-ansible/latest/

表 2.1 – 运行容器的 OpenStack 部署工具列表

OpenStack-Ansible (OSA) 项目是基于 LXC 容器最广泛使用的部署之一。运行 OpenStack 服务的 LXC 容器的部署由 Ansible 进行编排。

在我们的下一个部署中,我们将采用另一个新兴的 OpenStack 项目,名为Kolla-Ansible。与 OSA 类似,Kolla 项目使用 Docker 作为容器化工具,为每个 OpenStack 服务构建一个 Docker 容器。除了 LXC 和 Docker 之间的设计差异外,Kolla 扩展了参数化布局,使其容器更加可配置,提供了基础操作系统和模板引擎之间的一系列选择。更不用说 Docker 作为容器技术的设计优势,其镜像的分层特性、版本控制和便于共享的可移植性。

重要说明

Kolla 自 Liberty 版本以来正式集成进 OpenStack 子项目。根据 OpenStack 官方对 Kolla 项目的定义,“Kolla 的使命是提供用于操作 OpenStack 云的生产就绪容器和部署工具。”

这些额外的优势使得 Docker 更适合我们的部署管道,在这个管道中,我们将处理作为工件的容器服务,该工件可以通过不同的环境轻松部署,然后再推广到生产环境。如以下高层次架构图所示,对于每次合并的代码库变更,CI/CD 工具会构建一个由封装在 Docker 镜像中的软件包组成的工件。生成的镜像将被提交到私有 Docker 注册表,Ansible 会下载该镜像并在指定的 OpenStack 节点中进行部署。

图 2.4 – 高层次 CI/CD 管道 OpenStack 部署

图 2.4 – 高层次 CI/CD 管道 OpenStack 部署

部署工具栈的另一个组件是Jinja2模板工具。它主要由 Docker 用于基于 Ansible 生成的定义参数动态分配变量。Jinja2 主要设计用于 Dockerfile,以支持 RPM 和 DEB 容器分发版的完整系统调用接口兼容性。

重要提示

在 Kolla 环境中使用 Jinja2 模板提供了多种构建不同源分发的 Docker 镜像的方法,包括 CentOS、Debian、Fedora、Ubuntu 和 RHEL 容器操作系统,这些镜像可以按 OpenStack 服务代码进行参数化配置。

由于我们的主要目标是解决依赖关系的复杂性,并提供更简单、更具可扩展性的开发体验,Kolla 是最佳选择。事实上,自从 Kolla 正式发布第一个稳定版本以来,已经有多个生产环境的部署按照 Kolla 方式进行。

构建图像

将 OpenStack 部署视为 IaC 将帮助我们继承并使用大多数软件工具和流程,以更有信心地交付准备好的代码工件以进行部署。拥有强大的集成和部署管道对于确保我们的软件定义数据中心在生产日不发生故障至关重要。现代软件开发技术涉及多个工具,这些工具提高了自动化和敏捷性,从而加快了每次部署之间的反馈。

以下工具将用于我们的 OpenStack 基础设施代码开发:

  • 版本控制系统:GitHub 将作为我们 OpenStack 基础设施代码的代码库。

  • CI/CD 工具:Jenkins 将安装在部署机上,并提供额外的插件来构建和运行部署管道。

  • 系统管理工具:Ansible 包将安装在部署机上,并提供要在容器内部署的 OpenStack 剧本,与 Kolla 一起使用。

  • 镜像构建器:专门用于 OpenStack 容器,Kolla 构建运行不同 OpenStack 服务的容器镜像。

Kolla-Ansible 项目的代码库将作为我们首次 OpenStack 部署的起点,最小化定制以便最初拥有一个滚动部署管道。该项目代码的最新稳定主分支可以在此找到:github.com/openstack/kolla-ansible

Kolla-Ansible 支持一体化和多节点的 OpenStack 设置。由于我们目标是生产设置,如 第一章《重新审视 OpenStack - 设计考虑》中的初步设计草案所讨论的,我们将确保我们的初步草案准备好进行首次部署迭代。

设置开发环境

设置一个模拟生产环境的开发环境是强烈推荐的,以确保在开发阶段更快速地反馈,并在将代码推向生产设置之前修复任何异常。虽然将服务运行在容器中增加了在生产环境中检测到问题后回滚的灵活性,但最佳实践是通过不同的部署和测试阶段在隔离环境中运行服务容器,采取主动措施。在测试环境中成功部署后,服务容器将被提升并标记为可用于生产部署。

根据开发环境将投入多少台物理机器,DevSecOps 团队将要求为每个成员提供一个隔离的环境,以便在将其更改提交到主要开发分支之前进行测试,该分支目标是在开发环境中进行部署。

准备本地环境

Vagrant 是由 HashiCorp 创建的一种革命性工具,可以通过简单的 Vagrant 命令行创建、修改和管理可视化环境。Vagrant 的另一个令人兴奋的部分是通过它来管理本地开发环境。Vagrant 配置高度可定制,支持多种本地虚拟化软件运行虚拟机,如 VirtualBox、HyperV 和 VMware。

我们的下一个设置将考虑本地 VirtualBox 环境,具体取决于你的开发操作系统机器;大多数 Linux、Mac 和 Windows 发行版都被支持,可以在这里找到:www.virtualbox.org/wiki/Downloads

安装 VirtualBox 后,下载 OpenStack 环境将运行的基础镜像。对于 Vagrant 中的 VirtualBox 开发,最佳实践是开发环境和生产环境使用相同的操作系统发行版。在接下来的设置中,选择的操作系统是 Ubuntu 22.04 LTS。在以下的向导中,我们将逐步准备 Vagrant 文件,准备开始部署本地 OpenStack 环境:

  1. 通过执行以下命令行生成 Vagrant 文件:

    # vagrant init
    
  2. 修改 box 配置段,通过提供操作系统镜像来进行配置:

    Vagrant.configure("2") do |config|
      config.vm.box = "generic/ubuntu2204"
    end
    

重要提示

可以通过备份任何操作系统的镜像来在本地创建 Vagrant box,使用的工具如 Packer。Vagrant box 可以在 Vagrant 云库中共享,并标记版本,详细信息请参见:developer.hashicorp.com/vagrant/vagrant-cloud/boxes/create

  1. 本地开发机器应具备最低硬件规格,如 RAM 和 CPU,以支持 OpenStack 环境的最小配置,具体配置请参见以下 Vagrant 配置段:

    config.vm.provider :virtualbox do |vb|
       vb.memory = 8096
       vb.cpus  = 4
    end
    
  2. 在新的 box 配置段行中,将虚拟磁盘空间设置为至少 50 GB:

    Vagrant.configure("2") do |config|
     ….
       config.disksize.size = "55GB"
    

重要提示

确保已安装 vagrant-disksize 插件,可以通过运行以下命令行来安装:vagrant plugin install vagrant-disksize

  1. 可选地,添加一个同步文件夹,将开发机器上的 OpenStack 基础设施代码同步:

    Vagrant.configure("2") do |config|
      ….
        config.vm.synced_folder(
           "openstack_deploy/", "/openstack_deploy/"
        )
    

重要提示

确保本地机器中的同步文件夹存在,可以通过创建 openstack_deploy 文件夹来实现。

  1. 可以配置网络以转发端口访问,允许从开发机器到来宾 box 特定服务的访问。例如,访问 OpenStack Horizon 需要将端口 80 从来宾机器进行端口转发,可以按以下方式调整:

    Vagrant.configure("2") do |config|
    ...
       config.vm.network :forwarded_port, guest: 80, host: 80
    
  2. 通过执行以下命令行来启动 Vagrant box:

    # vagrant up --provider virtualbox
    
  3. 一旦启动且没有错误,Vagrant box 就可以访问了。默认的登录使用的是 Vagrant 用户,可以提升为 root 以继续进行下一步设置:

    # vagrant ssh
    # sudo -i
    

一旦 Vagrant box 启动并运行,您应该能够开始安装部署一体机 OpenStack 环境所需的软件包。

运行本地云

Kolla-Ansible 项目代码包含了多种在一体机或多节点上安装 OpenStack 的方式。作为基础设施代码的一部分,我们将调整一些设置,以便在开发机器上运行一体机模式。但首先,我们需要在本地开发主机上安装 Git 包:

$ apt-get install git

将 OpenStack-Kolla 仓库克隆到先前设置的本地文件夹中。Vagrant 配置文件将使对本地文件夹 openstack_deploy/ 的任何更改对来宾 box 可见。理想情况下,克隆仓库应从您选择的本地 Git 服务器进行。在此示例中,使用了一个私有 Git 仓库(ci.os)。以下命令克隆运行在 CI/CD 实例上的本地仓库:

$ git clone https://git@ci.os/git/openstack_deploy/openstack_deploy

重要提示

这里有一个简单的指南,可选地设置一个本地 Git 服务器,运行 NGINX,并使用最新版本的 Ubuntu:www.howtoforge.com/tutorial/ubuntu-git-server-installation/。本地 Git 服务器使用从 Kolla-Ansible 仓库克隆的最新稳定主分支:github.com/openstack/kolla-ansible.git

可选地,从主分支创建你的开发分支,以便在将本地更改推送到下一个开发分支之前进行追踪:

$ git checkout -b local_dev_branch

重要提示

理想情况下,应在你选择的专用开发分支中进行更改,然后再将更改合并到主分支中。

登录到你的 Vagrant box,并继续安装环境依赖项并创建虚拟环境。确保更改来宾主机上环境的路径:

# apt-get update
# apt-get install python3-dev libffi-dev gcc libssl-dev
# apt install python3-pip
# apt install python3-virtualenv
# python3 -m venv local
# source local/bin/activate
(local)# pip install -U pip

安装 Ansible。确保安装至少 2.16 版本:

# pip install  'ansible-core>=2.16,<2.17.99'

安装 kolla-ansible 运行时:

#  pip install git+https://opendev.org/openstack/kolla-ansible@master

从 OpenStack Yoga 开始,需要安装一些额外的依赖项,可以通过运行以下命令行来解决:

# kolla-ansible install-deps

Kolla-Ansible 仓库包含两个我们需要编辑的关键文件来运行本地部署——globals.ymlpasswords.yml。将这些文件复制到你选择的目录中(该目录可以新建),并确保运行中的来宾用户拥有这些文件:

# mkdir -p /etc/kolla
# chown $USER:$USER /etc/kolla
# cp -r /local/share/kolla-ansible/etc_examples/kolla/* /etc/kolla

globals.yml 文件包含了多个设置和可调配置,适用于不同的 OpenStack 控制平面服务以及共享服务。作为我们最小化测试环境的一部分,我们将在 / etc/ kolla/ 文件夹下的复制 globals.yml 文件中编辑以下设置:

  • 使用 Ubuntu 作为容器的基础 Linux 发行版:

    kolla_base_distro: "ubuntu"
    
  • 确保 HAProxy 不在我们初始设置的测试环境范围内:

    enable_haproxy : "no"
    
  • 选择要分配给所有类型 OpenStack 网络的网络接口名称:

    network_interface: "eth0"
    
  • 为 Neutron 外部网络分配一个专用接口:

    neutron_external_interface: "eth1"
    
  • 分配一个 Keepalived 浮动 IP,这应该保留作为 HA 的虚拟 IP:

    kolla_internal_vip_address: 172.28.128.47
    
  • passwords.yml 文件集中存储所有 OpenStack 相关用途及其他服务的密码。为了通过一条命令生成随机密码集,而不是手动为每个密码生成,Kolla 提供了一个简单的命令工具来生成密码,这些密码将在部署过程中使用,如下所示:

    # kolla-genpwd  -p /etc/kolla/passwords.yml
    

    确保将生成的密码保存在你自定义目录下的 passwords.yml 文件中。

另一个关键文件位于inventory文件夹中,描述并指示 Kolla-Ansible 哪些主机将是应用配置的目标。库存文件使用 Ansible 主机组格式定义,可以根据可用主机和分配的角色进行自定义。默认的可用文件设计用于运行所有-in-one 和多主机的库存。要运行干净的主机目标设置,请复制inventory目录下的文件:

# cp -r  /local/share/kolla-ansible/ansible/inventory/*  /etc/kolla/

对于我们的开发设置目的,all-in-one Ansible 库存文件不需要任何更改。该文件的格式非常简单,每个主机角色部分描述主机的名称或 IP 地址。对于本地测试环境,所有主机角色将配置为localhost,如以下片段所示:

[control]
localhost       ansible_connection=local
[network]
localhost       ansible_connection=local
[compute]
localhost       ansible_connection=local
[storage]
localhost       ansible_connection=local
….

执行kolla-ansible命令行以安装引导服务器。该命令将对库存文件中分配给每个主机角色的主机运行 Ansible playbook。到目前为止,所有角色都汇集在同一个 localhost 上:

# kolla-ansible -i /etc/kolla/all-in-one bootstrap-servers

以下是输出结果:

图 2.5 – kolla-ansible 引导服务器输出

图 2.5 – kolla-ansible 引导服务器输出

可选地,运行一些部署检查,以密切监控引导过程并检测可能的失败:

# kolla-ansible -i /etc/kolla/all-in-one prechecks

这是输出结果:

图 2.6 – kolla-ansible 预检查输出

图 2.6 – kolla-ansible 预检查输出

一旦引导过程完成且没有检测到任何失败,即可执行 OpenStack 环境的部署,这将需要较长时间来创建所有容器服务并将其链在一起:

# kolla-ansible -i  /etc/kolla/all-in-one deploy

这是输出结果:

图 2.7 – kolla-ansible 部署输出

图 2.7 – kolla-ansible 部署输出

重要说明

Ansible 部署将应用 playbook 和 OpenStack 角色,使用来自默认 OpenStack Docker 仓库的容器镜像。对于下一个开发阶段,请确保构建并推送更多镜像到本地仓库。接下来的章节将讨论如何为不同服务构建本地容器镜像并进行本地管理。

OpenStack 容器的最小部署设置应在kolla-ansible deploy命令行结束时没有任何失败。以下的 Docker 命令行列出了在前一步部署中所有正在运行的容器,这些容器应被视为健康。某些容器仍在与其他系统服务进行通信,这将需要几分钟时间,才能开始评估 OpenStack 服务:

# docker ps

这是输出结果:

图 2.8 – 正在运行的 OpenStack 服务容器列表

图 2.8 – 正在运行的 OpenStack 服务容器列表

让我们通过运行客户端测试命令来查看 OpenStack 是否在容器中运行。要进行快速测试,请安装 OpenStack 客户端包:

 # pip install python openstackclient

要与 OpenStack API 服务交互,必须使用管理员凭据,这些凭据可以通过 kolla-ansible 后部署 命令生成,如下所示:

# kolla-ansible post-deploy

以下是结果:

图 2.9 – kolla-ansible OpenStack 部署后的输出

图 2.9 – kolla-ansible OpenStack 部署后的输出

上述命令将生成 cloud.yaml 文件,该文件包含与 OpenStack 服务交互的不同 OpenStack 管理员凭据。文件变量的内容可以通过导出生成的 cloud.yaml 文件的路径来填充,如下所示:

# export OS_CLIENT_CONFIG_FILE=/etc/kolla/cloud.yaml

通过列出正在运行的 OpenStack 环境,例如 nova 主机,来验证环境:

# openstack hypervisor list

以下是输出结果:

图 2.10 – OpenStack 主机列表输出

图 2.10 – OpenStack 主机列表输出

可以通过 Docker 容器命令行接口轻松管理 OpenStack 服务。例如,可以通过运行以下命令查看 Keystone 容器服务日志:

# docker logs keystone

另一种检查 OpenStack 服务容器并返回容器信息(例如 IP 地址和网络设置)的方法,可以通过使用通用的 docker inspect 命令行来执行,如下所示:

# docker inspect keystone

尽管容器的使用灵活性和几乎可以在短时间内销毁并重建新容器的简便性,但在某些情况下,您可能需要通过 shell 访问调查特定的 OpenStack 服务问题或配置,如下所示:

# docker exec --it nova /bin/bash

一体化设置有助于在本地开发和测试代码。更大的环境,包括预发布和生产环境,将需要扩展设置,具体内容将在下一节中详细说明。

扩展部署

扩展我们在第一章中讨论的初步物理设计,重访 OpenStack – 设计考虑因素,将需要评估不同的硬件规格和为所选设计提供的选项。随着我们逐步确定部署方式和构建首个生产版本所需的不同工具集,我们将开始将 OpenStack 组件的角色划分到不同的物理系统上。与测试环境不同,生产环境应遵循良好的架构设计模式,基于服务隔离、容错性、可扩展性和每层的冗余性。我们将在第三章中深入探讨这些架构方面的扩展,OpenStack 控制平面 – 共享服务,以及第七章中,运行高可用云 – 满足 SLA

如果考虑通过最小化的全一体测试环境到仿真生产环境的所有阶段,我们的部署流水线将是部署任何环境的真相源,如果管道测试的所有阶段(包括安全阶段)都以 0 个错误执行,则将其提升为生产环境。

重要提示

在 OpenStack 环境的每个控制平面和数据平面至少达到最低冗余级别之前,请确保不要引入任何用户生产工作负载。有关扩展到高可用设置的详细信息将在第七章讨论,运行高可用云 - 满足 SLA

环境的部署扩展应采用增量方法,在可行时分割角色,并应考虑某些服务可以选择在其自己的物理服务器上分离。一个良好的实践是在核心服务滚动后并在每次迭代中获取更多操作经验后开始分割附加角色的物理布局。随着部署流水线反馈每个新部署的状态,将需要做出更多技术决策以引入对物理基础架构布局的改进,并且您可以选择在下一次迭代中将哪些服务移动到它们自己的服务器上。为了安全地开始部署旅程,我们将需要在继续进行基础设施部署之前安装和配置我们的部署程序。

安装部署程序

我们的部署程序主机将安装以下软件和硬件设置:

  • 软件

    • Jenkins 版本 2.414.1

    • Docker 版本 1.12.6 或更高版本

    • Ansible 2.3.1 或更高版本

    • Docker Python 1.10.0 或更高版本

    • Kolla-Ansible 16.1.0-16 - OpenStack Antelope 版本或更高版本

    • Git 版本控制

    • 操作系统:Ubuntu 22.04 LTS

    • pip 和 Python 依赖项,包括python-dev

  • 硬件

    • CPU:至少 4 个 CPU 核心和 64 位 x86

    • 内存:至少 4 GB 的 RAM

    • 磁盘空间:至少 50 GB 的可用磁盘空间

    • 网络:至少两个网络接口

首先通过更新本地系统和 Java 运行时来安装 Jenkins:

$ sudo apt-get update
$ sudo apt install openjdk-11-jdk

为 Jenkins 存储库文件添加所需的 GPG 密钥:

$ curl -fsSL https://pkg.jenkins.io/debian-stable/jenkins.io-2023.key | sudo tee /usr/share/keyrings/jenkins-keyring.asc > /dev/null

以下命令将定位本地系统存储库以下载 Jenkins 的最新版本:

$ echo deb [signed-by=/usr/share/keyrings/jenkins-keyring.asc]
https://pkg.jenkins.io/debian-stable binary/ | sudo tee 
/etc/apt/sources.list.d/jenkins.list > /dev/null

运行更新apt软件包列表并安装 Jenkins:

$ sudo apt update
$ sudo apt install jenkins

确保 Jenkins 正在运行,通过执行以下命令:

$ sudo systemctl status jenkins

如果 Jenkins 守护程序未运行,请发出start命令启动其进程:

$ sudo systemctl start jenkins

一旦 Jenkins 服务启动运行,通过默认8080端口在浏览器中指向 CI/CD 服务器地址以访问用户界面,然后继续进行服务器的初步设置:

图 2.11 – Jenkins 首页

图 2.11 – Jenkins 首页

首先,我们需要在构建流水线之前添加一些插件,从Git SCM 插件开始。为此,点击左上角的管理 Jenkins选项卡。在可用插件标签页的搜索框中输入git,然后点击安装 (无需重启)

图 2.12 – Jenkins Git SCM 插件设置

图 2.12 – Jenkins Git SCM 插件设置

一旦安装了 Jenkins 和其所需的插件,我们就可以继续配置 CI/CD 流水线和不同的阶段,以便进行未来的部署。

执行部署操作

我们的 Jenkins 文件可以提交到仓库中。SCM 流水线将使用配置的路径运行作业定义。Jenkins 流水线定义可以在高层次上总结为以下步骤:

  1. 在目标测试主机上创建本地测试环境。

  2. 从定义的分支中检查仓库。

  3. 安装所需的测试包,包括kolla- ansible 和 Docker 运行时。

  4. 初始化引导服务器脚本。

  5. 在引导的测试环境上运行 Kolla 预检查。

  6. 部署 OpenStack 测试环境。

重要提示

根据您计划通过 CI/CD 流水线运行的目标环境,请确保在每个环境中分别调整主globals.ymlinventory.yml文件的配置布局。每个环境都应该使用专门的 Jenkins 流水线文件运行。

下一步是为测试环境创建我们的第一个流水线。Jenkins 提供了多种选项来创建作业流水线定义,可以通过用户界面向导,或直接创建一个 Jenkins 文件,将其放在 OpenStack 基础设施的代码仓库主目录中。为此,我们的第一个作业定义将采用 SCM 方法。以下代码片段定义了 Jenkins 部署流水线,从第一阶段开始,在该阶段,将创建一个虚拟的 Python 环境来运行每个构建在其各自的本地环境中:

pipeline {
  agent any
  stages {
    stage('Setup Local Environment') {
      steps {
        echo '--RUNNING LOCAL ENVIORNMENT --'
        sh ''' #!/bin/bash 
        sudo apt-get update
        sudo apt-get install \ 
        python3-dev libffi-dev gcc libssl-dev docker.io -y
        sudo apt install python3-pip -y
        sudo apt install python3.10-venv -y
        sudo python3 -m venv local
        source local/bin/activate
        ''' 
      }
    }

下一阶段将安装所有必需的依赖项,包括pip、Ansible 运行时和kolla-ansible包:

    stage('INSTALLING PIP') {
      steps {
        echo '--INSTALLING PIP --'
        sh ''' #!/bin/bash 
        pip install -U pip
        ''' 
      }
    }
    stage('INSTALLING Ansible') {
      steps {
        echo '--INSTALLING Ansible --'
        sh ''' #!/bin/bash 
        pip install 'ansible-core>=2.16,<2.17.99'
        ''' 
      }
    }
    stage('INSTALLING Kolla Ansible') {
      steps {
        echo '--INSTALLING Kolla Ansible --'
        sh '''#!/bin/bash 
        pip install \
        git+https://opendev.org/openstack/kolla-ansible@master
        kolla-ansible install-deps
        ''' 
      }
    }

一旦所有必需的包都在本地安装完成,下一阶段将定义基础设施代码在/etc/kolla目录下的文件结构,并在globals.yml文件中设置一些参数,如网络接口和 Kolla 将使用的发行版类型:

    stage('Preparing Infrastructure') {
      steps {
        echo '--Preparing Infrastructure Files Structure --'
        sh ''' #!/bin/bash 
        sudo mkdir -p /etc/kolla
        sudo chown $USER:$USER /etc/kolla
        cp -r /usr/local/share/kolla-ansible/etc_examples/kolla/* \
        /etc/kolla/
        cp -r /usr/local/share/kolla-ansible/ansible/inventory/* \
        /etc/kolla/
        sed -i 's/^#kolla_base_distro:.ls*/kolla_base_distro: \
        "ubuntu"/g' /etc/kolla/globals.yml
        sed -i 's/^#enable_haproxy:.*/enable_haproxy: \
        "no"/g' /etc/ kolla/globals.yml
        sed -i 's/^#network_interface:.*/network_interface: \
        "eth0"/g' /etc/kolla/globals.yml
        sed -i 's/^#neutron_external_interface:.*/neutron_external\
        _interface: "eth1"/g' /etc/kolla/globals.yml
        sed -i 's/^#kolla_internal_vip_address:.*/kolla_internal\
        _vip_address: "10.0.2.15"/g' /etc/kolla/globals.yml
        '''
      }
    }

下一步将为所有 OpenStack 服务生成不同的密钥,注入每个服务的密钥到 OpenStack 服务安装过程中:

    stage('Secrets Setup') {
      steps {
        echo '--Generating OpenStack Services Secrets --'
        sh '''#!/bin/bash 
            kolla-genpwd -p /etc/kolla/passwords.yml
           ''' 
      }
    }

接下来,流水线将指示 Jenkins 准备启动容器脚本,包括系统配置:

    stage('Boostrap Servers') {
      steps {
        echo '--Running Ansible Kolla Boostrap Server Script --'
        sh '''#!/bin/bash 
             kolla-ansible -i /etc/kolla/all-in-one bootstrap-servers
           ''' 
      }
    }

下一阶段将运行预检查任务,以确保引导步骤没有问题:

    stage('Infrastructure Pre-Checks') {
      steps {
        echo '--Running Ansible Kolla Prechecks Script --'
        sh '''#!/bin/bash 
            kolla-ansible -i /etc/kolla/all-in-one prechecks
           ''' 
      }
    }

最后一阶段是部署服务,拉取镜像,并在容器中运行服务:

    stage('Deploy Infrastructure') {
      steps {
        echo '--Running Ansible Kolla Prechecks Script --'
        sh '''#!/bin/bash 
        kolla-ansible -i /etc/kolla/all-in-one deploy
        ''' 
      }
    }
  }
}

确保创建一个新的测试分支:

$ git branch test

提交并推送创建的文件到源代码库的新分支:

$ git add Jenkinsfile
$ git commit -m 'Initial Test Environment Pipeline'
$ git push --set-upstream origin test

重要提示

使用 Jenkins 文件的 SCM 方式使我们能够将流水线定义视为代码。确保所有作业定义的更改和更新都通过流水线代码进行。流水线文件使用 Groovy 语法编写。建议使用 IDE 来突出显示 Jenkins 文件代码格式,就像对 YAML 文件一样。如果您的 IDE 不突出显示 Groovy 语法,请在流水线 Jenkins 文件顶部添加 #!/usr/bin/env groovy

从 Jenkins 用户界面中,从左上角菜单选择 新建项目。选择作业类型为 Pipeline,并为要运行测试流水线的名称选择 openstack-dev。下一个向导会创建一个名为 openstack-dev 的流水线项目:

图 2.13 – Jenkins 流水线创建

图 2.13 – Jenkins 流水线创建

配置 选项卡中从 SCM 选择 Jenkins 文件的流水线脚本,并通过指定存储库 URL 来使用 Git。确保在存储库目录路径中配置 Jenkins 文件的脚本:

图 2.14 – Jenkins 流水线 SCM 作业定义

图 2.14 – Jenkins 流水线 SCM 作业定义

我们为测试环境准备的第一个部署设置已经准备就绪。剩下的就是按按钮。在 Jenkins 中新创建的作业定义的左侧,点击 立即构建,可以看到在流水线代码中声明的不同阶段:

图 2.15 – Jenkins OpenStack 测试部署流水线

图 2.15 – Jenkins OpenStack 测试部署流水线

运行中的 Jenkins 作业可以通过点击 控制台输出 选项卡进行监控,在这里,流水线文件中定义的每个阶段都会报告以支持进一步调试和故障排除,以应对可能发生的错误:

图 2.16 – Jenkins OpenStack 测试部署输出

图 2.16 – Jenkins OpenStack 测试部署输出

Jenkins 控制台输出在排除 Ansible 运行期间可能出现的任何问题时非常方便。确保 失败 状态为 0。当部署状态以 SUCCESS 值结束时,我们可以通过额外的安全检查来强化流水线。

带安全性部署

正如我们在本章开头强调的那样,安全性应该在构建和部署项目的早期步骤中考虑进去。这就是被定义为向左转移的内容。自动化安全检查的技艺应该在测试环境中学习,以便在将基础架构推广到生产环境之前报告任何潜在的漏洞。

我们的第一个安全执行将通过安装额外的 Jenkins 插件来完成,这将成为我们 DevSecOps 管道中的一个有趣资产。由于我们主要处理容器作为构建产物,因此我们将安装一个容器检查插件,用于在后续阶段对构建的容器进行安全扫描。Anchore是最广泛使用的容器漏洞扫描平台之一,能够无缝集成 CI/CD 工具、源代码,甚至 Docker 和 Kubernetes 的容器注册表。Anchore 插件适用于 Jenkins,并且可以像安装 Git 插件一样直接安装。在可用插件选项卡中,搜索anchore

图 2.17 – 搜索 Jenkins Anchore 插件

图 2.17 – 搜索 Jenkins Anchore 插件

选择Anchore Container Image Scanner插件并点击安装(不重启)

图 2.18 – Jenkins Anchore 插件设置

图 2.18 – Jenkins Anchore 插件设置

重要提示

你可以在这里找到更多关于 Anchore 平台的详细信息:anchore.com/container-vulnerability-scanning/

插件安装完成后,我们需要调整设置,指示我们的部署工具使用特定地址和端口的 Docker 仓库。以此示例,镜像注册表将在部署主机上以master_registry命名,通过运行以下命令部署:

$ sudo python3 -m pip install kolla
$  docker run -d \
   --network host \
   --name master_registry \
   --restart=always \
   -e REGISTRY_HTTP_ADDR=0.0.0.0:4000 \
   -v registry:/var/lib/registry \
   registry:2

确保更新globals.yml文件,使用本地 Docker 注册表,方法是编辑以下配置行:

…
docker_registry: 10.0.2.15:4000
docker_registry_insecure: yes
...

将你的更改提交并推送到主基础设施代码仓库,以便我们的 CI/CD 可以在后续的镜像构建步骤中指向本地注册表:

$ git commit -m 'Docker registry global setting'
$ git push

在启动镜像构建管道之前,我们将安装 Anchore 引擎,以便稍后运行容器检查。Anchore 开源版本作为 Docker 镜像提供,可以独立运行。接下来,请下载 Anchore 引擎的docker-compose文件,如下所示:

$ curl https://engine.anchore.io/docs/quickstart/docker-compose.yaml > docker-compose.yaml

可选地,重置docker-compose.yaml文件中通过ANCHORE_ADMIN_PASSWORD配置行定义的管理员密码。该密码将在后续步骤中使用。

重要提示

为了长期访问 Anchore 引擎接口,将 Anchore 端点、用户名和密码分别导出为ANCHORE_CLI_URLANCHORE_CLI_USERANCHORE_CLI_PASS环境变量。如果这些变量未在操作系统中填充,你需要在每次运行 CI/CD 管道执行时导出它们。

现在,让我们创建并运行 Anchore 引擎的 Docker 容器:

$ sudo apt install docker-compose
$ docker-compose up –d

Anchore CLI 非常方便与引擎进行交互,可以通过以下方式安装:

$ git clone https://github.com/anchore/anchore-cli
$ cd anchore-cli
$ pip install --user --upgrade .

在 Jenkins 仪表板上,配置已安装的 Anchore 插件,方法是指向管理 Jenkins并点击系统。提供admin的引擎用户名、密码和在docker-compose.yaml文件中定义的 Anchore 引擎 URL:

图 2.19 – Jenkins Anchore 引擎配置

图 2.19 – Jenkins Anchore 引擎配置

重要提示

Anchore 引擎开源项目不再维护,但仍可在 GitHub 和 Docker Hub 上供评估使用,以及其 Jenkins 插件。企业版已取代了开源版本。有关开源 Anchore 引擎的更多信息,请参见:github.com/anchore/anchore-engine。其他类似的容器安全检查解决方案可以在 github.com/anchore/syftgithub.com/anchore/grype 中找到。

构建镜像并将其推送到本地注册表,可以通过可选的专用管道自动化,步骤如下:

  1. 使用 Kolla 构建 OpenStack 服务 Docker 镜像。

  2. 对推送的镜像运行 Anchore 安全检查。

  3. 如果 Anchore 没有检测到特定漏洞,则使用 Kolla 推送已创建的 OpenStack 服务 Docker 镜像。

我们的镜像管道脚本分为三个阶段 – 构建镜像、Anchore 安全扫描和推送镜像 – 如果漏洞扫描成功。这可以如下表示:

 pipeline {
    agent any
    stages {
        stage('Build Images') {
            steps {
                echo '-- KOLLA BUILD OPENSTACK SERVICES IMAGES --'
                sh '''#!/bin/bash
                kolla-build -b ubuntu
                '''
            }
        }
        stage('Anchore Security Scan') {
            steps {
                echo '--RUNNING LOCAL ENVIRONMENT --'
                sh '''#!/bin/bash
                anchore-cli registry add 10.0.2.15:4000
                anchore-cli image add master_registry:latest
                '''
            }
        }
        stage('Push Images') {
            steps {
                echo '--RUNNING LOCAL ENVIRONMENT --'
                sh '''#!/bin/bash
                kolla-build --registry 10.0.2.15:4000 --push
                '''
            }
        }
    }
}

将管道脚本保存在 Jenkins 中,并从新的作业定义中运行管道:

图 2.20 – 运行 OpenStack 检查镜像管道

图 2.20 – 运行 OpenStack 检查镜像管道

运行 OpenStack 安全扫描镜像管道将生成有用的漏洞评估,并触发停止操作,导致管道失败。Anchore 会报告先前运行失败的原因,该失败未符合引擎策略。

通过从开发环境开始自动化部署 OpenStack,可以交付更高质量的代码,并提供安全防护。云运维人员将在云基础设施部署过程中了解可能的问题,并能更早掌握解决方法。这与安全性和异常检测实践密切相关,能够在更有信心的情况下支持生产环境的迁移。

总结

本章在定义以 DevSecOps 风格运行完整 OpenStack 部署的正确方式和最佳实践方面是一个重要的里程碑。将现代敏捷软件开发实践应用于基础设施管理被认为是云操作人员的一个巨大机遇,因此也是 DevSecOps 的一个机遇,使其能够专注于基础设施的改进和扩展,而不是被传统的手动操作任务所阻碍。OpenStack 生态系统,随着最新的附加服务和功能,如果从一开始就没有考虑到适当的敏捷方法,可能会变得繁琐难以管理。本章强调了从第一天起就融合安全性。基础设施和安全职责之间不应再有孤岛。毫无疑问,这是朝着成功部署经验迈进的关键因素,借助安全性和自动化武装自己。随着我们与正确的工具和流程共同构建了一个坚实的草案,我们将带着这一势头进入下一章,扩展我们的生产设计和部署,涵盖 OpenStack 集群,定义其各种服务的角色,并以 DevSecOps 方式进行部署。

第三章:3

OpenStack 控制平面 – 共享服务

“一个想法的价值在于它的应用。”

– 托马斯·爱迪生

解决 OpenStack 私有云中的业务连续性挑战归结为其控制平面的特性和能力。如第一章所述,多个核心服务,包括计算、镜像、存储、网络和身份,应在早期阶段设计以适应可扩展性和安全性。此类需求的另一个方面是将非原生 OpenStack 服务与核心服务同等对待,设计时考虑故障和可扩展性。此类服务包括消息队列和数据库。在我们考虑生产环境部署的最佳实践时,必须逐一迭代每个将成为 OpenStack 控制平面一部分的服务。部署过程中出现的另一个挑战是 OpenStack 服务的构建和部署方式。正如我们在第二章《启动 OpenStack 设置 – 正确的方式(DevSecOps)》中看到的,容器用于运行 OpenStack 服务,将控制平面服务拆分成更小的单元,将提高每个运行服务的可靠性和可扩展性。在本章中,我们将通过以下主题将设计的布局扩展到生产就绪环境:

  • 定义 OpenStack 控制平面的边界

  • 识别占用部分控制平面的不同 OpenStack 服务

  • 准备首次生产部署

  • 使用 kolla-ansible 部署下一个 OpenStack 环境

  • 揭示 OpenStack 控制平面部署的其他自定义选项

OpenStack 控制平面

当我们开始设计首次迭代布局时,遇到了各种 OpenStack 服务,每个服务由多个组件组成。一个或多个组件可以设计成在不同的物理机器上运行,这些机器被分配了用于逻辑操作和管理的角色。正如第一章《重新审视 OpenStack – 设计考虑》所强调的,逻辑上分离角色将支持 OpenStack 部署和操作的编排。术语 控制平面 在网络词汇中广泛使用,它决定了如何处理和运行请求。作为一个抽象概念,控制平面可以由一个或多个系统组件组成,这些组件集中管理和描述如何满足请求。在 OpenStack 逻辑布局中,云控制器被指定为运行控制平面的大部分组件。

运行控制平面 – 云控制器

OpenStack API、调度服务(包括计算、存储和文件共享调度器)、API 端点、数据库和消息队列都被视为 OpenStack 控制平面的一部分。本节将逐一讲解作为云控制器设置一部分的每个服务,并将其总结为两大类:OpenStack 服务和基础设施服务,如下所示:

图 3.1 – OpenStack 控制平面概览

图 3.1 – OpenStack 控制平面概览

我们将在以下小节中逐步讲解控制平面,并检查每个服务、其子组件和最新的更新。

身份服务

如在第一章《重温 OpenStack – 设计考虑》中所探讨的,身份服务是一个重要组件,用于授权和验证服务通信,以完成特定请求,如存储创建或实例配置。作为控制平面的一部分,Keystone 整合了所有现有 OpenStack 服务的目录,用户可以通过其 API 访问这些服务。

在运行控制平面服务时,提供 Keystone 的关键术语词汇表非常重要。这是为了确保在处理不同域、项目和用户时符合合规性和治理政策,如下所示:

  • 项目:在身份 API 的版本 3 中,项目的概念取代了租户的概念。概念并没有变化,项目是资源集合的逻辑构建,用于隔离用户和组。

  • :上移一层,域包含一组用户、组和项目。这种抽象的隔离对于拥有不同部门的大型企业非常有帮助。例如,每个部门可以分配一个由不同项目和用户组成的域。

  • 角色:自 Keystone 服务初期以来,角色的概念一直是其关键机制之一。可以将一个用户或一组用户分配到不同的项目,并使用不同的授权布局,而无需创建多个具有不同分配的用户,也不需要手动切换到不同的环境来通过不同的项目访问特定资源。

  • 目录:Keystone 通过其发现服务授予访问不同服务的权限。从 Keystone 的角度来看,这些服务作为 OpenStack 服务端点公开,并注册在服务目录中。

  • 令牌:访问特定服务必须通过获取令牌来完成。它可以被视为验证用户的身份证明卡,包括过期日期和时间。它还检查令牌与哪些项目关联,并指向哪些端点。令牌概念本身经历了不同的版本和工作方式。当扩展生产环境中的 OpenStack 时,了解 Keystone 令牌的作用范围机制是非常必要的。由于大量用户会竞争访问服务和资源,作用范围将有助于更好地组织 Keystone 请求中的访问边界,通常可以分为两类:

    • 有范围令牌:一旦创建令牌请求,身份 API 将指定请求者将使用哪些 OpenStack 服务(端点)及其关联的角色。它主要包含诸如项目和域 ID 的引用信息。

    • 无范围令牌:与有范围令牌不同,创建的令牌请求不会包含任何特定的授权范围来访问服务。当用户首次提交凭证时,使用无范围令牌可以避免过度的身份验证循环。稍后,無範圍令牌可以转化为有范围令牌,以将授权限制在特定的服务组件上。

  • 用户:这是一个 API 请求者,用于消耗 OpenStack 服务和资源。

  • :这是属于同一域的用户或 API 请求者的集合,如前所述。

Keystone API 已通过提供更多认证机制选项得到改进,除了传统的密码方式,还支持基于 OAuth 的 SAML2 和 OpenID Connect。身份联合支持是 Keystone 实现的重要里程碑,它通过不同的后端启用了可插拔的身份提供者IdP),包括 SQL、LDAP,甚至是联合的 IdP。在最新的 OpenStack 版本中,包括 Antelope 和 Bobcat,已经支持了多个后端,允许企业利用现有的认证/授权系统,实现更为集中化的管理。

当前支持的认证后端的简要总结如下:

  • LDAP:许多组织可能已经有现有的 LDAP 实例,并要求遵循一套安全策略以满足不同的合规要求。在这种配置下,Keystone 需要授予访问 LDAP 服务器的权限,以进行读写操作,并且不会在内部处理身份提供者(IdP)角色。

  • SQL:大多数默认的 OpenStack 部署都配置了 SQL,以将用户信息存储在 SQL 数据库中,并提供与 Keystone 服务的直接交互。

  • 联合身份提供者(IdP):这是最常见的设置之一,允许组织利用一个完整的整合身份点,Keystone 将在其中建立信任关系,并充当服务提供者。OpenStack 社区围绕这种布局开发了更稳定的发布版本,提供了通过 SAML 断言对多个后端(如 SQL、LDAP 和 Active Directory)进行身份验证的更多方法。最近,在 OpenID Connect 和 OAuth 第二版方面也有了更多的工作。这甚至允许使用 Google 和 Facebook 等公共社交登录平台进行身份验证。

重要说明

Keystone 身份 API 支持完整的创建、读取、更新和删除CRUD)RESTful 操作 API。命令通过 OpenStack CLI 发出,而非 Keystone CLI,因为后者在 Antelope 及后续版本中不再支持,并且最新的 OpenStack 版本已采用身份 API 版本 3。

根据您采用的身份验证和授权策略,当处理纯 OpenStack 生态系统工作流时,Keystone 的机制是相同的。在处理大型基础设施布局时,身份 API 与其他服务的交互可能会让人感到难以应对。此时,在我们梳理完 Keystone 的最新技术状态后,简要概述交互如何工作将有助于在列出下一个服务之前理解。我们应当记住,Keystone 将成为 OpenStack 生态系统中 AA 的安全中心,默认配置不理想,应避免可能的安全漏洞,并进一步提升合规性和治理。

重要说明

Keystone 配置可以通过位于/kolla-ansible/ansible/roles/keystone的 Keystone kolla-ansible剧本进行自定义。编写本书时,Antelope 及后续版本中的默认kolla-ansible配置使用 Keystone fernet 令牌进行身份验证,而非传统的基于公钥基础设施PKI)的令牌。

以下工作流简要演示了 API 请求者(用户或系统)与身份服务之间的典型 Keystone 请求和响应交互,以访问特定的 OpenStack 服务:

  1. 用户或 API 请求者使用凭证通过 Keystone 服务进行身份验证。身份 API 接收请求,并在验证成功后向请求者授予一个令牌。

  2. 用户或 API 请求者使用接收到的令牌提出请求,以访问所需的服务。

  3. 所需的服务通过身份服务验证所提供令牌的有效性。

  4. 一旦验证成功,请求的服务将向 API 请求者回复响应。

该工作流如下图所示:

图 3.2 – Keystone API 请求处理

图 3.2 – Keystone API 请求处理

如前所述,任何请求访问特定服务或资源将涉及身份验证服务,后续的交互将通过 API 请求处理。以更复杂的场景为例,例如虚拟机创建,将涉及更多的交互。这将触发更多服务的调用,如镜像、网络和存储,构成运行实例的基本资源。因此,Keystone 将使用原始认证令牌验证每个请求。新的服务请求将需要使用首次认证令牌生成新的经过认证的请求。

重要提示

Keystone 现在支持 OAuth 2.0 双向 TLS。Keystone Auth 具有一个新的插件,用于 OAuth 2.0 设备授权授予。

计算服务

我们的控制平面包括所有计算服务组件,除了nova-compute,它将在专用主机上运行。如第一章《重访 OpenStack - 设计考虑》中所述,不同计算守护进程的组成构建了 OpenStack 生态系统的主要能力。以下 Nova 服务将作为云控制器堆栈的一部分运行:

  • nova-api:这是处理计算请求的主要接口,包括计算资源的创建、列出、删除和管理。

  • nova-scheduler:这是一个过滤器和加权集合,用于根据自定义或默认特征(如主机位置、内存或 CPU 架构)来确定最适合运行实例的计算主机。

  • nova-conductor:这被认为是 Nova 架构中的一项新颖补充,在最新的 OpenStack 版本之前,nova-conductor将计算过程与直接联系数据库(从安全角度看,被认为是不受信的)隔离开来,转而直接连接数据库。

  • nova-novncproxy:此服务为实例提供 VNC 控制台访问。

重要提示

Nova 剧本位于 /kolla-ansible/ansible/roles/nova 目录下,位于 kolla-ansible 仓库中。请注意,剧本没有单独区分每个计算组件。

调度服务

第一章《重访 OpenStack - 设计考虑》中所强调的,Placement 服务被认为是对计算服务的极大补充,通过检查计算资源、网络和存储池,不仅实现精细化的预筛选,还实现了先进的实例调度。Placement 服务作为 Nova 架构的一部分被引入,并随着其发展,已成为一个独立的项目。使用此服务的一些重要构件如下:

  • 资源提供者:Placement 服务以抽象数据模型对象的形式跟踪底层资源(类型和实例),例如计算、存储池和网络。

  • 资源类别:跟踪的资源按类型分类,分为两大类资源类别:

    • 标准MEMORY_MBVCPUDISK_GBIPV4_ADDRESSPCI_DEVICESRIOV_NET_VFNUMA_CORENUMA_SOCKETVGPU等。

    • 自定义:以CUSTOM_前缀开始,可以创建并将自定义资源添加到放置服务的资源类别中。

  • 库存:由特定资源提供者提供的一组资源类别集合。例如,一个资源提供者RP01,与四个资源类别相关联:16 VCPU4096 MEMORY_MB200 DISK_GB50 IPV4_ADDRESS

  • 特性:这些表示资源提供者的特征。例如,资源提供者RP01提供的 vCPU 可以是HW_CPU_X86_SVM(SVM x86 硬件架构),DISK_GB可以是固态硬盘SSD)。分配给RP01的这两个特性将分别记为is_X86_SVMis_SSD,适用于VCPUDISK_GB资源。

重要说明

放置服务提供标准特性;然而,操作员仍然可以通过放置 API CLI 创建自定义特性。特性可以在 Glance 镜像特征中指定,或在实例启动时使用的实例规格的额外规格中指定。

  • 分配:占用计算节点资源的实例被视为资源提供者的消费者。这种资源的占用表示为分配,存储在数据模型记录中。

  • 分配候选:在处理每个请求后,放置服务会重新排列现有的资源提供者,并返回最新的可用资源组,以便为下一个合适的请求提供资源。

通过放置服务,可以实现更高级的筛选选项。以下工作流展示了网络服务如何通过放置与计算服务进行交互。期望的场景是基于网络带宽在计算节点中调度实例配置:

  1. 通过计算服务创建一个库存。

  2. 资源提供者由计算节点创建。

  3. 在计算资源提供者下,网络服务创建一个网络资源提供者。

  4. 网络服务报告带宽库存。

  5. 网络服务提供一个端口的资源请求。

  6. 计算服务从端口接收资源请求,并将其添加到GET / allocation_candidates请求的 API 请求中。

  7. 曝露的候选项将通过放置服务进行筛选,计算服务将选择最合适的一个。

  8. 计算服务在放置服务中申请资源。

  9. 计算服务与网络服务交换分配更新。

  10. 放置服务更新其下一次请求的分配候选。

部署 API 提供了额外的功能,通过帮助 Nova 调度过程。Newton 版本之前,仅跟踪和管理计算资源的使用情况(如 CPU 和 RAM)。随着多个资源提供者(存储和网络服务)的加入,部署 API 通过统一的管理方法简化了资源的记录和调度。

镜像服务

Glance API 是控制平面的一部分。然而,正如在第一章中强调的,重访 OpenStack – 设计考虑,存储镜像可以通过不同的数据存储类型来处理,例如 Swift 对象存储、AWS S3、Ceph 存储系统、VMware、文件系统以及最近的 Cinder 块存储服务。Glance 服务的发展主要体现在支持最新 OpenStack 版本中存储镜像后端的灵活性。在 Antelope 版本及之后的版本中,Glance API 服务可以配置为同时支持多个后端列表,Glance API 将使用默认的数据存储来处理磁盘镜像操作;否则,它将使用定义的后端列表。

重要提示

默认情况下,影像服务剧本支持文件、HTTP、VMware、Cinder、Swift 和 Ceph 后端,这些后端位于/kolla-ansible/ansible/roles/glance/defaults/main.yml文件中。启用或禁用额外的镜像存储后端可以通过在/kolla-ansible/etc/kolla/globals.yml文件中设置glance_backend_cephglance_backend_fileglance_backend_swiftglance_backend_vmware的值为yesno来实现,分别对应 Ceph、文件、Swift 和 VMware 存储后端。

在控制平面中运行的glance-registry进程将处理数据库中每个关联镜像的元数据更新,包括存储后端路径中定义的镜像位置,如下图所示:

图 3.3 – Glance 控制平面组件

图 3.3 – Glance 控制平面组件

另一个值得注意的增强功能是,控制平面可以定制为支持多个块存储后端。如果创建了两个 Cinder 存储卷,可以将一个属性分配给某个卷,例如 SSD 或 HDD,在这种情况下,Glance API 将根据云操作员的配置指示使用所需的 Cinder 卷。

网络服务

与许多其他 OpenStack 服务不同,Neutron 服务被认为更为复杂,原因在于其通过 OpenStack 版本的演变及其先进的虚拟网络功能和扩展。如第一章《重新审视 OpenStack – 设计考虑》所示,网络容量和分段应提前规划,不仅要容纳更多的流量,还要利用虚拟网络的可扩展性。为此,设计上专门设置了网络节点来处理不同类型的租户和提供商。同时,主要的 Neutron API 将作为控制平面的一部分运行在控制节点上。随着每个 OpenStack 版本的发布,Neutron 驱动程序和插件的数量也在增加;在 Antelope 版本中,支持大多数知名的 SDN 驱动机制,包括openvswitchOVNlinux bridgel2populationbaremetal。提供虚拟网络功能的高级服务插件,如 VPN、防火墙和路由,将在单独的网络节点上运行。强烈建议考虑对云控制器和网络节点进行硬件网络绑定,以提高性能和可靠性。

重要提示

通过kolla-ansible基础设施代码库进行的网络配置,形式会根据要添加的网络功能而有所不同。所有机制、驱动程序和服务插件都列在 Neutron 文件中(/kolla-ansible/ansible/roles/neutron/defaults/main.yml)。如 Open vSwitch 和 OVN 等 Neutron 驱动程序运行在它们自己的 playbook 中,位于相同的文件夹路径下,分别是/kolla-ansible/ansible/roles/openvswitch/kolla-ansible/ansible/roles/ovn-controller

块存储服务

Cinder 自从在 OpenStack 生态系统中孵化以来,主要使命就是为实例提供持久化存储。与临时存储不同,块存储概念自 Bexar 版本早期发布以来就已包含在 OpenStack 中,并作为 Nova 项目的一部分持续存在。然而,自 Folsom 版本起,它已被独立为一个服务。造成这种分离的原因有很多,主要原因是 Cinder 架构的发展。一些块存储的子组件被视为控制平面的一部分,包括cinder-apicinder-scheduler,如以下图所示:

图 3.4 – Cinder 控制平面组件

图 3.4 – Cinder 控制平面组件

我们将在第五章《OpenStack 存储 – 块存储、对象存储与文件共享》中更深入地介绍块存储扩展。

重要提示

当前 kolla-ansible 基础架构代码库中默认未启用块存储。通过在 /kolla-ansible/etc/kolla/globals.yml 文件中将 enable_cinder 设置为 'yes',可以启用已创建的实例将其磁盘存储在关联的卷中。支持的 Cinder 存储后端在 /kolla-ansible/ansible/roles/cinder/default/main.yml 文件中定义的 Cinder 剧本中列出,并通过 cinder_backend 配置段代码引用。确保准备一个名为 cinder-volumes 的初始 LVM 卷,因为 kolla-ansible 包装器将期望存在一个具有该名称的卷组,如 globals.yml 文件中所述。

对象存储服务

Swift 由多个子组件组成,用于管理对象,包括账户、容器和对象。在最高层级,与其他对象存储环交互的主要接口是 swift-proxy-server 守护进程,它将在云控制实例上运行。

重要提示

当前 kolla-ansible 基础架构代码库中默认禁用 Swift。可以通过在 /kolla-ansible/etc/kolla/globals.yml 文件中将 enable_swift 设置为 yes 来启用它。

文件共享服务

由于我们旨在提供一种托管的共享文件服务,在我们的初始生产草案中,Manila 服务的几个组件将成为控制平面的一部分,包括 manila-apimanila-scheduler。与 Cinder 类似,文件共享服务的后端存储类型可能会有所不同。我们将在第五章《OpenStack 存储 – 块、对象和文件共享》中讨论更多关于文件共享服务的配置细节。

重要提示

当前 kolla-ansible 基础架构代码库中默认禁用文件共享服务。通过调整 /kolla-ansible/etc/kolla/globals.yml 文件中的 enable_manila 设置为 yes,可以启用 Manila 服务。

监控

如在第一章《重新审视 OpenStack – 设计考虑》中所述,Ceilometer 已被更改为仅作为运行在 OpenStack 命令下的资源的度量收集器。ceilometer-api 组件是控制平面的一部分。考虑到 Ceilometer 的功能,它基于代理的架构涉及数据收集代理的存在,这些代理通过 REST API 收集度量数据并轮询资源。除了ceilometer-api,一个 ceilometer 轮询代理还在控制节点上运行,并且有一个中央代理用于轮询由不同租户在 OpenStack 基础设施下创建的所有资源。一个监听消息总线以消费代理发出的通知数据的通知代理可以选择性地在云控制节点上运行。

重要提示

当前 kolla-ansible 基础设施代码仓库默认禁用 Ceilometer 服务。在 /kolla-ansible/etc/kolla/globals.yml 文件中将 enable_ceilometer 设置为 yes。Ceilometer 的默认 playbook 配置位于 / kolla-ansible/ansible/roles/ceilometer 目录下。

报警

报警最初作为 Ceilometer 功能的一部分设计,后来被解耦并独立运行,代号为 Aodh。报警组件可以存在于云控制节点内,包含用于报警评估、通知以及状态数据库的附加组件。

重要提示

当前 kolla-ansible 基础设施代码仓库默认禁用 Aodh 服务。在 /kolla-ansible/etc/kolla/globals.yml 文件中将 enable_aodh 设置为 yes。Aodh 的默认 playbook 配置位于 / kolla-ansible/ansible/roles/aodh 目录下。

仪表盘服务

Horizon 在一个 Apache Web 服务器实例后端运行,作为前端暴露 OpenStack 服务的仪表盘,但默认情况下并不是所有非核心服务都会反映在仪表盘中。Horizon 需要通过启用特定服务和功能的指令来进行配置,例如 VPN 服务。Horizon 基于 Python Django 框架,如果终端用户数量不断增加且请求过多,可能会出现过度利用的情况。特别是当启用并将大多数附加服务的指令暴露给更多用户时,仪表盘的扩展性是一个必须考虑的问题。

重要提示

默认情况下,Horizon 被视为 kolla-ansible 基础设施代码仓库中的核心服务。enable_openstack_core 配置项默认设置为 yes,这意味着 Horizon 服务会被包含在 /kolla-ansible/etc/kolla/globals.yml 文件中。在同一个文件中,你可以通过注释掉 enable_horizon_service 配置行,来启用额外的 Horizon 指令,从而通过仪表盘管理该服务,该服务指向附加的 OpenStack 服务。默认情况下,仪表盘支持的所有附加服务都已启用,并在 Horizon playbook 中反映,具体内容见 / kolla-ansible/ansible/roles/horizon/default/main.yml 文件。

由于我们已经涵盖了大部分将作为控制平面一部分的 OpenStack 服务,接下来的部分将介绍那些被视为共享服务的非 OpenStack 服务。

共享服务 – 基础设施服务

第一章《重新审视 OpenStack - 云设计考虑》中,我们将共享服务定义为非 OpenStack 服务。共享服务,例如消息队列、数据库和(可选的)缓存层,除了其他核心服务外,是最关键的服务之一。

消息队列

作为控制平面的一部分,RabbitMQ 是 OpenStack 中最常用的消息服务。强烈建议为队列专门分配单独的节点,但这不是必须的。基于多区域 OpenStack 环境的广泛部署是运行专用 RabbitMQ 集群的合适案例,因为它需要处理不同服务(包括计算、存储和网络)的网状请求。

队列消息的另一个被忽视的方面是安全需求。RabbitMQ 作为大多数 OpenStack 服务之间的通信中心存在。保持消息交换的安全性至关重要。RabbitMQ 支持 TLS,可以保护订阅者和客户端免受篡改的消息,并强制在传输中进行加密。

重要提示

RabbitMQ TLS 选项在 kolla-ansible 基础设施代码库中默认为禁用状态。可以通过在 /kolla-ansible/etc/kolla/globals.yml 文件中将 rabbitmq_enable_tls 设置为 yes 来启用它。其他 RabbitMQ 配置可以在其关联的 playbook 中进行调整,例如消息和队列过期时间,在 kolla-ansible/ansible/roles/rabbitmq/default/main.yml 文件中设置。

数据库

OpenStack 拼图生态系统的另一个重要组成部分是存储所有服务状态和用户跟踪信息更新的数据库。作为控制平面的一部分,MariaDB 被视为数据库引擎,并通过 Galera 包装器在多主集群模式下提供更好的性能。

重要提示

MariaDB 集群依赖于 HAProxy 进行数据库实例切换。更多细节将在 第七章运行高可用云 – 满足 SLA 中讨论。默认数据库引擎配置为 MariaDB 在 kolla-ansible 基础设施代码库中。

缓存

缓存作为我们控制平面的可选部分。然而,由于其在云控制器利用率中的轻量级足迹,强烈建议从缓存开始。Memcached 正在成为提供身份验证令牌验证服务间 API 交互信息等 OpenStack 服务之间的临时数据的标准。

重要提示

Memcached 在 kolla-ansible 基础设施代码库中默认启用。可以在位于 kolla-ansible/ansible/roles/memcached/default/main.yml 文件中的 Memcached playbook 中设置最大缓存内存大小和连接数。

在开始部署私有云之前,识别 OpenStack 的控制平面是一个重要的步骤。这将有助于确定哪种设计布局适合您的环境,以确保高可用性作为最高优先级。接下来的部分将围绕 OpenStack 控制平面的设计草案进行迭代。

武装控制平面 – 为故障做准备

OpenStack 控制平面周围不同组件的组合需要更多的努力以保持它们正常运行并具有最大韧性。有多种方法可以实现控制平面的最大可用性,但这些方法应提前准备并测试。在 OpenStack 的最新版本中,已采用多个工具以确保控制平面的可扩展性和高可用性。另一种方法是简单地重用一些已存在的模式,例如高可用的数据库布局或消息总线集群。在第七章,《运行高可用云——满足 SLA》中,我们将更深入地讨论 OpenStack 各个层级的高可用性。在这一层次,定义一种策略来从可扩展性和可用性角度增强控制平面是至关重要的。

这两个术语应该从设计计划的第一阶段开始考虑,通过回答以下问题:

  • 控制平面如何应对大量的 API 请求?

  • 如何以最短的时间面对和解决硬件故障?

  • 哪些设计模式可以确保控制平面的稳定性和韧性?

  • 我们如何处理基础设施服务(如数据库和消息总线)的增长?

OpenStack 生态系统已经设计成可以大规模扩展。凭借其模块化架构,设计具有韧性的控制平面为不同实现方式提供了一个开放的门。为成功部署控制平面做好准备的已知设计选项总结如下:

  • 主动/主动:所有集群节点参与处理请求。这个模式主要与非对称集群布局相关,其中一个入口点(例如负载均衡器)将请求分发到活动的控制平面服务。主动/主动配置通过将负载分配到多个节点上,增加了云基础设施的性能和可扩展性。通过负载均衡器自动化订阅或丢弃节点的操作可以通过负载均衡器进行编排,根据负载均衡器的能力,可能不需要资源管理器。

  • 主动/被动:与之前的模式不同,活动节点处理请求,而备用节点仅在一个或多个活动节点失败时接管。被动控制平面节点被称为懒惰观察者,不像主动/主动模式中那样需要额外的前端点(如负载均衡器)。这种设计主要与对称集群相关,在这种模式下,资源管理器软件评估并确保在任何时候只有一个活动的控制平面组件在处理请求。

重要提示

kolla-ansible 基础设施代码库带有预定义的角色,用于高可用控制平面的配置,这些角色定义在 globals.yml 文件中的 'hacluster' 配置段落中。大多数采用的 OpenStack 控制平面服务集群软件工具,包括 Antelope 版本,都使用若干 HAProxy 实例进行负载均衡,并基于 虚拟 IPVIP)地址的概念使用 Keepalived 进行动态集群节点健康检查。HAProxy 的剧本带有最新的可自定义配置设置,位于 /kolla-ansible/ansible/roles/loadbalancer/ 目录下。第七章《运行高可用云–满足 SLA》将更详细地介绍 HAProxy 和 Keepalived 的设置,以部署高可用的 OpenStack 控制平面。

控制平面故障设计将依赖于目标服务级别协议SLA)以及在您的基础设施内可用的选项。主动/主动模式可能是一种尽力而为的可扩展和高可用性实现,但通过专用硬件或软件设备来分配集群的负载均衡角色会产生额外成本。数据库的选择是另一个大多数云架构师和运维人员特别关注的难题,因为其复杂性和性能问题。例如,某组织的政策要求使用 Oracle 数据库引擎。设置主动-主动数据库配置可能无法直接解决控制平面高可用性要求,因为这可能需要更多的特定工具和额外的集成,而使用其他引擎如 MySQL Galera 则可能会更简单。

更多的规划

依赖于 CI/CD 工具作为真实来源是一种最佳实践,可以保持控制平面服务集群的一致性。正如我们在第七章《运行高可用云–满足 SLA》中所述,添加新的云控制器节点应该是透明进行的,不会打扰到正在运行的 API 服务。这也是在独立环境中开发更多服务一致性集成测试的有效理由,以确保新控制平面节点部署的顺利进行。监控系统应反馈容量、服务可用性和资源使用情况,以确保如果一切如预期那样,生产环境的成功运行。

部署额外的云控制器节点以增强控制平面的过程可以在加入额外控制平面服务时以相同方式应用。部署更多的 OpenStack 服务将暴露更多的 API 以与其他节点交互,并处理更多的用户或服务请求。这可能会导致每分钟数百个 API 请求的负载增加,毫无疑问,更多的 CPU、内存、网络和磁盘将被消耗。在这种情况下,关于性能和可扩展性的担忧不应限制 OpenStack 云服务组合的增长,因为有多种方式可以解决这一挑战。只要在所有操作任务中保持自动化,作为新控制平面服务的 OpenStack 组件部署应通过 CI/CD 阶段。新组件应通过测试和开发环境,并在提升到生产环境之前发送包含容量和使用限制等一些指标的反馈。之后可以做出设计决策,例如,将新组件运行在同一个云控制器集群中,或将其分配给一个单独的物理或虚拟节点运行。

作为控制平面一部分的新 API 服务的添加应在运行特定服务角色的节点上反映出来。CI/CD 系统在此时发挥作用,确保在节点和服务的基础设施呈指数级增长时保持一致性。

重要提示

在接下来的章节中,将涵盖并集成一些其他的 OpenStack 服务,作为控制平面的一部分,例如 第四章中的 MagnumZunOpenStack 计算 – 计算能力与规格第六章中的 LBaaSv2,OpenStack 网络 – 连接性与托管服务选项;以及 第九章中的 Watcher,基础设施基准测试 – 评估资源容量 和优化

扩展部署

一旦识别出构成控制平面的不同服务,便是更新初始设计草稿的好时机。为了在即将到来的生产阶段中理想地开始部署,最佳方式是为每个物理节点分配一组角色来运行不同的 OpenStack 服务。这将引导我们进入以下配置:

  • 云控制器节点:该节点运行包括 OpenStack API、身份认证、镜像、文件共享、遥测和仪表盘服务在内的控制平面服务。共享服务,包括 MySQL Galera 集群数据库、RabbitMQ 消息服务和 Memcached,将成为分配给云控制器节点角色的一部分。

  • 计算节点:该节点将 KVM 作为主要的虚拟化平台,运行 Nova 计算和网络代理服务。

  • 网络节点:该节点运行 Neutron 代理服务,包括Layer3LBaaSDHCP 和插件代理。

  • 存储节点 : 运行 Cinder 卷服务,与 Cinder 调度器交互,提供块存储资源。

  • 部署节点 : 运行编排部署工具链,包括 Ansible、Kolla 构建器和 CI 服务器。部署节点还可以选择托管本地私有 Docker 注册表。

更新后的设计草案展示了一个多节点 OpenStack 环境,如下图所示:

图 3.5 – 多节点 OpenStack 部署布局

图 3.5 – 多节点 OpenStack 部署布局

重要说明

根据硬件的可用性,网络和存储角色可以分配给云控制器节点。使用监控指标数据提前决定在何时将这些服务安装到独立的物理节点上。当处理 OpenStack 基础设施使用量的指数增长时,建议分离存储和网络服务。如果计划在虚拟环境中运行节点,使用 VMware ESXi 或 VirtualBox 等工具时,确保安装硬件虚拟化扩展,并配置虚拟网络。

初始化网络

如在第一章中所示,重新审视 OpenStack – 设计考虑,应该提前准备一些网络。提前准备物理网络是必需的,作为下一个迭代中生产布局扩展的一部分。我们初步草案中提出的标准网络包括管理、租户、存储和外部网络,连接我们初始集群布局中的不同节点。

以下接口将被考虑:

  • eth0 : 管理接口

  • eth1 : 覆盖和租户接口

  • eth2 : 外部接口

  • eth3 : 存储接口

如下图所示,OpenStack 网络设置考虑了四种不同类型的流量,包括管理、租户和覆盖、存储以及外部网络。请注意,一个网络节点专门用于管理各种 OpenStack 网络服务,这样可以提高性能,并减少云控制器节点层级的网络饱和风险。

图 3.6 – 物理网络分段布局

图 3.6 – 物理网络分段布局

在交换层,网络通过 VLAN 进行逻辑组织,每个网络都分配了一个 VLAN ID,并与分配的网络 IP 子网地址池关联。下表提供了给定保留 IP 池 10.0.0.0/8 的初始网络映射示例:

网络名称 IP 池 VLAN ID
管理 10.0.0.0/24 100
覆盖和租户 10.10.0.0/24 200
外部 10.20.0.0/24 300
存储 10.30.0.0/24 400

表 3.1 – OpenStack 网络 IP 地址

重要说明

在内部管理 OpenStack 包时,管理界面不需要外部网络的出站访问来下载包。部署实例可以连接到相同 VLAN 内的管理网络,以便直接安装所需的包。外部网络访问可以限制为部署实例和租户网络,以便未来需要外部访问的实例。

由于我们处理的是在 Docker 容器中运行的 OpenStack 服务,因此必须考虑底层创建的虚拟网络组件。一旦部署了 OpenStack 环境,Kolla 将使用 Neutron 网络模型在集群中的每个节点上创建一些桥接、端口和命名空间。正如我们将在下一部分配置中看到的,Kolla 会将每个网络接口映射到一个 Neutron 物理网络,称为 physnet。Neutron 创建的每个容器桥接在 neutron_bridge_name 配置段中定义,以设置默认的 Kolla 命名约定,命名为 br_ex。如前所述,kolla-ansible 部署模式高度可定制,因此我们可以为每个桥接分配有意义的名称,分别映射到每个网络接口。

重要提示

分配的网络接口将由 Neutron 用于访问公共网络,以便允许租户创建路由器并为需要互联网访问的工作负载分配浮动 IP,配置文件 /etc/kolla/globals.yml 中定义的 neutron_external_interface 设置将被分配到计算节点的专用接口 eth2 上。

强烈建议为每个主机预先配置网络绑定布局。如前所述,绑定配置取决于工具和运行软件,当使用 Linux 操作系统时,不同的发行版有所不同。常用的绑定配置包括本地 Linux 绑定和 Open vSwitch。

重要提示

本书不涉及绑定配置。关于使用内核模块在 Ubuntu 上进行绑定配置的良好参考资料可以在此找到:help.ubuntu.com/community/UbuntuBonding

列出集群规格

第一章《重新审视 OpenStack——设计考虑》中的物理布局初稿可以作为我们为每个主机选择硬件规格的起点。尽管主机角色之间存在细微差异,以下表格总结了每个主机的典型生产硬件和软件设置:

主机名 CPU 核心数 内存 磁盘 网络 软件 角色
cc01.os 8 128 GB 250 GB 4 x 10 GB Ubuntu 22 LTS, OpenSSH, Python 2.7 或更高版本, NTP 客户端 云控制器
cn01.os 12 240 GB 500 GB 4 x 10 GB Ubuntu 22 LTS, OpenSSH, Python 2.7 或更高版本, NTP 客户端 计算节点
net01.os 4 32 GB 250 GB 4 x 10 GB Ubuntu 22 LTS, OpenSSH, Python2.7 或更高版本, NTP 客户端 网络节点
storage01.os 4 32 GB 1 TB 4x10 GB Ubuntu 22 LTS, OpenSSH, python2.7 或更高版本, NTP 客户端 存储节点

表 3.2 – OpenStack 主机配置

请注意,OpenStack 是设计用于运行在普通硬件上的。表格中没有提到任何具体的硬件型号,这取决于启动第一个配置时的预算和资源。如我们所计划,在第一章中,为了容纳 200 个实例,我们在首次部署时将使用 小型 配置,生产环境的设置应该能够通过增加更多硬件来扩展,并且每一层 OpenStack 生态系统都能水平扩展。undercloud 监控工具应定期收集每个节点的性能和使用情况数据,以帮助决定所需的正确配置和需要添加的资源。首次主机和硬件列表在为集群添加冗余层之前不应承担任何生产负载,冗余层将在 第七章 中详细讨论,构建高可用云 – 满足 SLA

准备基础设施代码

使用相同的 kolla-ansible 仓库,我们可以像 第二章 中所述,启动 OpenStack 配置 – 正确的方法(DevSecOps) 一样,自定义不同 OpenStack 服务(包括控制平面服务)的设置。

作为最佳实践,在合并到主分支之前使用一个独立的分支,然后开始部署到生产环境。

配置主机组

kolla-ansible 基础设施代码定义了目标主机和相关参数,如主机名和网络 IP 地址,这些信息存储在 /ansible/inventory 目录下。主机组的列出可以根据与初步草稿相关的角色进行定制。清单文件的格式简单明了,如 第二章 中所述,启动 OpenStack 配置 – 正确的方法(DevSecOps)。下表定义了我们在下一次部署迭代中使用的不同主机组:

OpenStack Kolla – Ansible 主机组 OpenStack 节点角色
control 运行大部分 OpenStack 控制平面服务,包括核心服务 API、数据库和消息队列服务
compute 运行 nova-compute 服务的主机
network 专用于运行 Neutron 插件和代理的网络节点
haproxy 运行 HAProxy 的目标主机
storage 运行 Cinder 卷服务
monitoring 专用主机,用于监控运行 Prometheus 和 Grafana 的 OpenStack 服务器
logging 运行并处理不同 OpenStack 服务的日志
deployment 使用 Ansible 和 Kolla 运行基础设施代码的部署
对象 运行 Swift 对象存储服务器的实例

表 3.3 – OpenStack Ansible 主机组

库存文件高度可定制,可以根据需要适应不同的服务,既可以为新角色容纳不同服务,也可以将更多的核心服务分配到专用主机上。我们的下一步将考虑多节点设置的部署,包括分别为每个云控制器、计算、存储和网络角色部署一个专用主机。此部署不应被视为生产就绪,因为每个角色将部署在单个节点上,该节点尚未满足高可用性的要求。我们将在第七章中介绍 OpenStack 部署的高可用性和容错,运行高可用云 – 满足 SLA

从真相源开始,在 CI/CD 链所在的部署节点上,创建一个新的分支,专用于暂存环境:

$ git branch staging

在克隆的仓库中创建一个名为multi_packtpub_prod的新文件,路径为/ansible/inventory。可以在同一目录/ansible/inventory中找到一个简单的方法,用于从默认的多节点配置文件中分配不同的主机组,文件名为multinode

每个主机组的配置格式如下所示:

[role_name1]
Hostname01
Hostname02
…
[role_name2]
Hostname03
Hostname04
…

库存文件可以通过明确分配一个或多个 OpenStack 服务在特定主机上运行的方式进行不同的定制。这可以通过添加以下配置段来实现:

[service_name:children]
Hostname

例如,以下配置指示kolla-ansible在分配为控制的云控制节点组上安装 Swift 服务:

[swift:children]
control

之前的配置段将安装并运行所有 Swift 组件在控制主机组中。通过更细粒度的配置,可以指示哪些组件将在哪些主机上安装。如果没有特别提到,服务将安装在控制主机组中。下一个示例指示kolla-ansible在引用为object_storage的主机组中安装除swift-proxy-server之外的其他组件:

[swift-proxy-server:children]
swift
[swift-account-server:children]
object_storage
[swift-container-server:children]
object_storage
[swift-object-server:children]
object_storage

对于我们的下一次迭代,指向共享服务(如数据库缓存层和消息队列)的库存部分如下所示:

[control]
cc01.os.packtpub
[mariadb:children]
control
[rabbitmq:children]
control
[outward-rabbitmq:children]
control
[memcached:children]
control

核心控制平面服务将在云控制器主机组上运行,如下所示:

…
[keystone:children]
control
[glance:children]
control
[nova:children]
control
[placement:children]
control
[cinder:children]
control
[neutron-server:children]
control
[horizon:children]
control
[swift:children]
control
[manila:children]
control
[ceilometer:children]
control

更细粒度的共享和控制平面服务配置可以按服务进行定制,如下所示:

  • 对于镜像服务,Glance 可以按如下方式配置:

    ..
    [glance-api:children]
    glance
    
  • nova-compute外,所有计算组件可以按如下方式配置:

    [nova-api:children]
    nova
    [nova-conductor:children]
    nova
    [nova-super-conductor:children]
    nova
    [nova-novncproxy:children]
    nova
    [nova-scheduler:children]
    nova
    [nova-spicehtml5proxy:children]
    nova
    [nova-compute-ironic:children]
    nova
    [nova-serialproxy:children]
    nova
    
  • Placement 服务 API 可以按如下方式配置:

    [placement-api:children]
    placement
    
  • 块存储 API 和卷调度器服务可以按如下方式配置:

    [cinder-api:children]
    cinder
    [cinder-scheduler:children]
    cinder
    
  • 对象存储代理组件可以按如下方式配置:

    [swift-proxy-server:children]
    swift
    
  • 遥测核心和通知组件可以按如下方式配置:

    [ceilometer-central:children]
    ceilometer
    [ceilometer-notification:children]
    ceilometer
    

共享服务和控制平面部分可以以不同方式定义。一旦新项目的设计草案已完成并准备在云控制节点上运行,更多的服务和组件将继承相同的配置。由于本章没有涵盖所有服务,我们将坚持前面定义的第二次迭代,并将在本书的后续章节中添加更多的控制平面服务。清单文件将作为确立环境中运行服务最新版本的真实来源。

清单部分的下一个类别定义了计算目标节点及其将运行的相应组件:

…
[compute]
cn01.os.packtpub

可选地,由于每个计算节点都需要收集指标以供进一步监控,collectd 将在计算主机组上运行,此外还有 ceilometer-computeipmi 组件:

[collectd:children]
compute
[ceilometer-compute:children]
compute
[ceilometer-ipmi:children]
compute

由于每个计算节点都将与其他节点互联以服务租户网络,设计在前一部分中的一些 Neutron 代理将运行在计算主机组上:

[ovn-controller-compute:children]
compute
[neutron-ovn-agent:children]
compute

重要提示

OVN 将在 第五章 中详细讨论,OpenStack 网络 – 连接性和管理服务选项,作为 OpenStack 中最新版本(包括 Antelope)中最常用的网络服务。

OpenStack 网络服务设计为在其自己的主机上运行,除了其 API 作为云控制平面的一部分。以下代码在清单文件中定义了网络节点及相关组件:

[network]
net01.os.packtpub
[neutron:children]
network

除其 API 外,所有 Neutron 服务和代理将在网络节点上运行,如下所示:

[neutron-dhcp-agent:children]
neutron
[neutron-l3-agent:children]
neutron
[neutron-metadata-agent:children]
neutron
[neutron-ovn-metadata-agent:children]
network
[neutron-bgp-dragent:children]
neutron
[neutron-infoblox-ipam-agent:children]
neutron
[neutron-metering-agent:children]
neutron
[ironic-neutron-agent:children]
neutron
[neutron-ovn-agent:children]
network

此外,manila-share 组件将运行在使用 Neutron 插件来提供文件共享资源网络访问的网络主机组上:

[manila-share:children]
network

OVN 控制器已配置为在计算节点和网络主机组中运行,如下所示:

[ovn-controller:children]
ovn-controller-compute
ovn-controller-network

ovn-controller-network 继承与网络主机组的关联:

[ovn-controller-network:children]
network

请注意,OVN 机制使用其自己的数据库,该数据库可以运行在云控制器主机组上。OVN 数据库本身支持三种不同的架构,可以在同一云控制器主机组上运行,如下所示:

[ovn-database:children]
control
[ovn-northd:children]
ovn-database
[ovn-nb-db:children]
ovn-database
[ovn-sb-db:children]
ovn-database

清单的下一部分是存储层,最初将定义一个存储节点:

[storage]
storage01.os.packtpub

存储节点将运行 Cinder 卷:

[cinder-volume:children]
storage

清单文件的最后一部分包括部署主机本身,定义为 localhost:

[deployment]
localhost       ansible_connection=local

其他服务可以算作额外的安装服务,例如,如果你在所有节点或特定扫描工具上运行自定义Zabbix 代理并报告给中央集线器。实现这一目标的简单方法是创建一个新的段落,引用清单中定义的所有主机组。例如,以下代码部分指示 Ansible 安装一些工具,如cron,以及使用fluentd来管理和收集日志的服务,适用于运行 OpenStack 服务的 Kolla 容器。可选地,kolla-ansible附带了kolla-toolbox,可以在安装后快速在 Docker 容器中运行特定的命令行:

[common:children]
control
network
compute
storage
[cron:children]
common
[fluentd:children]
common
[kolla-logs:children]
common
[kolla-toolbox:children]
common

重要提示

在多节点配置中,确保部署机器能够访问所有其他主机以运行 Ansible playbook。可以在清单文件中指定 Ansible 如何与每个目标主机交互。在当前配置中,已经生成并推送了 SSH 密钥到每个目标主机,以便在部署过程中使用 Ansible。请注意,如果清单文件中未使用 IP 地址,则主机名应在每个节点的/etc/hosts中进行传播。

保存文件,提交并推送到创建的分支:

$ git add multi_packtpub_stg
$ git commit -m 'Multi Node Inventory - Staging'
$ git push --set-upstream origin staging

一旦主机映射和分支配置完成,便可以深入研究kolla-ansible代码,并为不同服务自定义未来的 OpenStack 参数。

参数化环境

下一个关键文件是globals.yml配置文件,该文件位于/etc/kolla/目录中。这个文件充当所有 OpenStack 环境的中央配置中心。社区版kolla-ansible仓库附带的默认文件定义了每个服务选项的 OpenStack 服务配置。你可以复制并注释掉所需的配置行,或者生成一个新的配置行来持有 OpenStack 配置设置。

当前迭代中的globals.yml文件包括以下配置:

  • 使用 Ubuntu 作为 Kolla 基础容器发行版:

    kolla_base_distro: "ubuntu"
    
  • 安装最新的稳定版 OpenStack 发行版:

    openstack_release: "master"
    
  • 为一个控制器接口分配一个未使用的默认 VIP:

    kolla_internal_vip_address: "10.0.0.47"
    
  • 使用 KVM 作为默认的虚拟化驱动程序:

    nova_compute_virt_type: "kvm"
    
  • 使用 Neutron Open vSwitch 插件:

    neutron_plugin_agent: "openvswitch"
    
  • 启用 Neutron 提供者网络:

    enable_neutron_provider_networks: "yes"
    
  • 为 API 服务分配一个网络接口:

    network_interface: "eth0"
    
  • 为 Neutron 外部端口分配一个网络接口:

    neutron_external_interface: "eth1"
    
  • 使用在第二章中创建的本地 Docker 镜像库,启动 OpenStack 设置——正确的 方式(DevSecOps)

    docker_registry: "docker-registry:4000"
    
  • 保存文件,提交并推送到创建的分支:

    $ git add multi_packtpub_stg
    $ git commit -m 'Multi Node Global Configuration - Staging'
    $ git push staging
    

重要提示

kolla-ansible 社区仓库中的一些配置参数可能会随着 OpenStack 版本的不同而更新,例如 globals.yml 文件中的新配置参数或仓库结构本身。强烈建议在部署特定版本之前查看仓库文档。本文使用的是最新的稳定版本。请确保在首次拉取时检查分支名称及其相关标签。

高级配置

globals.yml 文件默认不提供所有详细的配置设置。例如,HAProxy 的最大连接数和 Memcached 实例的最大内存量是更具体的设置,无法直接在 globals.yml 文件中调整。

在 OpenStack 生产环境中进行更高级配置的一种方式是通过查看 Ansible playbooks。请记住,globals.yml 文件是从一个单独的中心文件部署 OpenStack 环境的高级表示。

使用 kolla-ansible 配置 OpenStack 部署有三个不同的级别,按照以下顺序:

  • /etc/kolla/globals.yml :这是通用和自定义 OpenStack 的第一个中心,包含共享服务设置。

  • /kolla-ansible/ansible/group_vars/all.yml :该文件反映了 OpenStack 服务的全局和特定设置。一旦它们被编辑并运行,all.yml 文件中的设置将与 globals.yml 文件合并。在 globals.yml 文件中未显式声明的设置将使用 all.yml 中的默认值。

  • Ansible playbooks :少数情况下,可能需要为特定服务引入高级配置。每个 Ansible playbook 应包含给定服务或组件的所有可用选项。Ansible playbook 位于 /kolla-ansible/ansible/roles 目录下,其中列出了 Antelope 版本及更高版本中所有可用的 OpenStack 组件和共享服务。正如在 第二章 启动 OpenStack 设置 – 正确的方式(DevSecOps) 中强调的那样,在讨论如何构建 Ansible playbook 时,调整特定服务的设置非常简单。例如,通过简单更新位于 / roles/memcached/defaults/ 文件夹中的 main.yml 文件中的 memcached_max_memory 配置项,可以更改 Memcached 的最大内存量。

自定义控制平面配置相当简单,只需查看给定 OpenStack 核心服务的 Ansible 角色和 playbook 即可。/kolla-ansible/ansible/roles/ 包括所有 OpenStack 核心服务集和其他在最新稳定版本中官方孵化的项目。请注意,有一种直接的方法可以将 playbook 设置反映到 globals.ymlall.yml 文件中。

部署环境

将一个 staging 环境专门用于在生产环境之前进行部署,是在关于代码和工件发布稳定性的讨论中,最常被提及的开发支柱之一。在部署代码时,总是有跳过 staging 环境的诱惑,尤其是对于资源密集型的环境(如 OpenStack)。Staging 环境可能很昂贵,但考虑到最终结果,它能为在将代码合并到主分支之前模拟生产环境提供信心。如果你无法负担与生产环境完全相同的复制品,解决成本问题的常见方法是使用生产环境的较小版本,但保持相同的设计布局。

在下面的代码片段中,所有必需的步骤将通过一个针对multi_packtpub_stg分支的 Jenkins 流水线自动化实现。为此,创建一个新的 Jenkins 文件,目标是 staging 分支:

pipeline {
  agent any
  stages {
    stage('Setup Local Environment') {
      steps {
        echo '--RUNNING LOCAL ENVIORNMENT --'
        sh ''' #!/bin/bash 
        sudo apt-get update
        sudo apt-get install \
        python3-dev libffi-dev gcc libssl-dev docker.io -y
        sudo apt install python3-pip -y
        sudo apt install python3.10-venv -y
        sudo python3 -m venv local
        source local/bin/activate
        ''' 
      }
    }
    stage('INSTALLING PIP') {
      steps {
        echo '--INSTALLING PIP --'
        sh ''' #!/bin/bash 
        pip install -U pip
        ''' 
      }
    }
    stage('INSTALLING Ansible') {
      steps {
        echo '--INSTALLING Ansible --'
        sh ''' #!/bin/bash 
        pip install 'ansible-core>=2.16,<2.17.99'
        ''' 
      }
    }  

    stage('INSTALLING Kolla Ansible') {
      steps {
        echo '--INSTALLING Kolla Ansible --'
        sh '''#!/bin/bash 
        pip install \
        git+https://git@ci.os/git/openstack_deploy/openstack_deploy
        kolla-ansible install-deps
        ''' 
      }
    } 
    stage('Preparing Infrastructure') {
      steps {
        echo '--Preparing Infrastructure Files Structure --'
        sh ''' #!/bin/bash 
        sudo mkdir -p /etc/kolla
        sudo chown $USER:$USER /etc/kolla
        cp -r /usrlocal/share/kolla-ansible/etc/kolla/* /etc/kolla/ 
        cp -r /usr/local/share/kolla-ansible/ansible/inventory/* \
        /etc/kolla/
        ''' 
      }
    }
    stage('Secrets Setup') {
      steps {
        echo '--Generating OpenStack Services Secrets --'
        sh '''#!/bin/bash 
            kolla-genpwd -p /etc/kolla/passwords.yml
           ''' 
      }
    }
    stage('Boostrap Servers') {
      steps {
        echo '--Running Ansible Kolla Boostrap Server Script --'
        sh '''#!/bin/bash 
             kolla-ansible -i /etc/kolla/multi_packtpub_prod \
             bootstrap-servers
           ''' 
      }
    }
    stage('Infrastructure Pre-Checks') {
      steps {
        echo '--Running Ansible Kolla Prechecks Script --'
        sh '''#!/bin/bash 
            kolla-ansible -i /etc/kolla/multi_packtpub_prod prechecks
           ''' 
      }
    }
    stage('Deploy Infrastructure') {
      steps {
        echo '--Running Ansible Kolla Prechecks Script --'
        sh '''#!/bin/bash 
        kolla-ansible -i /etc/kolla/multi_packtpub_prod deploy
        ''' 
      }
    }
  }
}

提交并推送创建的文件到源代码仓库,并创建新分支:

$ git add Jenkinsfile
$ git commit -m 'Jenkins Staging Environment Pipeline'
$ git push staging

第二章所示,启动 OpenStack 设置 – 正确的方法(DevSecOps),通过选择 Jenkins 用户界面左上角的新建项目,创建一个新作业。选择流水线作为我们作业的类型,并为运行 staging 流水线指定一个所需的名称。通过指定 Jenkins 文件在仓库中的路径,按照相同的步骤设置 staging 流水线。流水线中不同的构建阶段可见,如下图所示:

图 3.7 – 一个 OpenStack staging 环境部署

图 3.7 – 一个 OpenStack staging 环境部署

第一次构建运行可能需要更长时间来安装 Jenkins 服务器上所需的软件包和依赖项。自动化部署流水线非常方便,因为通过一个单一的流水线文件来协调所有步骤,减少了在流水线某个阶段出现错误时手动执行特定步骤的时间。可以配置 Jenkins 构建定期拉取源代码(例如cron),或者在有新的代码推送并合并到开发分支时触发构建。请注意,通过集成更多的单元测试,有多种方法可以实现更强大的部署流水线。到目前为止,我们已经构建了一个初步的部署流水线。从中,可以从一个地方并且更有控制地安装额外的服务或进行更改。在接下来的章节中,我们将继续坚持这种部署方法,结合最佳实践,将部署保持为小批量、持续进行并且以测试驱动。

总结

本章我们回顾了 OpenStack 部署的基石:控制平面。识别控制平面层中每个组件的角色有助于为高度可用且可扩展的编排层做准备,我们将在第七章 运行高可用云 - 满足 SLA 中详细讨论。一些核心服务,如 Keystone、Glance 和 Placement,已被更详细地探讨,以突出您的下一次生产迭代可以支持的不同选项,例如通过身份合并或映像后端。请注意,控制平面不仅限于我们在本章中探讨的已部署服务。OpenStack 生态系统仍在增长,随着更多服务的加入,更多的 API 可以成为控制平面的一部分。从架构的角度来看,Designate API 可以是控制平面的一部分,并与其他管理组件一起运行在相同的云控制器中,而其他管理组件则可以在专用主机上运行,以提高大规模环境中 DNS 请求的性能。

最重要的是,无论您选择哪种选项,控制平面必须为故障做好准备,并且经过验证可以扩展,正如我们在本章中所学到的那样。向控制平面集群中添加或移除服务单元不应是破坏性的操作。这也是我们选择基于容器的部署方法来构建 OpenStack 生产环境的合理原因。本章通过深入探讨各种控制平面 playbook 和附加的高级设置,扩展了使用 kolla-ansible 的首次部署。虽然本章没有详细讨论控制平面高可用性的方面,但设计草案应能够在将云环境开放供使用之前,通过容错来加强控制平面。

下一章将通过计算层扩展我们的部署。由于我们已经将控制平面分离,并设计了只有计算 API 和调度器作为云控制器的一部分,下一步是深入探讨 OpenStack 计算服务,揭示各种部署选项以及最新 OpenStack 版本中的功能,包括容器化选项。

第四章:4

OpenStack 计算 – 计算能力和规格

“魔法就是相信自己。如果你能做到,你可以让任何事情发生。”

– 约翰·沃尔夫冈·冯·歌德

作为私有云提供商,典型的 OpenStack IaaS 服务是其向最终用户提供的构建块。在 IaaS 服务的核心是计算服务,它在不同方面运行和管理工作负载的生命周期。OpenStack 基金会致力于通过定制 Nova 服务以不同方式扩展 OpenStack 生态系统的范围,并推出新服务。管理弹性数据处理(代号为Sahara)、管理数据库(代号为Trove)以及容器应用目录(代号为Murano)等新的流行项目,都是在 Nova 服务之上提供的服务的例子。

作为云操作员,在 OpenStack 环境中具备对计算资源和不同隔离方法的扎实理解,是成功运行私有云旅程和提供所需服务的基础要求。在撰写本版时,Nova 服务已有一些更新,除了周围更多相关特性和服务的出现。为了确保基于第一章详述的草案进行安全计算设计更新,有必要详细了解从 Antelope 版本开始发布的最新 OpenStack 版本中推出的新计算服务。在本章中,我们将讨论以下主题:

  • 从架构角度重新审视 Nova 计算服务。

  • 检查计算服务支持的最新的虚拟化程序。

  • 探索大规模 OpenStack 计算部署的计算隔离概念。

  • 揭秘过滤艺术,构建基于一系列策略的高级计算资源分配和托管工作负载的先进方法

  • 讨论容器编排引擎COEs)及其与 Magnum 集成的情况

  • 学习如何以最灵活的方式使用新的流行 Zun OpenStack 容器服务来管理和操作容器。

  • 使用 Kolla-Ansible 基础设施即代码范式,在运行中的 OpenStack 环境中配置和部署新的计算节点

计算服务组件

计算服务由多个组件组成,负责处理传入的计算请求,然后启动和管理实例,如下图所示展示的 Nova 架构:

图 4.1 – Nova 组件架构

图 4.1 – Nova 组件架构

让我们在以下章节中探索每个计算组件。

API

nova-api组件通过排队消息服务处理不同(基于 HTTP 的)请求。请记住,在将计算请求转发到下一个 Nova 组件并建立完整工作流之前,API 是接受计算请求的第一个接口。

调度器

Nova 工作流抽象层中的下一个站点是 nova-scheduler 组件。它是工作流中的一个重要部分,决定每个传入的实例创建请求将在哪个计算节点上运行。

调度器组件使用多种过滤器和偏好设置,可以根据不同的需求和资源可用性进行定制。过滤加权 是 Nova 调度器用来定制底层物理资源分配的主要机制。本章将详细拆解在 Antelope 版本及以后的版本中新增加的过滤器和加权参考。

Conductor

一旦请求通过 nova-scheduler 进程处理,nova-conductor 组件将确保在物理主机上所做的预定保存在共享数据库中。nova-scheduler 进程需要事先检查数据库并验证可用容量,然后才能做出调度决策。与 OpenStack 生态系统中 Nova 项目的早期版本相比,conductor 组件是 Nova 工作流中的一项重要新增功能。作为上版的简要提醒,conductor 带来了安全性提升,防止计算节点直接访问数据库。在早期版本中,计算节点会直接更新它们在共享数据库中的状态。如果其中一台物理机器被攻破,这样可以减少数据库层面可能的安全漏洞带来的影响范围。如今,conductor 负责这一任务。conductor 组件的另一个重要新增功能是专门处理计算节点的操作,如调整大小、构建和迁移。

通过将这些能力集成到 nova-conductor 中,计算节点将作为简单的工作节点,只需将协调和数据库操作交给 conductor 进程处理。

计算

来到 Nova 工作流的末尾,nova-compute 组件将处理剩余的请求,通过与虚拟化管理程序(hypervisor)的交互来完成。OpenStack 计算核心为不同支持的虚拟化管理程序添加了各种新特性,使得每个新版本都比前一个版本更具吸引力。Nova 服务支持的虚拟化管理程序包括 Libvirt KVM、VMware vSphere、XenServer、XenAPI、Microsoft HyperV、Linux 容器LXC)、快速模拟器(Quick Emulator)等。最令人兴奋的部分是,每个虚拟化管理程序的功能都在不断发展和集成,由拥有该虚拟化项目的供应商进行更新。本章将详细说明这些虚拟化管理程序,并突出一些常见的架构计算布局。

控制台访问

通过 OpenStack Horizon(仪表盘)或 命令行接口CLI)访问虚拟机,在 OpenStack 社区的不同版本中得到了很好的开发。控制台访问不是运行完全工作 Nova 服务的必需组件,但它是与已分配来宾进行交互的附加方面。直到 Liberty 发布,nova-consolenova-novncproxynova-consoleauth 主要被认为是最稳定的控制台类型。现在,随着 Antelope 及之后的发布,更多的控制台类型已加入列表,如 SPICE 控制台和串行控制台,作为图形控制台的替代扩展。微软还通过 远程桌面协议RDP)为控制台服务做出了贡献。然而,后者有一个限制,即仅支持 Hyper-V 并需要与 OpenStack 中尚未开发的控制台代理进行集成。因此,应提供第三方工具与控制台配置一起使用,例如可以在 GitHub 上找到的 FreeRDP-WebConnect 应用程序。与微软的 RDP 类似,VMware 也通过另一种控制台类型 鼠标、键盘、鼠标MKM)做出了贡献。它绑定到基于 VMware vSphere 超级管理程序的虚拟机访问控制台,但与 OpenStack 中现有的控制台代理服务无关。在最新发布的版本中,随着控制台支持服务列表的不断增长,自 Train 发布以来,一个控制台支持服务已被弃用,即 nova-consoleauth

相关的 Nova API 服务,包括 nova-schedulernova-conductornova-api,作为控制节点的一部分运行,nova-compute 服务则在每个计算节点上运行。Nova 计算服务的运行基于硬件平台和所选的超级管理程序,相关内容将在下一节中介绍。

超级管理程序的推理

通过浏览不同的 OpenStack 版本,Nova 支持多种 虚拟机监控器VMM),也称为虚拟化管理程序。虚拟化管理程序软件允许访问物理机器硬件资源,并提供不同的功能来创建和管理计算节点中的虚拟机。在编写本书时,包括 Dalmatian 版本在内的最新 OpenStack 版本支持 内核虚拟机KVM)、LXCQEMUVMware vSphere(5.1.0 及更高版本)、zVMIronic(原生 OpenStack 裸机)、Hyper-VVirtuozzo(7.0.0 及更高版本)。不同的功能和虚拟机管理能力因虚拟化管理程序而异。每个虚拟化管理程序所支持的完整功能列表可以在官方的虚拟化管理程序支持矩阵中找到,网址为 docs.openstack.org/nova/latest/user/support-matrix.html。请根据您的需求解析每个提供的功能。KVM 是 OpenStack nova-compute 设置中最常用的虚拟化管理程序,因其早期采用并且具有最大的一组支持功能。

重要提示

其他著名的虚拟化管理程序,如 XenXCPUMLDocker 驱动程序,并未在最新的 OpenStack 版本中列出,包括 Antelope 和 Bobcat(2023 年 10 月发布)。Docker 驱动程序自 Havana 版本以来已被支持,并迁移到其独立的项目中,代号为 Zun 项目,后续将在本章中详细介绍。

Nova 计算服务使用 Virt Driver 通过 API 调用与 Libvirt 库进行交互,并通过虚拟化管理程序管理虚拟机,如下图所示:

图 4.2 – Nova 支持的计算型虚拟机监控器

图 4.2 – Nova 支持的计算型虚拟机监控器

Nova 中的虚拟化管理程序后端配置可以通过调整 compute_driver 选项来完成,配置文件位于 /etc/nova/nova.conf 中。

KVM 实现要求 nova-compute 部署在安装了 KVM 虚拟化模块的 Linux 服务器上。对于每个计算节点,请确保通过以下命令行正确加载 KVM 模块:

# lsmod | grep kvm
kvm_intel or kvm_amd

根据节点中支持的 KVM 模块(Intel 或 AMD),可选择性地将列出的模块添加到 /etc/modules 文件中,以便在重启时保存更改。

下一节将 KVM 作为我们生产计算节点中采用的主要虚拟化管理程序进行讨论。

计算隔离

OpenStack 设计上能够大规模扩展,以应对基础设施规模和用户需求的增长。由于计算服务是云基础设施的主力,设计计算层的可扩展性和业务连续性至关重要。定义计算隔离策略将帮助你了解私有云基础设施的限制,并预测用户的计算需求——这将在下一节中进行探讨。

基础设施隔离

根据可用计算集群资源、库存规格以及所使用的虚拟化管理程序,OpenStack 提供了多种可以利用的计算隔离机制,包括可用区区域单元主机聚合。以下各个概念将在下一节中详细说明。

区域

OpenStack 术语表中的一个区域表示一个完全独立的 OpenStack 部署。从运营和管理的角度来看,每个区域可以暴露其自己的 OpenStack API 服务,包括计算资源。如果你计划进行 Nova 多区域部署,则应在每个区域创建一个 Nova API 端点,并将其添加到身份服务目录中。用户可以通过可用的计算 API 在可用的区域之间启动实例并分配工作负载。在多区域配置中运行工作负载为最终用户提供了诸多优势,但也给运营商带来了挑战,如维护 OpenStack 控制平面和共享服务层的一致性。这主要是因为计算资源在多个区域之间运行时可能会出现脑裂的风险。在多个区域运行的计算节点群集上托管用户工作负载需要采取一定方法来确保共享资源的一致性,如虚拟机镜像、数据库或文件共享。多区域一致性的另一个重要方面是处理请求计算资源的授权方式。常见的设计方法之一是通过联合的身份提供者IdP)将所有身份验证调用集中到 Keystone,如下图所示:

图 4.3 – OpenStack 多区域部署

图 4.3 – OpenStack 多区域部署

每个区域可以托管一个或多个定义为 可用区 的离散计算结构,这将在下一节中详细介绍。

可用区

一个区域可以逻辑上由一个或多个可用区组成。与区域设置不同,无需部署完整的独立 OpenStack 部署并在控制平面服务之间提供一致性。从物理实现的角度来看,计算节点将被拆分成称为 故障域 的逻辑组树。每个故障域将是给定机架内一个 电源分配单元PDU)的一部分,且不同的虚拟化管理程序将在不同的机架上运行。这样,在失去与 机架顶端交换机ToR)的连接或发生 PDU 故障时,用户工作负载不会完全崩溃,尤其是在多可用区配置中,如下图所示:

图 4.4 – 扩展的 OpenStack 多区域和可用区部署

图 4.4 – 扩展的 OpenStack 多区域和可用区部署

Nova 可用区选项为用户工作负载提供高可用性,这可以视为对需要最高 SLA 的关键工作负载的高级选项。计算节点只能属于一个可用区,因为它绑定于机架的物理设计,如机架 ID、位置和 PDU。

重要提示

可用区的逻辑抽象除了覆盖计算服务外,还包括网络和块存储服务。

用户可以选择在哪个可用区启动实例。因此,监控每个可用区的计算资源使用情况至关重要。这将确保在需要时,每个可用区能够容纳更多的计算资源分配,同时确保用户可以在不同的区域间跨多个计算节点启动工作负载。

主机聚合

与可用区(Availability Zones)概念不同,主机聚合策略将计算节点基于更精细的硬件配置类别(定义为元数据)进行分组。这种分组可以基于特性定义,例如虚拟化管理程序(hypervisor)、存储类型、CPU 架构、网络速度等。云运营商应通过将一组元数据附加到选定的计算节点,提前创建不同的主机聚合。这样,用户可以通过选择响应工作负载需求的主机聚合来启动实例。元数据可以根据大量硬件规格创建,这取决于私有云运营商购买的硬件。例如,聚合可以为优化的磁盘主机组进行配置,基于 SSD、GPU 架构、高性能网络能力,甚至通过为单个租户聚合计算节点进行配置。一个计算节点可以属于一个或多个主机聚合。作为最佳实践,一旦计算节点到位,列出所有不同的硬件能力并将它们按照预期的工作负载进行分组,按树状结构进行排序是非常重要的。例如,如果 HPC 工作负载被包含在云业务案例中,面向最终用户,你可能会考虑提前基于 GPU 能力创建一个主机聚合,并将其暴露给最终用户。下图展示了提供四个主机聚合的使用案例,其中一些计算节点可以是多个主机聚合的组成部分:

图 4.5 – 在多个可用区的部署中进行主机聚合

图 4.5 – 在多个可用区的部署中进行主机聚合

之前的多区域隔离计算布局涉及四个不同的主机聚合,这些聚合可以跨不同的可用区进行分布,具体如下:

  • 主机聚合 1HA_1):这涉及将一组计算节点在同一地区和可用区内进行分组,以适应需要低网络延迟性能的工作负载,如在大网络带宽和 GPU 架构下运行的 HPC 应用程序。该主机聚合中的工作负载没有高可用性作为主要要求。

  • 主机聚合 2HA_2):该聚合涉及将一组计算节点分布在两个可用区内,并且位于同一地区,以适应需要大规模分布式工作负载的工作负载,例如运行 Hadoop 或 Cassandra 的大数据处理。主机聚合的元数据包括大网络带宽、基于 SSD 的优化磁盘和内存容量。

  • 主机聚合 3HA_3):这涉及将一组计算节点分布在三个可用区内,并跨越两个区域,以适应需要最高级别可用性和可扩展性的关键工作负载,例如 Web 应用程序和电子商务网站。元数据描述了适中的网络带宽、磁盘、内存和 CPU 标准能力。

  • 主机聚合 4HA_4):这涉及将一组计算节点组合在同一区域和可用性区域内,以容纳在 VSphere 环境中需要增强网络能力的工作负载。主机聚合的元数据包括配置为超虚拟化平台的 VMware,用以扩展现有的 VCenter 环境,并在 VMware 主机(运行 nova-compute 服务)之间分配应用负载。

本章稍后我们将演示,如何通过主机聚合方法、Placement 服务和 Nova 调度的结合,揭示出多种方式以最有效的方式为云用户托管不同类型的工作负载。

单元

OpenStack 中的单元概念主要是为了解决在单一 OpenStack 区域内大规模 Nova 部署的性能瓶颈。大量计算节点会增加主控制平面服务的负载,包括消息队列和数据库,导致性能下降,从而限制整个系统的扩展性。通过使用单元方法,可以解决 Nova 计算资源大规模部署的性能下降问题:计算节点可以在逻辑边界内进行分组,每个组都运行自己的数据库和消息队列服务。单元架构已经经历了不同的阶段,最终形成了两个版本:CellV1CellV2。CellV1 是第一个版本,由于存在一些问题,未被广泛实施。自 OpenStack Ocata 发布以来,推出了 CellV2 版本,对前一版本进行了增强,并成为 Pike 版本中的正式版本。接下来我们将讨论这两个版本之间的主要区别。

CellV1

形成每个单元的计算节点的逻辑分组以树形结构安排,其中顶层单元称为根单元,它运行nova-api服务。第二层单元运行 Nova 计算服务,称为子单元,如下图所示:

图 4.6 – OpenStack 计算 CellV1 部署

图 4.6 – OpenStack 计算 CellV1 部署

运行 Nova API 和 Nova 计算的单元之间的交互通过专用消息队列进行,使用由一个单独的 Nova 服务 nova-cell 处理的 RPC 调用(这是 CellV1 在 Juno 发布中引入的一项重大增强)。每个单元都运行自己的消息队列进行交互同步,并由 nova-cell 用来选择在哪个单元中启动实例。这提供了更高层次的实例调度,但仅限于单元级别。一旦选择了单元,那个单元中的 nova-scheduler 服务将处理请求工作流的其余部分,以选择一个计算节点。

CellV2

初始的单元格版本经历了实验阶段,并未在大多数大型计算部署中成功采用。这主要是由于从单元格选择到所选单元格中的计算调度服务的多层次调度,以创建实例的复杂性。图 4 .6 展示了一个由根单元格和子单元格组成的简单树形结构,但其他更广泛的部署可能会采用更多的子单元格,称为 孙子 单元格。第一个版本的另一个主要缺点是需要在单元格之间映射和同步的数据量(实例和计算节点信息),导致单元格之间发生繁重的数据复制过程。新的版本,称为 CellV2,已经在 Ocata 版本中被开发并正式采纳,通过解决先前版本的缺陷,引入了重大变化,例如删除了 nova-cell 组件和整体单元格架构,这不再是类似于 CellV1 的树状结构。以下图示展示了这一变化:

图 4.7 – OpenStack 计算 CellV2 部署

图 4.7 – OpenStack 计算 CellV2 部署

通过 Nova 的第二版单元格(CellV2)对超融合虚拟化节点进行分片涉及到在多单元格部署中调度工作流的重大变化,如前图所示。一个单元格 API 运行 nova-api 服务、nova-scheduler,以及最近的 Placement 服务(Placement 服务在 Cellv1 开发中没有被引入到 OpenStack 生态系统中),以统一调度所有定义的单元格中的资源。单元格 API 暴露一个名为 nova_api 的独立数据库,包含所有全局资源的元数据,如实例规格、配额、密钥对等。在多单元格部署中,API 单元格中的指挥器(conductor)称为 nova-super-conductor,它处理所有数据库的隔离。此外,从 API 层级来看,一个特殊的单元格称为 Cell0,它不运行任何服务,仅包含名为 nova_cell0 的数据库,里面存储有关由于调度器故障而无法启动的失败实例的信息。

每个单元格(cell)管理自己的计算节点资源,并且它们之间没有任何关联。每个单元格都有自己的数据库来存储实例信息,并使用自己专用的消息队列来协调本地单元格中的 nova-conductornova-compute 服务。新的 CellV2 方法涉及以下工作流程步骤来在多单元格部署中创建新实例:

  1. nova-api(在 API 单元格中)接收 API REST 调用,并将其转发到 nova-scheduler 服务(在 API 单元格中)。

  2. nova-scheduler 联系 Placement 服务,应用其筛选器,并确定将分配给哪个计算节点。

  3. nova-api 将映射实例信息存储在其 nova_api 数据库中(instance_mappings 表)。

  4. nova-api 将选定的计算节点记录存储在目标 cell 的数据库中(例如,如果选定的计算节点位于 Cell01,则为 nova_cell01)。

  5. nova-apinova-super-conductor 发送 RPC 调用以构建实例。

  6. nova-super-conductor 向目标 cell 中的 nova-conductor 发起 RPC 调用,通过计算服务启动实例。

CellV2 架构与最初的 CellV1 架构发生了显著变化,去除了额外的调度层,并将数据划分到多个数据库中,而不是为每个请求进行复制过程。这样,扩展一个 cell 范围以迎接更多计算主机变得更加容易,而无需像 CellV1 中那样每个 cell 都经历整个同步过程。此外,新的 cell 架构简单,因为所有的 cell 都是平等的,使得整个多 cell 部署呈现平面结构(仅有两层),与之前基于树状结构的版本不同。一旦 cell 的逻辑布局设计完成并准备好部署,操作员只需选择将哪些虚拟机监控节点与哪些 cell 关联。与主机聚合、区域和可用区不同,用户并不需要了解 cell 的概念,因为 cell 策略主要是为了帮助云操作员在扩展大规模计算环境时提供最佳的管理和性能提升。

工作负载隔离

Nova 服务的最新功能通过区域、可用区、主机聚合和 cell 概念提供了不同的策略,以解锁一个完全可扩展的 OpenStack 计算基础设施。要全面了解大型部署,采用这些方法中的一种或多种将需要定义一个调度器元素来调度特定集的虚拟机监控主机上的实例。在实例启动过程中,nova-scheduler 服务发挥着核心作用,决定一个实例将被放置在哪个主机上。如 第一章第三章 中所强调,最新的 OpenStack 版本都带有 Placement 服务,该服务在 Newton 版本中首次引入。Placement 服务与 Nova 调度器协同工作,为更先进、更精细的主机预过滤选择过程提供支持。为了充分利用上一节中定义的隔离方法,必须快速了解不同的计算调度方法,这些方法需要考虑到你在 OpenStack 部署中的整体计算隔离策略。

预过滤

设置一个专门的 Placement 服务,与 Nova 调度器一起运行,主要目的是解决大规模计算部署中的困境。在引入 Placement 服务之前,Nova 调度器必须遍历整个大规模部署中的所有计算农场,包括启用的过滤器,导致效率低下和性能问题。此外,由于 Nova 在计算资源的详细数量和库存使用方面的基本功能,计算节点报告的资源总和缺乏准确性。

随着 Placement 服务的出现,资源报告的逻辑发生了变化,通过在计算节点中添加 resource_tracker 组件,计算节点将其库存和可用资源报告给 Placement 服务,后者定期存储报告资源的完整同步。正如在 第三章 中详细描述的那样,OpenStack 控制平面 – 共享服务,Placement 服务通过定义 资源提供者traits 来应用预过滤器,以便在 nova-scheduler 联系时对计算节点列表进行处理。在后台,nova-scheduler 通过传递不同的调度参数(如 VCPUDISK_GBMEMORY_MBVGPU)通过 GET API 请求调用 placement-api 服务。这些请求将在 placement-api 层转化为 trait 请求。

资源提供者分配

如在第一章第三章中回顾的那样,Placement 服务由 nova-scheduler 使用,用于在评估候选节点之前,根据特定属性列出一组经过预过滤的计算节点,如下图所示:

图 4.8 – OpenStack 计算资源分配工作流

图 4.8 – OpenStack 计算资源分配工作流

nova-api 服务接收到用户请求创建新实例时,nova-scheduler 将向 placement-api 服务发出 GET /allocation_candidates() 请求。allocation_candidates 方法是一个资源提供者集合,根据请求中封装的属性分配资源。一个示例 API GET 请求使用以下格式作为筛选条件,以嵌入启动实例所需的资源:

GET/placement/allocation_candidates?resources=DISK_GB:500,MEMORY_MB:2048,VCPU:4

根据先前的请求,placement-api 服务将获取符合要求的主机,这些主机将容纳实例规格:500 GB 磁盘容量、2048 MB 内存和 4 个 vCPU。

前面的请求可以通过在请求字符串的末尾添加 &required 查询参数,扩展为根据资源特征进行筛选,因此分配查询将如下所示:

GET/placement/allocation_candidates?resources=DISK_GB:500,MEMORY_MB:2048,VCPU:4 &required=HW_CPU_X86_SVM

这样,placement-api 服务将结合所需的资源属性和额外的特征,筛选出支持 X86_SVM 架构 CPU 的主机。

通常,云运营商可以使用 OpenStack CLI 通过allocation candidate命令行来处理定位配置,如以下示例所示:

# openstack allocation candidate list --resource VCPU=4, 
MEMORY_ MB=2048,DISK_GB=500GB --required   HW_CPU_X86_SVM

这是输出:

图 4.9 – 注册分配的定位详情

图 4.9 – 注册分配的定位详情

影响后续调度器预过滤过程逻辑的主要参数是allocation_requestsprovider_summaries。这些对象由placement-api服务返回给nova-scheduler服务,以两种类型的对象以 JSON 格式列出,数据结构如下:

  • allocation_requests:一个资源提供者列表,用于满足分配请求:

    "allocation_requests": [
            {
                "allocations": {
                    "ad54422c-b345-5v44-ba23-00cad76e376a": {
                        "resources": {
                            "DISK_GB": 500
                        }
                    },
                    "652f6729-cd55-4747-91a1-543adfeea2a": {
                        "resources": {
                            "VCPU": 4,
                            "MEMORY_MB": 2048
                        }
                    }
                }
            },
    ...
    
  • provider_summaries:满足分配请求的所有资源提供者的总资源和信息使用情况:

    ...
    "provider_summaries": {
            "ad54422c-b345-5v44-ba23-00cad76e376a": {
                "resources": {
                    "DISK_GB": {
                        "used": 0,
                        "capacity": 2000
                    }
                },
                "traits": ["SRG_SHARES_STORE"],
                "parent_provider_uuid": null,
                "root_provider_uuid": 
                  "ad54422c-b345-5v44-ba23- 00cad76e376a"
            },
            "652f6729-cd55-4747-91a1-543adfeea2a ": {
                "resources": {
                    "VCPU": {
                        "used": 0,
                        "capacity": 244
                    },
                    "MEMORY_MB": {
                        "used": 0,
                        "capacity": 192604
                    }
                },
                "traits": ["HW_CPU_X86_SVM", "HW_CPU_X86_SSE2"],
                "parent_provider_uuid": null,
                "root_provider_uuid": 
                  "652f6729-cd55-4747-91a1-543adfeea2a"
            },
    ...
    

JSON 格式的provider_summaries对象输出包括与资源提供者关联的特性。前面的输出示例显示了一个计算节点 UUID 为52f6729-cd55-4747-91a1-543adfeea2a的资源提供者,并标注了支持HW_CPU_X86_SVMHW_CPU_X86_SSE2 CPU 架构的特性类。

过滤

一旦placement-api服务将候选主机列表返回给nova-scheduler服务,后者会根据 Nova 服务中预配置的过滤器执行多种过滤操作。可以通过调整enabled_filters选项配置/etc/nova/nova.conf文件,以运行一个或多个调度器。

重要说明

kolla-ansible仓库中的调度器过滤器可以在filter_scheduler部分进行配置,位于/kolla-ansible/ansible/roles/nova/templates/nova.conf.j2文件中。

一些在调度器中默认配置和支持的常见过滤器如下:

  • ComputeFilter:返回一个完全可操作的超管主机列表,默认情况下应启用。

  • ComputeCapabilitiesFilter:返回能够启动具有请求规格实例的超管主机列表。例如,额外的规格可能包括验证运行 KVM 超管的计算主机。

  • ImagePropertiesFilter:返回符合实例镜像中定义的期望镜像属性的超管主机列表。镜像属性可以根据硬件架构或超管类型添加。例如,启动一个实例需要一个可以在支持 KVM 作为超管的主机上运行的镜像:

    # openstack image set --property img_hv_type=kvm img-uuid
    

重要说明

Liberty 版本的一个主要更新是图像属性被传递到筛选器进行检查。新的支持属性包括 hw_architecture(之前称为 architecture),它定义了硬件架构;img_hv_type(之前称为 hypervisor_type),它描述了超算类型;img_hv_requested_version(之前称为 hypervisor_version_requires),它定义了所需的超算版本;以及 hw_vm_mode(之前称为 vm_mode),它指的是超算应用二进制接口。

  • ServerGroupAntiAffinityFilter:该筛选器将同一组的实例调度到不同的超算主机。一个常见的使用场景是启动运行相同工作负载且需要额外高可用性的实例。要使用反亲和力策略创建服务器组,请在 Nova 命令行工具中使用 --hint 标志,如下所示:

    # openstack server group create --policy anti-affinity 
    pp_webgroup
    # openstack server create --image "Ubuntu 22.04" --hint group=122ee342-3345-2234-bac4-1515321e1ebb --flavor 5 "instance 01"
    # openstack server create --image "Ubuntu 22.04" --hint group=122ee342-3345-2234-bac4-1515321e1ebb --flavor 5 "instance 02"
    

    上述命令的结果将确保 instance 01instance 02 是同一个应用服务器组 pp_webgroup 的一部分,并且具有 122ee342-3345-2234-bac4-1515321e1ebb UUID,并将在不同的计算节点上运行。

    • ServerGroupAffinityFilter:该筛选器将实例调度到已经运行某个亲和力服务器组的相同超算主机。建议使用亲和力调度器筛选器来运行需要最高性能和低延迟的工作负载。要使用亲和力策略创建服务器组,请在 Nova 命令行工具中使用 --hint 标志,如下所示:

      # nova server-group-create --policy affinity pp_perfgroup
      # nova boot --image "Ubuntu 22.04" –hint group=44ee217-5543-9871-cda3-1e57522ecde1 --flavor 5 "instance 01"
      # nova boot --image "Ubuntu 22.04" –hint group=4ee217-5543-9871-cda3-1e57522ecde1 --flavor 5 "instance 02"
      

    上述命令的结果将确保 instance 01instance 02,它们是同一个应用服务器组 pp_perfgroup 的一部分,并且具有 144ee217-5543-9871-cda3-1e57522ecde1 UUID,将运行在同一计算节点上。

OpenStack 调度支持其他筛选器,并且在 OpenStack 的最新版本中包含了更多细粒度和自定义的选项。在撰写本版本时,最新的筛选器和配置的完整列表可以在docs.openstack.org/nova/latest/admin/scheduling.html#filters找到。

加权

加权是调度过程的最后阶段,在此阶段,nova-scheduler 服务会对从通过所有分配过滤器的放置中选择的每个候选主机进行评分。调度器将在最后阶段选择具有最高权重的计算节点。表面上看,加权逻辑似乎不复杂,但实际上需要考虑额外的因素。计算节点的度量值会定期监控并输入到数据库中,以跟踪主机的使用情况和资源声明。加权过程使用这些信息作为因素,并通过将每个计算节点的值标准化到 0.01.0 之间来计算权重。具有最多可用资源的计算节点(如监控所报告的)将被赋予最大值 1 ,而具有最少可用资源的计算节点将被赋予最小值 0

标准化因子是根据可用资源使用以下公式计算的:

(host_availability_resource - min_value_all)/(max_value_all – min_value_all)

这里,适用以下规则:

  • host_availability_resource 是计算节点中可用资源的值

  • min_value_all 是所有计算节点中资源的最小值

  • max_value_all 是所有计算节点中资源的最大值

函数的第二步是将每个可用资源的每个计算节点的标准化值与相关的加权乘数相乘。在加权过程结束时,调度器将汇总所有标准化的权重,并选择得分最高的计算节点,概括如下:

Σ (weight(i)*norm_factor)

这里,适用以下规则:

  • weight(i) 是资源 i 的相关权重乘数

  • norm_factor 是为每个计算节点分配的标准化权重因子

以下示例通过计算五个计算节点中可用的 RAM 容量和 CPU 的标准化因子和权重来说明加权过程。该图展示了第一个节点子集大小(子集 1)– 这是 Nova 调度器通过过滤器评估的第一个主机列表,具体如下:

图 4.10 – OpenStack 计算加权机制

图 4.10 – OpenStack 计算加权机制

然后,调度器运行加权机制,并根据加权评分生成最合适的虚拟化主机,具体如下:

  • 节点 A 和 D 容纳了最高的 RAM 容量,并被赋予最大权重,标准化为 1 。权重成本表示为 100 (1 乘以 100)。

  • 节点 B 和 C 拥有最小的 RAM 容量,且其标准化后的权重为 0 。权重成本表示为 0 (0 乘以 100)。

  • 节点 E 通过将先前的公式应用于计算归一化因子来分配归一化权重为 0.4,计算如下:(350 - 250) / (500 - 250)。权重成本表示为 40(0.4 乘以 100)。

  • 主机 A 和 D 容纳最多的 CPU 数量,并分配了最大的权重,归一化为 1 。权重成本表示为 100(1 乘以 100)。

  • 节点 C 具有最少的 CPU 容量,并分配了最小的权重,归一化为 0 。权重成本表示为 0(0 乘以 100)。

  • 节点 B 和 E 通过将先前的公式应用于计算归一化因子来分配归一化权重为 0.5,计算如下:(10 - 5) / (20 - 10)。权重成本表示为 50(0.5 乘以 100)。

  • 每个主机的最终权重计算方式是将每个 CPU 和 RAM 资源的权重成本相加,如下所示:主机 A(100 + 100),主机 B(0 + 50),主机 C(0 + 0),主机 D(100 + 100)和主机 E(40 + 50)。

在本例中,主机 A 和 D 均赢得了权重投标,调度程序将从第二个节点子集中随机选择一个来启动实例。资源可用性将反映在数据库中,并且调度程序将在每个新实例创建请求上相应地更新权重。

计算服务中引入的附加选项可以在管理和分发计算农场中的工作负载需求时非常方便。默认情况下,调度程序通过在可用主机之间分配实例来分散资源。在其他一些情况下,分派具有不同规格和大小的多个实例会在分配资源时创建并发问题,并因此阻止启动一部分实例。调度权重策略可以调整为使用 堆叠 方法。在这种情况下,实例将分配给第一个经过过滤的主机,直到其所有资源完全耗尽,然后再移动到下一个主机。堆叠方法的一个良好示例是服务器关联配置和权重机制的结合。

要在部署中自定义权重机制,请确保在 / etc/nova/nova.conf 文件中应用以下配置:

  1. 通过设置 compute_monitors 参数在计算节点上启用监控以收集 CPU 指标:

    compute_monitors = cpu.virt_driver
    
  2. 启用 weights.all_weighers 类:

    weight_classes = nova.scheduler.weights.all_weighers
    
  3. 将主机子集大小设置为 1 。通过将主机子集大小设置为 1 来调整调度程序以选择具有最高权重的主机:

    host_subset_size = 1
    
  4. 调整权重乘数为 1 。这样,新实例的启动将在计算节点之间均匀分布:

    weight_multiplier = 1.0
    
  5. 调整 RAM 权重乘数为 1 。这样,将在具有空闲内存的计算节点之间均匀分布新实例的启动:

    ram_weight_multiplier = 1.0
    

重要说明

将加权乘数设置为1.0将使资源分配均匀分布在所有可用的筛选主机上。如果首选堆叠选项,则将权重乘数的关联值设置为-1

  1. 添加一个新的乘数来计算加权主机 I/O 操作。通过将权重乘数设置为1.0,指示 Nova 以最少 I/O CPU 指标均匀使用活动主机,如下所示:

    io_ops_weight_multiplier = 1.0
    
  2. 在控制节点和每个计算节点上重新启动nova-schedulernova-compute服务,以应用更改:

    # service nova-compute restart
    # service nova-scheduler restart
    

重要提示

kolla-ansible 仓库默认情况下不提供 Nova 加权策略的低级配置。可以通过添加前述配置行,调整位于/kolla-ansible/ansible/roles/nova/templates/nova.conf.j2nova.conf模板文件。还建议查看最新支持的nova.conf 设置,具体内容请参见此处的最新版本:docs.openstack.org/nova/latest/configuration/sample-config.html

OpenStack Bobcat 版本引入了一个新的调度器权重计算器,NumInstancesWeigher,该计算器有助于根据每个计算节点托管的活动实例数量来调度实例。如前面的示例所示,将乘数值设置为1将启用打包策略,优先选择具有最多活动实例的主机。将值设置为-1则会优先选择分布策略,选择活动实例最少的主机。有关不同权重计算器的完整列表,请参见 docs.openstack.org/nova/latest/admin/scheduling.html#weights

为容器扩展计算能力

自 2014 年以来,OpenStack 社区一直在围绕容器化技术开发其他项目,允许云用户利用不同的服务集在计算服务之上运行应用程序。最成熟且正在生产环境中使用的服务是MagnumZun,我们接下来将介绍这两个服务。

Magnum

运行容器化环境的主要动机是以最小的配置复杂度运行和部署应用程序,这些应用程序便于移植且维护成本最低。运行由多个容器组成的工作负载需要一层编排来管理不同组件生命周期的逻辑,以及自动化的组件间通信。这被称为容器集群管理平台,例如MesosKubernetesDocker Swarm等。还有一些知名的公共云服务,如 AWS Elastic Container ServiceECS)、AWS Elastic Kubernetes ServiceEKS)、GCP Google Kubernetes EngineGKE)和Azure Kubernetes ServiceAKS)。在 OpenStack 世界中,Magnum 是一个已集成到 OpenStack 生态系统中的项目代号,被称为 COE。像其他 OpenStack 服务一样,Magnum 暴露一个 API 与 COE(如 Kubernetes 和 Docker Swarm)作为一等资源进行交互。容器将部署并运行在虚拟化节点上。对不同容器引擎的支持让云运维人员能够为用户提供一系列可供选择的选项,如下图所示:

图 4.11 – OpenStack Magnum 多 COE 架构

图 4.11 – OpenStack Magnum 多 COE 架构

Magnum 使用以下术语来表示每个 COE 节点集合及其关联的容器:

  • Bay:这是一组运行 COE 的节点。在 bay 的核心运行时,Magnum 调用 Heat 服务来部署 bay。Bays 只是通过 Heat 创建并编排的 Nova 实例集合,使用的镜像针对虚拟机和裸金属节点。

  • BayModel:这是一个资源集合,用于构建在简单模板中定义的 bay。一个 bay 可以使用相同的BayModel模板在不同的 COE 上运行。

  • Pod:这是在同一个 COE 节点上运行的一组容器。

  • Service:这是一个抽象,表示一组 bay 和访问策略的配置。

  • Replication controller:这是一个专门的进程,用于监控、复制、重启失败的容器,并在 COE 节点之间扩展 pods。

  • Magnum client:这是一个原生客户端,用于查询 COE,并且自带原生Docker CLI(用于 Docker COE)和kubectl(用于 Kubernetes COE)。

Magnum 成功的另一个关键因素是与其他 OpenStack 服务的良好集成,以下是相关功能:

  • Identity:这是与 Keystone 的集成,用于管理容器集群平台的身份认证和授权——例如,通过 Keystone 为用户创建 Kubernetes 角色以便在集群上执行操作任务。

  • 网络:通过支持的网络驱动程序利用 Neutron 服务——例如,Flannel覆盖网络是 Kubernetes 和 Swarm COE 的默认网络,允许多主机通信并管理每个容器池中容器的 IP 地址。

  • 镜像:为 Kubernetes 和 Swarm COE 提供了一个预构建的 Glance 镜像,可以配置并用于启动集群中的节点。

  • 存储:官方支持的存储由 Cinder 提供,作为块存储有两种形式:临时存储和持久存储选项。除了 Docker 存储驱动外,Cinder 还提供了额外的后端存储,如Rexray作为卷驱动程序。在撰写本文时,Cinder 仅支持 Swarm 的 Rexray 驱动和 Kubernetes 的默认 Cinder 驱动。

Magnum 的其他主要亮点,已启动或正在进行中的部分,概述如下:

  • 安全性:Magnum 架构是从设计上就考虑到安全性的。每个容器池(bay)都是相互隔离的,确保它们所承载的工作负载的安全性。此外,Magnum 通过防止容器池在 OpenStack 租户之间共享,实现了多租户布局。

  • 可扩展性:集群节点的扩展是通过自动调整 Heat 模板属性或通过 OpenStack COE CLI 手动完成的。请注意,容器扩展将根据 COE 的集群容器配置来决定。

  • 高可用性:在撰写本文时,Magnum 高可用性标准仅支持一个默认的可用区。计算节点组将会在同一个逻辑可用区中启动。OpenStack 社区正在考虑在未来版本中将 Magnum 集群节点的范围扩展到更多的多可用区。

自 Liberty 版本以来,Magnum 服务因其支持多种 COE(容器编排引擎)和逐步成熟而获得了许多赞誉,这些可以在数十个生产工作负载中看到。该服务使得工程和架构团队能够迁移到基于微服务的架构,而无需重新设计和重新集成现有的容器工具集。其他增强功能已被捕获,用户可以通过查看docs.openstack.org/magnum/latest/上的发布更新来了解。

在当前的kolla-ansible基础设施代码库中,Magnum 服务默认未启用。通过在/kolla-ansible/etc/kolla/globals.yml文件中将enable_magnum设置为yes,可以启用 Magnum API 服务。请确保更新上一章节中创建的库存文件/ansible/inventory/multi_packtpub,通过在控制节点中添加 Magnum 服务,包括magnum-apimagnum-conductor服务,如以下配置代码所示:

…
[magnum:children]
control
[magnum-api:children]
magnum
[magnum-conductor:children]
magnum
…

重要说明

更多 Magnum 配置选项列在 Ansible 剧本中,位于 /kolla-ansible/ansible/roles/magnum/default/main.yml 文件下。此外,Horizon 支持 Magnum 面板,但默认情况下是禁用的,可以通过在 /kolla-ansible/etc/kolla/globals.yml 文件中将 enable_horizon_magnum 设置为 yes 来启用。

更新两个文件后,运行 CI/CD 流水线以推出 Magnum Ansible 剧本,并将 Magnum 服务容器作为 OpenStack 环境中的控制平面一部分提供。

Zun

除了 Magnum 服务及其多种容器编排支持选项外,还有 Zun 服务——这是一个非常简单的服务,可以快速在 OpenStack 中运行容器,无需管理或部署基于 Kubernetes Pods 或 Docker Swarm 集群的容器编排环境。你只需运行一个 Zun 命令行来创建任何类型的容器,针对任何 Docker 仓库运行工作负载。为了消除 Magnum 和 Zun 用例之间的混淆,Zun 专注于通过 OpenStack 直接管理和操作容器,而无需与额外的编排工具层(如 Kubernetes 或 Swarm)交互,这与 Magnum 服务不同。另一个可能的混淆源是 Zun 与前 OpenStack 容器发起者 nova-docker 服务之间的区别。虽然 nova-docker 依赖 Nova API 服务来管理容器,但 Zun 独立于 Nova API,并利用其功能齐全的 API 接口来创建和操作容器。Zun 服务与多个灵活的 OpenStack 服务紧密集成,包括 Nova、Glance、Keystone、Neutron、Cinder、Ceilometer 和 Magnum,如下图所示:

图 4.12 – OpenStack Zun 计算集成

图 4.12 – OpenStack Zun 计算集成

图 4 .12 展示了 Zun 计算与 Neutron 和 Cinder 并行运行的另外两个服务,分别总结如下:

  • Kuryr:它与 Neutron 集成,通过 libnetwork 提供容器的高级网络功能。

  • Fuxi:它利用 Docker API 来管理由 Cinder 和 Manila 存储服务支持的卷。

当前 kolla-ansible 基础设施代码库中默认未启用 Zun 服务。要启用该服务,需在 /kolla-ansible/etc/kolla/globals.yml 文件中调整以下设置:

...
enable_zun: "yes"
enable_kuryr: "yes"
enable_etcd: "yes"
docker_configure_for_zun: "yes"
containerd_configure_for_zun: "yes"
...

确保通过在前一章节中创建的清单文件 /ansible/inventory/multi_packtpub 中添加 Zun 服务,包括 zun-api 和可选的 zun-wsproxy,将其作为控制平面的一部分更新,如下所示:

…
[zun:children]
control
[zun-api:children]
zun
[zun-wsproxy:children]
zun

zun-compute 和可选的 zun-cni-daemon 服务可以作为计算节点的一部分添加,如下所示:

...
[zun-compute:children]
compute
[zun-cni-daemon:children]
compute
…

重要提示

更多 Zun 配置选项列在 Ansible 剧本中的 /kolla-ansible/ansible/roles/zun/default/main.yml 文件中。此外,Horizon 支持仪表板中的 Magnum 面板,默认情况下该面板被禁用,可以通过在 /kolla-ansible/etc/kolla/globals.yml 文件中将 enable_horizon_zun 设置为 yes 来启用它。

一旦更新了这两个文件,运行 CI/CD 管道来部署 Magnum Ansible 剧本。Zun 服务及其相关进程将作为 OpenStack 环境控制平面的一部分在容器中启动。

重要说明

确保etcd守护进程在控制节点上运行。同样,确保 Docker 运行时和kuryr-libnetwork在计算节点上正确安装。

检查 Zun 服务是否可以通过 Zun 服务列表命令行执行:

$ openstack appcontainer service list

Zun 容器应在计算节点上创建。要列出已注册的 Zun 计算节点,请使用以下命令行:

$ openstack appcontainer create --name container_pp_zun cirros

使用 Zun CLI 创建容器是直接的。默认情况下,可以使用Docker Hub来拉取镜像并快速在指定的计算节点上运行容器。以下示例命令行使用 CirrOS 镜像创建一个 Zun 容器:

$ zun create --name container_pp_zun cirros

Zun 带来的一个令人惊叹的实操特性是通过使用原生 Docker API 或 Zun API 本身来灵活管理容器生命周期。例如,附加终端到正在运行的容器,可以通过运行 openstack appcontainer attach <container_name> 来执行,类似于执行 docker attach 命令行。

扩展计算农场

通过kolla-ansible管理计算集群 hypervisors 以生成实例或容器非常简单。在收集计算需求、硬件容量、工作负载类型和调度策略后,可以在不产生复杂操作开销的情况下即时执行计算节点的添加。应考虑的主要要求是列出计算服务,主要是nova-compute和网络插件代理,以提供与控制平面的连接性,并与nova-scheduler同步以进行每个资源分配。前一节展示了其他组件可以作为计算节点的一部分,包括 Zun 计算服务,如果您计划为最终用户提供一个简单快速的容器游乐场。通过kolla-ansible从代码管理计算节点的另一个方面是列出计算服务的可用配置选项,例如第一章重新访问 OpenStack - 设计考虑中涵盖的 CPU 和内存超额配额。由于可能部署具有不同配置的多个计算节点,kolla-ansible提供了定制计算服务配置并使用/etc/kolla/globals.yml文件中定义的全局配置覆盖配置的方法。以下示例将指导 Kolla 添加名为cn02.os.packtpub的新计算主机(24 个 CPU 和 255 GB 的 RAM),具有支持 QEMU 作为 hypervisor 的自定义配置,并分别具有 CPU 和 RAM 超额配额比例为8.04.0

  1. 首先,在清单文件中填写主机名:

    …
    [compute]
    …
    cn02.os.packtpub
    
  2. /etc/kolla/config/nova/cn02.os.packtpub/下创建一个新的nova.conf文件。Kolla 会查找/etc/kolla/下的任何可能的配置文件。如果找到一个配置文件,Kolla 将使用单独文件中提供的自定义设置覆盖和合并全局配置。请注意,您需要在kolla-ansible存储库中创建路径目录,包括计算节点的主机名,遵循/etc/kolla/config/nova/COMPUTE_HOSTNAME/nova.conf格式,其中COMPUTE_HOSTNAME是计算节点的主机名。

  3. 编辑新创建的nova.conf文件,通过在新的部分中分别添加8.04.0的 CPU 和 RAM 分配比例值:

    [DEFAULT]
    cpu_allocation_ratio = 8.0
    ram_allocation_ratio = 4.0
    
  4. 将所需的qemu hypervisor 添加到同一文件以在新的计算节点上运行:

    ...
    [libvirt]
    virt_type=qemu
    cpu_mode = none
    
  5. 可以通过强制一组过滤器来覆盖默认调度程序,并使用ComputeCapabilitiesFilter过滤器来使用具有超过 250,000 MB 总可用 RAM 的任何主机:

    ...
    [filter_scheduler]
    enabled_filters = ComputeFilter,ComputeCapabilitiesFilter,
    ImagePropertiesFilter,ServerGroupAntiAffinityFilter,
    ServerGroupAffinityFilter
    
  6. 可选地,您可以通过在同一主机上堆叠具有定义规格的实例来使用 RAM 筛选策略。这样,您可以确保计算节点恰好容纳一个定义数量的实例和特定规格,这样您就能提前预测。通过这种方式,250 GB 的内存可以被充分利用,不会留下任何小的空闲区域,否则这些空闲区域将无法使用。此时,采用的策略是堆叠策略,通过在同一个custom nova.conf文件中定义负权重乘数,如下所示:

    ...
    weight_classes nova.scheduler.weights.all_weighers
    ram_weight_multiplier -1.0
    
  7. 使用您的 CI/CD 管道,在将代码合并到生产分支之前,触发运行作业以在暂存环境中部署代码,正如前几章所展示的那样。部署阶段应该在新的计算节点中配置新的额外 Kolla 容器,并开始与控制平面同步。

  8. 一个受到本章所述筛选策略启发的资源分配示例,以及第一章,《重新审视 OpenStack – 设计考虑因素》,是将特定规格的实例分派到专用的计算节点。例如,云操作员会使用步骤 5 中描述的调度器过滤器,只为中等大小的分配请求配置实例。为了使该策略生效,请在控制节点中运行以下命令行:

    $ openstack flavor set m1.medium --property total_usable_ram_mb=">= 250000"
    

    启用的ComputeCapabilitiesFilter过滤器应匹配任何计算节点的属性与规格,依据其可用的内存属性为特定实例规格进行定义。如果第一个计算节点的可用内存低于 250 GB,则调度器很可能会将m1.medium规格的新实例请求分派到刚刚加入计算节点集群的新的计算节点。

在完成前述步骤后,一个新的计算节点应加入 OpenStack 计算集群,并基于过滤和加权机制配置了高级调度。任何新的计算请求,只要m1.medium规格的内存至少为 250 GB,就会在新的计算节点上启动。

摘要

在本章中,我们探讨了 Nova 服务带来的一些强大功能和附加特性。你应该已经了解了计算服务中最新更新所提供的广泛选择——从支持的虚拟化技术种类,到计算和工作负载隔离,再到过滤的艺术。调度是 OpenStack 中的一个关键要素,云操作员在处理日益增长的基础设施和高资源需求时,应该特别关注这一点。尽管我们没有涵盖所有可能的场景,但过滤机制是在 Nova 项目的早期就被引入的,本章展示了超出有限范围部署计算能力的扩展功能如今已经成为可能。感谢新版本的成熟 Nova CellV2,主机聚合和可用区概念使得大规模部署成为可能,前提是规划和设计得当,正如我们所学的那样。在本章的最后,我们讨论了作为 OpenStack 生态系统中流行容器项目的 Magnum 和 Zun。我们了解到,云用户可以使用 Magnum 作为 COE,运行原生容器应用程序,并且 Zun 作为与 OpenStack 生态系统周围不同核心服务高度集成的简单容器 API。此外,我们还学到,采用微服务原型和运行原生云应用程序不再是 OpenStack 用户的挑战。随着这些服务的不断发展,企业可以在私有云和公有云之间采用混合环境,这不仅得益于容器的可移植性和灵活性,还因为 OpenStack 已经证明了它能够在容器竞赛中与其他公有云厂商竞争。我们在本章中讨论了这一点。

Nova 并不是唯一一个经历更新的服务。包括文件共享、块存储和对象存储在内的存储服务也通过附加功能得到了增强,我们将在下一章中进行讲解。

第五章:5

OpenStack 存储 – 块存储、对象存储和文件共享

“毅力是所有胜利的秘诀。”

– 维克多·雨果

OpenStack 服务的广泛采用增加了用户需求,从而也扩展了其功能,正如上一章中对计算服务的展示那样。这种功能的变化也扩展了 OpenStack 的存储服务。运行工作负载的用户除了需要一个强大可靠的开箱即用的存储解决方案外,还需要多种存储类型。软件定义存储SDS)方法的推广使得 OpenStack 社区能够采纳更多的存储项目,其中数据存储已从物理存储中抽象出来。存储系统可以建立在通用硬件之上,但这需要对每个存储项目的目的和背后的架构有充分的了解,然后才能将该服务暴露给云用户,以便他们运行工作负载。

本章将讨论并启用在现有 OpenStack 环境中的大量存储服务。在本章中,我们将涵盖以下主题:

  • 回顾 OpenStack 中的 Cinder 块存储服务

  • 通过配置三个最常用的驱动后端,使用 Kolla-Ansible 来扩展块存储设置,包括 LVM、NFS 和 Ceph

  • 揭示 Cinder 中的调度状态并在现有集群中启用加权机制

  • 讨论 OpenStack 中的 Swift 对象存储服务

  • 使用 kolla-ansible 部署对象存储集群

  • 探索最新的文件共享服务 Manila 更新

  • 集成 Manila 服务并使用 kolla-ansible 部署它

定义块存储 – Cinder

Cinder 为实例提供持久存储。块存储服务通过每个 OpenStack 版本的更新得到了广泛发展,以支持更多的功能和厂商的后端驱动程序,从而支持多种存储设备的使用。常用的存储后端包括 逻辑卷管理LVM)、IBM 存储驱动程序、NetApp 和 Dell 存储。在最新的 OpenStack 版本中,支持了新的后端驱动程序,如 Yadro、TOYOU 和 Pure Storage FlashArray。

存储设备通过 Cinder 的管理访问 API 访问,并提供对实例的直接访问,以便访问和附加卷。附加到实例的卷显示为一个额外的硬盘,可以分区并挂载到虚拟机的文件系统上。卷通常通过定义的存储路径进行访问,可以使用 iSCSI、NFS 和光纤通道等方式。需要记住的是,块存储是持久化的,这意味着当实例终止时不会丢失数据,这与临时磁盘不同。

在我们的多节点环境布局中,Cinder 服务的最新新颖性可以如下所示:

图 5.1 – 块存储核心架构

图 5.1 – 块存储核心架构。

核心 Cinder 组件可以总结如下:

  • cinder-api:处理块存储 REST API 请求和响应。

  • cinder-scheduler:像计算服务中的nova-scheduler一样,它在过滤步骤后将请求重定向到适当的cinder-volume 服务器,该服务器将处理并配置请求的卷。

  • cinder-volume:作为一个卷管理器,并在每个存储节点上运行。

  • cinder-backup:启用将卷备份到不同存储系统的功能。

默认的 OpenStack 部署将配备基于 LVM 的块存储后端。另一个非常常见的后端使用场景是网络文件系统NFS),它利用现有的共享存储。在这种情况下,唯一需要做的就是配置 Cinder 服务,使其能够使用 NFS 驱动程序。通过查看 Cinder 驱动程序功能矩阵,确保了解最新支持的后端驱动程序,具体内容请参见:docs.openstack.org/cinder/latest/reference/support-matrix.html

驱动程序的存储后端应支持最基本的卷功能,如卷附加、分离、创建、删除、扩展、迁移以及从卷创建镜像。驱动程序还应提供快照管理功能,如创建、删除以及从快照或克隆卷创建卷。在最新的 OpenStack 版本中,可以根据每个后端驱动程序考虑更广泛的功能,这些功能在最新版本中被视为可选,如精简卷配置、实时迁移、多附加支持和服务质量QoS)。在进行完整块存储部署之前,请确保扫描现有存储后端并在矩阵中反映支持的功能。

除了前述驱动程序的功能外,Cinder 还支持各种可配置的驱动程序,适用于不同的存储厂商,如 NetApp、IBM、VMware、Dell 和 Synology。请记住,并非所有后端产品都支持所有 Cinder 驱动程序功能。另一方面,前述的 Cinder 操作被视为在将新驱动存储后端包括到 Cinder 代码中时的必备项

块存储的安全性也通过更详细的关于传输中和静态加密的内容进行了调整。Antelope 版本支持大多数 Cinder 驱动程序的 TLS,这是旧版本中安全团队处理来自不同服务端点以及终端用户发起的流量时的一个障碍。静态加密也达到了一个里程碑,允许使用 Cinder API 对卷中的数据进行加密。

另一个最近的 Cinder 增强功能是块存储备份功能。只需发出一个命令行,指示 Cinder 执行卷的完全备份或增量备份(如果备份已存在),变得更加简单。

使用多个后端扩展存储

我们的初始部署突出了使用专用节点来处理 OpenStack 环境中的存储和卷管理。在接下来的部分中,我们将扩展初始部署,详细介绍 第二章以正确的方式启动 OpenStack 设置 – DevSecOps。根据使用的存储后端,可能会有额外的节点专门用于托管 Cinder 卷,作为数据平面的一部分。云控制器节点托管 Cinder API 和调度服务。

使用 LVM 部署

OpenStack 的默认块存储后端是 LVM。cinder-volume 服务使用 iSCSI 目标来操作和管理存储节点中逻辑卷的访问。

在存储节点上,我们将创建一个 LVM 物理卷组。在本示例中,我们假设 /dev/sdb 是目标存储节点上可用的块设备:

$ pvcreate /dev/sdb

重要说明

根据操作系统的不同,磁盘分区的名称可能会有所不同。你可以通过使用 fdisk 命令行工具检查这些名称。

接下来,创建一个名为 cinder-volumes 的新卷组:

$ vgcreate –f cinder-volumes /dev/sdb

kolla-ansible 代码库中,将新存储主机名添加到位于 /ansible/inventory 中的库存文件 multi_packtpub_prod。在此示例中,我们将使用 storage02.os 存储节点:

…
[storage]
storage02.os.packtpub
[cinder-volume:children]
storage
…

/ etc/kolla/globals.yml 文件中启用 LVM 后端:

…
enable_cinder_backend_lvm: "yes"
…

重要说明

启用 LVM 后端后,kolla-ansible 激活了 Ubuntu 操作系统自带的 iSCSI 模块,并且在 Cinder 角色中默认配置,该角色位于 /kolla-ansible/ansible/roles/cinder/defaults/main.yml 文件中。对于 CentOS 发行版,确保提前安装了 LioAdm iSCSI 目标助手。

/ etc/kolla/globals.yml 文件中配置之前创建的 Cinder 卷组的名称:

…
cinder_volume_group: "cinder-volumes"
…

在将额外的节点提升为生产节点之前,首先在你的暂存环境中运行 CI/CD 流水线。一旦部署,目标存储节点应运行一个新的 kolla 容器,容器内运行 cinder-volume 服务。

使用 NFS 部署

NFS 是另一个常用的存储后端。在现有的 NFS 存储中,云操作员可以通过 NFS 协议平稳地管理卷。创建的共享将可用并由 cinder-volume 服务挂载到计算节点上。Cinder NFS 驱动程序使得访问共享 NFS 服务器上的文件镜像成为可能,并将文件映射为块存储提供给实例。

在以下示例中,可用的 NFS 服务器名为 nfs-host-pp,共享文件路径为 nfs-host-pp:/nfs/share/cinder

通过运行以下命令,在目标存储节点上创建共享文件:

 $ echo "nfs-host-pp:/nfs/share/cinder" > /etc/cinder/nfs_share

确保在计算节点和存储节点上都安装了 NFS 客户端。你可以使用 Ansible 或以下命令行工具来完成此操作:

 $ apt-get install nfs-common

在块存储节点中启用cinder-volume,通过调整文件权限访问共享文件:

$ chown root:cinder /etc/cinder/nfs_share
$ chmod 640 /etc/cinder/nfs_share

在 NFS 后端中,确保在/etc/exports文件中指定存储节点上的共享目录路径、存储网络和访问模式,包括共享、读写和非 root 远程用户访问:

/nfs/share/cinder 10.30.0.0/24(rw,sync,no_root_squash)

对于自定义 NFS 部署设置,您可以在/etc/kolla/config下创建一个新的配置文件,在运行kolla-ansible时会优先使用该文件。以下示例配置文件,名为nfs_shares,将包含一个目标存储节点storage02.os,并带有自定义的 NFS 挂载文件共享:

…
storage02.os:/nfs/share/cinder
…

/etc/kolla/globals.yml文件中启用 NFS 后端:

…
enable_cinder_backend_nfs: "yes"
…

在通过新的 NFS 共享配置运行作业 CI/CD 流水线时,将会重启目标存储节点中的cinder-volume服务。部署并运行后,新的 NFS 共享目录应已挂载并在存储节点中可见。在存储节点上,运行以下命令行验证已映射的 NFS 挂载:

 # mount | grep nfs
nfs-host-pp:/nfs/share/cinder on /etc/cinder/nfs_share 223af296419e436d9142928374d8e57e
type nfs4
(rw,relatime,vers=4.1,rsize=81921,wsize=81921,namlen=255,hard,proto
=tcp,port=0,clientaddr=10.30.255.1,local_lock=none,addr=10.30.255.1
)

每个 NFS 共享使用/etc/cinder/nfs_share下的一个挂载点,并带有哈希目录223af296419e436d9142928374d8e57e,该目录将托管任何新创建的卷。您可以通过运行以下命令行来检查:

# openstack volume create --size 10 nfs-volume

新卷应位于 NFS 挂载点的哈希目录下:

# ls /etc/cinder/nfs_share/223af296419e436d9142928374d8e57e
volume-b2be4de1-6e42-e3de-15e8-a72b60ca91ef

NFS 存储在 OpenStack 中是一种非常流行的存储后端。另一种类型的后端基于 SDS,下一节将会介绍该内容。

使用 Ceph 部署

自 Ceph 的早期以来,其 SDS 系统取得了显著的成功。Ceph 旨在大规模扩展至可运行在普通 x86 硬件架构上的 exabyte 存储池。此外,Ceph 接口支持大多数存储类型,包括对象存储、块存储和文件共享。

OpenStack 基金会承诺确保 Ceph 的集成,并且可以将其纳入现有的 OpenStack 环境中。其核心是可靠的自适应分布式对象存储RADOS),用于处理 Ceph 存储集群中对象的分发、复制和管理。基于 Ceph 的 RADOS 设计,操作员可以定义 Ceph 存储池,作为块存储并为 OpenStack 实例提供卷。这可以通过另一种成熟的 Cinder 后端驱动程序实现,称为RADOS 块 设备RBD)。

重要提示

Ceph 的官方文档提供了使用 cephadm 设置 Ceph 集群的完整说明,地址为docs.ceph.com/en/latest/cephadm/install/

Ceph 定义了一组核心逻辑组件:

  • 对象存储设备OSDs):这些对应于文件系统中的物理磁盘,如XFSBtrfs

  • 监视守护进程服务器MON):监控每个 OSD 节点的数据一致性状态和其他度量指标。

  • : 提供存储在 OSD 中的对象映射。

  • 放置组 (PGs): 存储的每个对象和 OSD 的映射。将对象复制到池内多个 OSD 中。

如果你有一个现有的 Ceph 集群或愿意部署一个新的集群,下面的操作指南将引导你完成在 OpenStack 中进行基本 Ceph 集成所需的步骤。在以下示例中,三个 Ceph 节点组成的专用集群运行 ceph-osd。可选地,ceph-mon 会在云控制节点上运行,如下图所示:

图 5.2 – OpenStack 中的 Ceph 存储集成

图 5.2 – OpenStack 中的 Ceph 存储集成

确保你在每个控制节点、计算节点和存储节点上安装了 Ceph 客户端和 Python rbd 库包。如果 Ceph 客户端尚未安装,可以运行以下命令行:

$ apt-get install ceph-common python-rbd

在 Ceph 节点上创建一个 Cinder 使用的存储池:

$ ceph osd pool create cinder-volumes 256

使用 rbd 命令行界面初始化创建的池:

$ rbd pool init cinder-volumes

创建 Ceph 用户和密钥环,以便 Cinder 访问创建的 cinder-volumes 池:

$ ceph auth get-or-create client.cinder mon 'profile rbd' osd 'profile rbd pool=cinder-volumes' mgr 'profile rbd pool=volumes' > ceph.client.cinder.keyring
[client.cinder]
key = QA7sduw73dx83ks02210dj9Lmfj00sdju3ndoy==

将创建的密钥环复制到 OpenStack 部署者、存储节点和计算节点:

# ceph auth get-or-create client.cinder | ssh storage02.os sudo tee /etc/kolla/config/cinder/cinder-volume/ceph.client.cinder.keyring
# ceph auth get-or-create client.cinder | ssh cc01.os sudo tee /etc/ceph/ceph.client.cinder.keyring
# ceph auth get-or-create client.cinder | ssh cn01.os sudo tee /etc/ceph/ceph.client.cinder.keyring

通过运行以下命令行,验证 Cinder 客户端是否能够访问 Ceph 集群:

# ceph –s --name client.cinder --keyring /etc/ceph/ceph.client.cinder.keyring

/ etc/kolla/globals.yml 文件中启用 Ceph 后端:

…
cinder_backend_ceph: "yes"
…

此外,确保在 globals.yml 文件中指定 Ceph cinder 用户、池的名称和密钥环:

…
ceph_cinder_keyring: "ceph.client.cinder.keyring"
ceph_cinder_user: "cinder"
ceph_cinder_pool_name: "cinder-volumes"
…

/ etc/kolla/passwords.yml 文件中设置 RBD Cinder UUID 密钥:

# cat /etc/kolla/passwords.yml |grep cinder_rbd_secret_uuid cinder_rbd_secret_uuid: 612271b2-4537-3e21-65fa-a2e2523d3e421

从 Ceph 节点复制 ceph.conf 文件到自定义的 /etc/kolla/config/cinder 目录。这里展示了一个 Ceph 配置摘录示例:

[DEFAULT]
enabled_backends=rbd-1
[rbd-1]
rbd_ceph_conf=/etc/ceph/ceph.conf
rbd_user=cinder
backend_host=rbd:volumes
rbd_pool=cinder-volumes
volume_backend_name=rbd-1
volume_driver=cinder.volume.drivers.rbd.RBDDriver
rbd_secret_uuid = 612271b2-4537-3e21-65fa-a2e2523d3e421
[client]
rbd_cache = True
rbd_cache_size = 335544320
auth_cluster_required = cephx
auth_service_required = cephx
auth_client_required = cephx
...
fsid = 83baa63b-c421-480a-be24-0e2c59a70e17
mon_host = 10.30.0.22
mon_initial_members = ceph-1
cluster_network = 10.30.0.0/24
...

通过运行作业 CI/CD 流水线来滚动更新新更改。kolla-ansible 剧本将重新启动 cinder-volume 容器,并应用新的配置。存储节点应启用 Ceph RBD 驱动程序,并且能够正常访问 Ceph 集群。新的卷请求应触发 cinder-volumecinder-volume Ceph 池中创建该卷。

OpenStack 运维人员可以同时利用多个存储后端。为了有效地启用这种能力,Cinder 支持一种特殊的调度机制。我们将在下一节中探讨此功能。

存储过滤和调度

如前一节所示,Cinder 支持多种存储后端。块存储请求及其相关的存储后端类型由cinder-scheduler处理。与计算调度服务类似,块存储调度服务负责将每个要创建的卷分配到存储池中可用的特定后端。Cinder 调度器使用过滤策略来选择最适合新卷创建请求的后端。根据存储信息的能力,将评估几个过滤标准,例如状态、可用空间和磁盘状态。之后,cinder-scheduler 使用加权机制,为每个过滤后的后端分配权重并进行排序,如下图所示:

图 5.3 – Cinder 的调度和过滤机制

图 5.3 – Cinder 的调度和过滤机制

调度器定期检查列出后端的状态,并持续更新存储后端候选列表。

默认情况下,Cinder 使用 CapacityFilter 进行过滤,并使用 CapacityWeigher 进行加权,基于存储容量利用率对卷后端进行过滤。最新的 Cinder 调度器过滤器和加权器,至少在 Bobcat 版本之前,可以在 docs.openstack.org/cinder/latest/configuration/block-storage/scheduler-filters.htmldocs.openstack.org/cinder/latest/configuration/block-storage/scheduler-weights.html 中找到。以下 Cinder 调度器加权器列表在 OpenStack 版本更新中发生了变化,列出了在大规模部署中最常用的加权器:

  • CapacityWeigher:根据最可用和空闲的存储容量,为存储后端分配最高权重。

  • VolumeNumberWeigher:在调度器过滤的不同存储后端之间平衡卷分配。这是将多个卷创建请求均匀分配到共享相同名称的不同后端的最佳选择。

  • GoodnessWeigher:一种更精细的加权器,基于特定的存储属性分配卷。它使用一个公式评估存储后端,使用评分函数,表示为 goodness_function,格式为 "(property_rule )?challengeVal1 : challengeVal2"。根据对 property_rule 的评估,权重的分配在 0(最低)和 100(最高)之间变化,具体如下:

    • 如果 property_rule 返回 true,则存储后端将分配 challengeVal1 值的权重

    • 如果 property_rule 返回 false,则存储后端将分配 challengeVal2 值的权重

以下的逐步配置将演示如何使用 Cinder 调度,通过启用默认的过滤器并使用GoodWeigher为每个卷请求选择理想的存储后端。在此配置中,我们在前面的章节中配置的两个存储后端将分别用于 LVM 和 Ceph。我们可以继续通过创建一个新文件/etc/kolla/config/cinder/cinder.conf来添加自定义调度配置。运行kolla-ansible将会把/etc/kolla/config/cinder目录下的任何配置文件与/kolla-ansible/ansible/roles/cinder/templates/cinder.conf.j2文件中的主模板配置合并。新文件将按以下设置进行配置:

  1. 在新部分中启用调度器列表:

    [default]
    scheduler_default_filters = DriverFilter,CapacityFilter,CapabilitiesFilter
    
  2. GoodnessWeigher作为主要的加权机制添加,具体如下:

    scheduler_default_weighers = GoodnessWeigher
    
  3. 对于每个后端部分,添加goodness_function来根据存储提供商的能力定义评分。下一个简单配置评估卷的大小,并检查两个后端lvm-1rbd的利用率是否都低于 50%。如果是,分别将分配5080的权重。在这种情况下,rbd是放置卷的最佳候选者。如果lvm-1的后端利用率大于 50%,而rbd小于 50%,加权器将会为rbd分配80的权重,为lvm-1分配30的权重。最后一种加权逻辑是当两个后端的利用率都大于 50%时——在这种情况下,将选择lvm-1,赋予其30的权重,相比之下rbd被赋予20的权重:

    [lvm-1]
    ...
    goodness_function = "(capabilities.utilization < 50.0)?50:30"
    ...
    [rbd]
    ...
    goodness _function = "(capabilities.utilization < 50.0)?80:20"
    
  4. 运行相同作业的 CI/CD 流水线,并确保kolla-ansible会使用新配置重新启动cinder-volume容器。cinder.conf文件应具有配置的调度器和加权器的扩展配置列表。

Cinder 提供了构造来请求具有特定存储后端的卷,使用卷类型。以下示例显示了如何为 LVM 和 Ceph 定义两个卷类型,基于每个后端名称在创建卷时使用:

$ openstack volume type create lvm_standard
$ openstack volume type set lvm_standard --property volume_backend_name=lvm-1
$ openstack volume type create rbd_large
$ openstack volume type set rbd_large --property volume_backend_name=rbd-1

用户应该能够根据前面命令行中定义的存储类型透明地创建卷。存储池可以分为具有复制功能的大型块存储,定义为rbd_large,以及第二个用于一般用途的标准存储功能,定义为lvm_standard

$ openstack volume create --size 10 --type lvm_standard general_volume
$ openstack volume create --size 50 --type rbd_large large_volume

在此场景中,Cinder 调度器将分别为每个卷请求分配指定的后端存储——lvm-1rbd。在其他情况下,两个或多个存储后端可以共享相同的卷后端名称volume_backend_name——在这种情况下,调度器将根据其调度和加权过滤器推广存储后端类型。

通过集成各种存储解决方案和先进的调度机制,云运营商可以利用每个存储解决方案中的一系列功能,通过单一的 Cinder 界面进行管理。除了块存储选项外,OpenStack 还提供了一个专注于对象的存储服务,代号为 Swift。我们将在下一节中讨论此内容。

回顾对象存储 – Swift

Swift 是一种专门用于存储大规模非结构化对象数据(如文本或二进制数据)的服务。它使 OpenStack 操作员能够通过使用普通存储构建分布式对象存储系统。Swift 服务的标志性特点在于它的设计方式,确保数据的可用性和持久性。可以在 OpenStack 云环境中运行的多个工作负载(如 Web 应用程序)可以通过享受这种简单服务的使用和管理优势,以及其透明的数据复制和水平扩展功能,从而利用对象存储。

回顾 Swift

Swift 的逻辑核心组件主要包括以下内容:

  • 账户服务器:表示与 Swift 账户关联的容器列表的命名空间。

  • 容器服务器:指的是在 Swift 账户中用户定义的存储区域,用于存储对象列表。

  • 对象服务器:管理容器中的实际对象。对象存储定义了实际数据及其元数据的存储位置。每个对象必须属于一个容器。

  • 代理服务器:处理不同类型的传入对象 API 或 HTTP 请求,如容器创建、对象上传和删除。

  • 分区:管理对象、容器和账户数据库的位置。

  • 区域:在物理区域隔离内分隔对象,以防止在集群中发生区域性故障时导致更广泛的数据丢失。

  • :定义对象、账户和容器的逻辑映射,并将其映射到 Swift 集群中的物理位置。Swift 对每个存储构造使用一个环。它还使用 swift-ring-builder 来创建集群的清单并创建分区。

如下图所示,每个分区将有三个副本,反映同一个对象、容器或账户的三个副本,以保持数据的高可用性:

图 5.4 – 三区域布局中的 Swift 环和复制

图 5.4 – 三区域布局中的 Swift 环和复制

与之前的核心组件一样,Swift 使用额外的后台守护进程来管理对象的索引、更新和复制。

构建 Swift 集群

在将对象存储集群与现有的 OpenStack 环境集成之前,应该考虑多种参数。重点应放在硬件需求上,以实现高可用、独立且可扩展的集群。以下是部署 Swift 集群的起点:

  • 对象存储容量:100 TB

  • 每个 机箱的硬盘插槽数量 :50

  • 硬盘存储容量 :3 TB

  • 推荐的集群 副本 :3

  • 支持的 文件系统 :XFS

根据推荐的三副本策略,总存储容量应为推荐大小的三倍,即 3 * 100 = 300 TB

使用 XFS 作为文件系统需要在存储中增加 1.0526 倍的元数据开销。所需存储空间的四舍五入计算方式如下:

300 * 1.0526 = 316 TB

使用所需的总空间将帮助您计算所需的硬盘数量,如下所示:

316 / 3 = 106 个硬盘

存储节点的数量将根据以下方式确定:

106 / 50 = 3 节点

我们的初始集群将由三个存储节点组成,这些节点将承载容器、账户和对象。为了管理 Swift 请求,在我们的初步草图中,我们将 swift-proxy 服务器分配到控制节点上。将 swift-proxy 角色保持在控制节点上的一个问题是可能会导致云控制器资源的过载。作为云运营商,建议监控到达 swift-proxy 服务的对象 API 请求,并在存储集群继续扩展时,根据大小和使用情况,开始将其迁移到专用硬件。

处理扩展的 Swift 存储系统时,另一个关键的考虑因素是网络布局。在我们的初步设计草图中,网络接口专门用于处理存储。根据 Swift 架构,还可以分配更多接口用于不同的网络用途。具体列举如下:

  • 存储接口 :一个代理服务器,用于接口存储节点,运行对象、容器和账户服务器。相关配置在 kolla-ansible 中定义,位于 globals.yml 文件中,配置项为 swift_storage_interface

  • 复制接口 :可选地,每个存储节点可以为处理存储节点之间的 Swift 存储复制而专门配置一个附加接口。相关配置在 kolla-ansible 中定义,位于 globals.yml 文件中,配置项为 swift_replication_interface。在当前设置中,此选项未被考虑,复制流量将使用存储接口进行处理。

  • 内部 API 接口 :可以定义此接口以允许用户在内部访问代理服务器。相同的接口可以被 HAProxy 用来在两个或更多的 swift-proxy 服务之间建立负载均衡,确保高可用性。相关配置在 kolla-ansible 中定义,位于 globals.yml 文件中,配置项为 api_interface。在当前设置中,此选项未被考虑。

  • 外部 API 接口 :可选地,当工作负载需要公共 API 访问时,Swift 可以在外部访问。相关的配置在 kolla-ansible 中定义,在 globals.yml 文件中作为 kolla_external_vip_interface 。在当前设置中,此选项未考虑。

由于其常见的使用案例,Swift 可以轻松地呈指数级扩展;因此,云运维人员应预期基础设施可能会增长。一个常见的痛点是被限制在有限的硬件配置中,而事先未为此做好准备。当运维人员发现网络性能下降时,拥有额外的网络接口将是一个巨大的优势。将不同类型的流量分配到专用接口将避免操作过载和应急处理的负担。

运行 Swift

在使用 kolla-ansible 部署 Swift 集群之前,我们需要准备存储节点文件系统。以下 shell 脚本将会在每个可用磁盘上创建分区——sdcsddsde ——这些分区应在每个存储节点中运行:

for i in sdc sdd sde; do
     parted /dev/${i} -s -- mklabel gpt mkpart KOLLA_SWIFT_DATA 1 -1
done

对于每个创建的分区,使用以下 shell 脚本创建一个 XFS 文件系统:

loop=0
for i in sdc sdd sde; do
     sudo mkfs.xfs -f -L i${loop} /dev/${i}1
    (( loop++ ))
done

重要提示

文件系统标签被称为 KOLLA_SWIFT_DATA ,应在存储节点中可见。设备名称应与 globals.yml 文件中的配置设置相匹配,由 swift_devices_name 设置定义。

接下来,生成环以准备 Swift 集群中的映射对象。撰写时,Object Storage 操作手册尚未自动化环生成过程。从生成对象环开始,然后从部署节点运行以下脚本。脚本的第一部分分别定义了集群存储 IP 地址、Swift Kolla 镜像以及自定义 Swift Kolla 配置路径的新目录:

$ STORAGE_NODES=(10.30.0.81 10.30.0.82 10.30.0.83) 
$ KOLLA_SWIFT_BASE_IMAGE="kolla/ubuntu-source-swift-base:8.0.5" 
$ sudo mkdir -p /etc/kolla/config/swift

Swift 使用 swift-ring-builder 工具来生成对象环。环构建命令的通用格式如下:

swift-ring-builder <builder_file> create <part_power> <replicas> <min_part_hours>

在这里,我们有以下内容:

  • <builder_file> :这可以是 account.buildercontainer.builderobject.builder 中的一个。

  • <part_power> :分区数近似为 2 的最接近幂次,以获得集群的 part power。例如,对于 50 个硬盘,推荐的 part power 为 11,这使得所有分区的平均值为 2,048。建议将近似值向上舍入。

  • :推荐值是选择三个副本。

  • <min_part_hours> :这决定了在一个小时内只能移动一个分区副本的时间。

Rackspace Lab 提供了一个在线工具来计算 Swift 环。该工具可以在 rackerlabs.github.io/swift-ppc/ 找到。

脚本的下一部分将为对象构建环,并通过向端口 6000 上的环添加可用设备来迭代每个存储节点:

docker run \
  --rm \
  -v /etc/kolla/config/swift/:/etc/kolla/config/swift/ \
  $KOLLA_SWIFT_BASE_IMAGE \
  swift-ring-builder \
    /etc/kolla/config/swift/object.builder create 11 3 1
for node in ${STORAGE_NODES[@]}; do
    for i in {0..2}; do
      docker run \
        --rm \
        -v /etc/kolla/config/swift/:/etc/kolla/config/swift/ \
        $KOLLA_SWIFT_BASE_IMAGE \
        swift-ring-builder \
          /etc/kolla/config/swift/object.builder add \
          r1z1-${node}:6000/d${i} 1;
    done
done

脚本的以下部分将为账户生成一个 ring 文件,并为每个存储节点在端口6001上将可用设备添加到 ring 中:

docker run \
  --rm \
  -v /etc/kolla/config/swift/:/etc/kolla/config/swift/ \
  $KOLLA_SWIFT_BASE_IMAGE \
  swift-ring-builder \
    /etc/kolla/config/swift/account.builder create 11 3 1
for node in ${STORAGE_NODES[@]}; do
    for i in {0..2}; do
      docker run \
        --rm \
        -v /etc/kolla/config/swift/:/etc/kolla/config/swift/ \
        $KOLLA_SWIFT_BASE_IMAGE \
        swift-ring-builder \
          /etc/kolla/config/swift/account.builder add \
          r1z1-${node}:6001/d${i} 1;
    done
done

脚本的下一部分为容器生成一个 ring,并为每个存储节点在端口6002上将可用设备添加到 ring 中:

docker run \
  --rm \
  -v /etc/kolla/config/swift/:/etc/kolla/config/swift/ \
  $KOLLA_SWIFT_BASE_IMAGE \
  swift-ring-builder \
    /etc/kolla/config/swift/container.builder create 11 3 1
for node in ${STORAGE_NODES[@]}; do
    for i in {0..2}; do
      docker run \
        --rm \
        -v /etc/kolla/config/swift/:/etc/kolla/config/swift/ \
        $KOLLA_SWIFT_BASE_IMAGE \
        swift-ring-builder \
          /etc/kolla/config/swift/container.builder add \
          r1z1-${node}:6002/d${i} 1;
    done
done

可选地,为了在 ring 内分配可用驱动器的分区,添加脚本中的最后一部分,通过触发 rebalance 选项,使用相同的swift-ring-builder rebalance命令行工具:

for ring in object account container; do
  docker run \
    --rm \
    -v /etc/kolla/config/swift/:/etc/kolla/config/swift/ \
    $KOLLA_SWIFT_BASE_IMAGE \
    swift-ring-builder \
      /etc/kolla/config/swift/${ring}.builder rebalance;
done

这将遍历每个生成的 ring 文件,并确保在每次分区移动后每个 ring 都保持平衡。运行 ring 准备脚本后,确保没有错误生成,且所有三个 ring 文件都位于/etc/kolla/config/swift/目录下。下一步是确保对象存储主机名已添加到清单文件中,该文件位于/ansible/inventory,如下所示:

…
[storage]
storage03.os.packtpub
storage04.os.packtpub
storage05.os.packtpub
[swift-account-server:children]
storage
[swift-container-server:children]
storage
[swift-object-server:children]
storage

我们将在云控制节点上保持swift-proxy角色:

…
[swift:children]
control
[swift-proxy-server:children]
swift

通过启用 Swift 服务编辑globals.yml文件,如下所示:

enable_swift : "yes"

如果存储分区标签使用与先前在磁盘分区准备中定义的默认KOLLA_SWIFT_DATA不同的名称,请确保通过在globals.yml文件中设置以下配置行进行调整:

swift_devices_name: "KOLLA_SWIFT_DATA"

触发管道作业应运行每个目标节点中的 Kolla Swift 容器。在集群节点之一中创建一个容器,如下所示:

$ openstack container create pp_container

在创建的容器中创建一个简单的对象:

$ openstack object create pp_container obj1.txt obj2.txt

您可以显示容器的详细信息,包括对象数量和关联的账户:

$ openstack container show mycontainer
+--------------+---------------------------------------+
| Field        | Value                                 |
+--------------+---------------------------------------+
| account      | AUTH_4c32445a3d2e431f3ab3347e522556a9 |
| bytes_used   | 6778                                  |
| container    | pp_container                          |
| object_count | 2                                     |
+--------------+---------------------------------------+

正如本节所示,Swift 架构具有简单的 API,使得将非结构化数据存储在冗余集群中变得容易,且运维负担较轻。Swift 还经常用于备份、归档和灾难恢复。OpenStack 中的最后一种存储选项是文件共享存储,称为 Manila,将在下一节中介绍。

探索文件共享服务 – Manila

OpenStack 中的下一个存储服务是文件共享,代号为 Manila。该服务为各种客户端和存储后端提供对存储基础文件共享的同时访问。Manila 支持多种共享协议,至少在 Bobcat 版本之前,包括 NFS、GlusterFS、CephFS、CIFS、HDFS,以及最近的 MapRFS。请注意,存储后端使用的驱动程序必须支持其中一个先前列出的协议。

Manila 的底层实现

如下图所示,在 Manila 中协调文件共享并管理其生命周期的核心组件如下:

  • Manila 共享服务器 : 托管共享文件的存储单元

  • API 服务器 : 为客户端请求处理暴露 REST API 接口

  • 调度器 : 选择最合适的共享服务器以满足文件共享请求

  • 数据服务 : 处理数据备份、恢复和迁移

Manila 与几个 OpenStack 核心服务交互,包括以下服务:

  • Nova:创建运行共享服务器的实例

  • Neutron:通过租户实例网络提供文件共享访问

  • Cinder:在块存储池中创建文件共享作为卷:

图 5.5 – 文件共享服务核心架构

图 5.5 – 文件共享服务核心架构

重要提示

在写作时,Manila 支持超过 25 种共享驱动程序的后端,包括 CephFS、GlusterFS、LVM 以及其他厂商,如 EMC 和 Hitachi NAS。完整更新的列表可以在 docs.openstack.org/manila/latest/configuration/shared-file-systems/drivers.html 找到。

Manila 新增的扩展功能和驱动程序列表使其能够同时使用多个存储后端并管理它们。类似于块存储多后端设置,Manila 的最新版本引入了筛选和加权机制,以根据特定属性选择共享后端。默认情况下,manila-scheduler 使用 DriverFilter 进行筛选,使用 GoodnessWeigher 作为加权机制。

重要提示

筛选器和功能加权器应在 manila.conf 文件中配置,类似于 Cinder 的筛选功能语法。筛选功能在共享和主机级别定义能力检查。可以通过在命令行运行 manila extra-specs-list 来列出可用的共享类型属性。有关筛选功能支持的最新属性的完整列表(直到 Antelope 和 Bobcat 版本),请参见 docs.openstack.org/manila/latest/contributor/driver_filter_goodness_weigher.html

对于下一个部署,将使用默认调度配置,该配置基于空闲可用容量筛选最佳后端。

运行 Manila

在现有的 OpenStack 环境中部署 Manila 服务是直接的。以下设置中,我们将使用一个通用后端,利用 Cinder 创建共享作为卷。实例附加的卷可以存在于在 使用多个后端扩展存储 部分为 LVM 或 Ceph 配置的 Cinder 池存储后端中。

kolla-ansible 代码中启用 Cinder 服务是运行 Manila 与通用存储后端的必要条件。在 globals.yml 文件中启用 Manila 服务,如下所示:

enable_manila: "yes"

globals.yml 文件暴露了另一个后端给 Manila,包括 Ceph 中的 NFS 和 HNAS。对于通用后端,请记住将使用 NFS 和 CIFS 共享。继续启用通用共享:

enable_manila_backend_generic: "yes"

重要提示

在撰写时,启用 Manila 服务将自动添加 Manila 的 Horizon 面板,通过仪表板管理文件共享。如果部署后在仪表板中看不到 Manila 服务,请确保enable_horizon_manila设置为true

可以在自定义 Manila 配置文件中配置更多 Manila 设置,该文件不通过globals.yml文件直接控制。创建一个新的配置文件,命名为/etc/kolla/config/manila-share.conf,用于自定义 Manila 共享设置。一个重要的设置是实例共享所需的大小。你可以提前在 Nova 中创建实例口味,或者使用默认的口味,可以通过以下命令行列出:

$ openstack flavor list

例如,我们可以指示文件共享实例使用m1.medium口味,引用的 ID 为3,来自列表中:

[generic]
service_instance_flavor_id = 3

可以自定义其他设置,例如 Manila 共享后端名称,如果打算有多个后端。为了反映通用后端的名称,请添加以下配置设置:

[generic]
…
share_backend_name = GENERIC_SHARE

由于它是一个 Nova 实例,文件共享服务器需要一个 Glance 镜像。默认情况下,Manila 剧本使用manila-service-image作为参考名称。如果打算更改它,请确保它与文件中配置的名称相同。

准备 Manila 部署的下一部分是确保 Manila 服务被分配到集群角色。设置主机名,并确保 Manila 服务已添加到位于/ansible/inventory/multi_packtpub_prod中的清单文件,如下所示:

…
[manila]
control
[manila-api:children]
manila
[manila-scheduler:children]
manila
[manila-data:children]
manila

第三章中所强调,OpenStack 控制平面 – 共享服务manila-share服务使用 Neutron 插件提供文件共享资源的网络访问:

…
[manila-share:children]
network

启动管道作业,以便在跨目标节点中部署 Manila 服务。Manila 服务容器应该在云控制器和网络节点中运行。确保 Manila 任务无误地完成,如下所示:

图 5.6 – kolla-ansible Manila 部署的服务输出

图 5.6 – kolla-ansible Manila 部署的服务输出

验证云控制器节点中的 Manila 服务:

$ openstack share service list

上一命令行的输出显示,manila-scheduler服务已在云控制器主机上启用,且manila-share作为网络节点的一部分正在运行:

图 5.7 – OpenStack Manila 服务列表

图 5.7 – OpenStack Manila 服务列表

在最新的 OpenStack 版本(包括 Bobcat)中,文件共享服务得到了极大改进,例如引入了文件共享控制访问。这样,文件共享可以被锁定,以防止意外删除。

重要提示

从 Antelope 版本开始,计划弃用 Manila CLI,强烈建议使用 OpenStack CLI 与 Manila REST API 进行交互。

总结

本章探讨了最流行的 OpenStack 存储服务。每项存储服务功能和能力的扩展,包括 Swift、Cinder 和 Manila,几乎是不可阻挡的。这一点得到了广泛支持的后端驱动程序的验证,无论是开源世界中的 Ceph,还是特定存储供应商的驱动程序。最新的 OpenStack 版本,包括 Antelope 和 Bobcat,也通过调度和过滤机制引入了更稳定的高级功能,主要针对 Cinder 和 Manila。请记住,理解每个存储用例及其相应架构是根据需求在 OpenStack 环境中舒适运行存储解决方案的关键。选择满足特定需求的正确选项的挑战不仅限于存储问题,还适用于 OpenStack 中的网络范式。计算和存储服务的不同元素的连接将在我们 OpenStack 旅程的下一章中讨论。

第六章:6

OpenStack 网络 – 连接性和托管服务选项

“事情总是看起来不可能,直到它完成。”

– 纳尔逊·曼德拉

Neutron 是 OpenStack 的网络服务,随着不同版本的发布不断发展,提供了更多的功能和特性。云架构师可以根据现有的网络资源和需求,设计多种拓扑结构的 OpenStack 网络堆栈。与之前仅提供基础网络服务的 Nova 网络服务不同,OpenStack 租户可以在 Neutron 中获得更细粒度的网络控制和灵活性。云和网络管理员可以为租户提供更高级的网络功能,如路由、防火墙、负载均衡和私有网络。

在本章中,我们将介绍 OpenStack 网络的丰富更新,涵盖以下主题:

  • OpenStack 中 Neutron 架构及其核心服务交互

  • Neutron 插件和支持的驱动程序

  • 现有的 Neutron 代理和所需的网络类型

  • 使用Open vSwitchOVS)和Open Virtual NetworkOVN)机制设计并实现 OpenStack 虚拟交换布局,作为软件定义网络SDN)的实现

  • 了解并实现路由,使用虚拟路由器互联租户网络并提供外部连接

  • 使用新兴的 Octavia 项目将负载均衡作为服务功能进行集成

探索 Neutron 的核心组件

OpenStack 网络通过不同版本的发布不断发展,构建了一个先进且功能完善的云网络堆栈。像许多其他 OpenStack 服务一样,Neutron 由多个服务组成,可以跨多个主机进行扩展,正如以下图所示:

图 6.1 – OpenStack Neutron 核心架构

图 6.1 – OpenStack Neutron 核心架构

这些组件可以简要地分解如下:

  • Neutron 服务器:它充当一个 API 门户,接收由服务或最终用户生成的 API 请求,并将其转发到下一个处理环节——在这种情况下,通过消息队列服务将请求传递给 Neutron 代理。OpenStack 生态系统中服务器交互的另一个部分是访问数据库,以便更新每个 API 请求的网络对象。

  • Neutron 代理:Neutron 架构在很大程度上依赖于安装在其他主机上的不同类型的代理,以处理不同的网络功能。插件代理,标记为 neutron-*-agent,是处理每个计算节点中虚拟交换功能的进程。这种类型可以被描述为 第二层L2)代理。一种非常常见的 L2 代理是 OVS,它通过 ML2 机制驱动程序提供 L2 连通性。第二种 Neutron 代理是 第三层L3)代理,标记为 neutron-l3-agent,安装在网络节点上,处理 L3 网络访问的实例,如 NAT、防火墙和 虚拟私人网络VPN)功能。DHCP 代理,标记为 neutron-dhcp-agent,管理每个租户网络的 DHCP 配置实例(dnsmasq 配置)。

根据网络功能请求的性质,Neutron 服务将与部署在网络节点和/或计算节点上的代理进行交互。云运营商应列出基础设施支持的网络功能,这将决定可以安装的插件和代理的选择。

揭示 Neutron 代理的秘密

Neutron 依赖与 neutron-server 通过排队消息服务交互的代理服务,以实现 L2 和 L3 连通性、DHCP 和路由服务的虚拟网络。不同的代理将在网络和计算节点上部署:

  • L2 代理:部署在网络节点和计算节点上,为实例和虚拟网络(如路由器)实现 L2 网络连通性。

  • L3 代理:部署在网络节点上,并可选地部署在计算节点上,用于在不同类型的网络之间执行 L3 路由,例如租户网络和外部网络。L3 还可以实现更高级的网络功能,如防火墙和 VPN。

  • DHCP 代理:部署在网络节点上,为租户网络运行 DHCP 服务。

  • 插件代理:部署在网络节点上,处理依赖于已实现 Neutron 插件的虚拟网络中的数据包。

  • 元数据代理:部署在网络节点上。Nova 提供的元数据服务使得可以通过元数据 HTTP 请求(169.254.169.254)检索实例信息,如主机名和 IP 地址。Neutron 元数据代理通过其内部代理组件将元数据转发到 Nova 元数据服务,并附加额外的信息,如实例和租户 ID。

部署的 Neutron 代理的正常功能将根据 OpenStack 环境中设计的网络类型而有所不同。下一节将简要介绍我们初步设计草稿中应存在的不同网络类别。

网络类别

必须了解不同的网络类型以启用流量流动,具体取决于它们的使用方式。以下术语表涵盖了主要与 OpenStack 最新版本一起使用的网络类别:

  • 提供商网络:由云操作员创建和管理,操作员定义一组网络属性,例如网络类型——例如,VXLAN通用路由封装GRE)或平面。云操作员提供并配置底层基础设施,例如指定用于流量流动的物理网络接口。

  • 自服务网络:也称为 租户网络,这些网络由云用户创建。自服务网络是独立的,完全与由 Neutron 管理的多租户环境中的其他网络隔离。租户只能根据云操作员预定义的网络类型来创建虚拟网络。例如,如果云操作员未提供该选项,则云用户无法实现 GRE 网络。云用户无法访问底层的 Neutron 配置。

  • 外部提供商网络:指特定外部网络连接的提供商网络。云操作员配置外部路由设备以访问互联网。

下一部分将通过探讨插件的概念及其最新使用模式,涵盖 Neutron 最具吸引力的功能。

网络核心 – Neutron 插件

Neutron 支持使用插件和驱动程序,这些插件和驱动程序使用由开源社区或供应商解决方案提供的不同软件和硬件技术。Neutron 插件有两种类型:

  • 核心插件:启用 L2 连接功能和网络元素的编排,包括虚拟网络、子网和端口。

  • 服务插件:启用额外的网络功能,包括路由、私有网络、防火墙和负载均衡。

重要提示

插件的代码在 Neutron 服务器上运行,该服务器可以配置为云控制节点的一部分。

以下部分将深入探讨最常用的核心插件。

核心插件 – 模块化二层

Neutron 中最广泛采用的核心插件是 模块化二层ML2)。ML2 引入 OpenStack 网络服务,增加了设计网络架构的灵活性。ML2 的“秘诀”在于它支持同时使用来自不同供应商的多种技术。因此,云架构师和操作员不会局限于特定的功能集,可以轻松扩展或更改他们的网络架构。

由于在 Havana 发布之前的历史限制,开发了这个插件。在那个时候,操作员只能使用一个核心插件,称为单体插件组件。最常用的两个核心插件是 Linux BridgeOVS,在 OpenStack 的最新版本中,它们已经被 ML2 替代。替代并不意味着直接删除它们,而是将它们作为 机制驱动程序 打包到核心 ML2 插件中。ML2 不仅限于 Linux Bridge 和 OVS,还支持其他厂商的驱动程序,如 VMware、Cisco 和 OpenDayLight。在 OpenStack 社区网站上可以找到一个很棒的过滤列表:www.openstack.org/marketplace/drivers/#project=neutron%20(networking)

Neutron 中支持的模块化插件和驱动程序的概览如下所示:

图 6.2 – OpenStack Neutron 核心和服务插件架构概览

图 6.2 – OpenStack Neutron 核心和服务插件架构概览

如前图所示,Neutron 依赖于插件机制,这些插件提供一组特定的网络服务。API 请求将由 Neutron 服务器转发给控制节点中配置的相关插件。ML2 插件将两个主要元素结合到同一个框架中,如下所示:

  • 类型驱动程序:这些暴露了 L2 功能,用于创建更多分段的网络,包括以下内容:

    • VLAN:使用 802.1Q 标签隔离网络流量。属于同一 VLAN 的虚拟机是同一广播 L2 域的一部分

    • VXLAN:使用 虚拟网络标识符VNI)来分隔和区分不同网络之间的流量

    • Flat:不支持 VLAN 标签和网络隔离,其中实例连接在同一网络中

    • GRE:使用 GRE 隧道协议封装流量

    • GENEVE:类似于 VXLAN 覆盖技术,但具有更优化的封装方法

    • Local:仅连接同一网络中托管在相同计算节点中的实例,而不连接不同节点中的实例

  • 机制驱动程序:通过网络软件方法(如 OVS、Linux Bridge 和 OVN)以及基于硬件的方法实现类型驱动技术

最新的 ML2 驱动支持矩阵列表可以在 docs.openstack.org/neutron/latest/admin/config-ml2.html 找到。每个机制驱动程序都支持一组网络类型(类型驱动程序)。例如,OVS 支持大多数网络类型,包括 VLAN、VXLAN、GRE、flat 和 local。如果在生产环境中提出了支持 GENEVE 类型驱动的需求,可以通过仅安装驱动并重新配置 Neutron 驱动程序列表来集成新的机制驱动程序。

构建虚拟交换

本节将讨论两种机制驱动程序,用于在虚拟网络端口与物理网络之间建立连接。OVS 是功能最丰富的机制驱动程序之一,具有高级网络功能,如 OpenFlow。我们将讨论的第二个驱动程序是 OVN,这是一种 SDN 实现,通过控制数据包流动来编程网络。Linux Bridge 和 L2 Population 也是经过充分测试和成熟的机制。由于 ML2 是一个支持驱动程序的无关插件,介绍新的机制驱动程序不会对现有的 OpenStack 环境带来太多复杂性。

在 OpenStack 中启用 vSwitch

大多数 OpenStack 网络实现至少需要使用基于隧道的虚拟网络技术,提供极高程度的网络分段,如 VXLAN 和 GRE。基于隧道的网络能够支持多达 1600 万个网络。OVS 支持大多数在大型复杂 OpenStack 网络环境中使用的驱动程序,如 VLAN、VXLAN、GRE 和扁平网络。作为云操作员,了解 OVS 在 OpenStack 环境中如何运作是至关重要的。OVS 提供了完整的核心架构,并通过不同组件在主机内核空间中作为软件交换机运行。OVS 实现中包含多个服务,当它安装在 OpenStack 环境中时,具体如下:

  • openvswitch:一个内核模块,处理数据平面,负责处理网络数据包。

  • ovs-switchd:一个运行在物理主机上的 Linux 进程,用于控制和管理虚拟交换机。

  • ovsdb-server:一个本地数据库,用于存储本地运行的虚拟交换机。

  • neutron-openvswitch-agent:配置在使用 OVS 机制驱动的计算节点中。

  • neutron-server:处理 API 请求,ML2 插件加载 OVS 机制驱动程序。neutron-server 进程通过 RPC 广播消息将网络请求传递给 OVS 驱动程序,后者通过 neutron-openvswitch-agent 配置计算节点上的 OVS 交换机,并设置本地实例所需的资源。

一旦 OVS 被实现,一套虚拟网络设备将被安装,云操作员在部署或故障排除任务中应当牢记这一点。一个以太网帧将通过以下接口从实例传输:

  • tapXXXX:一个 tap 接口,其中 XXXX 是分配的 tap 接口 ID。

  • br-int:一个桥接接口,称为集成桥接,它将所有虚拟设备(如虚拟机、路由器、防火墙)整合在一起。

  • int-br-ethX:一个虚拟补丁端口,将不同接口连接到 OVS 集成桥接接口(br-int)。

  • phy-br-ethX:一个虚拟补丁端口,将不同接口连接到 OVS 提供者桥接(br-ethX)。

  • br-ethX:一个桥接接口,其中X是分配的桥接接口 ID,用于连接物理网络。它也被称为提供程序桥接,通过虚拟补丁电缆与br-int集成桥接连接,由补丁端口(int-br-ethXphy-br-ethX补丁端口分别用于int-brbr-ethX)提供。

  • qbrXXXX:一个 Linux 桥接接口,其中XXXX是分配的桥接接口 ID,专门用于 IP 表。

  • br-tun:一个桥接隧道接口,用于处理数据包的封装和解封装。

  • br-ex:一个提供与外部网络连接的桥接接口。

每个启动的实例通过其 tap 接口连接,表示为tapXXXX,该接口在虚拟化主机中创建。相关的 Linux 桥接,表示为qbrXXXX,连接到 OVS 的br-int集成桥接,流量将根据编程的 OpenFlow 规则进行路由,然后通过虚拟交换机转发。

集成桥接和提供程序桥接之间的连接通过补丁电缆处理。数据包通过 OVS 提供程序桥接(br-ethX)离开物理网络,连接到主机的物理网络接口。在我们的现有 OpenStack 环境中配置 OVS 时,每个节点将运行自己的集成桥接和提供程序桥接。OpenStack 节点之间的连接,包括云控制器、网络节点和计算节点,通过物理网络建立,正如下图所示:

图 6.3 – 使用 OVS 通过不同接口的流量流动

图 6.3 – 使用 OVS 通过不同接口的流量流动

现在我们已经理解了 OpenStack 设置中 OVS 的基本核心组件,可以继续配置我们的基础设施代码,将 OVS 部署为 Neutron 中的主要机制驱动程序。

使用 OVS 进行部署

OVS 机制驱动程序实现 L2 隔离,提供基于 VXLAN、GRE 和 VLAN 的网络。接下来的配置将实现 ML2 插件,以使用基于 VXLAN 的网络。这将允许实例通过 VLAN 分段和 VXLAN 隧道连接。租户的虚拟网络将不会暴露到计算或网络节点之外。kolla-ansible默认启用 ML2 插件。在部署OVS配置之前,必须满足一些先决条件。为了通过路由器和提供程序网络访问外部网络,请在/etc/kolla/globals.yml文件中调整neutron_external_interface设置,指向专门用于此目的的网络接口。eth2接口已被分配用于连接外部网络,正如在第三章中设计的那样,OpenStack 控制平面 – 共享服务。您可以按如下方式调整设置:

...
neutron_external_interface: "eth2"
...

重要说明

如果计划使用多个提供者桥接,则需要考虑使用带有 OVS 提供者桥接(br-ethX)的物理接口。在这种情况下,neutron_external_interface可以分配一个以逗号分隔的列表——例如,neutron_external_interface: "eth2,eth3"

另一个检查是验证kolla-ansible是否配置了带有 ML2 插件的 OVS 驱动机制。请检查并调整globals.yml文件中的以下配置设置:

...
neutron_plugin_agent: "openvswitch"
...

下一个检查是验证我们的 Neutron 服务是否分配给/ansible/inventory/multi_packtpub_prod文件中的相应 OpenStack 节点。如第三章所示,OpenStack 控制平面——共享服务neutron-server将在控制节点中作为一部分运行,如下所示:

...
[control]
cc01.os.packtpub
...
[neutron-server:children]
control
...

Neutron 代理,包括 DHCP、L3 和元数据代理,将在专用网络节点上运行,如下所示:

...
[network]
net01.os.packtpub
[neutron:children]
network
[neutron-dhcp-agent:children]
neutron
[neutron-l3-agent:children]
neutron
[neutron-metadata-agent:children]
neutron
...

OVS 将在网络和计算节点中安装。

重要提示

第五章所示,OpenStack 存储——块存储、对象存储和文件共享manila-share服务通过使用 Neutron 插件提供文件共享访问。

在清单文件中列出的 OVS 设置如下:

...
[openvswitch:children]
network
compute
manila-share
...

启动管道任务以在目标节点上安装 OVS。请注意,VXLAN 在kolla-ansible代码中未显式配置。默认情况下,Neutron 租户网络使用 VXLAN 类型。默认的 VNI 范围定义为从 1 到 1000 个 ID,当租户网络创建时将为其保留。此设置在控制节点的ml2_config.ini文件中的vni_ranges行中表示。可以扩展 ML2 配置,并且我们可以通过创建/ etc/kolla/config/neutron/ml2_config.ini文件来采用配置重写。

以下命令行列出了来自云控制器节点的不同网络代理,包括 OVS 代理:

$ openstack network agent list

以下是输出:

图 6.4 – Neutron 代理列表输出

图 6.4 – Neutron 代理列表输出

如图所示,OVS 代理应该在各自的网络和计算节点中正常运行。在接下来的部分中,我们将跟踪使用 OVS 机制的网络流。

OVS 的流量流向

OVS 驱动程序的设置将决定以太网帧的传输跳数,从实例一直到物理网络。将使用多个接口,包括虚拟交换机端口和集成桥接。openvswitch剧本在计算节点的部署应该在主机上创建 OVS 逻辑桥接,可以通过运行以下命令行来检查:

$ ovs-vsctl list-br

输出将如下所示:

图 6.5 – OVS 桥接列表

图 6.5 – OVS 桥接列表

在计算节点中启动的实例通过相同的本地 VLAN 连接。采用 VXLAN 布局时,实例端口连接到集成桥,该桥将分配一个本地 VLAN ID。从实例发起的流量将由集成桥(br-int)转发到隧道桥(br-tun)。通过运行以下命令行,可以查看连接桥及其各自端口的整体布局:

$ ovs-vsctl show

这里是输出:

图 6.6 – OVS 接口列表

图 6.6 – OVS 接口列表

如虚拟交换机接口所示,集成桥(br-int)标记为VLAN 1。当流量到达不同节点中的实例时,数据包将通过隧道桥(br-tun)封装在 VXLAN 数据包中传输。在背后,本地 VLAN ID 1 将与 VXLAN 隧道 ID 交换,如vxlan-476984a0所示。否则,如果实例连接到另一个位于同一计算节点的实例,数据包将通过集成桥(br-int)本地传输到目标端口,该端口通过qrXXXXtapYYYY端口接口表示。

接下来的部分介绍了更复杂的机制驱动程序 OVN,并展示了其在 OpenStack 环境中的部署。

OVN 在 OpenStack 中的应用

OpenStack 环境中另一个主要且首选的网络虚拟化是 OVN。OVN 被认为是 SDN 理念的成熟实现,提供了更大的网络流编程灵活性。操作员可以集中定义一组转发规则,来定义数据包流量的控制方式。OVN 使用网络控制器中的抽象软件层来编程交换机,应用于数据包流的条件和规则。与 OVS 相比,OVN 的最显著功能是其更丰富的能力和先进特性,如可编程的流量路由和访问控制。与 OVS 方法不同,OVN 通过流规则将网络设备的控制功能与实际的数据包转发功能解耦。OVN 支持大多数网络类型,包括 VLAN、VXLAN(版本 20.09 及以上)、平面网络和 Geneve。

如下图所示,OVN 建立在 OVS 之上,利用其交换能力并增加一个抽象层,该抽象层由控制器管理,这些控制器存储在一组OVS 数据库OVSDBs)中:

图 6.7 – OVN 集成架构

图 6.7 – OVN 集成架构

OVN 架构与 OpenStack 环境集成的主要构件在此进行解释:

  • 南向数据库:引用为 ovsdb-serverovnsb.db),它存储逻辑和物理网络流的数据。该数据库托管逻辑与物理网络之间的所有绑定信息,如与 Port_BindingLogical_Flow 表分别关联的端口和逻辑网络绑定。

  • 北向数据库:引用为 ovsdb-serverovnnb.db),它在虚拟网络的高层存储数据,这些虚拟网络代表一个 云管理系统CMS),在本例中即 OpenStack 环境。该数据库通过表格数据集反映 CMS 的网络资源,如与 Logical_RouterLogical_Switch_Port 表分别关联的路由器和交换机端口。

  • OVN 控制器:引用为 ovn-controller,它在 Hypervisor 节点上运行并连接到南向数据库。它充当 OVS 控制器,通过在每个 OVS 交换机实例上定义 OpenFlow 规则,将逻辑流转换为物理流,并将配置推送到本地 OVSDB。

  • OVN 北向服务:引用为 ovn-northd,它作为控制平面的一部分在云控制器上运行。ovn-northd 守护进程通过将来自 ovn-nb 数据的逻辑配置转换为逻辑数据路径流,将北向数据库连接到南向数据库。转换后的数据将被填充到 ovn-sb 数据库中,并为 ovn-controller 实例准备好使用。

  • OVS 数据平面服务:引用为 ovs-vswitchd,它作为数据平面的一部分在 Hypervisor 节点上运行。ovs-vswitchd 应用由 ovn-controller 提供的包转发规则。

  • 本地 OVSDB:引用为 ovsdb-server,它在每个 Hypervisor 节点上本地运行。OVN 参考架构通过使用数据库的一致快照来利用数据库扩展优势,以从可能的连接中断中恢复。

  • 元数据代理:引用为 ovn-metadata-agent,它在每个 Hypervisor 节点上运行。OVN 元数据代理,例如 Neutron 元数据代理,用于在每个计算节点上代理元数据 API 请求。这样,每个 Hypervisor 节点上运行的 OVS 交换机实例将把请求路由到本地元数据代理,然后查询 Nova 元数据服务以运行实例。

在以下部分,我们将使用 kolla-ansible 将 OVN 项目集成到 OpenStack 环境中。

使用 OVN 部署

OVN 扩展了 OVS 实现,以为实例提供网络服务。ML2 机制驱动程序帮助与 OpenStack 作为 CMS 集成。kolla-ansible 剧本包含了大部分 OVN 配置和所需的安装包。与 OVS 配置类似,通过配置 neutron_external_interface 设置,调整 /etc/kolla/globals.yml,以使用指定的接口连接外部网络,具体如下:

...
neutron_external_interface: "eth2"
...

配置 ML2 机制驱动程序以使用 OVN,如下所示:

...
neutron_plugin_agent: "ovn"
...

OVN 内置支持 L3 网络功能,使实例能够连接到外部网络。在 OVN 中提供此类连接性有两种方式——通过不使用分布式浮动 IP 设计的集中式布局,或者通过分布式虚拟路由DVR),这需要浮动 IP 配置。为了让两个实例通过 L3 到达外部网络或彼此之间的通信,流量必须通过网络节点。使用 DVR 方法时,通过在每个计算节点上部署 L3 代理,流量将得到优化,使得北南向(进出外部网络)的浮动 IP 流量可以从计算节点路由并返回,并额外跳转到达网络节点。类似地,东西向(实例间的流量)流量直接路由到计算节点。后者选项对于获得更优化的性能更为推荐。分布式浮动 IP 选项可以在globals.yml文件中启用,如下所示:

...
 neutron_ovn_distributed_fip: "yes"
...

启用 Neutron OVN 代理,通过配置以下设置,提供可扩展的网络监控和服务质量QoS)功能:

...
 neutron_enable_ovn_agent: "yes"
...

接下来,确保调整/ansible/inventory/multi_packtpub_prod库存文件,在指定的节点上安装 OVN 服务。类似于 OVS 配置,确保在控制节点和网络节点上分别运行 Neutron 服务器及相应代理,具体如下:

...
[control]
cc01.os.packtpub
...
[neutron-server:children]
control
[network]
net01.os.packtpub
[neutron:children]
network
[neutron-dhcp-agent:children]
neutron
[neutron-l3-agent:children]
neutron
[neutron-metadata-agent:children]
neutron
...

OVN 在 OpenStack 中部分所讨论,OVS 北向和南向数据库,以及 OVN northd 守护进程,将在控制节点上运行,具体如下:

...
[ovn-database:children]
control
[ovn-northd:children]
ovn-database
[ovn-nb-db:children]
ovn-database
[ovn-sb-db:children]
ovn-database

OVN 控制器实例和 OVN 元数据代理将在计算节点上运行,具体如下:

...
[neutron-ovn-agent:children]
compute
[ovn-controller:children]
ovn-controller-compute
[ovn-controller-compute:children]
compute
[neutron-ovn-metadata-agent:children]
compute
...

重要提示

从 Antelope 版本及以后的版本开始,已经创建了一个专用的 OVN 代理来实现缺失的ovn-controller功能。

启动管道作业应部署 OVN 服务并创建一个 ML2 文件,/etc/neutron/plugins/ml2/ml2_conf.ini,其中包含以下默认配置:

...
[ml2]
tenant_network_types = geneve
type_drivers = local,flat,vlan,geneve
mechanism_drivers = ovn
[ml2_type_geneve]
max_header_size = 38
vni_ranges = 1001:2000
...

默认的网络租户类型配置为使用 GENEVE 作为隧道协议。GENEVE 与 VXLAN(在前述部分中为 OVS 配置的协议)之间的主要区别在于两种协议之间如何封装和编码网络元数据。VXLAN 仅在封装头中编码 VNI。而 GENEVE 协议使用可扩展的 TLV 来承载有关封装头中的数据包的更多信息(其头部长度为 38 字节,而 VXLAN 帧可以承载 8 字节),例如入口出口端口。与 VXLAN 相比,GENEVE 提供了更强大的功能,例如传输安全、服务链和带内遥测。

另一个结果是默认的北向和南向数据库地址。每个计算节点中运行的 OVN 控制器应该能够访问这两个数据库。此配置可以在同一个文件 ml2_conf.ini 中找到,通过检查以下设置:

...
[ovn]
ovn_nb_connection = tcp:10.0.0.24:6642
ovn_sb_connection = tcp:10.0.0.24:6642
ovn_metadata_enabled = True
enable_distributed_floating_ip = True

一旦配置了 OVN,进一步的网络资源创建和管理将由 OVN 处理,它将每个 OpenStack 资源抽象映射到 OVN 南向和北向数据库中的条目对象。

OVS 和 OVN 提供不同的能力来将实例连接到网络。在接下来的章节中,我们将探讨 Neutron 中的路由是如何执行的,并展示 OpenStack 中不同的路由流量选项。

配置云路由

同一虚拟租户网络中的实例可以互相访问,但默认情况下,每个租户网络不能访问其他租户或外部网络。部署虚拟路由器是启用 L3 网络通信的方式,从而通过将子网与路由器关联,连接租户虚拟网络。

路由租户流量

在后台,与租户虚拟网络相关联的端口将与子网网关的 IP 地址相关联。不同虚拟网络中的实例通过虚拟路由器进行通信,使用网关 IP 地址和它们的私有 IP 地址封装在数据包中,从而互相访问。这称为 NAT网络地址转换)机制。在 OpenStack 网络中,Neutron L3 代理管理虚拟路由器。IP 数据包通过虚拟路由器转发到不同的自服务和外部网络,经过以下路由器接口:

  • qr : 包含租户网络网关 IP 地址,专门用于将流量路由到所有自服务流量网络

  • qg : 包含外部网络网关 IP 地址,专门用于将流量路由到外部提供商网络

当虚拟路由器实例启动时,将在 Neutron 节点中创建一个网络命名空间,该命名空间通过路由表、数据包转发和 iptables 规则定义与自服务网络或外部提供商网络的连接。如以下图所示,路由器命名空间指的是附加到多个桥接端口的虚拟路由器(qrqg)。托管在同一或不同计算节点中的实例之间的流量将通过虚拟路由器路由。

图 6.8 – 基于 OVS 实现的 Neutron 路由器命名空间连接

图 6.8 – 基于 OVS 实现的 Neutron 路由器命名空间连接

在之前的 OVS 实现中,L3 代理应该已经启动并运行,以开始创建和管理虚拟路由器。

重要提示

一旦部署了 Neutron 代理 L3,路由器服务插件应默认启用,使用kolla-ansible。可以通过检查 Neutron 云控制器节点的/etc/neutron/neutron.conf文件中的service_plugin = router行来验证该服务插件。

可选地,虚拟路由器可以通过 Horizon 进行管理。Neutron 部署的kolla-ansible运行应在仪表板中启用路由器模块。可以通过在云控制器节点的/etc/openstack-dashboard/local_settings.py文件中检查以下设置来验证:

...
OPENSTACK_NEUTRON_NETWORK = {
    'enable_router': True,
...

在下一个练习中,我们将使用在 OVS 中配置的 ML2 插件创建一个租户虚拟网络。将使用 OpenStack CLI 将虚拟路由器附加到租户网络,如下所示:

  1. 使用 OpenStack 网络 CLI 创建一个租户虚拟网络:

    $ openstack network create network_pp
    
  2. 创建一个 IP 范围为10.10.0.10/24的子网,自动分配 DHCP,默认 DNS 名称服务器为8.8.8.8

    $ openstack subnet create --subnet-range 10.10.0.0/24 --network network_pp --dns-server 8.8.8.8 priv_subnet
    
  3. 创建一个路由器并将其附加到创建的租户网络:

    $ openstack router create router_pp
    $ openstack router add subnet router_pp priv_subnet
    
  4. 路由器附加到租户网络将为路由器的内部接口分配一个私有 IP 地址。默认情况下,如果在附加命令行中没有指定 IP 地址,内部接口将分配子网的默认网关。以下命令行验证路由器内部接口分配的 IP 地址:

    $ openstack port list --router router_pp
    

    它给出的输出如下:

图 6.9 – 虚拟路由器端口列表

图 6.9 – 虚拟路由器端口列表

  1. 可以通过运行以下命令检查带有qr-前缀的路由器命名空间中的路由器接口:

    $ ip netns
    

    输出如下所示:

图 6.10 – 网络命名空间列表

图 6.10 – 网络命名空间列表

  1. 从先前的输出中复制qrouter ID,然后运行以下命令行显示路由器创建的接口以及从内部网络分配的 IP 地址:

    $ ip netns exec qrouter-3a211622-11da-9687-bda1-acae3d74ad12 ip addr show
    

    我们将获得如下输出:

图 6.11 – 虚拟路由器命名空间内部接口列表

图 6.11 – 虚拟路由器命名空间内部接口列表

为使实例能够访问外部网络,应创建虚拟路由器的第二个接口,并将其附加到提供商的外部网络。应将一个常见的网络设置,如外部网络设备或与防火墙设备集成的设备,放置在 OpenStack 端点(如负载均衡器)之前。启用互联网访问可以使用 OpenStack CLI 配置,如下所示:

  1. 创建一个外部网络提供者。如在 OVS 的 ML2 插件中配置的那样,我们可以将网络创建为 VLAN 类型,并定义分段 ID 和physnet1作为物理网络属性:

    $ openstack network create --external -–provider-network-type vlan --provider-segment 40 --provider-physical-network physnet1 external_pp
    
  2. 创建外部网络的子网部分,网络范围为10.20.0.0/24,默认网关为10.20.0.1,禁用 DHCP,并设置分配池为10.20.0.10-10.20.0.100

    $ openstack subnet create --subnet-range 10.20.0.0/24 --no-dhcp
    --network external_pp --allocation-pool start=10.20.0.10,end=10.20.0.100 pub_subnet
    
  3. 通过运行以下命令行,将路由器附加到外部提供商网络:

    $ openstack router set --external-gateway external_pp router_pp
    
  4. 附加操作将从外部 IP 池中分配一个外部 IP 到路由器,可以通过运行以下命令行进行检查:

    $ openstack port list --router router_pp
    

    这是输出结果:

图 6.12 – 创建的虚拟路由器外部端口

图 6.12 – 创建的虚拟路由器外部端口

  1. 最后的附加操作在路由器命名空间中创建一个以qg-为前缀的第二个接口,可以通过以下命令行进行验证:

    $ ip netns exec qrouter-3a211622-11da-9687-bda1-acae3d74ad12 ip addr show
    

    这是输出结果:

图 6.13 – 虚拟路由器命名空间外部接口列表

图 6.13 – 虚拟路由器命名空间外部接口列表

我们的连接性演示的下一部分涉及创建安全组和规则,以允许在网络端口级别的入站和出站流量。为了连接到互联网并访问实例,我们将创建一个新的安全组,并添加ICMPSSH访问:

  1. 使用 OpenStack CLI,创建一个新的安全组并将其应用到你的实例:

    $ openstack security group create SG_pp
    
  2. 创建与已创建安全组相关的规则,用于 SSH 和 ICMP,分别为:

    $ openstack security group rule create SG_pp --protocol tcp --dst-port 22
    $ openstack security group rule create SG_pp --protocol icmp
    
  3. 使用 OpenStack CLI,创建一个新的测试实例,选择tiny规格和cirros镜像,并连接到私有租户网络:

    $ openstack server create --flavor tiny --image cirros-0.5.2 --nic net-id=network_pp --security-group SG_pp instance_pp
    

重要说明

确保根据现有资源调整你的可用 Glance 镜像名称和规格列表。如果任何指定的参数不存在,openstack server create命令将会失败。Cirros 是一个最小化的 Linux 发行版,适用于快速测试和概念验证。默认的会话用户名是cirros,密码是gocubsgo

  1. 为了测试实例是否能连接到互联网,请确保实例的状态是ACTIVE,如下所示:

    $ openstack server list
    

    这是输出结果:

图 6.14 – 实例列表

图 6.14 – 实例列表

  1. 可以通过不同的方式访问创建的实例,使用计算节点上的virsh console命令行,或直接通过路由器命名空间的 SSH 进行访问。确保使用默认的cirros镜像凭证——即用户名cirros和密码gocubsgo——并运行一个简单的 ping 命令以连接到8.8.8.8

    $ ip netns exec qrouter-3a211622-11da-9687-bda1-acae3d74ad12 ssh cirros@10.10.0.12
    

    这是输出结果:

图 6.15 – 测试外部连接性

图 6.15 – 测试外部连接性

  1. 实例使用内部虚拟路由器 IP 地址作为默认网关来路由流量到达外部网络。通过路由器执行 SNAT,互联网可以访问。通过在实例中快速运行ip route命令,可以查看与网络路由表相关联的默认网关:

图 6.16 – 列出默认网关

图 6.16 – 列出默认网关

我们接下来的演示将展示托管在外部网络中的资源如何访问 OpenStack 环境中的实例。默认情况下,启动的实例将被分配一个在租户网络外不可见的 IP 地址。Neutron 提供了浮动 IP 地址来实现DNAT目标 NAT)。路由器通过检查其配置的 DNAT 规则,将到达其外部接口的传入数据包转发到目标实例。实例向外部资源发送的流量响应使用已翻译为浮动 IP 的源 IP 地址,演示如下:

  1. 提取创建的实例的端口 ID,并创建一个浮动 IP 地址与其关联:

    $ openstack port list --server instance_pp
    

    以下是输出结果:

图 6.17 – 列出实例端口

图 6.17 – 列出实例端口

  1. 复制端口 ID,并在-- port选项后粘贴外部端口 ID,然后运行以下命令:

    $ openstack floating ip create --port 524ead12-33da-dc11-e3a1-dc34e6da1c81 external_pp
    

    以下是输出结果:

图 6.18 – 将浮动 IP 地址分配给外部端口

图 6.18 – 将浮动 IP 地址分配给外部端口

  1. 在背后,路由器命名空间配置了一个与外部接口关联的辅助地址,前缀为'qg'

    $ ip netns exec qrouter-3a211622-11da-9687-bda1-acae3d74ad12 ip addr show
    

    以下是输出结果:

图 6.19 – 将 IP 地址与虚拟路由器外部接口关联

图 6.19 – 将 IP 地址与虚拟路由器外部接口关联

通过外部网络提供商路由的流量可以通过分配的浮动 IP 到达实例。

到目前为止,我们已经探讨了在 OpenStack 中实现标准路由的方式。接下来的部分将介绍通过动态路由在 Neutron 中执行路由的另一种方式。

Neutron 动态路由

OpenStack 网络中的动态路由基于BGP边界网关协议),使租户网络能够与支持 BGP 的物理或虚拟路由器和网络设备广告其网络前缀。Neutron 中新增加的 BGP 功能消除了对于不依赖网络管理员来将网络前缀向上游广告的租户网络而言,使用浮动 IP 的需求。Neutron 中的动态路由概念是在Mitaka版本中引入的。BGP 路由机制的采纳因云环境的不同而有所变化,主要取决于网络设置,尤其是要求网络节点与物理网络网关设备之间具有直接连接(如 LAN 或 WAN 对等连接)。为了避免广告 IP 前缀时的 IP 重叠,动态路由依赖于地址范围子网池,这是 Neutron 机制,用来控制子网地址的分配并防止重叠地址的使用。

在 BGP 实现的核心部分,Neutron 引入了 BGP speaker,它使租户网络与外部路由器设备之间能够建立对等连接。BGP speaker 将租户网络广告到租户路由器,最初作为第一跳。Neutron 中的 BGP speaker 不是路由器实例,也不会操作 BGP 路由。它主要负责协调租户路由器与外部路由器之间的 BGP 对等信息。BGP speaker 需要网络或云操作员配置对等端点。如以下图所示,要在 OpenStack 中成功实现 BGP 动态路由,Neutron 虚拟路由器必须同时连接到租户子网和外部提供商设备接口。

图 6.20 – Neutron BGP 对等连接与路由器的动态路由连接

图 6.20 – Neutron BGP 对等连接与路由器的动态路由连接

BGP speaker 和外部提供商设备必须建立对等连接(连接到 Neutron 虚拟路由器)。最后,租户网络和外部网络必须在相同的地址范围内。使用 kolla-ansible 添加 BGP 动态路由非常简单。我们将基于 OVS 实现配置动态路由。

重要说明

自 Antelope 版本以来,Neutron 支持使用 OVN 机制驱动程序进行动态路由。

由于 Neutron 提供了默认配置的 BGP 代理,我们只需要通过将以下行添加到 /ansible/inventory/multi_packtpub_prod 清单文件中,启用网络节点中的代理安装:

...
[neutron-bgp-dragent:children]
neutron

globals .yml 文件中启用代理安装,如下所示:

enable_neutron_bgp_dragent: "yes"

启动管道以在网络节点中部署 BGP 代理安装。在网络节点中,可以通过运行以下命令检查已安装的 BGP 代理:

$ openstack network agent list --agent-type bgp

以下是输出:

图 6.21 – 列出 BGP 网络代理

图 6.21 – 列出 BGP 网络代理

可以通过以下链接找到用于管理 BGP speakers 的 Neutron BGP CLI:docs.openstack.org/python-openstackclient/latest/cli/plugin-commands/neutron.html

虚拟路由器是 OpenStack 网络构建模块的一部分,为租户提供多种连接选项。需要注意的是,使用独立路由器运行会存在单点故障的问题。第七章运行高可用云 – 满足 SLA 将讨论 Neutron 高可用路由器的实现。通过 BGP 在 Neutron 中的动态路由被认为是 OpenStack 中的一项出色的路由补充。Neutron 在 OpenStack 版本中不断得到丰富和修改。其中一项重大修改是 OpenStack 中新网络服务的开发,下一节将讨论这些服务。

加入更多网络服务

除了 Neutron 在最新 OpenStack 版本中提供的强大路由和交换能力外,Neutron 还使云操作员能够提供额外的网络服务。诸如负载均衡、防火墙和私有网络等服务,支持租户网络构建适用于多种用例的良好架构的应用堆栈。在接下来的章节中,我们将介绍最常用和最稳定的额外 Neutron 服务,并使用kolla-ansible进行部署。

负载均衡即服务

Liberty版本发布以来,Neutron 负载均衡即服务LBaaS)插件已从版本 1 升级至版本 2,代号为Octavia。希望通过托管负载均衡器平衡工作负载的云用户,将会欣赏 Octavia 的功能。Octavia 的设计旨在水平扩展,因为它创建并管理作为负载均衡器实例的虚拟机,这些虚拟机被称为amphorae

Octavia 实现了与流行的HAProxy相同的负载均衡术语,具体如下:

  • 虚拟 IP(VIP):一个四层对象,用于暴露服务,供外部或内部访问,并与 Neutron 端口关联。负载均衡器被分配一个 VIP,所有到达 VIP 的请求都会在后端服务器或池成员之间分发。

  • :提供相同内容或服务的一组实例,例如 Web 服务器。

  • 池成员:通过 IP 地址和监听端口表示的池实例,暴露服务。

  • 监听器:与 VIP 相关的端口,用于监听传入的请求。

  • 健康监控器:基于对每个成员进行健康检查来协调池成员的管理。健康检查失败时,将从池中丢弃相应成员,流量将由健康成员处理。

  • 负载均衡算法轮询最少连接数源 IP是 Octavia 中支持的算法,可以在创建池时分配。

  • 会话持久性:强制客户端请求由同一后端服务器处理的机制。自 LBaaS v1 版本废弃以来,Neutron 中的负载均衡服务可以通过驱动程序进行配置。最常见的驱动程序是 HAProxy 和 Octavia。还可以集成其他第三方供应商的驱动程序,如 F5 和 Citrix,Neutron 将管理 OpenStack 环境中的 API 调用编排。Octavia 中不同组件的术语表如下:

    • Amphora:作为负载均衡器的虚拟机,运行在计算节点上,并预配置负载均衡参数,如池、后端成员和健康监控器。

    • 控制器工作节点:更新负载均衡实例(Amphora 实例)并配置其设置。

    • API 控制器:与控制器工作节点交互,用于负载均衡器(Amphora 实例)的配置、操作和部署、删除及监控。

    • 健康管理器:监控每个负载均衡器(Amphora 实例)的状态,并在负载均衡器意外故障时触发故障转移事件。

    • 清理管理器:删除过时的数据库记录并处理备用池。

使用kolla-ansible部署 Octavia 需要的步骤比仅安装代理多。要使用 Octavia 驱动程序在 OpenStack 中安装负载均衡服务,首先将核心 Octavia 组件分配为云控制器的一部分:

...
[octavia:children]
control
[octavia-api:children]
octavia
[octavia-driver-agent:children]
octavia
[octavia-health-manager:children]
octavia
[octavia-housekeeping:children]
octavia
[octavia-worker:children]
octavia

globals .yml文件中启用 Octavia 服务,如下所示:

...
enable_octavia: "yes"

确保在globals .yml文件中,enable_neutron_provider_networks设置为true。这是因为我们需要 Octavia 节点通过管理网络进行通信。分配云控制器节点的eth0管理网络接口:

octavia_network_interface: eth0

kolla-ansible自动化了 Octavia 的绝大部分部署过程,并在 OpenStack 环境中注册相关资源。Octavia 与多个 OpenStack 服务交互,包括 Nova 和 Neutron。相关资源可以在globals .yml文件中自定义,例如 amphorae 的 Nova flavor、安全组、Octavia 网络和子网,可以通过更新octavia_amp_flavoroctavia_amp_security_groupsOctavia 管理网络来设置。默认情况下,kolla-ansible被配置为自动注册所有依赖的 Octavia 资源。如果你想自定义 Octavia 注册服务,确保在globals .yml文件中为每个 Octavia 设置提供所有必需的值。可以在将以下设置从no更改为yes后进行此操作:

octavia_auto_configure: "yes"

运行部署管道以发布 Octavia 服务。部署过程应该创建必要的 Octavia 资源,包括证书、Octavia 网络、flavor、安全组和 SSH 密钥。确保kolla-ansible post-deploy运行成功,通过生成一个octavia-openrc.sh文件,并按以下方式加载:

$ kolla-ansible post-deploy
$ . /etc/kolla/octavia-openrc.sh

Octavia 使用镜像来启动 amphora 实例。运行以下命令下载 Bobcat 发布的最新 amphora 镜像,然后将其添加到 Glance 中:

$ wget https://swift.services.a.regiocloud.tech/swift/v1/AUTH_b182637428444b9aa302bb8d5a5a418c/openstack-octavia-amphora-image/octavia-amphora-haproxy-2023.2.qcow2
$ openstack image create amphora-haproxy --container-format bare --disk-format qcow2 --private --tag amphora --file octavia-amphora-haproxy-2023.2.qcow2 --property hw_architecture='x86_64' --property hw_rng_model=virtio

以下步骤假设已部署名为instance1instance2的两个 Web 服务器实例,并且它们已连接到之前演示中使用的租户网络10.10.0.0/24

  1. 请注意创建的两个实例:

    $ openstack server list
    

    以下是输出:

图 6.22 – 列出创建的实例

图 6.22 – 列出创建的实例

  1. 为了快速模拟负载均衡练习,在每个实例中运行SimpleHTTPServer Python 模块。创建一个简单的index.html文件来跟踪负载均衡器成员池的使用情况。在instance1上运行以下命令:

    $ echo "Reaching instance 1" > ~/index.html
    $ python -m SimpleHTTPServer
    
  2. 通过在index.html文件中指定第二个实例,运行相同的命令:

    $ echo "Reaching instance 2" > ~/index.html
    $ python -m SimpleHTTPServer
    
  3. 确保通过创建并添加以下安全组和规则来允许实例的入口端口80,如果尚未附加的话:

    $ openstack security group create lb-web-sg
    $ openstack security group rule create --ingress --protocol http --dst-port 80 --ethertype IPv4 lb-web-sg
    $ openstack server add security group instance1 lb-web-sg
    $ openstack server add security group instance2 lb-web-sg
    
  4. 创建一个附加到私有子网priv_subnet的负载均衡器。请注意,负载均衡器将被分配一个 VIP,用于暴露后端服务并允许客户端访问:

    $ openstack loadbalancer create --name lb --vip-subnet-id 
    priv-subnet
    

    这是输出结果:

图 6.23 – 创建负载均衡器

图 6.23 – 创建负载均衡器

  1. 一旦负载均衡器将其PROVISIONING_STATUS状态从PENDING_CREATE更新为ACTIVE,并且OPERATING_STATUS更新为ONLINE,则在端口80上创建一个名为listener80的 TCP 监听器端口:

    $ openstack loadbalancer listener create --name listener80 --protocol TCP --protocol-port 80 lb
    
  2. 创建一个名为poolweb的负载均衡池,并使用ROUND_ROBIN指定负载均衡算法:

    $ openstack loadbalancer pool create --name poolweb --lb-algorithm ROUND_ROBIN --listener listener1 --protocol TCP
    
  3. 为创建的poolweb添加健康监视器,并探测 HTTP 服务端口:

    $ openstack loadbalancer healthmonitor create --name http-check --delay 15 --max-retries 4 --timeout 30 --type HTTP poolweb
    
  4. 将后端实例(instance1instance2)加入到poolweb

    $ openstack loadbalancer member create --subnet-id private-subnet --address 10.10.0.114 --protocol-port 80 poolweb
    $ openstack loadbalancer member create --subnet-id private-subnet --address 10.10.0.125 --protocol-port 80 poolweb
    
  5. 可选地,检查已添加的后端成员和创建的池的状态:

    $ openstack loadbalancer member list poolweb
    

    这是输出结果:

图 6.24 – 列出负载均衡池的实例成员

图 6.24 – 列出负载均衡池的实例成员

  1. 通过连接到负载均衡器的 VIP 来测试负载均衡器。请注意,负载均衡使用的算法是轮询法(round robin),请求将被连续服务于两个实例:

    $ for ((i=1;i<=10;i++)); do curl http://10.10.0.14; sleep 1; done
    

    这是输出结果:

图 6.25 – 测试负载均衡池的后端

图 6.25 – 测试负载均衡池的后端

重要提示

从互联网访问池的 Web 后端有多种方式。一种方式是将负载均衡器直接连接到公共网络,而无需运行在虚拟路由器后面,负载均衡器 VIP 将被分配一个公共可路由 IP。另一种方式是创建一个浮动 IP,然后将其与负载均衡器的 VIP 关联,该 VIP 位于虚拟路由器后面的子网中。没有路由器应用 IP 转换并使用分配的浮动 IP 映射到公共 IP,浮动 IP 是无法通过互联网路由的,无法访问外部网络。

在 Neutron 中创建负载均衡器时,一个良好的做法是首先考虑安全性。OpenStack 中最新的 LBaaS 版本支持 TLS 证书部署。更好的是,OpenStack 拥有一个专门的项目来处理密钥和证书,代号为Barbican。要了解有关 Barbican 的更多信息,请参考 OpenStack 官方文档:docs.openstack.org/barbican/latest/。负载均衡器可以与 Barbican 服务配合使用,以最安全的方式处理其 TLS 证书。

摘要

OpenStack 网络提供了一个丰富的功能列表,使云运营商和架构师能够实现先进的网络拓扑,并为云用户和租户提供更多的托管网络服务。如本章所述,ML2 插件通过解锁一些在旧版本 OpenStack 中缺失的相关功能,扩展了 Neutron 的能力。OVS 作为机制驱动程序,基于流规则带来了更多的流量控制。对于需要常见 VLAN 和 VXLAN 拓扑的扩展网络,本章展示了在最新 OpenStack 版本中,Neutron 对 OVS 和 OVN 驱动程序的支持,以及它们使用kolla-ansible的部署。值得注意的是,基于机制驱动程序的未来网络方向几乎肯定会朝着采用 OVN 机制驱动程序发展,因为它在更大规模的生产级别和混合云环境中的性能表现突出。另一个大话题是 OpenStack 网络中的路由问题,本章还探讨了使用 OVS 的路由实现,并覆盖了 BGP 动态路由。OVN 正成为实现 BGP 的流行方式,未来的版本可能会在这一方向上提供更稳定的集成。然而,本章并未涉及所有其他额外的 Neutron 服务和代理,如VPN 即服务防火墙即服务Designate(DNS 管理)。Neutron 中的 LBaaS 在最新的 OpenStack 版本中有了更多的更新。通过新的 LBaaS v2,云运营商可以使用开源驱动程序,如 HAProxy 或 Octavia,配置他们的负载均衡服务。最后,本章展示了使用 Octavia 部署负载均衡器设置的过程,Octavia 已成为一种广泛采用的 LBaaS 解决方案,适用于大规模生产环境。

在下一章中,我们将通过解决 OpenStack 控制平面和数据平面的弹性与高可用性问题,来增强我们部署的 OpenStack 环境。

第二部分:运营 OpenStack 云环境

本部分将重点关注云运营商将云环境提升到下一个阶段的运营任务。将涵盖基本的运营卓越支柱,包括高可用性、监控与日志记录,以确保业务连续性,并关注云健康的常见最佳实践。本部分将以关于建立持续的基础设施评估和资源优化布局的独家内容作为结束。

本部分包括以下章节:

  • 第七章运行高可用的云——满足 SLA 要求

  • 第八章监控与日志记录——主动修复

  • 第九章基础设施基准测试——评估资源容量与优化

第七章:7

运行高可用云 – 满足 SLA

“过去比未来更像,就像一滴水不像另一滴水一样。”

– 伊本·赫尔敦

成功的云操作经验的一个主要方面是防止停机以及云资源和工作负载的故障。在第一章重新审视 OpenStack – 设计考虑中,我们草拟了一个初步的准备设计,以支持 OpenStack 服务的冗余。第三章OpenStack 控制平面 – 共享服务,和第四章OpenStack 计算 – 计算能力与规格,探讨了 OpenStack 控制平面部署的逻辑设计模式以及分离计算的一些方式,例如单元和可用性区域。OpenStack 被设计为大规模扩展,并且为专用的 OpenStack 服务提供硬件可以帮助隔离故障,但这需要机制来确保在事故发生时服务能够继续运行。

在 OpenStack 世界中,确保高可用性HA)与任何其他复杂的 IT 系统并没有太大区别。一项必不可少的做法是通过逻辑的 OpenStack 配置,找出并消除任何可能的单点故障SPOFs),这些故障点在不同设计中有所不同。本章的目标是在私有云基础设施的每一层实现 HA。

本章将涵盖以下主题:

  • 回顾 HA 和故障切换策略,以确保业务连续性

  • 反复探讨 OpenStack 控制平面 HA 设计模式

  • 使用 kolla-ansible 部署具有额外云控制器的 OpenStack 环境,以实现容错和冗余

  • 探索使用最新 OpenStack 更新实现 Neutron 网络 HA 的不同方式,包括路由和分布式虚拟路由器机制

  • 揭示本地 OpenStack 解决方案,通过 Masakari OpenStack 项目确保实例故障切换

探索 HA 策略

一个稳健的 OpenStack 云平台包括每个层级的容错能力。如果提前规划得当,这种设计可以非常成功。从小规模集群开始很容易并且可以实现,但扩展它是一个挑战。基本的 OpenStack 组件特点是能够在普通硬件上运行。OpenStack 设计之初就是为了大规模扩展,并通过在基础设施的每个层次上运用更先进的 HA 技术来提供 HA。这可能包括自动故障切换地理冗余第四章OpenStack 计算 – 计算能力与规格,介绍了单元、区域和可用性区域的概念,这些概念为大规模 OpenStack 部署提供了更强大和先进的容错和可用性能力。

衡量 HA

服务可用性应该通过标准的度量来衡量和定义。这可以用以下公式来总结:

可用性 = MTTF / (MTTF + MTTR)

在前述的方程中,我们可以看到以下内容:

  • 平均故障时间(MTTF):估计系统在故障前的平均运行时间

  • 平均修复时间(MTTR):估计修复系统部件或组件的平均时间

在像 OpenStack 这样的复杂环境中衡量高可用性,需要对部署的云环境能力有良好的理解,这些能力可以通过性能指标和关键绩效指标(KPI)进行跟踪,例如响应时间、系统正常运行时间和停机时间,用于修复时间目标RTO)和修复点目标RPO)。对于最终用户而言,更为关键的是从收集到的指标和 KPI 中揭示服务级别协议SLA),并基于此进行改进。SLA 根据常规收集的指标确定改进的领域,并将促进您的业务连续性策略。可用性管理是 IT 最佳实践的核心支柱,特别是在运行包括 OpenStack 在内的多个服务的云环境中,不能被忽视。为每项服务创建这些 SLA 的详细内容将占据整本书。为了简化,确保您参与可用性管理实践,并通过为每项服务分配可用性级别以及可用性和停机百分比来更新 SLA,如下表所示:

服务 可用性级别 可用性 停机时间/天
计算 一个 9 90 ~ 2.4 小时
网络 两个 9 99 ~ 14 分钟
计算 三个 9 99.9 ~ 86 秒
块存储 四个 9 99.99 ~ 8.6 秒
对象存储 五个 9 99.999 ~ 0.86 秒
镜像 六个 9 99.9999 ~ 0.0086 秒

表 7.1 – OpenStack 环境服务的 x-9s 示例 SLA

在设计 HA OpenStack 设置的架构时,应为云架构的每一层都规划好故障应对。这可以通过先进的 HA 模型和技术来实现。最新的 OpenStack 版本甚至更加丰富,内置了不仅为核心组件,还为用户工作负载提供高可用性的功能。例如,如果一台主机故障,运行在其上的应用将无法再访问。Nova 支持通过将来宾实例迁移到新的健康主机来恢复故障实例。对于扩展的 OpenStack 设置,云环境可以通过重新调用 Nova 服务下的可用区来扩展更多的域故障。HA 设计模式的核心可以总结为以下几点:

  • 消除控制平面和数据平面中的任何单点故障(SPOF)

  • 在可能的情况下采用地理复制设计

  • 自动化监控和异常检测

  • 规划并自动化快速灾难恢复

  • 尽可能地解耦并隔离 OpenStack 组件

在 OpenStack 的世界中,可以识别不同级别的高可用性(HA):

  • L1:这包括物理主机、网络和存储设备以及虚拟机管理程序(Hypervisors)。

  • L2:这包括 OpenStack 服务,包括计算、网络和存储控制器,以及数据库和消息队列系统。

  • L3:这包括在主机上运行并由 OpenStack 服务管理的虚拟机。

  • L4:这包括在虚拟机中运行的应用程序。

支持 OpenStack 高可用性(HA)的主要关注点是 L1、L2 和 L3。

设计高可用性(HA)

设计系统时的一个关键方面是考虑系统中每个元素可能发生故障的所有情况。每个元素都有一定的限制,在至少短时间内无法恢复,这会影响系统的其他部分,导致整个系统变得无响应。在考察旨在最大化可扩展性和可用性的常见设计模式时,重要的是要识别出两类主要服务:

  • 有状态服务:一种依赖于先前请求数据并进行同步交互以保持一致性的服务。由于这类服务依赖于状态,因此服务故障可能会影响整个系统,并且需要更多的备份和恢复机制来维持状态信息。

  • 无状态服务:一种不需要从先前请求或事件中保存数据或信息(状态)的服务。由于这类服务不在请求之间存储状态,因此突发故障不会影响系统的其余部分,系统可以在不同的处理器实例中继续运行。

如在 第三章 中讨论的,OpenStack 控制平面 – 共享服务,OpenStack 控制平面主要由无状态服务构成,包括 API、调度器、代理和处理器组件,涵盖所有计算、网络、镜像、监控和存储服务。数据库和消息队列系统属于有状态服务。这样,将 HA 引入我们初步的设置中,就需要验证每个服务和组件的正确模式,以确保在突发故障期间服务的连续性。有多种方式可以实现 OpenStack 控制平面的 HA,这些方式可以通过以下设计模式来总结,这些模式都在 第三章 中介绍过,OpenStack 控制平面 – 共享服务

  • 主动/被动:在 OpenStack 控制平面中,故障服务会在第二个云控制器节点上重新启动。对于像数据库这样的有状态服务,主节点处理所有的读写操作,第二个节点充当监听者,直到发生故障转移,此时数据入口点会切换到第二个节点。此模式适用于一些有状态服务,但不适用于其他无状态的 OpenStack 服务。此外,它不完全符合 OpenStack 中的横向扩展要求。

  • 主动/主动:在这种模式下,进入 OpenStack 控制平面的请求负载被分配到多个活动节点,这些节点并行处理。此模式在 OpenStack 部署中为控制平面和数据平面服务提供了最高级别的容错性。如果某个云控制器发生故障,剩余的负载将分配给第二个运行中的节点,从而保持服务不中断。该模式也适用于横向扩展,因为它可以添加新节点以适应增加的负载,而不影响集群的功能。由于 OpenStack 核心组件基于 API 调用和 RPC 通过队列消息系统处理消息,因此性能至关重要。在主动/主动模式下,服务恢复的平均修复时间(MTTR)比主动/被动模式短,后者可能出现较长的故障转移延迟,导致某些 OpenStack 服务超时。

大多数 OpenStack 参考架构采用主动/主动的基础架构设置,以实现容错和故障转移,主要是由于 OpenStack 服务的特性,这些服务可以轻松地横向扩展,并且不需要额外的机制。另一方面,某些服务可以根据服务的性质配置为主动/被动模式。在下一节中,我们将探讨可用于启用高可用性的不同服务。

为高可用性做好准备

每个 OpenStack 控制平面层都需要单独分析,以确定确保其可用性的最佳方法。在为生产环境设计容错时,还需要考虑其他技术因素。需要注意的是,不同选择的一个主要因素来自于给定云服务提供商在工具或硬件解决方案方面的经验。在本节中,我们将介绍一些主要采用的工具和设计模式,以实现高度可用且可扩展的 OpenStack 控制平面。

负载均衡设计

负载均衡解决方案服务无处不在,可以高效地分配并服务来自服务器池的传入请求。HAProxy 已被广泛采用,在数十个大型 OpenStack 生产部署中得到了应用。

HAProxy 设置涉及以下两种类型的服务器:

  • 前端服务器:此服务器监听来自特定 IP 和端口的请求,并决定将连接或请求转发到何处。

  • 后端服务器:集群中接收转发请求的服务器池

同时也需要注意在 HAProxy 负载均衡中涉及的功能层:

  • 第 4 层:负载均衡在 OSI 模型的传输层执行。所有用户流量将根据特定的 IP 地址和端口转发到后台服务器。例如,负载均衡器可能会将内部 OpenStack 系统的请求转发到 Horizon Web 后台服务器组。为此,无论选择哪个后台 Horizon 服务器,都应该在其范围内响应请求。在所有 Web 后台服务器提供相同内容的情况下,这一规则适用。

  • 第 7 层:将使用应用层进行负载均衡。这是一种非常有效的网络流量负载均衡方法。简而言之,这种模式允许你根据请求内容将请求转发到不同的后台服务器。

HAProxy 支持多种负载均衡算法,以将请求调度到后台池中的服务器:

  • 轮询:每个服务器依次使用。作为一种简单的 HAProxy 配置,轮询是一种动态算法,它定义了服务器的权重,并在被调用的实例挂起或启动较慢时动态调整该权重。

  • 最少连接数:选择服务器基于拥有最低连接数的节点。

  • :该算法确保基于源 IP 的哈希值将请求转发到相同的服务器,只要服务器仍然在线。

  • 统一资源标识符URI):这确保请求会基于 URI 转发到相同的服务器。它在代理缓存实现的情况下,理想用于提高缓存命中率。

HAProxy 通过对特定 IP 地址和端口执行健康检查,监控节点的后台可用性。它会禁用任何未通过健康检查的后台节点,并将其从后台池中移除,直到它恢复健康,能够重新处理请求。

配备负载均衡器后,部署在两个或更多节点上的 OpenStack 服务将通过虚拟 IPVIP)暴露。在活动/活动模式下,VIP 由负载均衡器管理,负载均衡器会确保在转发请求之前,节点的可用性足够。

重要说明

如果考虑将 HAProxy 部署分离到独立的物理环境中,请确保 VIP 可以通过公共网络访问。

由于将 VIP 与 HAProxy 结合使用增加了保护 OpenStack 服务免受故障的额外层,因此负载均衡层不应出现单点故障。根据您采用的软件或硬件负载均衡解决方案,确保增加其冗余级别。这应作为一个关键的网络设置进行审查,因为它定义了 OpenStack 环境的第一个接口。可以通过使用诸如 KeepalivedPacemaker 之类的 VIP 软件管理工具来实现这一目标,从而确保负载均衡层的高可用性。Keepalived 是一款免费软件,使用 虚拟路由冗余协议VRRP)通过使 IP 高可用来消除单点故障(SPOF)。如下图所示,VRRP 实现了虚拟路由,在静态的默认路由环境中执行两个或多个服务器之间的故障转移任务:

图 7.1 – 使用 HAProxy 和 Keepalived 进行负载均衡和故障转移

图 7.1 – 使用 HAProxy 和 Keepalived 进行负载均衡和故障转移

重要说明

为了确保 Keepalived 能轻松判断仲裁,我们将通过由 Keepalived 管理的三个云控制节点为我们的控制平面提供高可用性(HA)。

数据库的高可用性

数据库一直是处理数据存储增长、性能和弹性时的关键课题。这是因为数据库并不是一个简单的服务,且其扩展速度远不如简单的 API。任何到达 OpenStack API 服务的请求都会导致数据库的大小逐渐增加。在我们的部署过程中,使用 CI/CD 流水线的每次运行都会在多个表中生成一些额外的条目。如果没有设计成可扩展且进行紧密监控,数据库可能会面临故障,迅速成为瓶颈。多个开源和数据库供应商提供了可能的拓扑结构,以实现水平或垂直扩展,或两者兼具。另一个因素是 OpenStack 支持的数据库引擎类型,以及云运维团队在 OpenStack 中构建和架构高可用、可扩展的数据库解决方案所需的经验。

由于我们已经开始使用基于 MySQL 的单一数据库的初始生产草案,我们可以突出最常见的集群拓扑:

  • 主从复制:当主节点失败时,VIP 将切换到从节点。在故障切换时,主节点健康检查的延迟以及将 VIP 分配给从节点的延迟,可能导致数据不一致,如下所示:

图 7.2 – 数据库主从复制

图 7.2 – 数据库主从复制

  • 多主复制管理器 (MMM) : 通过设置两个服务器,它们都会成为主服务器,只在给定时间保持一个可接受的写入查询。这仍然不是一个非常可靠的 OpenStack 数据库高可用性(HA)解决方案,因为在主服务器发生故障时,可能会丢失一定数量的事务,如下所示:

图 7.3 – 数据库 MMM 复制

图 7.3 – 数据库 MMM 复制

  • MySQL 共享存储 : 在此拓扑结构中,两个服务器依赖于冗余的共享存储。如下面的图所示,数据处理的服务器和存储设备之间需要分离。请注意,任何时候都可能存在一个活动节点。如果它失败,另一节点会在检查到故障节点的不活动后接管 VIP,并将其关闭。此解决方案在正常运行时间方面非常优秀,但可能需要强大的存储/硬件系统,这可能非常昂贵。服务将在另一个节点上恢复,通过挂载共享存储到已接管的 VIP:

图 7.4 – 使用共享存储的数据库 MySQL

图 7.4 – 使用共享存储的数据库 MySQL

  • 块级复制 : 最常采用的高可用性实现之一是 分布式复制块设备 (DRBD) 复制。简而言之,它在块设备中复制数据,块设备即在 OpenStack MySQL 节点之间共享的物理硬盘。DRBD 可以是一个无成本的解决方案,但从性能上讲,当依赖于数百个节点时,它并不足够。它也可能影响复制集群的可扩展性:

图 7.5 – 数据库块级复制

图 7.5 – 数据库块级复制

  • MySQL 多主复制与 Galera : 基于 多主复制Galera 方案在 MySQL/InnoDB 数据库集群的 MMM 架构中存在一些性能挑战。Galera 配置正常运行的要求是至少有三个节点。如下面的图所示,同步复制由 Galera 管理,数据在整个集群中进行复制:

图 7.6 – 使用 Galera 复制的数据库多主

图 7.6 – 使用 Galera 复制的数据库多主

关于这些拓扑,任何 MySQL 复制设置都可以简单地设置并使其具有高可用性,但在故障切换过程中可能会丢失数据。Galera 提供的 MySQL 多主复制系统被精心设计来解决这种多主数据库环境中的冲突。你在典型的多主设置中可能会遇到的问题是,所有节点都试图用不同的数据更新相同的数据库,尤其是在主节点故障期间发生同步问题时。这就是为什么 Galera 使用基于认证的复制CBR)。CBR 的主要机制是假设数据库可以回滚未提交的更改,并且是事务性的,此外,所有实例上的复制事件将以相同的顺序应用。复制是真正的并行化;每个都需要进行 ID 检查。Galera 给我们的 MySQL(OpenStack 中的 MariaDB)高可用性带来的附加值是可扩展性,诸如在生产环境中自动将节点加入 Galera。最终的设计带来了最小延迟和事务丢失的主动/主动多主拓扑。在 OpenStack 中为 MariaDB 实现 Galera 时,确保数据一致性的最佳实践是将写操作仅提交到三台节点中的一个。

消息总线的高可用性

RabbitMQ 主要负责不同 OpenStack 服务之间的通信。问题很简单:没有队列,就没有 OpenStack 服务的相互通信。RabbitMQ 应被视为另一个关键服务,需要保持可用并能够承受故障。

重要说明

各种队列消息系统,如 Qpid 或 ZeroMQ,已经足够成熟,可以支持自身的集群设置,无需与其他资源管理器或集群软件一起运行。

RabbitMQ 是一个强大的消息系统,可以通过以下模式之一以主动/主动方式实现可扩展性:

  • 集群:RabbitMQ 经纪人所需的任何数据或状态都会在所有节点之间复制。

  • 镜像队列:由于消息队列无法在其所在的节点中生存,因此 RabbitMQ 可以作为主动/主动高可用消息队列。简而言之,队列会在同一 RabbitMQ 集群中的其他节点上进行镜像。因此,任何节点故障都会自动切换到其中一个队列镜像。

  • 法定队列:这是一种现代版的队列,使用Raft协议的变体(使分布式系统的成员能够在发生故障时就一组值达成一致并共享数据),通过分布式共识算法并实现复制的 FIFO。每个法定队列都有一个领导者和多个追随者,复制队列托管在不同的主机上。

由于镜像队列存在的同步失败和性能问题,RabbitMQ 已弃用镜像队列的实现,转而采用 quorum 队列。这解决了前者的一些问题。在 OpenStack 中,随着大量消息总线流量的传输,quorum 队列不仅能够提高可用性,还能增强消息的一致性,如下图所示:

图 7.7 – RabbitMQ 经纪人 quorum 模式

图 7.7 – RabbitMQ 经纪人 quorum 模式

在下一节中,我们将通过引入上述元素,扩展我们的部署,启用 OpenStack 环境中的高可用性(HA)和冗余。

部署高可用性(HA)

本节中,我们将通过扩展我们的 OpenStack 控制平面,采用由以下节点组成的高可用配置,来扩展最初的生产部署:

  • 虚拟 IP10.0.0.47

  • HAProxy 01hap1.os.packtpub):10.0.0.20

  • HAProxy 02hap2.os.packtpub):10.0.0.21

  • Cloud Controller 01cc01.os.packtpub):10.0.0.100

  • Cloud Controller 02cc02.os.packtpub):10.0.0.101

  • Cloud Controller 03cc03.os.packtpub):10.0.0.102

我们的 OpenStack 环境的 HA 版本要求我们在 globals.yml 文件中应用以下配置:

  • 启用 HAProxy,默认情况下将使用 Keepalived 来设置 HA:

    enable_haproxy: "yes"
    
  • 为 VIP 分配一个不用于管理网络的地址,HAProxy 主机连接并运行 Keepalived 的网络可以使用此地址。可选地,可以将外部和内部 VIP 分开。以下设置将使用相同的内部 VIP 地址:

    kolla_external_vip_address: "10.0.0.47"
    
  • RabbitMQ quorum 是 OpenStack 中消息队列高可用性的默认实现。在某些旧版本的 kolla-ansible 中,使用镜像队列,并通过 om_enable_rabbitmq_high_availability 设置引用它们。请确保禁用此设置,改用 quorum 队列,可以通过检查 ansible/group_vars/all.yml 文件来确认,或者如果在 globals.yml 文件中不存在该变量集,则添加以下变量集:

    om_enable_rabbitmq_quorum_queues: true
    

重要提示

在运行环境中填充 quorum 队列需要使用 kolla-ansible stop --tags kolla-ansible deploy --tags 命令手动重启所有 OpenStack 服务,其中 是指定 OpenStack 服务的名称。建议通过管道自动化服务重启,以保证配置的一致性和队列的持久性。

下一个配置更新是调整 multi_packtpub_prod 文件。以下布局建议部署三个云控制器节点:

...
[control]
cc01.os.packtpub
cc02.os.packtpub
cc03.os.packtpub

将添加一个新的主机组,包含两台负载均衡器,分别运行 HAProxy 和 Keepalived:

...
[haproxy]
hap1.os.packtpub
hap2.os.packtpub
[loadbalancer:children]
haproxy

第三章所述,OpenStack 控制平面 – 共享服务,关于生产环境的最佳实践之一是,只有在核心服务至少配置了 HA(高可用性)后,才开始在云环境中托管工作负载。由于尚未运行生产工作负载,因此建议通过执行以下命令行来清理运行环境:

$ kolla-ansible -i ./multi_packtpub_prod destroy --yes-ireally-really-mean-it

这将清理 OpenStack 服务容器及相关卷。新的流水线运行将从相同的镜像部署所有容器。

Galera InnoDB 的数据库部署将在三个控制节点上运行wsrep服务。在运行环境中部署额外节点时,常见问题之一是一个或两个节点无法读取二进制日志并更新复制状态。RabbitMQ 仲裁也需要额外的手动调整,以清理现有的交换并在不同的云控制器节点之间使用仲裁时迁移到持久队列。

在运行流水线之前,先提交更改。由于将同时部署新的云控制器节点和负载均衡器,并在不同节点上部署多主数据库仲裁队列,滚动更新新的多节点基础设施将比第一次运行花费更多时间。

一旦流水线完成多节点部署,在任何控制节点上运行以下命令行,观察为 HAProxy 和 Keepalived 加载的 Docker 镜像:

$ sudo docker images

我们将得到以下输出:

图 7.8 – 列出 HAProxy 和 Keepalived Kolla 镜像

图 7.8 – 列出 HAProxy 和 Keepalived Kolla 镜像

除了 OpenStack 服务的不同容器外,还应注意运行 HAProxy 和 Keepalived 的容器:

$ sudo docker ps

以下是输出内容:

图 7.9 – 列出 HAProxy 和 Keepalived Kolla 容器

图 7.9 – 列出 HAProxy 和 Keepalived Kolla 容器

可选地,验证所有计算节点是否可以作为 OpenStack 环境的一部分列出,并检查服务状态,方法如下:

$ openstack availability zone list --compute --long

输出如下:

图 7.10 – 列出所有 OpenStack 环境中启用的 Nova 服务

图 7.10 – 列出所有 OpenStack 环境中启用的 Nova 服务

每个在云控制器节点上部署的 HAProxy 实例都分配了一个优先级 ID,Keepalived 使用这个 ID 来引用选举出的主节点。每个控制节点中生成的文件可以在/etc/kolla/keepalived/keepalived.conf文件中找到。以下是其中一个云控制器节点上生成的 Keepalived 配置片段:

vrrp_instance kolla_internal_vip_51 {
    state BACKUP
    nopreempt
    interface br0
    virtual_router_id 51
    priority 40
    advert_int 1
    virtual_ipaddress {
        10.0.0.47 dev br0
    }
}
...

kolla_internal_vip_51 配置块定义了一个随机唯一的 VIP ID,可以通过更改 globals.yml 文件中的 keepalived_virtual_router_id 变量来设置。显示的默认值是 51,它指的是 Keepalived 配置中的 virtual_router_id 值。一旦由 Keepalived 管理的集群启动,每个节点将分配一个优先级,优先级越高,越优先获得 VIP,从而被选为主节点。在这个例子中,当前云控制器节点的优先级为 40。可以通过快速检查 Kolla Keepalived 容器日志来验证每个云控制器的状态。在以下示例中,当前云控制器被分配了主节点状态:

$ docker logs -f keepalived

我们得到以下输出:

图 7.11 – 验证 Keepalived 主节点分配

图 7.11 – 验证 Keepalived 主节点分配

在被选为主节点后,Keepalived 将 10.0.0.47 的 VIP 分配给云控制器节点。在这个例子中,云控制器 02(10.0.0.101)被分配了该 VIP。可以通过在主机中执行以下命令来检查:

$ ip a

它给出了以下输出:

图 7.12 – 检查 Keepalived VIP

图 7.12 – 检查 Keepalived VIP

在我们的 OpenStack 部署中启用 HAProxy 和 Keepalived 可确保大多数 OpenStack 服务的高可用性。另一方面,OpenStack 网络可能需要额外的加固才能启用故障容错能力,具体内容将在下一个子部分中描述。

网络的高可用性(HA)

OpenStack 网络服务涉及不同的组件,包括 Neutron 服务器 L2、L3、元数据和 DHCP 代理。L2 代理安装在每个计算节点上,无需维护其 HA 配置。DHCP 和元数据代理在多个节点上运行,默认支持高可用性配置。

另一方面,L3 代理需要更多的调整才能实现高可用性(HA),因为它们负责以下几个方面:

  • 每个租户管理虚拟路由器

  • 为实例提供外部连接

  • 为实例管理浮动 IP 以访问外部网络

Icehouse 版本之前,没有内置的解决方案来解决 L3 代理的 HA 问题。一些解决方法是利用外部集群方案,例如使用 Pacemaker 和 Corosync。自 Juno 版本以来,OpenStack 为 Neutron 引入了新的 HA 模式,包括以下选项:

  • 虚拟路由冗余 协议VRRP

  • 分布式虚拟 路由DVR

接下来的几个部分将讨论如何使用 VRRP 和 Keepalived 实现冗余的 Neutron 路由器配置。

使用 VRRP 实现路由冗余

本章中我们简要介绍了 VRRP 的概念。在网络上下文中,VRRP 和 Keepalived 在 Neutron 中配置,以在路由器命名空间之间实现短时间的故障转移。如下面的图示所示,路由器可以按组的形式呈现,每个组中的活动路由器正在将流量转发到实例:

图 7.13 – 使用 VRRP 的路由冗余

图 7.13 – 使用 VRRP 的路由冗余

此外,实例流量会根据主路由器及其余备份路由器的调度分布在所有网络节点之间。基于 Keepalived 机制的相同概念,主路由器会在内部配置其 VIP,并持续向路由器组通告其状态和优先级。

每个 VRRP 组根据分配的优先级选举一个主路由器,ID 值最高的路由器将被选为主路由器,其余的作为备份路由器。只有当主路由器停止向指定组发送 VRRP 广告时,才会进行新的选举投票,此时主路由器将被标记为失败。

每个新创建的 HA 路由器将添加一个新的路由器命名空间,在该命名空间中其 L3 代理启动 Keepalived。在背后,配置为 HA 模式的路由器将能够通过特定的 HA 网络进行通信,该网络对用户不可见。HA 网络接口表示为ha

重要说明

活跃路由器需要定期向备份路由器通告其状态,这一状态由广告间隔计时器决定。如果备份路由器未收到此类信息,它将基于最后一次广告的 VRRP 开始新的主路由器选举过程。该选举基于优先级,优先级值最高的路由器将被选为主路由器。优先级范围从0255,其中255为最高优先级。

默认情况下,Neutron 会自动创建一个 HA 池范围网络169.254.192.0/18,该网络由启用 HA 模式的租户路由器使用。以下配置展示了在 Neutron 中使用 VRRP 和 Keepalived 进行路由器容错的设置。根据我们的初始设计,将会添加一个运行 L3 代理并配置了 Open vSwitch 机制驱动的 Neutron 节点,该驱动支持 HA 路由器。

在清单文件中添加第二个网络节点,该节点运行 L3 代理,并可选地运行 DHCP 和元数据代理,如下所示:

...
[network]
net02.os.packtpub
...

运行流水线,并通过在控制节点上运行以下命令,确保 L3 代理正在正常运行:

$ openstack network agent list --agent-type l3

输出将如下所示:

图 7.14 – 列出已安装的 Neutron L3 代理

图 7.14 – 列出已安装的 Neutron L3 代理

重要说明

确保新网络节点连接到与第一个网络节点相同的网络段,如 第一章 重温 OpenStack – 设计考虑 中所示。第二个节点将使用与 globals.yml 文件中配置的 Open vSwitch 相同的 Neutron 机制驱动程序。

globals.yml 文件中将以下配置设置为 yes 以启用 Neutron L3 代理的 HA 状态:

enable_neutron_agent_ha: "yes"

运行管道以应用 Neutron 配置文件中的新更改。应该重启 Neutron 服务,并在 /etc/neutron/neutron.conf 文件中将 l3_ha 设置为 True。虚拟路由器上最多可调度的 L3 代理数量默认为 3,用于构建 VRRP 虚拟路由器。可以通过设置 roles/neutron/defaults/main.yml 文件中的 max_l3_agents_per_router 的值来修改此设置。

使用这些新设置,任何新创建的路由器都被视为 HA 路由器,而不是传统路由器。通过设置 ha 标志来创建新路由器:

$ openstack router create --ha haRouter

在运行 L3 代理的不同网络节点中,可以通过其在第一个网络节点中创建的命名空间观察到新创建的路由器:

@net01.os:~#ip netns | grep router
qrouter-ba14211-22ae-3422-cda1-aeb623dacd11
And on the second network node:
@net02.os:~#ip netns | grep router
qrouter-ba14211-22ae-3422-cda1-aeb623dacd11

一旦创建了 HA 路由器,主路由器将在任何给定时间分配一个虚拟 IP 地址 169.254.0.1

$ ip netns exec qrouter-ba14211-22ae-3422-cda1-aeb623dacd11 ip addr show

输出结果如下:

图 7.15 – 列出主路由器的路由器命名空间和 HA 范围

图 7.15 – 列出主路由器的路由器命名空间和 HA 范围

让我们检查在第二个节点上运行备份路由器的输出:

$ ip netns exec qrouter-ba14211-22ae-3422-cda1-aeb623dacd11 ip addr show

我们得到以下结果:

图 7.16 – 列出备份路由器的路由器命名空间和 HA 范围

图 7.16 – 列出备份路由器的路由器命名空间和 HA 范围

Neutron 在创建 HA 路由器时,会自动保留一个新的专用 HA 网络,该网络仅对管理员可见,并且不属于任何 OpenStack 项目:

$ openstack network list

输出如下所示:

图 7.17 – 列出保留的 HA 网络

图 7.17 – 列出保留的 HA 网络

Keepalived 被配置为在每个命名空间中运行,通过使用位于 /var/lib/neutron/ha_confs/ROUTER_NETNS/keepalived.conf 的持久配置文件,其中 ROUTER_NETNS 是 HA 路由器的路由器命名空间。故障切换事件也会记录在同一目录下的 neutron-keepalived-state-change.log 中。以下是日志中的一个提取,显示了在第一个网络节点发生故障切换事件时的路由器切换:

图 7.18 – 验证路由器故障切换日志条目

图 7.18 – 验证路由器故障切换日志条目

中子路由容错是处理 OpenStack 网络可用性的关键要求。OpenStack Neutron 设计不仅仅局限于使用 VRRP 进行路由器冗余。后来,Neutron 引入了 DVR 实现。我们将在下一小节中探讨这个问题。

使用 DVR 进行路由冗余

像 HA 路由器一样,DVR 在多个计算节点上运行。使用 DVR,网络负载分配到各个操作中的路由器上,从而减少了网络节点的流量负担。L3 代理在计算节点中运行,东西向(实例到实例)和南北向(从实例到外部网络,使用浮动 IP 或反向流动)的流量都通过这些节点路由,而不是单一的集中式网络节点。

在 Neutron 中配置 DVR 需要使用 Open vSwitch 机制驱动程序,并且 L3 代理必须安装在计算节点上。通过以下方式更新库存文件,将 L3 代理添加到所需的计算节点:

...
[compute]
cn01.os.packtpub
cn02.os.packtpub
...
[neutron-l3-agent:children]
compute

运行管道并通过在控制节点上运行以下命令,验证 L3 代理是否在计算节点中正常运行:

$ openstack network agent list --agent-type l3

我们得到以下输出:

图 7.19 – 列出已安装的 Neutron L3 代理

图 7.19 – 列出已安装的 Neutron L3 代理

通过设置以下配置行,在 globals.yml 文件中启用 DVR 路由:

enable_neutron_dvr: "yes"

运行管道并观察 /etc/neutron/neutron.conf Neutron 配置文件中的配置更新,如下所示:

...
router_distributed = True

每个安装了 L3 代理的计算节点应该包含 /etc/neutron/plugins/ml2/openvswitch_agent.ini Open vSwitch 代理配置文件,配置文件应包含以下设置:

...
[agent]
l2_population = True
enable_distributed_routing = True

运行管道,在代理和 Neutron 服务器配置设置中填充 DVR 配置。

作为管理员,通过指定 --distributed 参数创建新路由器,如下所示:

$ openstack router create --distributed router_dvr

在每个计算节点中,验证相同 qrouter 命名空间 ID 的存在:

root@cc01.os:~#ip netns | grep router
qrouter-a312143-ea11-3417-adc1-1eb513daeeda
root@cc02.os:~#ip netns | grep router
qrouter-a312143-ea11-3417-adc1-1eb513daeeda

连接两个网络到不同计算节点的路由器是相同的路由器实例,在每个计算节点中都创建了相同的命名空间。通常,属于相同命名空间的 qr 接口会在计算节点中具有相同的接口名称和 IP 地址。对于 东西向 连接,instance01 所在的 cn01.os 与在 cn02.os 中启动的 instance02 之间的流量流动可以如下图所示:

图 7.20 – DVR 模式下的东西向流量

图 7.20 – DVR 模式下的东西向流量

如前图所示,从 instance01instance02(东西向)流动的流量将经过以下路径:

  1. 来自 instance01 的流量从其本地网关通过路由器命名空间进行转发。

  2. cn01.os 中的路由器将源 MAC 地址替换为其接口 MAC 地址。

  3. 路由器将流量转发到 cn01.os 中的集成桥接。

  4. 数据包随后被转发到 cn01.os 中的提供者桥接。

  5. 数据包中路由器接口的源 MAC 地址被计算节点cn01.os的 MAC 地址替换。

  6. 流量通过物理网络转发到目标计算节点cn02.os

  7. 流量通过提供者桥接器到达cn02.os主机。

  8. 流量被转发到cn02.os主机中的集成桥接器。

  9. 在集成桥接器层面,源 MAC 地址被替换为cn02.os中的路由器 MAC 接口地址,按照路由器命名空间的规定。

  10. 流量被转发到目标instance02

  11. instance02返回的流量遵循从cn02.os到其各自的桥接器和路由器的路由路径。

DVR 实现类似于使用 VRRP,其简便性在于它包含了 Neutron 的内建功能。

本节概述了在 OpenStack 基础架构和控制平面服务中启用 HA 的构建模块。在接下来的章节中,我们将深入探讨为在 OpenStack 中运行的工作负载实现容错的不同选项。

管理实例故障转移

为云资源提供 HA 是 OpenStack 开发者自 OpenStack 早期版本以来一直面临的一个关键话题。工作负载用户寻求通过手动工具和脚本增加虚拟机的可用性,如果没有有效管理,这些方法可能会被忽视。随着Masakari项目在 OpenStack 中的引入,云运营商可以为工作负载用户提供一个自动化服务,确保 KVM 基础的实例具备 HA,从而减少了手动脚本编写的需求,并能够无缝集成到 OpenStack 生态系统中。

Masakari 还使用 Corosync 和 Pacemaker。作为 Linux 平台的原生 HA 负载均衡堆栈解决方案,Pacemaker 是一个集群资源管理器,它依赖 Corosync 来控制并组织 OpenStack 中主机间的 HA。Corosync 确保集群通信基于消息传递层,并将 VIP 分配给某个节点。一旦创建了工作负载实例的集群,Masakari 就可以提供对运行实例的主机的故障检测,此时 Corosync 发挥作用,确保将虚拟 IP 分配给一个正常运行的主机。Masakari 由一个处理 REST 请求的 API 和一个执行恢复请求到 Nova 服务的引擎组件组成。如下图所示,Masakari 主要通过三种监控形式提供实例 HA:

图 7.21 – 使用 Masakari 的实例 HA 监控

图 7.21 – 使用 Masakari 的实例 HA 监控

Masakari 的主要组件可以总结如下:

  • 实例重启:由计算节点中运行的代理检测到的实例故障将会重启。实例重启由masakari-instancemonitor Masakari 监控进程进行管理。

  • 实例疏散:当检测到虚拟化服务器故障时,实例将被疏散到另一个健康的计算节点。Masakari 术语中定义的 故障切换段 是指一组计算节点,在同一段中的计算节点出现故障时,负责承载疏散的实例。实例疏散由 masakari-hostmonitor Masakari 进程监控管理。

  • 进程监控:由 masakari-processmonitor 服务管理,该服务运行在计算节点上,收集虚拟化服务器机器上不同进程的状态,包括 libvirtd 和 Nova 计算服务。该监控确保在一个进程发生故障时,受影响的计算节点不会再调度更多实例,而是由其他节点处理。

下一部分描述了如何使用 kolla-ansible 在 OpenStack 中部署 Masakari 服务。

部署 Masakari

Masakari 由其 API、监控器和引擎组成,这些组件被安装在云控制器和计算节点上。从 globals.yml 文件开始,通过编辑以下变量启用 Masakari 服务:

enable_masakari: "yes"

要通过实例疏散选项控制实例的 HA,请在 globals.yml 文件中启用以下设置:

enable_hacluster: "yes"

multi_packtpub_prod 清单文件中,将 Masakari 服务分配到云控制器节点上,运行 API 和引擎服务:

...
[masakari-api:children]
control
[masakari-engine:children]
control

在云控制器级别,实例疏散监控要求对将要部署 Peacemaker 和 Corosync 的计算节点进行监控:

[masakari-hostmonitor:children]
control

这里,hacluster 是一个额外的 Ansible 角色,提供对 Masakari 的支持,用于计算节点故障监控和在健康的虚拟化服务器节点上恢复实例,符合 Pacemaker 和 Corosync 的要求:

[hacluster:children]
control
[hacluster-remote:children]
compute

实例重启监控要求计算节点本身对实例状态进行监控:

[masakari-instancemonitor:children]
compute

运行流水线,确保 Masakari 容器正在正常运行,可以通过检查新的 Masakari 容器来确认。为此,请在云控制器节点上运行以下命令行:

$ sudo docker ps

我们将获得以下输出:

图 7.22 – 列出 Masakari Kolla 容器

图 7.22 – 列出 Masakari Kolla 容器

为了模拟虚拟机 HA 场景,我们将在一个计算节点中启动实例,并使用 Masakari 实例重启监控模式:

$ openstack server create --image cirros-5.1 --flavor m1.tiny --network priv_net vm-ha

将创建实例的 HA_Enabled 标志属性设置为 True

$ openstack server set --property HA_Enabled=True vm-ha

检查实例运行的计算节点,并杀死实例的进程 ID 来模拟实例故障:

$ openstack server show vm-ha

这是输出:

图 7.23 – 列出 HA 测试的虚拟机

图 7.23 – 列出 HA 测试的虚拟机

登录到计算节点并杀死实例的 PID:

$ pgrep -f guest=instance-00000003
12652
$ kill –9 12652

通过查看 /var/log/kolla/masakari 中的 Masakari 日志文件输出,观察同一虚拟化服务器主机上实例重启的状态:

图 7.24 – 验证日志条目中 Masakari 实例重生过程

图 7.24 – 验证日志条目中 Masakari 实例重生过程

几秒钟内,被终止的实例将会在同一计算节点上重新创建。可以通过新创建的实例 PID 来检查这一点:

$ pgrep -f guest=instance-00000003
13442

正如我们所见,Masakari 可以很好地帮助确保工作负载的容错性,而无需为每个实例单独操作 HA 功能,从而避免了繁重的手动工作。Masakari 正在变得越来越流行,多个生产环境的部署已经证明了它在帮助工作负载管理员和云开发者解决实例级故障转移挑战方面的优势。

小结

在本章中,我们通过覆盖控制平面和数据平面的 HA 支柱,启用了 OpenStack 环境中的一个关键架构安全设计。现在,我们有多种方法可以构建一个高度可用的 OpenStack 环境,具体取决于首选的 HA 策略。在本章中,我们使用 HAProxy 和 Keepalived 强化了控制平面服务。其他部署可以采用 Corosync、Pacemaker 和一些厂商的负载均衡解决方案。正如本章所示,多个设计模式可以应用于常见的基础设施服务,如数据库和消息队列,以实现最佳的故障转移。OpenStack 中的网络 HA 已经达到了一个新的成熟水平,云运营商可以选择两种方式,以最小化租户网络连接丢失的潜在风险:通过 VRRP 和 DVR 路由。

本章还探讨了一个对云用户来说非常有吸引力的能力,通过使用 Masakari 和原生 OpenStack 服务实现工作负载的故障转移,帮助他们管理运行在实例中的工作负载。我们还展示了一些额外的代码片段,用于通过kolla-ansible 管理 OpenStack 层的 HA。目前,利用 Kolla 自动化 OpenStack 中计算服务的单元和区域部署的基础设施代码仍在不断改进,这在本章中没有涉及。HA 和冗余是你开始在 OpenStack 环境中迎接生产工作负载所需的关键要素,通过本章的学习,你应该已经准备好开始了。除了确保服务的 HA 外,我们还需要时刻关注它们,并在问题发生时主动采取措施。

下一章将讨论 OpenStack 之旅中的下一个运营卓越支柱。它将探讨如何监控你的云环境,以便早期检测异常,并深入研究更细粒度的自省选项以及收集的 OpenStack 服务日志分析。

第八章:8

监控与日志记录 – 主动修复

“仅仅接受某事物的假设,或者同样地,未加调查地忽视它,可能会掩盖事实、让人盲目,并误导他人。”

– 阿布·纳萨尔·法拉比

监控私有云的底层基础设施是一个至关重要的操作活动,要求使用一致的工具和自动化方式来实现实时的指标收集和告警机制。在不同的 OpenStack 版本中,存在多种开源和商业工具来支持监控 OpenStack 生态系统中的不同组件。在最新版本中,我们可以找到更多成功的监控工具,它们提供了更简便的操作方式,且更容易集成到 OpenStack 生态系统中。收集指标数据是 OpenStack 操作任务的一部分;另外一部分是日志数据。每个 OpenStack 和共享服务都会生成大量具有不同日志级别的日志数据,所有这些数据加起来会变得非常复杂,在发生问题时,手动解析和查找异常会变得非常困难。拥有一个强大的日志管道是满足 OpenStack 操作旅程其中一项需求的关键。本章将结合监控和日志记录的实践,并介绍能够集成到运行中的 OpenStack 环境中的最新工具。

我们将讨论以下主题:

  • 引入 Prometheus 作为 OpenStack 基础设施和工作负载监控的解决方案

  • 在当前的 OpenStack 部署中部署和集成 Prometheus,并开始使用单独的监控堆栈来暴露 OpenStack 的指标

  • 使用 Grafana 作为中央可观测性工具来构建、部署并探索仪表板,以便进行数据展示

  • 使用 OpenSearch 构建高效且集中的日志解决方案,通过该解决方案传输、解析并构建自定义搜索查询,以便收集的日志进行进一步分析

OpenStack 基础设施监控

除了运行在 OpenStack 租户中的工作负载外,云操作员还必须确保他们具备必要的指标来确保 OpenStack 服务的可用性、性能和使用状态。监控数据主要涉及 OpenStack 基础设施服务的两大类,如下所示:

  • 云软件:包括 OpenStack API、调度程序、数据库、消息总线和负载均衡服务。

  • 云下:包括运行的操作系统、存储和网络硬件。

在接下来的部分中,我们将探讨 Prometheus,这是一款已广泛集成和采用的监控与告警工具,适用于大规模部署。

Prometheus 简介

Prometheus允许你收集并存储作为时间序列数据的度量值。Prometheus 被认为非常适合大规模部署,因为它提供了导出器和组件,将各种度量数据发送到 Prometheus 服务器。此外,该工具包括一个警报机制,用于根据配置的阈值管理警报和通知。与 Zabbix 或 Nagios 等其他工具不同,Prometheus 提供了灵活的方式来传输其格式收集的度量值和数据。这是通过第三方导出器来完成的,第三方导出器提供了与 Prometheus 兼容的度量值,减少了为每个软件框架的系统开发单独转换器的工作量。一些官方导出器托管在 Prometheus 的 GitHub 仓库中,可以在github.com/prometheus找到。在 OpenStack 世界中,可以通过 OpenStack Prometheus 导出器将大量度量数据导出到 Prometheus,完整列表请见github.com/openstack-exporter/openstack-exporter。如下面的图示所示,Prometheus 还具有一个发现服务,OpenStack API 可以使用该服务来探索和生成 Prometheus 服务器的数据度量。这主要用于报告虚拟机的度量数据——例如,在 Nova API 服务中利用服务发现时。当 Prometheus 收集并存储度量数据后,应该有一个统一的视图来整合和组织所有数据,并展示在易于理解的仪表板上。Grafana 是一个出色的开源工具,用于度量数据的可视化,可以配置为使用 Prometheus 作为数据源。

图 8.1 – OpenStack 中的 Prometheus 集成和监控堆栈

图 8.1 – OpenStack 中的 Prometheus 集成和监控堆栈

在接下来的部分中,Prometheus 将作为主要监控工具在 OpenStack 环境中进行部署和集成。

部署基础设施监控

将 Prometheus 和 Grafana 组合作为 OpenStack 基础设施的中央监控和可观察性解决方案,对于云操作员来说是一个快速的胜利,因为在最新的 OpenStack 版本中,这种监控解决方案经过了良好的测试和集成。Kolla Ansible 在最新的代码发布中推动并支持 Prometheus 和 Grafana 的集成。可以专门设置一个额外的监控主机来运行 Prometheus 服务器,并可选地运行 Grafana。这可以通过以下配置在基础设施代码设置中实现:

  1. 通过添加新的监控主机来更新multi_packtpub_prod清单文件,如下所示:

    ...
    [monitoring]
    mon01.os.packtpub
    
  2. 将 Prometheus 服务添加到监控主机组:

    ...
    [prometheus:children]
    monitoring
    
  3. 将内置的 Prometheus 警报管理服务添加到监控主机组:

    ...
    [prometheus-alertmanager:children]
    monitoring
    
  4. 将 OpenStack Prometheus 导出器包括在监控主机组中。这将创建一个专用的服务容器,自动从 OpenStack 服务的指标中拉取格式化的 Prometheus 数据:

    ...
    [prometheus-openstack-exporter:children]
    monitoring
    
  5. 将 Prometheus Node Exporter 角色添加到每个主机中运行。Node Exporter 提供了广泛的 Linux 操作系统和硬件指标:

    ...
    [prometheus-node-exporter:children]
    monitoring
    control
    compute
    network
    storage
    
  6. Prometheus 提供了一个专门的导出器用于MariaDB 数据库。通过导出器暴露的 MySQL 服务器指标提供了一个可供抓取的扩展数据指标列表。Prometheus MySQL 导出器可以添加到运行在云控制节点中的mariadb角色:

    ...
    [prometheus-mysqld-exporter:children]
    mariadb
    
  7. 类似地,Prometheus 可以配置为通过其在负载均衡器节点中运行的专用导出器抓取 HAProxy 的负载均衡指标和统计信息:

    ...
    [prometheus-haproxy-exporter:children]
    loadbalancer
    
  8. 另一个可用的导出器是Prometheus Libvirt 导出器,它暴露了主机和实例的指标。该导出器从Libvirt API收集数据,并暴露计算节点和运行中的实例的有用指标。libvirt导出器可以在计算节点中安装,如下所示:

    ...
    [prometheus-libvirt-exporter:children]
    compute
    
  9. 对于 OpenStack 基础设施的更广泛监控设置,建议关注每个节点上运行的容器状态。Prometheus cAdvisor(即Container Advisor)导出器旨在收集、分析、汇总和导出容器性能和指标数据。cAdvisor导出器将跨所有 OpenStack 节点运行,如下所示:

    ...
    [prometheus-cadvisor:children]
    monitoring
    control
    compute
    network
    storage
    
  10. 下一步是使用kolla-ansible启用并安装 Prometheus 服务。在撰写本版本时,kolla-ansible将通过将以下变量添加到globals.yml文件中,安装 Prometheus 服务器的 2.0 之后的最新版本:

    ...
    enable_prometheus: "yes"
    
  11. 要启用数据暴露和可视化,请在globals.yml文件中启用 Grafana:

    ...
    enable_grafana: "yes"
    
  12. kolla-ansible允许为 Prometheus 和 Grafana 服务的监控层设置自定义配置。一旦安装了这两个服务,您将需要提供一个用户名和密码以进行访问。默认情况下,kolla-ansible通过 HTTP 使用基本认证安装 Prometheus,并使用admin用户和 Grafana 用户grafana。这两个默认变量分配到/kolla-ansible/ansible/group_vars/all.yml文件中,如下所示:

    ...
    prometheus_alertmanager_user: "admin"
    prometheus_grafana_user: "grafana"
    

    对于自定义用户访问设置,您可以通过直接调整all.yml文件中的变量或在/kolla-ansible/ansible/roles/prometheus/defaults/main.yml文件中的prometheus_basic_auth_users配置部分覆盖默认的用户名,如下所示:

    ...
    prometheus_basic_auth_users_default:
      - username: admin
        password: "{{ prometheus_password }}"
        enabled: true
      - username: "{{ prometheus_grafana_user }}"
        password: "{{ prometheus_grafana_password }}"
        enabled: "{{ enable_grafana }}"
    

    Prometheus 和 Grafana 的用户密码可以在/etc/kolla/passwords.yml文件中重新配置,该文件定义了所有服务的密钥。两个密码都使用以下变量定义:

    prometheus_password:
    prometheus_grafana_password:
    

    另一个选项是通过扩展prometheus_basic_auth_users_extra变量,在/kolla-ansible/ansible/roles/prometheus/defaults/main.yml文件中,使用自定义密码或默认密码创建新用户,而不覆盖现有用户,如下所示:

    prometheus_basic_auth_users_extra:
       - username: prometheus_pp_admin2
         password: "{{ prometheus_password }}"
         enabled: true
       - username: prometheus_pp_2
         password: prometheus_pp_password
         enabled: true
    
  13. 另一种很好的度量抓取方式是通过在globals.yml文件中的prometheus_cmdline_extras变量中列出一组启动参数来配置自定义 Prometheus 运行。例如,可以配置 Prometheus 通过--storage.tsdb.retention.size参数将度量数据保持到特定的大小。在以下列出的配置中,定义了一个自定义配置,用于将 Prometheus 仪表板上最大同时连接数限制为30个连接,调整日志严重性级别以包含error(默认严重性级别为info),每30秒将警报重新发送到 Prometheus 警报管理器,并将度量数据在存储中保留30天:

    prometheus_cmdline_extras: " --web.max-connections 30 --log.level error  --rules.alert.resend-delay 30s  --storage.tsdb.retention.time 30d "
    

重要提示

可以在prometheus.io/docs/prometheus/latest/command-line/prometheus/ 找到 Prometheus 启动参数的完整列表。

  1. 运行管道来部署 Prometheus 服务器、Grafana、Prometheus cAdvisor 和相关的导出器组件。一旦部署管道完成,通过在其中一个控制节点运行以下命令行来验证新部署的容器:

    $ docker ps -a | grep -e prometheus -e grafana
    

    我们获得了如下输出:

图 8.2 – 列出 Prometheus 和 Grafana 的 Kolla 容器

图 8.2 – 列出 Prometheus 和 Grafana 的 Kolla 容器

在接下来的部分中,我们将查看 Prometheus 收集的度量标准,并使用 Grafana 构建有洞察力的仪表板。

探索监控数据

最新的kolla-ansible部署使得 Prometheus 服务器开始收集可以在 Prometheus 仪表板上检查的不同度量标准。主 Prometheus 仪表板可以通过指向监控主机的 IP 地址访问:http://host_monitoring_ip/prometheus,其中host_monitoring_ip是运行 Prometheus 服务器的监控主机的 IP 地址。

图 8.3 – Prometheus 仪表板界面

图 8.3 – Prometheus 仪表板界面

Prometheus 从清单中定义的所有主机的每个已安装导出器收集详尽的度量标准。它使用labels来定义每个度量的目标端点。例如,一旦安装了 OpenStack 导出器,Prometheus 就开始收集与 OpenStack 相关的度量标准,可以通过指向http://host_monitoring_ip:9090/targets来检查,host_monitoring_ip是运行 Prometheus 服务器的监控主机的 IP 地址。

一旦每个节点的导出服务发送指标数据进行抓取,收集的指标将在 Prometheus 仪表板中显示。可能需要一些时间才能在 Prometheus 仪表板中可视化所有指标。例如,以下列表显示了初始 OpenStack 服务通过 http://host_monitoring_ip:9100/metrics 导出了指标,其中 host_monitoring_ip 是运行 Prometheus 服务器的监控主机的 IP 地址:

图 8.4 – Prometheus 中收集的 OpenStack 服务指标列表

图 8.4 – Prometheus 中收集的 OpenStack 服务指标列表

安装在每台 OpenStack 物理机器上的 Node Exporter 服务,用于收集主机指标,如内存使用情况和统计信息,可以通过在同一 Prometheus 仪表板 URL 上查看指标列表来检查,如以下示例所示:

图 8.5 – Prometheus 中收集的内存指标和统计信息列表

图 8.5 – Prometheus 中收集的内存指标和统计信息列表

随着更多节点加入 OpenStack 基础设施,收集的指标数量可能会增加一倍,这将影响监控主机的性能和磁盘容量。因此,强烈建议使用多个 Prometheus 服务器实例来处理更多的指标导出和抓取任务。Prometheus 被设计为在大规模部署中具有良好的可扩展性,能够支持成千上万的资源类型和指标。

在 Prometheus 仪表板上浏览数百个指标,以跟踪数百个服务状态和相关的使用信息可能会很麻烦。Prometheus 在大多数关键操作任务中都能发挥很大作用,包括以下任务:

  • 指标数据收集配置

  • 告警的管理与配置

  • 故障排除指标导出问题

Prometheus 是一个高度可配置的工具,提供本地命令行接口,以自定义指标收集和抓取设置,这超出了本书的范围。我们将使用 Prometheus 导出的指标数据,并在简单的 Grafana 仪表板中可视化它。

最新的 kolla-ansible 运行应启用 Grafana 服务,并使用默认仪表板配置 Prometheus 作为数据源。要验证 Prometheus 数据源,请访问 http://host_monitoring_ip:3000,其中 host_monitoring_ip 是运行 Grafana 实例的监控主机的 IP 地址。提供用户名和密码以访问前面步骤中配置的 Grafana 仪表板。如果你没有自定义 Grafana 访问凭据,请使用默认的用户名和密码组合 admin / admin

登录后,在仪表盘中导航至设置图标 | 配置 | 数据源,并确保已添加 Prometheus 数据源。验证数据源是否正常工作,并且没有报告错误。点击 保存并测试 按钮,应该显示数据源配置正常,如下图所示:

图 8.6 – 在 Grafana 仪表盘中添加 Prometheus 数据源

图 8.6 – 在 Grafana 仪表盘中添加 Prometheus 数据源

一旦数据源检查完毕,在 Grafana 中构建仪表盘就变得非常简单,可以通过创建自由格式的仪表盘或从 Grafana 网站目录导入仪表盘来完成。grafana.com/ 提供了每个 Prometheus 导出器的不同仪表盘,按仪表盘 ID 标识,可以轻松地将其添加到本地 Grafana 服务器中。你也可以导入 JSON 格式的仪表盘,并将其复制并粘贴到 Grafana 导入部分。在下一个向导中,我们将使用 仪表盘导入 ID 选项导入 OpenStack 和 Node Exporters 的 Grafana 仪表盘。为此,只需导航到 Grafana 首页,然后点击 + 图标并选择 导入

图 8.7 – 在 Grafana 中添加仪表盘

图 8.7 – 在 Grafana 中添加仪表盘

从 OpenStack 指标导出器开始,导航到 OpenStack Grafana 仪表盘 grafana.com/grafana/dashboards/9701-openstack-dashboard/,并复制仪表盘的 ID,如下所示:

图 8.8 – 获取仪表盘 ID

图 8.8 – 获取仪表盘 ID

将复制的仪表盘 ID 粘贴到 Grafana 仪表盘 导入 页面。仪表盘 ID 应为 9701

图 8.9 – 将仪表盘 ID 导入到 Grafana 中

图 8.9 – 将仪表盘 ID 导入到 Grafana 中

导入向导的下一页将引导你完成导入仪表盘的设置。输入你选择的仪表盘名称,并确保选择了Prometheus数据源,如下图所示:

图 8.10 – 配置仪表盘,使用 Prometheus 作为数据源

图 8.10 – 配置仪表盘,使用 Prometheus 作为数据源

一旦导入向导完成,导入的 OpenStack 导出指标的 Grafana 仪表盘将显示各种图表和指标,例如每个 OpenStack 服务资源使用情况的概览。服务指标的一些亮点如下:

  • 当前存在的 Keystone 用户、用户组和项目

  • Neutron 资源,如部署的浮动 IP、虚拟网络和安全组

  • Nova 服务运行的实例数量

  • 当前 Glance 镜像的数量

  • Cinder 服务管理的卷和快照

  • CPU、RAM 和磁盘资源的总体使用情况

可以显示多个仪表板,如下所示的截图所示:

图 8.11 – 以 Prometheus 为数据源的通用导入仪表板

图 8.11 – 以 Prometheus 为数据源的通用导入仪表板

导入的仪表板提供了对每个服务及其相关子组件(如 API 服务和代理)的更多洞察。

图 8.12 – 每个 OpenStack API 服务状态的导入仪表板

图 8.12 – 每个 OpenStack API 服务状态的导入仪表板

另一个有用的仪表板应存在,用于监控运行云环境的主机,通过 Prometheus Node Exporter。Grafana 模板仪表板可以在 grafana.com/grafana/dashboards/1860-node-exporter-full/ 上找到,仪表板 ID 为 1860。请按照与 OpenStack 导出仪表板相同的导入说明操作,确保选定的数据源为 Prometheus。

导入后,将创建一个新的 Grafana 命名空间,数据源为 Prometheus。收集的数据反映了来自每个 OpenStack 主机的操作系统和硬件指标的详细和深刻信息,使用已安装的 Node Exporter 服务:

图 8.13 – OpenStack 的整合仪表板

图 8.13 – OpenStack 的整合仪表板

同样,你可以为每个安装的 Prometheus 导出器导入现成的 Grafana 仪表板。数据库指标仪表板可以在 grafana.com/grafana/dashboards/14057-mysql/ 上找到,HAProxy 仪表板则可以在 grafana.com/grafana/dashboards/2428-haproxy/ 上找到。

关于从运行 OpenStack 服务的主机收集的数据,Prometheus Node Exporter 服务支持主动识别可能的系统异常。导入的仪表板将所有主机的指标整合在一个界面中,可以通过单个或一组主机进行过滤,提供更自定义的可视化体验。

接下来,我们将跟踪运行在 OpenStack 私有云上的工作负载。

OpenStack 工作负载监控

云运营商的下一项操作任务是为 OpenStack 租户的运行工作负载提供监控支持。运营商还应监控租户所提供资源的一些通用指标,以预测配额限制并深入分析基础设施的使用情况。可以使用上一节中提到的相同工具集来实现这一目标。工作负载监控更多关注每个租户所部署的资源——更准确地说,是 Nova 实例。Prometheus 能够查询 Nova API,并通过其标签配置设置,你应该能够将数千个实例筛选并组织成一组抓取目标。在上一节中,Prometheus Libvirt 导出器已经在每个计算节点上部署(见 部署基础设施监控 部分的 步骤 8)。因此,无需重新配置任何基础设施主机部分。实例指标应可在 Prometheus 服务器中使用,但是否为任何报告的实例提供附加信息是可选的。Prometheus 可以通过应用导出器配置和 relabel_configs 设置来配置发现 OpenStack 实例,以下是一个示例:

- job_name: 'openstack_pp'
openstack_sd_configs:
  - role: 'instance'
...
relabel_configs:
  - source_labels: [__meta_openstack_public_ip]
    target_label: __address__
    replacement: '$1:9100'
  - source_labels: [__meta_openstack_tag_prometheus]
    regex: true.*
    action: keep
- source_labels: [__meta_openstack_tag_node_exporter]
 regex: true.*
    action: keep
 - action: labelmap
   regex: __meta_openstack_(.+)

标签重新标记配置有助于提取与 Prometheus 中的正则表达式匹配的已发现实例的元数据。在前面的示例中,_meta_openstack(.+) 正则表达式被应用并添加到所有不同源标签接收的每个指标中。这有助于通过更具体的信息(例如实例名称、IP 地址和实例状态)来可视化租户资源,如下所示的 Prometheus 服务器端点仪表板示例:

图 8.14 – Prometheus 仪表板中的实例指标列表

图 8.14 – Prometheus 仪表板中的实例指标列表

kolla-ansible 的默认 Prometheus 配置不包括每个导出器类型的完整标签集。所有导出器的 Prometheus 主要配置可以在 kolla-ansible/ansible/roles/prometheus/templates/prometheus.yml.j2 文件中找到。包含自定义重新标签配置的一种方法是编辑该文件并修改每个导出器部分的设置。推荐的方式是创建一个新的自定义配置文件,例如在新配置目录下创建一个名为 custom.yml 的文件,如 /etc/kolla/config/prometheus/prometheus.yml.d/,并通过运行管道应用新的附加设置。kolla-ansible 会将附加配置合并到正在运行的 Prometheus 服务器中,但请注意,这将需要短暂重启服务器以加载新的配置。

在 Grafana 中可视化实例指标只需构建相应的仪表盘。类似于主机指标的可观察性操作,Node Exporter 和 Libvirt 模板仪表盘结合实例特定的指标,为每个计算节点的实例资源使用构建自定义选项卡。这包括总资源消耗概览,如 CPU、RAM 和分配的磁盘。撰写本版本时,通过 Prometheus 探测服务导入虚拟机指标的 Grafana 仪表盘尚不可用。

可以在 grafana.com/grafana/dashboards/15330-openstack-instance-metrics/ 找到来自 grafana.com 的实例指标 Grafana 仪表盘,仪表盘 ID 为 15330。在没有完全运行的 telemetry OpenStack 服务(包括 CeilometerGnocchi)的情况下,无法使用此仪表盘,后续章节将详细介绍该服务。

遥测与计费

OpenStack 为租户环境提供遥测服务,Ceilometer 服务为其中的一部分。Ceilometer 项目的目标是帮助云操作员收集指标,进一步协助理解资源的利用情况。这使我们能够在资源达到限制之前,解决基础设施的可扩展性问题,并更新资源规划以支持扩展和增长。从 Queens OpenStack 版本开始,遥测模块已扩展为包含与 Ceilometer 协同工作的其他组件,包括以下内容:

  • Aodh :一个基于收集的指标数据进行处理的告警服务

  • Gnocchi :时间序列数据的存储和收集

  • Panko :Ceilometer 生成的事件数据存储

重要提示

在撰写本版本时,Panko 模块已被弃用,且不再由 OpenStack 社区维护。

下一节将更详细地介绍遥测堆栈。

Ceilometer 架构

Ceilometer 项目最初的目标(直到 Folsom 版本)是从云租户处收集资源使用指标,并将其转化为可开具账单的项目。Ceilometer 项目的持续发展使其具备了更多的监控和告警功能。从 Liberty 版本开始,这些功能被分离到独立的模块中。

如下图所示,Ceilometer 依赖代理来收集、处理、存储和检索数据。

图 8.15 – Ceilometer 架构的总体概述

图 8.15 – Ceilometer 架构的总体概述

每个数据工作流由一个专用代理执行,代理清单如下:

  • Polling agents : 这些代理定期轮询每个 OpenStack 基础设施服务,通过 API 调用来生成度量。计算轮询代理从计算节点中运行的实例收集统计数据,并将其轮询到消息队列。中央代理运行在 OpenStack 中的中央管理服务器上,如云控制器。它轮询除实例之外的资源统计信息。

  • Notification agents : 这些代理定期监听消息队列总线,收集由不同 OpenStack 服务设置的新通知消息,并将其转换为度量,然后将其推送回相应的消息队列总线。

  • Collector agents : 这些代理监控消息队列,收集样本,并收集由轮询或通知代理生成的度量消息。因此,新的度量消息将被记录到后端存储中。

  • API service : 如果启用,它将公开一个标准 API,提供对内部 Ceilometer 数据库的访问,以查询相应的计量数据。

数据收集主要通过代理使用管道机制执行。它们定期发送请求以获取反映某个度量的样本对象。每个样本请求都将转发到管道。一旦传递到管道,度量可以由多个转换器类型进行处理:

  • Accumulator : 这是累积多个值并将其批量发送的功能。

  • Aggregator : 这将多个值汇聚为一个算术结果。包括用于计算百分比的算术函数。

  • Rate of change : 通过从先前的数据推导出另一个度量来识别趋势。

  • Unit conversion : 这是用于单位转换的类型。

一旦经过处理和转换,度量可能通过多种发布器类型之一继续其路径:

  • Notifier : 这是通过可靠的消息队列推送的度量数据。

  • rpc : 这是同步的 RPC 度量数据发布器。

  • udp : 这是通过 UDP 发送的度量数据。

  • file : 这是将度量数据发送到文件中的功能。

上述组件的说明如下:

图 8.16 – 通过度量管道进行度量数据转换和发布

图 8.16 – 通过度量管道进行度量数据转换和发布

收集到的数据可以存储在 Ceilometer 支持的不同类型的数据库中。最初,MongoDB 是一个广泛采用的数据存储用于遥测度量存储。由于 MongoDB 在可扩展性和性能方面的问题,Gnocchi 被评估为一个适合 Ceilometer 的时间序列数据库,相关内容将在下一节中介绍。

Gnocchi 数据存储

自从 Train 版本的 OpenStack 发布以来,Gnocchi被认为是 Ceilometer 的默认和官方支持的存储服务。考虑到之前的指标数据存储选项在性能和可扩展性方面的问题,引入 Gnocchi 作为时间序列数据库,解决了在大规模环境中处理和存储指标数据时的主要瓶颈问题。数据样本不再直接写入数据库,而是转换为 Gnocchi 元素,并随后通过其原生 API 提交。聚合数据以时间序列的形式记录。每个转换后的样本表示一个数据点,具有时间戳和度量值。

使用 Gnocchi 进行数据优化的特点是为资源及其相关属性建立索引。因此,数据搜索速度更快。如前所述,Gnocchi 通过利用可扩展存储系统(如SwiftCeph)中的指标数据存储,提供了可扩展的指标存储设计。如下一图所示,Gnocchi 可以配置为在 Swift 或 Ceph 中聚合和存储度量数据,作为存储后端,使用其内置的存储驱动程序:

图 8.17 – Gnocchi 数据存储多后端支持

图 8.17 – Gnocchi 数据存储多后端支持

数据通过metricd进行聚合和存储处理。metricd负责刷新标记为删除的指标。Gnocchi 提供了兼容的statsd协议(gnocchi-statsd),用于监听传入的指标。statsd将在后续的 Gnocchi 部署中使用。

使用 Aodh 进行警报设置

自 Liberty 版本以来,Ceilometer 警报模块被分叉并重命名为Aodh,它负责根据自定义规则触发警报。

如下图所示,将当前的警报服务与 Ceilometer 之前的服务进行比较时,可以明显看到一个区别——当负载增加时,能够进行水平扩展。使用相同的消息队列,Aodh 提供了一个事件监听器,捕捉新的通知并提供即时响应,零延迟。Aodh 监听器依赖于预定义的警报,根据事件和配置的度量值立即触发。在使用编排服务(例如Heat)时,反应自动扩展条件变得非常有用:

图 8.18 – OpenStack 中的 Aodh 警报概述

图 8.18 – OpenStack 中的 Aodh 警报概述

Aodh 主要由一个 API 服务器(aodh-api)构成,提供对数据存储的访问。Aodh 警报评估器(aodh-evaluator)基于收集到的统计趋势,在一定时间内超过阈值时触发警报。警报由 Aodh 通知监听器(aodh-listener)触发,基于通知代理报告的事件与规则匹配。Aodh 警报通知器(aodh-notifier)根据一组样本的阈值启用警报设置。

Aodh 通知支持基于事件和阈值的告警。在最新的 OpenStack 版本中,Aodh 默认从 Gnocchi 数据存储查询度量数据。

部署遥测服务

当前的kolla-ansible仓库支持在 OpenStack 中完全部署遥测服务。这包括 Ceilometer、Aodh 和 Gnocchi 服务。由于我们已经在第三章《OpenStack 控制平面 - 共享服务》中部署了 Ceilometer 服务,接下来我们将详细介绍遥测栈的 Ansible 角色配置:

  1. 如果 Ceilometer 服务尚未启用,则确保将其添加到云控制节点组中,可以通过将其添加到multi_packtpub_prod库存文件来实现,如下所示:

    ...
    [ceilometer:children]
    control
    
  2. 将 Ceilometer 中央轮询和通知代理添加到云控制节点组:

    ...
    [ceilometer-central:children]
    ceilometer
    [ceilometer-notification:children]
    ceilometer
    
  3. 将 Ceilometer 轮询代理添加到计算节点组:

    ...
    [ceilometer-compute:children]
    compute
    
  4. 作为云控制节点组的一部分运行 Gnocchi 服务:

    ...
    [gnocchi:children]
    control
    
  5. 将 Gnocchi 组件,包括 API、statsdgnocchi-statsd守护进程)和metricdgnocchi-metricd守护进程)服务,分配给作为云控制节点组中 Gnocchi 实例的一部分运行:

    ...
    [gnocchi-api:children]
    gnocchi
    [gnocchi-statsd:children]
    gnocchi
    [gnocchi-metricd:children]
    gnocchi
    
  6. 作为云控制节点组的一部分运行 Aodh 告警服务:

    ...
    [aodh:children]
    control
    
  7. 将 Aodh 组件,包括 API、评估器、监听器和通知器服务,分配给作为云控制节点组中 Aodh 实例的一部分运行:

    ...
    [aodh-api:children]
    aodh
    [aodh-evaluator:children]
    aodh
    [aodh-listener:children]
    aodh
    [aodh-notifier:children]
    aodh
    
  8. 接下来,确保在globals.yml文件中启用 Ceilometer 服务:

    ...
    enable_ceilometer: "yes"
    
  9. globals.yml文件中启用 Gnocchi 服务,并可选择启用statsd协议支持,该支持将安装并运行gnocchi-statsd守护进程:

    ...
    enable_gnocchi: "yes"
    enable_gnocchi_statsd: "yes"
    
  10. globals.yml文件中的最后一个配置是通过将相应的变量设置为yes来启用 Aodh 告警服务:

    ...
    enable_aodh: "yes"
    
  11. 运行部署管道,并确保在安装遥测服务时没有报告错误。使用以下命令行验证遥测服务容器是否在某个云控制节点中正常运行:

    $ docker ps -a | grep -e ceilometer -e gnocchi -e aodh
    

    这是我们得到的输出:

图 8.19 – 部署的遥测 Kolla 容器列表

图 8.19 – 部署的遥测 Kolla 容器列表

一旦 Ceilometer、Gnocchi 和 Aodh 三者加入到 OpenStack 部署中,你应该拥有一个完全功能的遥测服务。浏览 Ceilometer 指标非常简单,并且可以通过 Aodh 配置告警。指标和告警是应对日常监控操作的关键元素。然而,即使有了这些,也不足以应对问题,必须加入服务日志,我们将在下一节进行介绍。

掌握集中式日志记录

操作 OpenStack 云环境的第二个关键部分是通过日志信息来检查基础设施中的事件。由于 OpenStack 配置中涉及数十个部署的服务,云操作员应该在每个服务中启用日志记录,至少在控制平面内启用日志,以便进行故障排除、分析,甚至创建自定义度量标准以供警报使用。根据所使用的 OpenStack 部署工具和配置设置,Linux/Unix 系统中的标准服务将其日志写入/var/log/ 目录及其子目录中。

随着大量日志数据的生成,解析和处理所有日志数据成了提取有意义信息或排查意外问题的障碍,这些问题可能需要更长时间才能解决。为了克服这一挑战,你的日志环境必须发展为集中式。一个好的选择是开始将日志流入专用的rsyslog 服务器。你可能会输入如此多的数据,以至于日志服务器开始缺乏更大的存储容量。此外,当你需要为特定上下文提取信息时,归档上述数据将没有用处。此外,将具有不同格式的日志数据(考虑到 RabbitMQ 和 MySQL 日志)与生成的事件进行关联甚至可能变得不可能。所以,在这个阶段,我们需要一套质量要求来提供良好的 OpenStack 日志体验,如下所示:

  • 日志元数据的解析能力

  • 快速的日志数据索引

  • 易于理解的数据展示

  • 基于自定义日志数据聚合构建的度量标准

在 OpenStack 中生成的日志是结构化的,适合处理,并且可以通过多种工具解析,包括开源的ELK 堆栈,ELK 由ElasticsearchLogstashKibana 组成,甚至可以通过商业第三方工具,如 Datadog 和 Splunk 来解析。ELK 是在大型 OpenStack 部署中最常用的日志处理工具。除 kolla-ansible 外,大多数 OpenStack 部署工具开箱即用地支持 ELK 堆栈。尽管 ELK 堆栈仍然是管理 OpenStack 日志的有效选择,但最新的 OpenStack 版本已转向采用分叉的开源 Elasticsearch 解决方案,并宣布OpenSearch将成为未来 OpenStack 操作中处理日志的新方式。

OpenSearch 引擎

OpenSearch 是一个开源软件,采用 Apache 2.0 版本许可。由于其庞大的社区和活跃的提交,它已经成为一个非常流行的搜索引擎和日志分析套件,并且源自 Elasticsearch 项目。OpenSearch 套件包括一个搜索引擎、数据存储和用于可视化的仪表板,这些都源自 Kibana。OpenSearch 架构基于分布式设计,不同的组件可以在不同的集群节点上运行。下图展示了基于 OpenSearch 的 OpenStack 日志解决方案概览:

图 8.20 – OpenStack 环境中 OpenSearch 日志集群概览

图 8.20 – OpenStack 环境中 OpenSearch 日志集群概览

如前图所示,适用于中到大规模部署的典型 OpenSearch 环境包括多种集群节点角色,例如以下几种:

  • 集群管理节点:此节点跟踪 OpenSearch 集群状态,包括节点状态变化(如加入和离开)及健康状态、索引管理和分片分配。为了高可用性,建议在生产环境中至少运行两个管理节点。

  • 协调节点:此节点接收来自仪表板或客户端库发起的请求,并将它们委派给数据节点上的正确分片,然后获取、聚合并将数据结果返回给客户端。

  • 数据源节点:此节点代表 OpenSearch 集群的工作马,存储数据并执行不同的数据相关操作,包括索引、聚合和搜索。

重要提示

其他类型的节点,包括 主节点候选摄取节点,也可以成为 OpenSearch 集群的一部分。任何未被标记为主节点的节点都被指定为主节点候选角色。摄取节点适用于大规模数据摄取管道,并将索引工作负载从数据节点中卸载。

OpenSearch 是高度可扩展的,可以安装多种类型的插件,以增强搜索体验、安全功能、机器学习和性能分析。可用的插件列表请参见 opensearch.org/docs/latest/install-and-configure/plugins/#available-plugins

OpenSearch 解决方案采用分布式架构,使您能够为大规模搜索和分析操作进行扩展。OpenSearch 核心搜索服务支持多种独特功能,使得日志分析、数据摄取和可观察性功能的运行变得更加容易。此外,由于提供了在多个节点上处理分片的额外方式,从而加速了搜索操作,性能也成为了采用 OpenSearch 的有效理由。不同的 OpenStack 和常见基础设施服务生成的数据量可能巨大,可以输入到 OpenSearch 集群中。通过提供 OpenSearch 集群的最小规模,云操作员可以开始探索丰富的搜索和可视化体验。这使得您能够创建可视化图表,发现复杂且大型系统中难以通过基本指标检测到的故障部件。

部署 OpenSearch

在编写本版时,kolla-ansible 支持 OpenSearch 安装。社区推荐采用 OpenSearch 选项,它可以通过几个步骤进行部署。强烈建议专门配置一个日志集群,该集群运行不同类型的 OpenSearch 节点,正如前面一节所述。对于每个 OpenSearch 节点的需求,还应做其他考虑,以便您可以根据所需的性能量身定制日志集群。例如,数据节点需要更多的磁盘空间,并可以通过配备更高 IOPS 的快速磁盘(如 固态硬盘SSDs))进行升级。主节点和协调节点是更高要求的计算机,可以配备更强大的 CPU。对于下一个设置,我们将在控制节点中运行一个简单的 OpenSearch 服务实例:

  1. 将 OpenSearch 引擎和 dashboards 角色分配给控制节点:

    ...
    [opensearch:children]
    control
    [opensearch-dashboards:children]
    opensearch
    
  2. globals.yml 文件中更改以下变量,以将 OpenSearch 安装为中央日志服务:

    ...
    enable_central_logging: "yes"
    
  3. 默认情况下,Kolla 会部署 OpenSearch 服务,并使其监听 9200 端口。当部署在控制节点上时,OpenSearch Dashboards 应该能够通过分配给 Keepalived 的预留 VIP 访问,以运行云控制器集群。您还可以选择为其分配一个 FQDN,并在所有 OpenStack 节点内部填充主机名。仪表盘可以通过浏览器在内部的 5601 端口访问,且在 globals.yml 文件中设置的 kolla_internal_fqdn 变量指向 kolla_internal_vip_address 变量。请确保至少设置 kolla_internal_vip_address 变量为 VIP 地址或映射的 DNS 端点名称:

    kolla_internal_vip_address: "10.0.0.47"
    
  4. OpenStack 仪表盘使用默认的 'opensearch' 用户名创建,密码可以通过设置以下变量,在 kolla-ansible/etc/kolla/passwords.yml 文件中进行编辑:

    opensearch_dashboards_password: 'openstestpass'
    
  5. 其他可以提前执行的高级且有用的配置,以解决常见的 OpenSearch 操作设置包括日志保留策略,这对于处理磁盘空间管理、数据轮换和生命周期至关重要。OpenSearch 配备了索引状态管理插件,通过定义日志保留策略来管理数据轮换。确保在 ansible/roles/opensearch/defaults/main.yml 文件中定义的 Ansible OpenSearch 角色中启用此功能,方法是检查以下变量:

    opensearch_apply_log_retention_policy: true
    
  6. 启用后,OpenSearch 通过定义软保留期和硬保留期提供索引数据生命周期。软保留期由opensearch_soft_retention_period_days变量在 ansible/roles/opensearch/defaults/main.yml 文件中定义,其中索引被关闭,不再活跃,并处于删除阶段,但它们仍然占用磁盘空间并且可以重新打开。硬保留期是索引被永久删除并不再占用磁盘空间的持续时间。它们由opensearch_hard_retention_period_days变量在 ansible/roles/opensearch/defaults/main.yml 文件中定义。默认的软保留期和硬保留期分别设置为3060天。可以通过在 globals.yml 文件中创建新变量并在 OpenSearch playbook 中引用它们,或者直接在 ansible/roles/opensearch/defaults/main.yml 文件中修改软保留期为45天,硬保留期为90天来编辑这些值:

    opensearch_soft_retention_period_days: "{{ elasticsearch_curator_soft_retention_period_days | default(45) }}"
    opensearch_hard_retention_period_days: "{{ elasticsearch_curator_hard_retention_period_days | default(90) }}"
    
  7. 运行管道并确保输出不包含作业配置中的错误。完成后,运行以下命令行以验证额外的 Kolla 容器:

    $ docker ps –a | grep –e opensearch
    

    这是输出:

图 8.21 – 列出 OpenSearch Kolla 容器

图 8.21 – 列出 OpenSearch Kolla 容器

  1. 在浏览器中访问 OpenSearch Dashboards 的 URL http://10.0.0.47:5601。输入'opensearch'用户名和配置的密码以开始日志搜索:

图 8.22 – OpenSearch 登录页面

图 8.22 – OpenSearch 登录页面

  1. 要在首次登录后开始搜索日志,必须创建索引模式以从日志源提取数据。索引模式指向一个特定的索引,可以从指定日期提取日志数据,例如。从OpenSearch Dashboards面板中,点击索引模式按钮,如下所示:

图 8.23 – 在 OpenSearch 仪表板中创建索引模式

图 8.23 – 在 OpenSearch 仪表板中创建索引模式

  1. 接下来,通过应用过滤器来指定索引模式设置,以提取并聚合数据。在当前示例中,将应用时间戳过滤器。默认情况下,OpenSearch 会为每个索引模式关联一个唯一标识符,如下所示:

图 8.24 – 为索引模式应用过滤器

图 8.24 – 为索引模式应用过滤器

  1. 创建后,索引模式将把过滤器应用于源数据,并可视化 OpenSearch 保存的字段映射核心类型。例如,创建的索引模式引用了一组字段,这些字段在仪表板上方的 发现 标签中可见:

图 8.25 – 列出索引模式的字段选择

图 8.25 – 列出索引模式的字段选择

  1. 可以使用 发现 面板中的搜索栏对日志进行过滤,搜索栏列出所有带有时间框架的相关事件,如下图所示:

图 8.26 – 为日志过滤应用时间框架

图 8.26 – 为日志过滤应用时间框架

  1. 可以使用搜索过滤器栏进一步应用过滤。在下例中,添加的过滤器用于拉取 log_level 字段中值为 ERROR 的所有数据:

图 8.27 – 为日志过滤应用 log_level 过滤器

图 8.27 – 为日志过滤应用 log_level 过滤器

为了快速监控使用特定过滤器拉取的数据趋势,利用 OpenSearch 的可视化能力至关重要。通过丰富多样的仪表板对象,操作员可以为每个搜索过滤后的查询构建不同类型的可视化图表。要创建可视化图表,指向 可视化 标签并点击 创建可视化图表 按钮。从返回的列表中选择 垂直条形图 可视化类型,以展示从最后保存的查询中收集的过去一小时内的错误发生次数。创建后,会生成一个新的图表,可以将其细分为更具体的字段,称为 。通过在创建的图表设置中添加一个桶并选择 X 轴 选项,可以执行数据图表聚合。如下例所示,数据聚合已固定为 日期直方图 类型,默认使用 @ 时间戳 字段:

图 8.28 – 使用 OpenSearch 桶进行数据聚合

图 8.28 – 使用 OpenSearch 桶进行数据聚合

  1. 更新后,可以在单一视图中可视化所有拉取日志数据的错误率概览:

图 8.29 – 基于已应用过滤器的日志可视化仪表板

图 8.29 – 基于已应用过滤器的日志可视化仪表板

OpenSearch 仪表板具有高度可定制性,可以执行更多数据聚合,以便呈现更精细的数据。例如,之前的图形表示可以保存在专用的服务状态仪表板中,然后你可以通过暴露每个服务的错误信息,从相同的图表添加新的可视化。

总结

本章涵盖了操作 OpenStack 环境的两个基本实践,探讨了可能的监控和日志记录方式。部署的监控和日志堆栈可能因操作环境而异,这取决于操作员的经验、对特定工具的熟悉程度或其他第三方解决方案。最佳实践之一是始终监控云平台下方和上方发生的事情,提供捕获指标和收集数据的必要方式,以便在问题达到更高严重性等级之前进行处理,而不是等到必须开始应对事件时再采取行动。正如本章所展示的,Prometheus 提供了多种配置方式,并通过简单集成导出器,云操作员可以轻松实现自动化方式收集指标。单一面板工具 Grafana 将所有指标集中在综合仪表板中,操作员可以密切观察不同系统元素的趋势。OpenStack 的遥测服务,通常称为 Ceilometer、Aodh 和 Gnocchi 三重奏,已被涵盖并部署,以开始为租户计费和跟踪资源使用情况。在本章结尾,探讨了日志记录管道的挑战,以及一个广泛采用的解决方案 OpenSearch,它能够整合 OpenStack 各个角落生成的大量日志,操作员可以在其中探索可疑事件,并积极进行修复。日志提供了有价值的信息,如果结合在一个强大的管道中进行分析,云操作员可以发现那些通过简单指标难以检测的异常情况。故障迹象的早期检测有助于评估云基础设施性能并提供反馈,从而改善环境服务,确保服务水平协议(SLA)的兑现。

除了设置日志记录管道,下一章将介绍如何进行基准测试,以深入了解 OpenStack 基础设施,并评估私有云的容量。

第九章:9

基准测试基础设施——评估资源容量和优化

“为将来做准备。”

—— 伊索

操作一个不断增长的基础设施时,主要挑战之一就是确保不同服务在预期的服务级别协议SLA)内保持运行。即使已经设置了适当的监控解决方案,以便在检测到某些情况时采取主动措施,例如根据需要扩展或缩减集群节点以容纳更多租户工作负载,生产过程中仍然可能出现意外问题。在像 OpenStack 这样的复杂环境中,由于其分布式和松散的架构,达到系统性能的极限被认为是常见问题。随着更多服务加入生态系统,性能问题也会不断增加。你可能有一个监控仪表板,显示所有服务状态为绿色,但云租户用户在多次请求失败后仍无法启动虚拟机VM)。正如我们在上一章中讨论的,日志记录有助于深入分析根本原因,但无法追踪导致用户因未发现性能问题而产生的沮丧情绪。因此,最佳实践是持续对每个小版本或大版本的生态系统进行分析。最推荐的方法之一是在每次更改时将基准测试阶段纳入你的 CI/CD 流水线。另一种方法是在每次 OpenStack 环境的软件或硬件更新时进行性能分析周期,并收集性能指标与现有的 SLA 进行比较。OpenStack 云环境并非资源无限,提前了解你的限制对于在做出扩展服务目录的业务和运营决策之前是至关重要的。

在本章中,我们将介绍在 OpenStack 中运行基准测试的不同选项,检测潜在的瓶颈,并针对避免生产环境中性能问题提出建议。以下主题将被涵盖:

  • 使用缓存提升 OpenStack 中的数据库性能

  • 基准测试 OpenStack 并识别性能瓶颈的来源

  • 使用 Watcher 优化我们的云控制平面和数据平面

  • 学习如何追踪跨 OpenStack 服务传递的请求,识别瓶颈并提高性能

赋能数据库

OpenStack 中的数据库被视为最关键的共享基础设施服务之一,需要额外注意。从高可用性的角度来看,基于Galera MariaDB的多主集群将满足对弹性数据库设置的要求,但并不能完全保证高性能的写入或读取事务。当云环境不断增长而未测量新负载时,数据库性能会成为一个问题。OpenStack 中的数据库可能会大规模增长,导致表格庞大。每次读取或写入请求和 API 调用都会增加负载,从而导致数据库不一致等常见场景。租户可能会发出 API 请求以将网络接口与实例解绑,但数据库中的记录仍然未更改。快速修复方法是登录数据库并手动更改记录,这可能是一个容易出错的过程。另一个常见模式是多写并发,即两个服务基于不一致的状态属性分配相同的资源 ID。例如,可能会生成新实例,并且可能无法将已从终止实例中解除关联的浮动 IP 资源关联起来。关系数据库通常面临性能挑战,通常,云操作员利用数据库管理员来管理其庞大且复杂的数据库环境。在 OpenStack 环境中,每个请求都会到达数据库进行读取或写入,正如我们在前几章中学到的那样,大多数 OpenStack 服务与数据库交互以完成请求,理想情况下在可接受的响应时间内。

除了通过硬件升级和升级可能改善 OpenStack 数据库设置的可能方法之外,还重要的是跟踪数据库的通用指标,例如读取或写入次数、输入/输出存储趋势和错误率。这将帮助您大致确定数据库何时会出现瓶颈。如果软件和配置调整无法帮助避免突增,硬件升级将更为方便,以确保下一个生产周期中少些麻烦。

运行与缓存

确保数据库性能最优的最快方式之一是查看运行集群的硬件。物理磁盘的特性对其执行一定数量操作的能力有很大影响。例如,使用固态硬盘SSDs)作为数据库节点对提高访问时间、传输数据速度以及输入/输出等待因素非常有利。最新一代的设备会考虑闪存存储设备,这些设备能提高读/写操作,并且能够处理高并发操作速率。另一方面,也有更好且更具成本效益的方式来设计高性能数据库解决方案,比如通过缓存减少数据库侧的磁盘输入/输出活动。

缓存发生在每一个步骤中,从服务器到最终用户的浏览器。从最终用户的角度来看,缓存能够最小化查询传递到数据库时的无响应状态。此外,缓存可能适用于将长队列的数据库查询完全移出数据库服务器。在这种情况下,您最好使用外部缓存解决方案,如MemcachedRedis。通过暴露内存服务器,OpenStack 数据库服务器可以受益于 Horizon 缓存层来存储 OpenStack 服务数据。一个重要的考虑因素是,缓存层不存储数据。例如,一旦 Memcached 实例重新启动,数据将丢失。Memcached 是 OpenStack 中常用的缓存解决方案,可以在任何类型的配置中运行。大规模的 OpenStack 环境会将缓存层运行在专用的集群节点上,以提高性能。

一个典型的 Memcached 配置只需要使用比数据库需求更低 CPU 规格的硬件。下图展示了 Memcached 在 OpenStack 环境中的使用方式:

图 9.1 – Memcached 在 OpenStack 中的集成

图 9.1 – Memcached 在 OpenStack 中的集成

该工作流程图通过获取存储在 Memcached 中的数据,同时对 MySQL 数据库执行读取操作,展示了一种写透缓存机制。在下一节中,我们将使用kolla-ansible在现有的 OpenStack 环境中部署 Memcached 层。

部署缓存

在开始部署 Memcached 实例到现有的 OpenStack 环境之前,必须遍历 OpenStack 中常见的涉及缓存操作的工作流程。当触发实例创建请求时,会生成多个 API 请求并与特定的服务端点对齐。此过程涉及 Horizon 到 Nova 发起 API 请求,Glance 获取镜像,Cinder 附加卷,Neutron 分配网络端口等。

每次请求时,Keystone 都会检查其数据库中的记录,以验证内部令牌的有效性。

随着大量类似的 API 请求,Keystone 将消耗更多的 CPU 资源以从数据库获取这些令牌并相应地验证它们。这会增加履行新进入请求的延迟,并导致由于过期令牌导致的数据库表查找的延迟增加。缓存可以通过不在数据库中保存令牌而使用缓存层来显著减少数据库负载。Keystone 将在 Memcached 实例中保存其所有令牌记录。

在接下来的练习中,我们将作为控制平面节点的一部分部署一个 Memcached 容器。如前所述,Memcached 层可以在专用服务器上运行,甚至可以集群以获得最高性能,并且需要单独进行集群配置,这超出了本书的范围。更新multi_packtpub_prod文件以将memcached角色分配给云控制器节点,如下所示:

...
[memcached:children]
control

接下来的步骤是在globals.yml文件中启用 Memcached 服务:

...
enable_memcached: "yes"

最后,请在控制节点上执行以下命令来运行管道,并确保memcached容器已创建并正在运行:

$ sudo docker ps | grep memcached

这是我们得到的输出:

图 9.2 – 列出 Memcached kolla 容器

图 9.2 – 列出 Memcached kolla 容器

确保 Keystone 已重新配置为使用缓存,可以在云控制器节点的 Keystone 配置文件中进行检查:

$ cat /etc/keystone/keystone.conf
[cache]
backend = oslo_cache.memcache_pool
enabled = True
memcache_servers = url:127.0.0.1:11211

在执行 Keystone API 调用时,可以通过观察get_hits值的增加来进一步检查 Memcached 实例,如下所示:

$ watch -d -n 1 'memcached-tool 127.0.0.1:11211 stats'

我们得到以下输出:

图 9.3 – 列出 Memcached 的 get_hits 统计信息

图 9.3 – 列出 Memcached 的 get_hits 统计信息

实时验证 Keystone 缓存机制的当前行为非常有用,例如以下内容:

  • accepting_conns:这是连接到 Memcached 服务器的已接受连接数。任何新添加的服务配置为使用 Memcached 作为缓存后端都会增加其值 1。

  • bytes:这是实时缓存项目使用的字节数。

  • bytes_read:这是传入到 Memcached 服务器的字节数。

  • bytes_written:这是从 Memcached 服务器传出的字节数。

  • cmd_get:这是 Memcached 服务器接收的获取命令的次数。

  • cmd_set:这是 Memcached 服务器处理的设置命令的次数。

  • get_hits:这是成功的缓存命中(获取请求)的次数。可以通过将get_hits除以cmd_get值并生成百分比来获取命中率。

  • get_misses:这是失败的缓存命中(获取请求)的次数。

大多数 OpenStack 服务都可以利用缓存层,因此 Keystone 可以使用 Memcached 服务器存储每个服务请求的令牌,而不是默认在进程内缓存它们。一旦启用,kolla-ansible 将推出缓存层并调整服务配置以使用 Memcached 层。

由于 Memcached 是通过云控制器节点部署的,我们可以确保其客户端由 HAProxy 负载均衡器处理,并使用多实例的 Memcached 进行 TCP 模式。我们可以简单地编辑 kolla-ansible/ansible/group_vars/all.yml 文件中的 enable_haproxy_memcached 变量,如下所示:

...
enable_haproxy_memcached: "yes"

在运行管道后,Memcached 集群将会在 HAProxy 中列出,并通过其虚拟 IP 提供服务。

我们需要告诉 Nova 服务,我们已经在三个不同的云控制器节点上运行了多个 Memcached 实例。当 cc01.os 不可用时,cc02.os 会接管,依此类推。我们将在每个控制节点和计算节点的 /etc/nova/nova.conf 文件中设置以下指令:

...
memcached_servers = cc01.os:11211,cc02.os:11211,cc03.os:11211
...

Memcached 对我们的仪表盘也有益处。我们可以告诉 Horizon 使用 Memcached 来进行 Django 的 web 缓存。只需要指向虚拟 IP,就可以考虑可扩展的云控制器设置。仪表盘包括 CACHES 设置,我们需要编辑或添加它。在你的云控制器节点上,编辑 /etc/openstackdashboard/local_settings.py 文件,内容如下:

...
 CACHES = {
     'default': {
         'BACKEND':
              'django.core.cache.backends.memcached.'
              'MemcachedCache',
         'LOCATION': '10.0.0.100:11211',
     }
 }
...

可选地,可以将下一个配置片段添加到每个 HAProxy 实例中,以增强可扩展的 Django 仪表盘,该仪表盘现在将使用可扩展的 Memcached 设置:

listen horizon 10.0.0.47:80
balance roundrobin
maxconn 10000
mode tcp
server cc01.os 10.0.0.100:80 cookie cc01.os check inter 5s rise
2 fall 3
server cc02.os 10.0.0.101:80 cookie cc02.os check inter 5s rise
2 fall 3
server cc03.os 10.0.0.102:80 cookie cc03.os check inter 5s rise
2 fall 3

通过执行以下命令行来重新加载 HAProxy 配置:

$ service haproxy reload

在管理数据库性能的使用场景中,有成千上万的情况是非常重要的;这是一个庞大的话题,需要更多的数据库专业知识来发现异常并立即处理。Memcached 是处理大量读取操作激增的一种方式,但这可能还不足够。当数据库性能变得更复杂,且很少有工具可以自动化数据库性能检查和修复时,问题会更加棘手。OpenStack 提供了一些工具,围绕其核心生态系统,支持云操作员进行基准测试、监控和做出架构决策,以改善服务性能。在下一部分,我们将深入探讨使用自动化工具进行 OpenStack 基准测试的技巧。

云基准测试

扩展硬件资源是解决容量和性能限制的标准方法。在监控系统的帮助下,云操作员可以主动反应,在定义的时间窗口内增加更多资源以适应额外的负载。然而,监控系统不足以更好地了解我们的极限。在分布式计算系统中,每个循环请求都会带来性能损耗。在 OpenStack 世界中,大量的 API 请求负载可能很难追踪,并且很难大致测量某个部分或服务能承载多少负载。

从云计算之旅的初期开始,云操作员应定义并开发战略性的方法来衡量他们的云极限和性能指标。然而,挑战在于缺乏高效的工具,这些工具能够集成到云部署的生命周期中。

为了弥补性能测量的这一空白,一个关键因素是对私有云的负载进行基准测试,分别对控制平面和数据平面进行测试。值得高兴的是,随着 OpenStack 的巨大成功,更多的基准测试工具正在围绕其生态系统以及每个平面进行开发。在下一节中,我们将探索一个复杂的基准测试工具来衡量控制平面:Rally工具。

Rally 的实际应用

kolla-ansible不支持开箱即用的 Rally 安装,因为 Rally 最初并不是 OpenStack 生态系统的一部分。安装 Rally 有多种方式,其安装包适用于许多 Linux 发行版。我们将通过使用容器来保持平台独立性,但这并非必须。

重要提示

你仍然可以将 Rally 服务集成到kolla-ansible代码中。你需要构建自己的 Rally 容器,将其推送到自己的私有仓库,并编写 Ansible 角色。

在下一个安装练习中,我们将使用来自 Docker Hub 的最新 Docker Rally 镜像,该镜像包含 Rally 服务及不同的 OpenStack 插件。在其中一台云控制节点上,通过在新目录中运行以下命令来拉取 Rally 容器:

$ docker pull xrally/rally-openstack

拉取的 Rally 镜像版本为 2.3.0,这是写作时的最新版本。Rally 的数据库、配置和记录可以通过创建一个 Docker 卷来存储,方法如下:

$ docker volume create --name rally_storage

下一步命令只是通过指明 Rally 将在哪个路径下持久化数据,运行 Rally Docker 容器,该路径为/home/rally/.rally目录:

$ docker run -v rally_storage:/home/rally/.rally xrally/rally-openstack

重要提示

Rally 的默认配置将'rally.sqlite'数据库放在/home/rally/.rally目录下。可以通过更新/etc/rally/rally.conf文件中的可用选项来覆盖此默认配置。

我们需要通过提供一个部署文件来注册我们的 OpenStack 环境到 Rally,其中需要包括 OpenStack 环境变量,如管理员凭据等。

重要提示

admin 用户名、密码和租户的不同变量在/****etc/kolla/clouds.yaml文件中生成。

在 Rally 容器的 Bash 提示符下,创建一个deployment.json文件,并确保不同的变量值从/****etc/kolla/clouds.yaml文件中获取:

{
    "type": "cloud_my",
    "auth_url": "http://10.0.0.100:5000/v2.0",
    "region_name": "RegionOne",
    "admin": {
        "username": "admin",
        "password": "476212da112412",
        "tenant_name": "admin"
    }
}

使用 Rally 客户端命令行,通过之前创建的文件创建一个部署:

$ rally deployment create --file=deployment.json --name=perf_cloud

输出结果如下:

图 9.4 – 列出 Rally 部署状态

图 9.4 – 列出 Rally 部署状态

载入生成的openrc文件,该文件位于~/.rally

$ source ~/.rally/openrc

使用部署检查命令验证 OpenStack 部署的可用性,如下所示:

$ rally deployment check

这是输出结果:

图 9.5 – 列出 OpenStack 服务状态

图 9.5 – 列出 OpenStack 服务状态

现在我们已经安装并正确配置了 Rally 服务器,以便与 OpenStack APIs 进行交互,是时候进行云端基准测试了。默认情况下,您可以在 /rally/sample/tasks/scenarios 中找到大量针对所有 OpenStack 服务的基准测试场景,包括其他孵化项目,如 Murano 和 Sahara。我们将集中精力对现有运行中的 OpenStack 服务进行基准测试。在开始我们的第一个基准测试之前,了解一下 Rally 是如何工作的会非常有帮助。Rally 中的场景是基于任务执行的。一个任务可以包括一组针对 OpenStack 云的运行基准测试,这些基准测试以 JSON 或 YAML 文件格式编写。前者文件通常具有以下结构:

ScenarioClass.scenario_method:
-
args:
...
runner:
...
context
...
sla:
...

每个区块的定义如下:

  • ScenarioClass.scenario_method:这定义了基准测试场景的名称。

  • args:每个对应特定类场景的方法可以通过传递参数来定制,在启动基准测试之前。

  • runner:这定义了工作负载频率类型和基准测试场景的顺序。runner 区块可以支持以下不同类型:

    • constant:这涉及运行场景一定次数。例如,一个场景可以在总测试周期内运行 10 次。

    • constant_for_duration:这涉及在固定次数内运行场景,直到达到某个时间点。

    • periodic:这涉及定义一个特定周期来运行两个连续的基准测试场景。

    • serial:这涉及在单一基准测试线程中运行场景一定次数。

  • context:这定义了我们基准测试场景可以运行的环境类型。通常,context 的概念定义了与给定 OpenStack 项目关联的租户数量和活跃用户数量。它还可以指定每个租户或用户在特定角色中的配额。

  • sla:这对于识别基准测试的整体场景平均成功率非常有用。

如果你希望找到一个便捷的基准测试场景,以揭示当前 OpenStack 部署中更显著的结果,你将需要继续寻找一个更加专门面向云运营商的实际用例。例如,Rally 可以帮助开发人员轻松地运行合成工作负载,如虚拟机的提供和销毁实例,且只持续有限的时间。然而,对云运营商来说,这种情况似乎更为复杂。从工作负载生成的结果通常更为高层次,但可以帮助你识别云中的瓶颈。

让我们考虑一个实际的例子:公司有多个应用程序需要根据不同的使用模式进行部署。如果我们有多个并发的应用程序实例用于 QA/dev,它们将在云端的不同版本中一天被部署多次。以大规模部署为例,设定有若干团队运行一组标准堆栈应用程序,每个应用程序将包含大量需要在一天中的特定时间进行部署的虚拟机。这种工作负载需求转化为 OpenStack 术语如下:我们将有M数量的用户,在特定的口味和时间段内并发地提供N数量的虚拟机。如我们所知,OpenStack 不是一个单体结构,它是一个分布式系统,具有不同的守护进程和服务相互通信。如果我们将提供实例的用例分解成原子操作,这有助于我们理解在虚拟机提供阶段我们花费最多时间的地方,并建立历史数据记录。例如,通过多次运行相同的基准测试,但更改数据库配置的参数或启用 Glance。在下一小节中,我们将采用相同的基准测试方法来测试 Keystone 服务。

Keystone 压力测试

我们的示例场景是基于 Rally 方法的基准测试,名为KeystoneBasic.authenticate_user_and_validate_token。该场景旨在测量在特定负载下,Keystone 在认证用户时获取和验证令牌所需的时间。为了演示,重要的注意事项是负载测试将应用于一个不支持WSGI模块的特定 Keystone 配置,该配置用于 Apache Web 服务器。

重要提示

kolla-ansible的最新版本默认启用了 WSGI(mod_wsgi)模块配置,用于 Apache。你可以在 Keystone 配置文件中手动禁用该模块,或者创建一个新的 Kolla 容器来测试第一个 Rally 场景。请确保在单独的环境中执行负载测试,以免破坏 Keystone 配置,从而影响其他服务。

让我们创建一个名为perf_keystone_pp.yaml的新文件。该文件的任务内容如下:

KeystoneBasic.authenticate_user_and_validate_token:
- args: {}
  runner:
    type: "constant"
    times: 50
    concurrency: 50
  context:
    users:
      tenants: 5
      users_per_tenant: 10
  sla:
failure_rate:
  max:1

示例场景将创建一个恒定负载的 Keystone 场景,验证用户身份并验证令牌 50 次,且不中断,通过创建 5 个不同的租户,每个租户包含 10 个用户。请注意,在每次迭代中,50 个场景将同时在并发模式下运行,以模拟多个用户的访问。sla 部分定义了一个条件,如果某次身份验证尝试失败,任务将会中止。

让我们使用 Rally 命令行运行之前的基准测试,如下所示:

$ rally task start --abort-on-sla-failure perf_keystone_pp.yaml

请注意,这次我们为 abort-on-sla-failure 命令添加了一个新选项。如果您在实际的 OpenStack 生产环境中运行此类基准场景,这是一个非常有用的参数。Rally 生成了一个重负载,这可能会导致现有云环境中的性能问题。因此,我们告诉 Rally 在满足 sla 条件时,在某个时刻停止负载。我们执行的任务输出如下:

图 9.6 – 列出 Rally 任务统计信息

图 9.6 – 列出 Rally 任务统计信息

Rally 基准测试结果显示,场景测试已运行 50 次,并且以 100% 的成功率完成。要查看更详细的信息,我们可以通过运行以下命令,使用生成的 Rally 任务 ID 来可视化 HTML 报告:

$ rally task report c5493ee7-fba2-4290-b98c-36e47ed0fdb2 --out 
/var/www/html/bench/keystone_report01.html

我们的第一次测试迭代基准涉及在 Rally 任务期间满足的简单 SLA 条件:

图 9.7 – 一个 Rally SLA failure_rate HTML 报告

图 9.7 – 一个 Rally SLA failure_rate HTML 报告

从相同的报告仪表板中,在概述标签页中,第二个相关图表,负载配置文件,展示了在 Rally 任务期间有多少个迭代是并行运行的:

图 9.8 – Rally 生成的 Keystone 场景的负载配置文件报告

图 9.8 – Rally 生成的 Keystone 场景的负载配置文件报告

负载配置文件 图表可以用来说明在工作负载周期中同时运行的迭代变化情况。这些信息对于了解系统在某些峰值时的行为非常有用,并且有助于规划在任何特定时刻系统能够承载的负载量。更多详细信息可以在第二个标签页 详细信息 中找到,在那里我们可以看到原子操作时长图表,在我们的案例中,展示了两项操作——keystone_v2.fetch_tokenkeystone_v2.validate_token

图 9.9 – 一个 Keystone 步骤的原子操作时长图表,由 Rally 生成

图 9.9 – 一个 Keystone 步骤的原子操作时长图表,由 Rally 生成

该图表有助于查看每个操作的场景变化,以及迭代执行过程中持续时间的变化。如我们所见,由于获取和验证令牌是两个不同的操作,这两个操作的持续时间并不相同。如果我们的测试用例在 SLA 条件方面失败,例如场景执行时间过长,我们可以使用此图表进行详细分析,确定瓶颈出现在了哪个操作上。

我们可以在第二次迭代中稍微调整成功标准参数,以实现更严格的 SLA,从而可视化更现实的场景。例如,我们可以按如下方式修改sla部分:

...
  sla:
    max_avg_duration: 5
    max_seconds_per_iteration: 5
  failure_rate:
  max: 0
  performance_degradation:
    max_degradation: 50
    outliers:
      max: 1

新的sla部分定义了五个条件:

  • max_avg_duration :如果认证的最大平均时长超过五秒,任务将终止。

  • max_seconds_per_iteration :如果认证请求的最大时长超过五秒,任务将终止。

  • failure_rate :如果多次认证失败,任务将根据max参数终止。

  • performance_degradation :如果已完成迭代的最大时长与最小时长之间的差异超过 50%,任务将终止。最大值由max_degradation参数定义。

  • : outlier :离群值限制长时间运行的迭代次数为1,由max参数定义。

一旦修改了 Rally 场景,按照以下方式重新运行任务:

$ rally task start --abort-on-sla-failure perf_keystone_pp.yaml

让我们通过生成一个不同名称的新报告再次检查我们的图表,以便比较与上次迭代结果的差异:

$ rally task report 980957ef-4c4c-4e9b-a9c1-573839dcad80 --out 
/var/www/html/bench/keystone_report02.html

图 9.10 – 由 Rally 生成的 Keystone 负载配置文件的 SLA

图 9.10 – 由 Rally 生成的 Keystone 负载配置文件的 SLA

在测试过程中,Rally 检测到迭代的最大值为11.27秒,这不符合我们的 SLA 要求:

图 9.11 – Keystone 操作持续时间的堆叠概览

图 9.11 – Keystone 操作持续时间的堆叠概览

在新的 SLA 条件下,Rally 执行在第六次迭代时停止。验证用户并验证令牌的平均时间未能满足要求,因此,这将影响整体场景的执行时长。下一步目标是与该值竞争,并将其降到五秒以下。我们的基准测试表明,在某一工作负载峰值时,验证用户令牌的操作无法达到我们的 SLA 要求。此外,身份验证一个用户所花费的时间会增加,并且当并发水平达到某个阈值时,可能会超时。这个性能挑战可以通过重新审视我们的 Keystone 设置来调整。我们可以参考一种先进的 Keystone 设计模式,在 OpenStack 环境中增强我们的身份服务性能。由于许多 OpenStack 组件支持eventlet-based进程,Keystone 组件可以通过支持多线程处理来以不同方式运行,这将消耗我们云控制器的 CPU 资源。一个建议是在 Nginx 服务器下通过 WSGI 或在启用了mod_wsgi模块的 Apache 服务器中部署 Keystone。

使用 Web 服务器作为前端来处理 Keystone 实例,可以提供并行 HTTP 连接的处理功能,并且通过代理身份验证请求到我们的身份实例,支持多线程处理模式。默认情况下,社区版kolla-ansible代码启用了 WSGI 模块,将用于本次实验。WSGI Keystone 配置在/ansible/roles/keystone/templates目录下的wsgi-keystone.conf.j2模板中提供。

以下代码片段展示了在 Keystone 中使用VirtualHost选项的基本 WSGI 配置:

...
<VirtualHost *:{{ keystone_public_listen_port }}>
    ServerName {{ keystone_public_url }}
    WSGIDaemonProcess keystone-public processes={{ keystone_api_workers }} threads=1  user=keystone group=keystone display-name=keystone-public
    WSGIProcessGroup keystone-public
    WSGIScriptAlias / {{ binary_path }}/keystone-wsgi-public
    WSGIApplicationGroup %{GLOBAL}
    WSGIPassAuthorization On
...

请注意,WSGI 进程组定义了 Keystone 用户将运行的线程数(threads=1)和进程数(keystone_api_workers)。我们可以通过调整keystone_api_workers选项中定义的进程数和WSGIDaemonProcessdirective中的线程数来增加处理请求的数量:

...
WSGIDaemonProcess keystone-public processes={{ keystone_api_workers }} threads=30  user=keystone group=keystone display-name=keystone-public
...

由于我们进行了配置更改,请运行管道以拉取并运行新配置,并使其在 Web 服务器中生效。

现在,我们有一个由 Web 服务器支持,并通过 WSGI 模块实现多线程处理模式的 Keystone。我们已经定义了将帮助我们通过再次运行相同场景来追踪硬件和 Keystone 性能限制的进程守护程序和线程:

# rally task start --abort-on-sla-failure perf_keystone_pp.yaml

通过展示上一个 Keystone 设置,我们的云控制器应该会运行更多的apache2进程,从而使用更多的 CPU 资源。这可以通过身份验证和验证时长变化的新性能结果来说明:

# rally task report b36e4b72-0e86-4769-965d-cbe3662d647e --out 
/var/www/html/bench/keystone_report03.html

图 9.12 – Web 服务器线程增加时 Keystone 的 SLA

图 9.12 – Web 服务器线程增加时 Keystone 的 SLA

现在我们通过将每次迭代的最大秒数减少到五秒以下(4.19 秒)达到了我们的目标。由于我们已经达成了 绿色 SLA,我们可以从 负载 配置文件 图表中分析我们新的 Keystone 提升配置:

图 9.13 – 增加 web 服务器线程数后 Keystone 负载配置文件

图 9.13 – 增加 web 服务器线程数后 Keystone 负载配置文件

与之前的迭代相比,多个请求可以通过线程池进行处理,因此 Keystone 能够在工作负载时间线期间处理并发迭代。尽管设置的并发水平较高,但我们可以注意到,负载测试的最大值仅为 24。这证明我们为 WSGI 设置的线程和进程配置走在正确的方向上,为更多的并发留出了更多空闲插槽,同时每次迭代的处理时间也更短。

Rally 还有更多可以做的事情,但上述场景已经足够复杂,可以作为我们在 OpenStack 中开始基准测试的起点。Rally 也是一个可插拔平台,允许操作员创建和定制他们的基准测试场景,以满足某些特定的使用案例。基准测试有助于了解 OpenStack 在定义的 SLA 下的表现。然而,当检测到性能异常时,基准测试不能直接帮助修复问题。因此,下一节中介绍的分析实践应该考虑到。

云端分析

OpenStack 生态系统由多个服务组成,这些服务彼此连接以完成请求。在某些情况下,请求可能会非常慢,甚至失败。如果请求失败的频率不断增加,云操作员必须调查并了解问题的根本原因。监控、调试和日志工具在某些情况下可以部分解决这些问题,但它们缺少请求流机制。在 OpenStack 生态系统中有一个小巧而强大的工具,名为 OSProfiler,它专注于服务追踪。OSProfiler 提供了请求在不同 OpenStack 服务中流动的视图,并将数据编译成时间轴图表进行可视化。云操作员可以通过比较不同条件下的追踪集,确定 OpenStack 部署中的瓶颈并提升其性能。OSProfiler 工具能够提供有价值的洞察和追踪数据,捕捉 API、数据库、驱动程序和 RPC 调用的响应时间。云操作员可以将追踪信息存储在持久存储中以便进一步分析,例如 Redis、Elasticsearch、简单文件或 MongoDB。

在像 OpenStack 这样的复杂系统中,追踪请求的大部分时间花费在哪里,对更快地排除故障、识别瓶颈并防止问题再次发生非常有帮助。使用 OSProfiler,云操作员可以找出原因,例如,为什么启动虚拟机请求需要很长时间。OSProfiler 能显示与这些请求相关的服务及其依赖关系。操作员可以得出哪个服务存在瓶颈,并了解如何改进响应时间。

下一节将说明如何在现有的 OpenStack 环境中安装和运行 OSProfiler。

Profiler 在运行

从 Antelope 版本开始,OSProfiler 除了其他项目外,还可以追踪所有 OpenStack 核心服务。OpenStack 社区的目标是将 OSProfiler 应用于所有 OpenStack 项目,毫无例外,因为它具有轻量且强大的追踪能力。kolla-ansible 基础设施已经支持 OSProfiler,并且可以轻松安装。可以通过在globals.yml文件中配置以下设置来启用 OSProfiler:

enable_osprofiler: "yes"
enable_elasticsearch: "yes"

请注意,OSProfiler 使用 Elasticsearch 作为后端来存储追踪数据。

重要说明

如果enable_elasticsearch设置为"no",Kolla 将安装并使用 Redis 作为 OSProfiler 的默认后端。

OSProfiler 不需要安装在专用主机上。写作时,OpenStack kolla-ansible 支持 Keystone、Nova、Glance、Cinder、Neutron、Placement、Swift、Heat、Trove、Senlin 和 Vitrage 等服务的 OSProfiler。

一旦更新并推送了globals.yml文件,运行管道,OSProfiler 库应该已经安装。在开始进行性能分析之前,我们需要从/etc/kolla/passwords.yml文件中获取由osprofiler_secret键引用的生成的 OSProfiler 密钥。该osprofiler_secret键将用于通过 OpenStack 客户端命令行为支持的服务创建 profiler UUID。以下示例说明了一个 Glance API 调用的追踪操作,具体步骤如下:

  1. 使用在云控制器节点上运行的官方 OpenStack Python 客户端来生成追踪输出:

    $ openstack --os-profile <OSPROFILER_SECRET> image list
    

    这是我们得到的输出:

图 9.14 – OSProfiler 图像列表

图 9.14 – OSProfiler 图像列表

<OSPROFILER_SECRET> 是从/etc/kolla/passwords.yml文件中检索到的 OSProfiler 密钥,参考了osprofiler_secret参数。

重要说明

通过配置每个对应服务的hmac_keys设置,可以为每个支持的服务自定义OSPROFILER_SECRET值。

命令行返回一个 OSProfiler 追踪命令行,如下所示:

图 9.15 – OSProfiler 追踪命令输出

图 9.15 – OSProfiler 追踪命令输出

  1. 使用osprofiler命令行打印 HTML 格式的追踪图。检索到的追踪数据可以存储在创建的 Elasticsearch 实例中:

    $ osprofiler trace show --html 75da221e-ffe1-7dac-aae7-22eaed337761 --connection-string elasticsearch://localhost:9200 --out "/tmp/image_perf.html"
    

    HTML 报告应该可以在本地的/****tmp目录下找到。

  2. 通过在浏览器中访问生成的image_perf.html文件来可视化追踪结果:

图 9.16 – OSProfiler 追踪结果示例

图 9.16 – OSProfiler 追踪结果示例

生成的 HTML 报告会展示每次处理调用时的请求信息,包括服务调用的性质(如 API、数据库等)及其相应的项目。Levels列对应一个追踪点,包含以 JSON 格式呈现的低级详细信息。

追踪是一种很好的实践,可以在低级别调试监控系统中无法检测到或日志数据中被忽略的问题。性能分析和基准测试提供了足够的信息来了解云的性能和资源利用趋势。随着云基础设施不断接纳新租户,硬件需求会增加。如果从一开始没有进行监控和分析,成本可能会上升,风险也将失控。应该为运营商提供策略和工具,自动化预算控制和管理。对于资源有限的情况,最好的方法之一就是寻求优化,这将在下一节中讨论。

观察云

一旦你的云环境开始扩展,并且更多的硬件资源被部署,云运营商应该寻找优化成本的方法。有些特定的使用案例,比如优化虚拟机(VM)的位置(在检测到不平衡时,虚拟机会在主机之间迁移)。

缺乏工具和高效的流程来进行资源优化演练是私有云运营商面临的一大挑战。传统上,OpenStack 管理员需要手动获取资源使用的历史指标,在定期的冲刺中分析这些指标,并根据收集的数据做出决策。然而,在大型 OpenStack 部署中,手动处理容易出错。为了自动化这一过程,OpenStack 社区提出了一个名为Watcher的不断发展的孵化项目。Watcher 项目的主要目标是为云运营商提供新的方法来减少云的拥有总成本TCO)。Watcher 被设计用来基于预定义目标监控、分析并执行优化任务。下图展示了 Watcher 如何通过一系列步骤设计其持续优化循环:

图 9.17 – OpenStack 的 Watcher 步骤工作流

图 9.17 – OpenStack 的 Watcher 步骤工作流

它从Monitor状态开始,在此状态下,来自各种数据源的数据指标被收集,例如 CPU 类型、内存使用率和能耗。然后,收集到的信息会被分析和汇总。Watcher 随后会启动一个分析器组件,该组件会总结出一些模式,并使用这些模式来预测虚拟机资源的使用情况。一个优化计划将由Optimizer组件创建,该组件以一组目标和约束为输入,例如,通过在 Nova 调度器中创建一些亲和性和反亲和性规则。Watcher 会根据这些输入做出调度决策,并可以利用其他项目定义的一些约束。下一阶段运行Planner组件,因此 Watcher 会构建行动项目,例如,如果虚拟机需要从一个主机迁移到另一个主机。在计划阶段,Watcher 会列出一组可以执行的步骤,并按顺序或并行执行。最后,Watcher 执行行动计划,并根据定义的目标应用基础设施的最佳状态。

下一部分将介绍如何使用 kolla-ansible 在现有 OpenStack 环境中安装 Watcher 项目,并演示其使用方法。

Watcher 运行中

最新的 kolla-ansible 代码发布版本已经包含了用于安装 Watcher 的 Playbook。在安装 Watcher 之前,Keystone、Nova 和 Ceilometer 必须已经在运行。以下设置中,所有 Watcher 组件,包括 watcher-apiwatcher-enginewatcher-applier,将成为云控制器节点组的一部分。要安装 watcher 组件,请通过添加以下部分来配置 multi_packtpub_prod 库存文件:

...
[watcher:children]
control
[watcher-api:children]
watcher
[watcher-engine:children]
watcher
[watcher-applier:children]
watcher

接下来,通过调整以下配置行,在globals.yml文件中启用 Watcher 服务:

enable_watcher: "yes"

Watcher 服务带有一个 Horizon 插件,一旦安装,它将在 Horizon 仪表盘上可见。提交更改并运行管道。完成后,通过在任何控制节点上运行以下命令,检查 Watcher 服务的新 Docker 容器:

$ sudo docker ps | grep watcher

以下是输出:

图 9.18 – Watcher 部署检查

图 9.18 – Watcher 部署检查

在开始使用 Watcher 服务之前,重要的是要强调 Watcher 工作流的不同步骤:

  1. 创建一个优化目标并将其与策略关联。

  2. 创建一个与优化目标关联的审计模板。

  3. 创建一个由审计模板触发的审计。

  4. 通过创建的审计生成行动计划。

  5. 采取手动或自动的行动。

在本节的接下来的部分,我们将演示一个预定义的 Watcher 策略,称为VM 工作负载合并策略。该策略的目标是将云中正在运行的工作负载进行合并,并优化运行该工作负载所需的资源数量。

要快速检查 Watcher 中预定义目标列表,请运行以下命令行并记下输出中的服务器合并目标UUID名称

$ openstack optimize goal list

输出如下:

图 9.19 – Watcher 优化目标列表

图 9.19 – Watcher 优化目标列表

接下来,使用上一步输出中列出的目标UUID名称获取服务器合并目标的可用策略列表:

$ openstack optimize strategy list --goal 8726da12-01da-42b5-65da-86165daca514

现在我们得到以下输出:

图 9.20 – Watcher 优化策略列表

图 9.20 – Watcher 优化策略列表

从返回的策略列表中,我们将使用vm_workload_consolidation策略,以减少运行在与资源容量约束相关的工作负载的主机数量。在创建审计模板之前,在 Watcher 面板中应用所选的优化策略前,我们可以检查不同虚拟化管理程序机器上实例的分布:

图 9.21 – 优化应用前实例分布状态

图 9.21 – 优化应用前实例分布状态

虚拟化管理程序列表包括三个计算节点和它们之间实例的特定分布。

接下来,通过运行以下命令行创建与所选目标和策略关联的审计模板:

$ openstack optimize audittemplate create consolidation_template 8726da12-01da-42b5-65da-86165daca514 --strategy cdc1244d-0eb2-3312-9871-987daca123da

这是输出:

图 9.22 – Watcher 优化审计模板创建

图 9.22 – Watcher 优化审计模板创建

接下来,运行从创建的审计模板中的审计,如下所示:

$ openstack optimize audit create -a consolidation-template

输出如下:

图 9.23 – Watcher 优化审计创建

图 9.23 – Watcher 优化审计创建

请注意,审计创建可能需要更长时间才能完成。状态字段显示PENDING。在此状态下,审计请求由 Watcher 决策引擎处理,Watcher 决策引擎将审计传递到下一个状态。如果 Watcher 决策引擎在当前目标和策略的上下文中找到至少一个可应用的优化选项,则审计状态将更改为SUCCEEDED

使用optimize audit show命令,并使用生成的审计 UUID 验证审计创建的状态是否已完成:

$ openstack optimize audit show da23a982-deaa-3231-3120-237dea123cba

这是输出:

图 9.24 – Watcher 优化审计验证

图 9.24 – Watcher 优化审计验证

对于每个创建的审计,优化服务会生成一个行动计划。行动计划定义了为实现开始时设定的目标需要执行的任务。行动计划使用先进的算法并返回一些相关信息,如效能指标(基于生成的审计解决方案反映的改进得分)和全局效能(评估的行动计划的总体得分)。

一旦审计创建状态更改为成功,请使用审计的 UUID 运行以下命令行,以检索审计生成的行动计划:

$ openstack optimize actionplan list --audit da23a982-deaa-3231-3120-237dea123cba

输出如下:

图 9.25 – Watcher 优化行动计划列表

图 9.25 – Watcher 优化行动计划列表

请注意,前面的输出中,Watcher 计划器已经创建了一个等待操作员验证的行动计划。推荐状态是计划器组件执行的最后一步。从全局效能信息来看,watcher-planner进程得出结论,约 33% 的计算节点可以在保持相同运行负载的情况下被撤回。

返回的行动计划行不足以列出所有不同的行动项。为此,存在单独的命令行。在应用任何行动计划之前,操作员应按如下方式查看相关的行动项。使用前一步生成的行动计划 UUID 运行以下命令行:

$ openstack optimize action list --action-plan 23a766da-77da-2361-bca1-efeda124870d

行动计划列出了所有将被执行的项目。以下列表是一个简化版本,表示在第一行中 Nova 服务状态的变化。接下来的行是基于第一项计划的行动,将按顺序执行。每个后续的行动项是 Watcher 计划器的推荐,旨在更新父行动(Nova 服务状态)后迁移一组实例:

图 9.26 – Watcher 优化动作列表

图 9.26 – Watcher 优化行动列表

审核完成后,操作员可以继续运行 watcher-applier 进程,通过运行以下命令行并使用行动计划 UUID 来执行该行动计划:

$ openstack optimize actionplan start 23a766da-77da-2361-bca1-efeda124870d

由于分配给行动计划指标的值(效能指标全局效能嵌入的 JSON 值),输出可能非常大。可以将其可视化为一个简化的截断版本,如下所示:

图 9.27 – Watcher 优化行动开始

图 9.27 – Watcher 优化行动开始

最重要的是,请注意行动计划执行的待处理状态。由于后台迁移一组实例任务,这一状态预计会持续较长时间。效能指标全局效能字段仅反映推荐的行动计划描述,概要如下:

  • 效果指标:指的是Applier 组件执行优化操作的计算节点数量。在我们的示例中,我们处理的是三个节点。根据推荐,审核旨在从这三个节点中释放一个计算节点。此外,当 Nova 服务报告完成迁移时,该指标会继续计算每个迁移的实例。instance_migrations_count 推荐表明要执行的实例迁移数量为2

  • 全局效果:这是指在执行所有操作项后,计划释放的节点比例。该比例通过将已释放的计算节点数除以审核范围内的总计算节点数来获得。在我们的例子中,比例大约为 33%。

你可以多次运行之前的命令行,并注意到行动计划执行状态从PENDING变为ONGOING的变化。一旦所有迁移任务完成,行动计划的状态应该更新为SUCCEEDED,并在效果指标全局效果字段中显示执行摘要:

$ openstack optimize actionplan start 23a766da-77da-2361-bca1-efeda124870d

输出如下:

图 9.28 – Watcher 优化行动计划开始

图 9.28 – Watcher 优化行动计划开始

通过检查 Watcher 仪表板,我们可以注意到列出超管的实例数量发生了变化,其中cn01.os变得完全空闲。Watcher 已确定,给定的工作负载可以在两个计算节点上运行,而不是三个,从而释放了一个超管机器的资源,如下所示:

图 9.29 – 应用优化后的实例分布状态

图 9.29 – 应用优化后的实例分布状态

通过这一优化成果,云运营商应该能够获取更多的空闲资源,以便将请求路由到未来的工作负载。预定义的目标是执行优化操作的一个良好开端。运营商可以根据工作负载需求以及已经配置的调度机制,为不同的情况定义自定义策略和目标。从大局观来看,精心设计的过滤和调度配置不仅有助于应对计算资源和分配的定制化,还能帮助 Watcher 规划者找到最佳的优化方案。这将节省运营开销并大幅降低成本。

概述

在本章中,我们通过突出了几项利用 OpenStack 性能的高级设置(例如数据库),将我们的 OpenStack 设置提升到了一个新的水平。你现在应该理解,对云平台进行严格且有效的测试是必要的。

基准测试的艺术有一定的学习曲线,它可以深入了解在 OpenStack 环境中运行的各个组件的各个方面,包括系统硬件和软件资源。本章重点介绍了一个小组件——OSProfiler,它可以轻松安装在 OpenStack 中,用于跟踪和调试在 OpenStack 服务之间传递的请求。通过对请求的全面视图,运维人员可以收集更多数据并生成详细的服务地图,进一步用于性能分析。本章的最后部分讨论了与资源优化相关的最佳实践,并在有机会减少成本和提升性能时,自动化推荐方案。借助 Watcher,运维人员无需寻找第三方解决方案,除非需要更多功能。基准测试、性能分析和优化实践应该定期执行。虽然本章没有讲解如何自动化这些实践,但强烈推荐为每个基准测试、性能分析和优化过程创建专门的管道。

本章结束了本书的第二部分。在接下来的部分,我们将探讨一些现代方法,这些方法利用了私有云和公有云的优势。在下一章中,我们将讨论一些常见的云混合设计模式,OpenStack 在这些模式中继续发挥作用。

第三部分:扩展 OpenStack 云

本书的最后部分将具体讲解一个趋势话题——混合云架构的采用。通过将 OpenStack 作为私有云环境,并与公有云提供商连接,本书这一部分将展示如何利用这两种云模型以最有效、最节省成本的方式分配工作负载。借助微服务设计模式和容器化技术,本部分将探讨在基于 OpenStack 的私有云和基于 AWS 的公有云上运行 Kubernetes 工作负载的不同工具和方法。

本部分包含以下章节:

  • 第十章OpenStack 混合云——设计模式

  • 第十一章混合云超大规模用例——扩展 Kubernetes 工作负载

第十章:OpenStack 混合云——设计模式

“团结就是力量。”

— 伊索

随着组织不断利用云技术,云服务的消费方式在不同云模型之间发生了显著变化。最近的研究和经验表明,采用混合方法同时使用多个供应商的托管服务的需求不断增加。遵循多云路线已经成为一种趋势,企业寻求最优选择,以最有效和最优化的方式来处理其工作负载。在本书的前面部分,我们展示了 OpenStack 在云领域中的位置。然而,对于许多组织而言,仅运行一个私有云环境可能不足以满足所有业务需求。同样,公有云提供商提供了更广泛的服务层,包括基础设施即服务IaaS)、平台即服务PaaS)和软件即服务SaaS)。然而,一些公司可能由于特定原因不会完全公开使用所有服务。OpenStack 的私有云可能是开始云旅程的答案,但由于各种原因,它可能不够。多个组织的妥协方案是采用混合方法,同时使用公有云和私有云。由于我们已经有一个基于 OpenStack 的私有云,本章将通过以下主题扩展 OpenStack 的边界:

  • 探索混合云模型

  • 重新审视公有云模型和多云战略

  • 使用 OpenStack 构建混合云战略

  • 迭代混合云设计模式

混合云范围内

云技术已经被广泛采用超过十年。在从本地环境迁移时,组织寻求通过根据 IaaS、PaaS 和 SaaS 模型找到最佳方案来提高敏捷性。除了服务交付模型的多样性,接下来开始出现的术语是私有云和公有云。在寻找最佳云战略时,其他新兴模型也被许多组织采用。在 IT 领域,我们可以看到提到一个组织是多云的,意味着它使用了多个云提供商,或者将公有云和私有云服务相结合,从而形成混合 云环境

确定正确的云战略取决于每个组织的需求,这些需求因地理位置、安全性和预算要求而有所不同。最终,并不是所有的工作负载都可以迁移到公有云环境中,例如,出于数据合规控制的原因。在其他情况下,组织会选择一个公有云提供商,在多个地理位置提供按需资源,并立即开始为业务服务。在深入了解混合云的背景之前,让我们先看看公有云模型。

公有云战略

云计算的使用增长更多地出现在公共云领域。由于公共意味着可以通过互联网访问,组织只需要访问自服务门户,就可以按需提供基础设施,并享受弹性和无限的可扩展性。主要的云服务提供商如亚马逊网络服务AWS)、微软 Azure谷歌云平台GCP)不断在定期的周期中扩展管理服务的数量。公共云消费者从每一个新的管理服务中获益,这些服务减少了运营开销,并且以更少的努力,甚至更少的专业知识,来消费这些服务。全球化的覆盖是许多全球活跃的组织的另一个重要因素。大多数大型公共云提供商在全球多个区域建立了数十个数据中心,使得它们成为支持不同位置业务的有吸引力的选择。因此,开发人员可以专注于应用程序的业务逻辑。他们还可以以较低的成本进行实验,而无需提前投入大量预算。公共云还解决了敏捷性难题,许多初创公司和中型企业一直难以负担能够提供敏捷性的基础设施。尽管DevOps一词早在公共云革命之前就存在,但由于缺乏工具以及无法利用整个敏捷软件生命周期的基础设施,这一直是一个主要障碍。在公共云领域出现之前,基础设施即代码IaC)概念仅仅是一个理论。

运营团队将不再花费相同的时间和精力在传统的行政任务上,而是会寻求更好的性能指标,如延迟和响应时间。公共云提供商提供的基础设施资源没有限制。然而,底层资源在某些时刻仍然是有限的。公共云提供商定期评估每个区域、每个可用区甚至每个服务器机架的资源使用情况。由于本地团队会积极监控并根据需求扩展资源池,云消费者无需担心限制,因为他们仍然可以在需要时请求更多资源。

如今,大多数公共云供应商提供不同的服务交付模型,包括 IaaS、PaaS 和 SaaS。如下面的图所示,从左到右,越来越多的层级落在云提供商的责任范围内。大多数云提供商旨在提供可以在主要超大规模公共云提供商(IaaS、PaaS 和 SaaS)中找到的三种服务交付模型,但并非所有的私人提供商都涵盖这三者。如下一图所示,每个服务模型定义了云提供商和云消费者之间共享的责任边界:

图 10.1 – 云服务模型的责任边界

图 10.1 – 云服务模型的责任边界

在传统的本地环境中,组织需要全面负责管理其基础设施中运行的所有不同工作负载。通过迁移到云环境,从 IaaS 到 SaaS 模型的过渡,管理和运营的负担得到减轻。

在选择云服务提供商时,我们还应该考虑创新因素。随着每个新兴技术的兴起,公共云供应商纷纷推出托管服务,并使其可供使用。以蓬勃发展的人工智能AI)领域为例,在撰写本版时,我们发现大多数大型公共云厂商都已推出显著的 AI 计划。AWS 推出了其Bedrock云服务,作为一种专门针对生成性 AI 的 PaaS 平台。微软 Azure 迅速与私营 AI 研究机构 OpenAI 合作,并最终将其纳入 Azure AI 服务套件中。GCP 则构建了自己的 AI PaaS 平台,命名为Vertex AI

公共云中的 AI 托管服务有不同的名称,选择一个云服务提供商可能是一个具有挑战性的决定。答案可能很简单: 真的取决于!

这不仅回答了给定的 AI 案例,也最终涵盖了每个云服务提供商推出的类似新服务。因此,面临选择悖论的组织应该投入时间和预算来了解新的前沿服务,给它设定一个实验性里程碑,并得出是否符合他们需求的结论。

采用公有云方法可以带来无数的优势。另一方面,经过几个月和几年的公有云服务使用后,组织开始注意到一些不足之处。公有云的采用是基于按需付费模式;正是这种模式让企业相信它是减少传统基础设施成本的正确选择。然而,如果没有仔细分析,它可能比预期的更昂贵。无论一个企业是迁移到云端,还是天生就是云端企业,如同投资方法所体现的那样,建立商业案例和确定投资回报率ROI)是必须在旅程开始时就进行的实践。一个简单的商业案例应该考虑到利用公有云资源时每个工作负载的资本支出和成本。例如,一个应用可以运行在一个或多个虚拟机之上。假设一台虚拟机 100% 的时间都在运行,那么它的成本曲线将保持线性。如果从成本角度没有仔细标记和跟踪,这样操作团队很容易失去对预算花费的控制。超级云服务提供商提供透明的计费选项和更细粒度的成本拆解视图,帮助客户理解他们的使用情况。然而,在大多数情况下,优化工作负载支出需要对其架构和基础设施组件进行一些更改。担心这些更改可能会导致生产环境出现问题,可能会使操作人员不敢采取实验性的成本优化措施。在公有云中,如果事先没有估算好,成本可能成为一个主要的劣势。因此,财务运维FinOps)学科应运而生,旨在让云端的财务责任成为 IT、财务和业务团队之间的集体事务。欲了解更多有关 FinOps 的信息,您可以访问官方的 FinOps 基金会网站,网址是www.finops.org/

公有云使用中的另一个问题是安全性和合规性问题。当公有云提供商开始提供托管服务时,安全团队提出了关于数据传输和存储的地点和方式的问题。尽管公有云提供商已经澄清了其合规性认证,证明其底层基础设施的安全性,但许多组织仍不愿将数据分散存储在自己数据中心以外的地方。我们知道,一些合规控制,如萨班斯-奥克斯利法案SOX)、国际标准化组织ISO)等,得到了公有云提供商的良好支持。然而,全球范围内运营的组织应该拥有符合其经营所在地区的托管基础设施。以欧洲联盟EU)内的通用数据保护条例GDPR)合规标准为例,像 AWS 这样的云提供商必须采取严格的措施,保护数据从欧盟传输到非欧盟国家和地区。因此,欧盟以外的任何地区也必须遵守此规定。

从安全角度来看,云服务提供商将安全责任定义为提供商与消费者之间的共享模型。正如下图所示,AWS 在其共享 责任模型中定义了云的安全责任边界:

图 10.2 – AWS 共享责任模型

图 10.2 – AWS 共享责任模型

橙色层表示提供商定义其责任,确保底层基础设施的安全,并确保其符合区域法规。这不仅涵盖了安全,还包括弹性和服务可用性,这在不同服务之间有所不同。如需了解更多关于AWS 风险与合规的白皮书,请参考 AWS 合规网页:aws.amazon.com/compliance/

列表中的下一个关注点是缺乏对云基础设施的完全控制。从表面上看,前面的图表可能显得不太直观。组织选择公有云服务的主要原因是可以更快地将产品推向市场,无需深入了解硬件细节或底层网络设备。这是采用公有云的一个合理原因,但当我们需要定制底层硬件时怎么办?由于这仅由供应商管理,消费者将无法控制它。从第一反应来看,这可能显得有些奇怪,但与传统的本地部署模式相比,有时应用团队会要求某些硬件组合和细化的规格,而这些在公有云中无法找到。在某些边缘情况下,网络团队可能会被要求构建在公有云环境下不方便实现的网络拓扑图。来自本地部署环境的云消费者可能对底层基础设施有一定的控制期望,而这在初期是不可行的。这可能变成接受这些限制,代价是构建一个复杂的网络设置。另一方面,一些云服务商已经回应了许多客户的需求,提供了控制硬件配置的方式,以便运行特定工作负载。例如,AWS 提供了 专用实例 功能,允许在专门为单一 AWS 环境提供的硬件上运行一批 EC2 实例,并将这些实例与其他 AWS 环境中的实例隔离,避免它们共享底层物理机器。虽然云服务提供商已经意识到这些限制,这也是 托管服务模式 的目的,但企业仍在不断寻找更多方式来控制云环境,以达到最佳效果。

公共云的最后一个缺点是供应商锁定困境。防止被锁定的情况是大多数企业在追求基础设施无关之前需要云无关的主要要求。能够在不同环境和平台之间自由切换,是许多企业为了保持资源使用经济性并在需要时响应开发需求的奢侈驱动因素。锁定有不同的表现形式。例如,假设一个组织希望在不同的云提供商或本地环境之间迁移其运行在虚拟机上的工作负载。为了进行这种迁移,在执行之前需要更多的计划和测试,例如在云源和目标环境之间建立专用连接,构建应用程序工件,将其部署到目标环境并进行测试。好消息是,得益于一些了不起的开源倡议,容器化技术成为了推动标准化应用部署的明星,使得在环境之间的迁移变得更为简单。现在,环境之间的迁移只需要通过共享的容器注册表进行连接。另一种供应商锁定的形式是基础设施管理的方式。我们之前已经强调过,只有当公共云投入使用时,IaC(基础设施即代码)概念才开始崭露头角。随着更多的服务和资源变得难以管理,公共云提供商构建了适当的托管服务来编写基础设施代码。例如,我们可以在 AWS 中找到CloudFormation,在 Azure 中找到Azure Deployment Manager,在 GCP 中找到Cloud Deployment Manager。如果你进入 AWS 并开始为你的 AWS 资源编写代码模板,那么如果你以后计划在 GCP 或 Azure 中使用相同的代码抽象,这将不可行。对于许多企业而言,IaC 的云无关性几乎是一个宗教问题。在很多情况下,这些企业跳过了学习任何这些资源管理工具,而坚持使用像TerraformPulumi这样的云无关工具。

本节总结了为什么公共云如此重要,以及采纳公共云可能带来的担忧,接下来的部分将以相同的方式展示为什么混合云模型应该被考虑。

混合云战略

根据几份云计算状态报告,数据显示公共云服务的采用持续增长。FlexeraRightScale 云计算状态报告(最近更名为Flexera 云计算状态报告)一直在跟踪云计算采用的最新动态。超过 12 年来,Flexera 一直在对从小型到大型企业的企业云用户进行调查。根据 2019 年调查报告(resources.flexera.com/web/media/documents/rightscale-2019-state-of-the-cloud-report-from-flexera.pdf),一些有趣的数字被突出显示,报告显示组织在公共云上运行了超过 38%的工作负载。同时,更多的 PaaS 服务被采用,并且相比去年增长了 50%。同一份报告还显示,38%的公司将公共云视为其 IT 基础设施的首要任务,而去年为 29%。这些数字似乎在整体上推动了公共云的采用。然而,我们可能会被同一份云计算状态报告中的一些发现所惊讶,其中企业表示希望将公共云和私有云结合用于其 IT 使用。根据 2018 年的报告,51%的公司正在寻找混合云策略,而这一比例在次年增长至 58%。这一趋势可能与《福布斯 2017 年云计算采用状况报告》(www.forbes.com/sites/louiscolumbus/2017/04/23/2017-state-of-cloud-adoption-and-security/?sh=69d3eacd1848)中的另一个云计算采用状态报告相吻合,报告显示混合云的采用增长了大约三倍(从 19%增长到 57%)。下图展示了 2015 年至 2016 年期间混合云模型采用的增长情况,数据摘自福布斯 2017 年报告。我们可以清楚地看到,公共云和私有云的采用都有所下降,而混合云模型的采用则有所上升:

图 10.3 – 根据福布斯 2017 年云计算采用报告使用的云模型类型

图 10.3 – 根据福布斯 2017 年云计算采用报告使用的云模型类型

尽管这些统计数据来自七年前,但 2024 年Flexera 云计算状态报告www.flexera.com/about-us/press-center/flexera-2024-state-of-the-cloud-managing-spending-top-challenge )表明,混合云的采用仍然是许多组织首选的方案。通过积累更多的云计算经验和教训,组织已经决定转向多云模式(无论是不同的公共或私有提供商,还是将两者结合)。随着每一次公共云的转移,公司将公共云与私有云相结合。如最新报告所示,约 73%的受访云决策者和云爱好者考虑将混合云战略应用于他们的 IT 基础设施:

图 10.4 – 基于 Flexera 2024 年云计算状态报告的多云采纳调查结果

图 10.4 – 基于 Flexera 2024 年云计算状态报告的多云采纳调查结果

有多种原因解释了混合云模型使用的扩展。最好的入门定义是 Gartner 对混合云环境的定义:“混合云计算是指基于政策并协调的服务提供、使用和管理,涉及内部和外部云服务的混合”www.gartner.com/en/information-technology/glossary/hybrid-cloud-computing )。简而言之,结合多个公共云和私有云解决了仅使用公共云或私有云的不足之处。我们可以看到,混合模型能够满足组织在公共云或私有云模型中无法找到的需求。接下来我们将逐步讨论采用混合云模型所带来的几个优势:

  • 成本效益:通过稳定利用私有云资源,偶尔的高峰可以外包给公共云,从而将成本保持在最低水平。如果没有进行适当监控,概念验证和测试环境在公共云中可能会变得更昂贵。在某些情况下,开发人员可能会启动大型 EC2 实例,如果在测试后忘记终止它们,可能会非常昂贵。如果没有正确设置成本控制政策,这种情况是非常常见的。在这种情况下,运行在私有云中可能更便宜,而且由于资源不像公共云中的资源池那样无限,容易检测到。对于需要定期授权续期和维护的工作负载,公共云可能是托管这些工作负载的合适地方,并能节省与私有云相比的维护成本和管理开销。

  • 治理和合规性:数据驻留可以更加灵活地满足每个工作负载的监管要求。并非所有数据都可以托管在公有云中,因此,私有基础设施环境可以满足这些限制,而不会影响应用的业务连续性。

  • 可定制性和控制:在基础设施的底层没有控制权可能会成为某些工作负载的障碍。公有云无法提供直接的方法来指定低级配置,包括计算硬件和网络设备。通过在公有环境中使用私有资源,可以调整这种定制化。

  • 无锁定:多云策略正在成为一些组织保持灵活性的一个重要方面,特别是在部署工作负载时。在混合模型中,无供应商锁定意味着可以在私有和公有基础设施之间移动工作负载,而无需完全依赖某一特定供应商。由于容器化的存在,混合云的采用得到了推动,容器化使得应用可以在多个云提供商之间运行,并在环境间迁移时,所需时间和精力最小化。

  • 增强的弹性:跨分布式基础设施运行工作负载增加了冗余级别。一些关键应用可以同时在私有和公有环境中运行。如果私有云可用性区域出现故障,这将包含更强的灾难恢复策略;公有环境可以通过快速指向其端点来提供救援。工作负载组件可以在公有和私有环境中以分散模式运行。这种情况要求工作负载组件例如在私有环境中运行,并通过公有云中的安全连接与其他组件互操作,以利用托管服务。

  • 增加的可扩展性云爆发是混合架构模型的关键要素。通过结合私有和公有云世界,拥有更多的工作负载部署选项能够提高灵活性。当需求超过私有云容量时,组织可以利用云爆发来加速扩展并应对负载高峰。本章后续将更详细探讨云爆发的使用案例。

最近,超大规模云服务提供商正在跟随混合云采用趋势,并将混合云平台作为其托管云服务的一部分。例如,AWS 推出了AWS Outposts服务,允许云用户在组织的边界内本地运行 AWS 服务。欲了解更多关于 AWS Outposts 的案例,请参考 AWS 官方文档:docs.aws.amazon.com/outposts/latest/userguide/what-is-outposts.html

同样,我们可以在 Azure 中找到Azure Stack服务,在 GCP 中找到Google Anthos服务。

企业通过他们在公有云中的经验已经意识到,公有云并不总是最合适的选择。私有云能力的崛起,如 OpenStack,使得同时在公有云和私有云中存在成为可能。采用 OpenStack 作为私有云解决方案的组织,发现自己处于一个非常有利的位置,能够最大化利用这两种环境的优势。OpenStack 的模块化架构及其丰富的 API 使其与公有云环境协同工作成为一种理想选择,接下来我们将探讨这一点。

OpenStack 与公有云的对接

为混合云模型进行架构设计对许多寻求上述混合云优势的组织来说可能是一个很好的选择。如果你正在基于 OpenStack 构建一个私有云,无论是为了内部使用还是为潜在客户使用,云运营商可以扩展基础设施边界,与公有云服务结合,创造有价值的成果。在混合模型中,创建一个集中的平台来管理私有云和公有云,使其像一个统一的界面一样工作是一个好的方法。该平台无需增加复杂性来与不同云提供商的 API 进行交互,而只需要一个具有代理能力的管理仪表板,用于路由跨不同环境的请求。借助现有的 OpenStack 环境,云运营商可以在 OpenStack 私有云和每个公有云端点之间建立安全的高带宽连接,正如下图所示:

图 10.5 – 通用混合云架构

图 10.5 – 通用混合云架构

将 OpenStack 私有云与公有云服务结合需要满足一定条件,才能形成一个完整的混合云图景。在这种情况下,业务工作负载应设计为在 OpenStack 环境、公有云或两者中运行。另一个重要条件是私有云与公有云之间的数据迁移准备。这需要对何时可以将数据存储在公有云或私有云基础设施中有充分的了解。例如,有些情况可能要求在公有云中存储短期数据,而将长期数据保存在私有云中。

在混合云环境中运行工作负载时,另一个需要考虑的重要方面是不同类型云之间的兼容性和差异。你可能在两个或更多不同的云之间运行工作负载,支持相同类型的多个 API,并且使用相同的技术栈。这种情况下,运行起来可能更简单,实施起来也更容易。另一个差异是不同云不支持相同类型的 API,具有不同类型的组件,例如数据库引擎或虚拟化管理程序的类型。在这种情况下,需要更多的调整来提高复杂度。好消息是,OpenStack 已经被设计为利用一些公有云的能力。它的秘密武器是其丰富的 API 曝露。作为一款私有云软件,OpenStack 被认为是一个不错的选择,能够驱动私有云和公有云的网络。OpenStack 被用于管理其他公有云提供商(如 AWS)的资源。例如,OpenStack 支持 AWS 的一些驱动程序,如 Nova 用于 EC2,Neutron 用于 VPC,以及 Cinder 驱动程序用于 AWS 的 EBS。这些驱动程序属于OpenStack-Omni项目,可以在 opendev.org/x/omni 中找到。尽管这个项目的进展较慢,OpenStack 社区正在考虑将更多的能力集成到 OpenStack API 中,以管理混合云和多云环境,如 GCP 和 Azure。

理想的云混合实现方式利用统一的云管理平台CMP)集中控制公有云、私有云和本地资源。正如下图所示,为混合云管理提供额外的层或工具有助于集中管理任何基础设施中的工作负载和数据:

图 10.6 – CMP 的能力

图 10.6 – CMP 的能力

如今,越来越多的组织正在学习根据自己的业务需求或公共需求开发自己的 CMP。在市场中,Flexera、CloudBolt、OVHcloud 和 Nutanix(仅举几个例子)提供统一的平台,用于管理公有云和私有云中的资源。混合架构的 CMP 由编排工具提供支持,能够跨云环境运行。服务目录和可重用蓝图可以提供混合管理层,以在所有连接的云端点之间部署基础设施,并实现最大程度的自动化。

云服务提供商意识到云客户的不同需求,设计更多的服务以促进混合云部署。这些服务可以是 CMP 的一部分,也可以单独运行,跨私有云和公有云操作工作负载,正如我们在下一节中将要探讨的那样。

启用混合云

今天,我们可以找到由大型公共提供商提供的一系列托管服务,方便构建混合架构。AWS 一直走在前面,通过提供多种云服务来满足客户对混合模型的需求。例如,AWS Outposts 通过使用相同的 AWS API 和工具来利用 AWS 资源,但这些资源是在组织的本地部署的。在 Outposts 之上,云用户可以运行Relational Database ServiceRDS)托管数据库,享受 MySQL、Microsoft SQL Server 和 PostgreSQL 的完全托管数据库服务。要了解更多关于 RDS Outposts 的内容,请访问以下链接:aws.amazon.com/rds/outposts/

一些令人惊叹的混合服务已经为容器推出,包括Elastic Container Services AnywhereECS Anywhere),你可以在aws.amazon.com/blogs/containers/introducing-amazon-ecs-anywhere/了解更多内容,以及Elastic Kubernetes Service AnywhereEKS Anywhere),你可以在aws.amazon.com/eks/eks-anywhere/阅读更多信息。 这两项混合容器服务使云用户能够在本地运行容器化工作负载,同时保留可扩展性和编排工具集的优势。混合存储解决方案已成为许多组织在本地环境和公共环境之间执行备份、恢复和灾难恢复所必需的。AWS 提供了AWS Storage Gateway服务,用于混合云存储解决方案。有关 AWS Storage Gateway 服务的更多信息,请访问aws.amazon.com/hybrid/services/。其他使用案例可能需要加速在私有云和公共云之间传输数据的方式。AWS 推出了AWS Datasync服务(aws.amazon.com/datasync/),作为一种混合存储解决方案。

云爆发

选择运行工作负载的位置主要取决于客户的业务和治理需求。一些组织可能会指定希望在哪个区域和云中托管其应用程序。其他组织可能更倾向于在一个云上部署其服务,但数据(包括数据库或大数据)必须存储在私有云环境中,甚至是本地裸金属环境中。任何不涉及数据的内容可以运行在公有云中。面对这些不同的需求,云运营商应当找到一个可以满足每个工作负载需求的混合模型。借助 OpenStack 提供的丰富 API 集合,与其他厂商的自动化工具和外部 API 的集成使得实现混合云变得更加简单,并且风险最小化,避免被单一厂商锁定。通过获得这种灵活性,企业应用的增长将不再担心是否能够在任何公有或私有云环境中运行。例如,假设一个组织开发了一个打包成容器镜像的服务。该镜像被部署在私有 OpenStack 云环境中,很快,应用程序的全球覆盖成为了一个业务需求,目标用户群体扩大。这时,云爆发就起到了作用。工作负载将利用公有云在最近请求区域的资源进行扩展。通过正确的设计,云架构师应能够让任何应用程序同时在两个环境中运行,并且利用混合云模型的能力,而不被某一模型锁定。云爆发是混合云中非常常见的使用案例,甚至在其他文献中被视为混合云特性。正如下图所示,云爆发利用混合云基础设施的使用率来更快速地处理应用程序的突发请求和流量高峰:

图 10.7 – 混合云使用案例中的云爆发

图 10.7 – 混合云使用案例中的云爆发

最终,一家公司预测其私有云基础设施的使用情况,并通过将负载分配到公有云资源来应对额外的负载。云爆发本质上是一种动态部署工作负载的方式,它能够在私有云资源需求过载时,通过弹性和可扩展性来应对高峰期的需求。云爆发的常见模式是,企业主要依赖其私有云资源,并仅在流量激增时启用云爆发以应对额外负载。一旦突发的工作负载激增结束,公有云资源将被终止,应用程序将继续在私有云环境中运行。

混合云中的安全性

云中的安全云的安全是私有云和公有云之间没有差异的两个方面。在混合模型中,云运营商会从安全角度审查所提供的内容。在一定程度上,混合模型中的安全性可以在利用私有部分时得到更多的执行,但也可能会遇到由于不安全的 API 端点、数据泄露或缺少静态和传输加密等原因带来的额外威胁。在 OpenStack 世界中,云运营商应该考虑私有云的安全,而云中的安全则是用户的责任。遵循安全纪律在处理混合云环境时与纯私有云或公有云并无不同。从零信任原则开始,云架构师应该在设计混合环境的最早阶段就将安全性作为核心原则,这与构建私有云时的做法相同。在混合配置中,更多的组件参与到安全配置中。基于零信任方法,架构中的任何实体默认都被视为威胁,包括用户访问、工作负载、数据、网络设备和流量。如果你已经确保基于 OpenStack 的私有云遵循相同的方法,你只需结合云服务提供商的安全边界和共享责任模型即可。好消息是,大多数超大规模提供商已经定义了共享责任模型。在混合云之旅开始时,应明确责任边界。例如,如果用户正在查看一个不受私有 OpenStack 云支持的 SaaS 解决方案,那么安全责任将转移到目标公有云提供商。定义基于混合云设置的共享责任时,会涉及多个实体,包括硬件、存储、加密、物理网络、客户操作系统、网络和平台安全、数据位置、用户认证和授权等。

在接下来的章节中,我们将采用迭代的方法,展示在混合云环境中运行的工作负载周围建立安全模式时涉及的不同实体。这包括在 OpenStack 环境和公有云之间扩展在 Kubernetes 上运行的应用程序的用例。

治理优先

数据保护是鼓励组织采用混合环境设置的主要动因之一。企业和决策者定义数据隐私要求的规则,而云用户则负责遵守这些规则。云服务提供商应遵守定义好的数据保护规则,这些规则会因地区不同而有所差异。以 GDPR 规则为例,混合云应在欧盟范围内提供数据保护的保障,包括数据隐私、存储地和保留期。在混合云环境中,基于 OpenStack 的私有云与公共云的结合应该符合以下简化的要求列表:

  • 透明地定义共享责任模型的扩展版本。

  • 记录混合环境中安全配置的不同方面。这包括如何连接私有云和公共云,以及数据如何传输和存储。

  • 提供用户访问和利用最佳实践的方法,使用访问策略、最小权限原则和加密。

  • 定义数据生命周期标准和数据分类的衡量标准。

最终,托管在混合云中的工作负载不应仅符合单一的合规性要求,而应符合多个要求,因为这种公私结合的特性。若在接收工作负载之前未能检查所有治理措施,这样的过程可能容易出错。为此,在私有云与公共云之间建立一个安全的平台至关重要,必须花时间确保两者之间的安全。容器化应用程序在私有云和公共云之间的部署会更容易。我们在前几章已经讨论了 OpenStack 生态系统在处理容器时的成熟度。例如,在 OpenStack 私有云和公共云环境中分布一个容器化应用程序时,应考虑以下治理和合规性问题:

  • 我的 Kubernetes 集群将如何以及在哪里运行,短期和长期的安排是什么?

  • 是否会有数据存储在私有云和公共云中?

  • 混合云如何控制对我的 Kubernetes 集群的访问,从而控制在其上运行的应用程序?

  • 混合云是否提供一个统一的界面来监控和记录我的应用程序?

  • 是否有标准的事件管理流程,用于在发生数据泄露或未经授权访问时报告安全问题?

混合云中的合规性和治理可能更复杂,因为每个工作负载都会有不同的合规性要求。标准化云基础设施的规则可以减少这种复杂性,但需要深入理解每个公共云提供商的责任边界。从私有云的角度来看,运行 OpenStack 时,你应该已经对安全拼图的各个部分有了更全面的了解,尤其是在设计私有云时。

网络安全

网络通常是云消费者部署工作负载时讨论的下一个要点。公共云提供了无数种方式来为工作负载设计网络,而最终由云用户定义网络边界。如果应用程序是公开可访问的,云用户将利用互联网网关或设备将应用程序暴露在其虚拟网络中。混合环境将被要求提供最大的灵活性以支持网络选项。正如我们在 OpenStack 世界中所看到的,基础设施不仅包括物理路由器和交换机,还有在物理网络基础设施上方的覆盖网络层(软件定义网络)。由于两个网络层(物理和覆盖层)都是虚拟的,私有云运营商应考虑在保持完全控制的情况下对网络进行分段。在托管任何工作负载之前,必须存在一个云用户无法看到的基础网络安全层。可以通过利用防火墙或部署 Web 应用防火墙来防御 DDoS 威胁来实现这一目标。同样,公共云提供商根据共享责任模型确保一定程度的网络安全,包括硬件和流量管理。公共提供商骨干网络中的流量被视为可信的,但如何隔离应用程序或将其公开,仍然由云用户定义。无论哪种方式,都会提供网络服务以控制其网络边界内或更广泛暴露范围内的流量类型。如果您在私有云和公共云之间扩展应用程序,必须存在多种网络安全机制,可以总结如下:

  • 确保到达任何支持传输层安全性TLS)协议(v2 和 v3)云端点的流量是安全的。

  • 确保应用程序容器已部署并加密静态数据。

  • 提供安全机制,保护通过负载均衡器公开访问的应用程序。

  • 通过利用Web 应用防火墙WAF)解决方案,强制执行应用程序安全,保护多个云环境中的应用程序。

  • 通过将应用程序网络划分为不同子网以运行在每个层级上,实现分层网络架构。分散环境(公共和私有)可以配置为使用私有地址空间(RFC 1918)。这样,不同部分的应用程序仍然可以相互访问,同时被隔离在独立的网络中,从而降低公共暴露的风险。

  • 在不同的云环境之间建立私有连接。这是前一个要点的延伸,其中应用程序可以通过私有连接而非互联网访问混合环境中的任何云。例如,在 Kubernetes 集群中,OpenStack 环境中的 Pod 可以通过如DirectConnectVPN等私有连接访问 AWS 中同一集群上下文的其他 Pod。云运营商需要定义不同的路由,以便即使在不同的云环境之间,应用组件的互联互通仍然保持私密。

混合云可以设计为使用不同类型的连接和网络实现。考虑到网络安全方面,需要为私有云和公有云的端点安全做好充分准备。私有部分需要更多的加固,因为云运营商对网络基础设施有完全的控制权。在我们的案例中,必须确保 OpenStack 私有云中每个服务的 API 端点安全。OpenStack 社区会在每次新版本发布时提供更新的安全指南,值得参考。API 端点安全指南可以在docs.openstack.org/security-guide/api-endpoints/api-endpoint-configuration-recommendations.html找到。

加固操作安全。

应用跨不同云基础设施的分布式架构的特点,可能会在操作时带来挑战。在混合架构中利用云溢出技术,虽然能提高灵活性,但也需要明确操作安全责任的定义。通过继承DevSecOps的实践,混合环境中的操作复杂性可以大大简化。我们在本章中专门介绍了 DevSecOps 如何成为自动化 OpenStack 基础设施操作安全的关键风格。当处理跨多个基础设施分布的工作负载时,我们只需应用相同的方法。一个在混合云环境中运行的 Kubernetes 集群中的应用案例,要求进行以下额外检查,以确保以最安全的方式运行:

  • 使用 CI/CD 管道自动扫描镜像中的漏洞。

  • 干运行测试,以检测并警告任何潜在的安全漏洞。

  • 使用仅限私有访问的容器镜像注册表。

  • 使镜像注册表仅通过私有连接对公有云或私有云端点可用。

  • 加固并自动化容器镜像的创建,定期发布并仅分享稳定且经过充分测试的版本给其他云端点。

  • 从单一的 CI/CD 管道部署应用容器镜像。

  • 设置日志管道以收集不同基础设施中的日志。这可以通过集中式方式实现,拉取网络流量、应用日志和防火墙日志来分析潜在问题。

  • 配置监控和指标,集中报告每个云基础设施端点的安全问题。

混合模型中的安全性可能会更加复杂,因为数据流动在不同的基础设施中,需要额外的控制措施。数据处理应谨慎执行,因为不当的数据流动可能会引发重大数据泄露,而这些问题难以恢复。混合实施的另一个挑战是访问管理的复杂性。用户需要以灵活的方式进行身份验证和授权,以便在多个基础设施中授予访问权限。使用身份与访问管理IAM)并结合单点登录工具,可以帮助解决访问复杂性问题。

总结

本章揭示了混合云的新颖性。除了 OpenStack 私有云的功能外,总有机会接入公共云环境并构建混合环境,正如我们在本章中所学到的那样。后者作为一种新的云模式持续扩展,因为企业已经意识到,结合不同云模式以享受各自的云优势是非常必要的。我们了解到,最近的云体验表明,单一的多云战略仍然不足以填补成本差距,还需要解决合规性问题。混合模型的主导地位日益增加,并伴随着更多的 OpenStack 私有云实现。掌握构建和管理 OpenStack 私有云的技能是过渡到混合模型的基石之一,这也是我们在本章中重点讨论的内容。此外,我们还学到,OpenStack 提供了多种云能力,凭借其丰富的 API,我们的私有云能够很好地融入混合云模型。

在下一章中,我们将展示如何基于 OpenStack 构建私有云环境,以确保成功的混合云体验,其中 OpenStack 将继续发挥重要作用。

第十一章:混合云超大规模用例——扩展 Kubernetes 工作负载

“虽然味觉的基本味道不超过五种,但它们的组合产生的风味远超过能尝试的种类。”

– 孙子,《孙子兵法》

在上一章中,我们简要探讨了混合云设计模式,以及混合部署如何成为许多组织的云趋势。混合云模型反映了服务的复杂混合,这些服务协同工作以满足不同的工作负载需求。当你加入 OpenStack 私有环境时,由于私有云和公有云中分布的资源的动态混合,混合模型的搭建可能更具挑战性。构建混合云网络是组织面临的第一个挑战,这需要公有云和私有云之间稳定、专用和一致的连接。此外,能够在裸金属、虚拟机或容器上运行的应用程序需要一种方法来确保不同云环境之间的配置一致性。在上一章中提到的若干实施挑战仍然是许多组织享受混合云优势的障碍。好消息是,随着应用架构模式的演进,容器化技术已经改变了应用程序的部署方式和位置。如果我们寻求应用迁移、云爆发或备份与灾难恢复策略,采用容器化技术是最佳选择。在本章中,我们将实践上一章所涉及的内容,并通过以下主题揭示容器化在混合云设置中的强大力量:

  • 设计 OpenStack 私有云与公有云环境(如 AWS)之间的混合云网络

  • 简要回顾 Kubernetes(也称为 K8s)的主要概念,为 OpenStack 和 AWS 云之间的云无关工作负载模型做准备

  • 探索实现混合云设置的不同方法

  • 在 OpenStack 私有云和 AWS 公有云之间部署 Kubernetes

  • 学习使用 Juju 进行混合云部署的编排工具

  • 通过联邦控制平面连接私有和公有云中的 Kubernetes 集群,并运行混合部署

资格验证混合架构

本节将探讨采用混合云实施的主要动机。我们将简要说明容器化如何帮助实现混合模型的大部分优势,并使企业能够在云环境之间高效地迁移。连接的云环境的网络和安全性是采用混合方法时必须仔细考虑的另一个重要支柱。

采用云无关堆栈

云中立性是许多组织在进入云计算旅程时,寻求最佳云体验的关键动因。得益于按需付费模式,组织可以使用云资源,并仅为实际使用的部分付费。然而,一些业务负载可能需要进行调整,切换或扩展到另一个云服务提供商可能变得必要。云服务提供商之间的自由迁移一开始可能并不简单。这是由于每个云服务提供商所提供的技术,业务负载自然会被绑定到某个特定云服务提供商的更多依赖上。迁移或扩展到另一个云服务提供商可能是一个昂贵、复杂且容易出错的过程。因此,云中立性应提前考虑,从负载架构本身开始着手。一个很好的例子就是新兴的微服务架构。选择微服务设计的主要好处之一是它将应用程序拆分为更小且独立的模块,使得它们可以单独进行测试和部署,而无需依赖特定的技术栈。微服务设计的另一个好处是其运行的基础设施。这就是容器化的作用所在。与虚拟机相比,容器具有更高效的计算资源利用和时间优化。这使得微服务与容器化概念成为实现云中立性的理想组合。因此,混合云模型在加入一些附加功能后,更容易实现。如以下图所示,这些附加功能包括容器编排层和自动化部署,使得云中立模型几乎完整:

图 11.1 – 混合模型的云中立架构

图 11.1 – 混合模型的云中立架构

容器编排引擎几乎不需要管理即可管理工作负载的生命周期。大多数著名的容器编排引擎,如 Docker 和 Kubernetes,都被视为云无关的容器编排平台的一部分。虽然容器编排本身带来了更多的容器管理自动化,但没有基础设施即代码IaC)概念,它的价值将大大降低。每个云服务商都提供自己的基础设施模板机制(AWS 的CloudFormation,Google 的Cloud Deployment Manager,Azure 的Deployment Manager,以及 OpenStack 的Heat)。每个服务的厂商特定语法构成了一个挑战,因为在不同云部署环境之间切换变得更加复杂。显然,解决方案是采用云无关的方法,通过使用第三方工具来实现,这些工具允许我们在多个云环境中部署相同的工作负载基础设施,并使用相同的代码来抽象基础设施层。这些工具只有在 IaC 概念作为 DevOps 原则出现后才得以实现。Hashicorp 的Terraform已成为最常用的云无关工具,用于基础设施管理。今天,更多的开源项目受到了 Terraform 的启发,最近,Pulumi工具已经出现在 DevOps 领域。除了使用代码管理基础设施外,Pulumi 还允许使用 Python、Java、Go、.NET 和 Typescript 等最流行的编程语言来描述基础设施。

重要提示

2023 年 8 月 10 日,Hashicorp 宣布 Terraform 不再受 Mozilla 公共许可证 v2.0 的约束。Pulumi 已成为 Terraform 在开源世界中的继任者,并在过去一年里获得了极大的关注和流行。欲了解更多关于 Pulumi 的信息,请访问其官方网站 www.pulumi.com/docs/get-started/

为了协调整个基础设施管理过程,CI/CD 工具定义了在不同云环境中自动化一切的引擎。

现在我们已经涵盖了混合云拼图的不同部分,我们将重点讨论如何连接两个云环境——在我们的案例中是 OpenStack 和 AWS 之间的连接。

准备混合模型

建立混合云架构首先需要私有云和公有云之间的适当网络连接。这种网络连接对于保持业务连续性至关重要。因此,必须对连接进行持续评估,评估内容包括延迟、正常运行时间和带宽。安全性是混合连接的另一个关键方面。根据用于此类连接的硬件和网络服务,操作员应确保启用传输加密并考虑冗余。当使用云网络托管服务时,实现云混合连接可以大大简化。如下一张简化的网络图所示,OpenStack 私有云终端通过两种不同的连接与 AWS 虚拟私有云VPC)相连:

图 11.2 – OpenStack 与 AWS 云之间的混合连接

图 11.2 – OpenStack 与 AWS 云之间的混合连接

图上方的连接类型展示了通过互联网使用 IPSec 隧道的站点到站点 VPN 连接。在两个云环境(OpenStack 私有网络范围和 AWS VPC)中没有暴露任何资源的情况下,通信发生在通过互联网传输的加密隧道中。OpenStack 租户环境和 AWS VPC 之间的 VPN 连接实现比经典数据中心更加自动化。正如我们在 第六章 中提到的,OpenStack 网络 – 连接性和托管服务选项,Neutron 提供了一种托管网络服务 VPNaaS,可以在几分钟内部署为站点到站点 VPN 连接。AWS 提供类似的托管 VPN 功能,作为其 VPC 服务的一部分,只需创建 VPN 网关并配置客户网关(即 OpenStack 终端)即可建立 VPN 连接。

重要提示

使用 AWS 中的站点到站点 VPN 连接时,将创建两个隧道以实现冗余。每个隧道终止于不同的可用区。如果一个隧道出现故障,流量会自动切换到第二个活动隧道。

VPN 可以是建立这种混合云连接的最快方式。连接两个不同地区的不同位置的站点到站点 VPN 连接的一个主要陷阱是性能有限。在 AWS 的情况下,每个 VPN 隧道最多可以支持 1.25 Gbps 的带宽。其他公共云提供商可能提供不同的选项。例如,Azure 允许云用户指定所需的 VPN 网关类型,根据其大小,带宽可以在 100 Mbps 到 10 Gbps 之间变化。

在 OpenStack 端,Neutron 会配置一个具有特定带宽限制的虚拟设备。Neutron 提供了 服务质量QoS)功能,可用于设置网络流量策略,以更好地控制网络带宽。

在处理需要在不同云环境之间存在并移动的复杂和大规模工作负载时,有限的带宽容量可能会成为瓶颈。此外,使用简单的 VPN 连接来保持两个云环境之间的一致连接并不总是能够得到保障。这是因为数据需要经过共享的互联网设备,路径较长。因此,公共云服务提供商提供了第二种类型的网络连接,以便与私有环境建立连接。在 AWS 世界中,当需要稳定、专用、隔离且高性能的连接时,DirectConnect 是一个理想的选择。

实施 DirectConnect 连接需要比 VPN 连接设置更多的部署步骤。云操作员可以通过 AWS 控制台或 CLI 订购 DirectConnect 连接,并决定要使用哪种类型的连接。DirectConnect 提供两种类型的连接:

  • 托管连接:AWS 合作伙伴将处理物理连接,并将其链接到位于 OpenStack 私有云环境边缘的设备。

  • 专用连接:这建立了从 OpenStack 端点到 AWS DirectConnect 位置的物理连接。此类型的连接提供多个带宽容量选项。

选择这些连接选项中的哪一种取决于许多因素,如成本、地理位置和带宽吞吐量。要了解有关 AWS DirectConnect 技术细节的更多信息,请查看以下 AWS URL:docs.aws.amazon.com/directconnect/latest/UserGuide/Welcome.html

混合连接需要一定程度的冗余。如果一条链路失败,你仍然可以使用第二条链路来传输流量,即使带宽吞吐量较低。之前的架构图展示了经典的网络设计,利用 DirectConnect 和 VPN 建立了两条连接。操作员可以在 OpenStack 私有云端配置设备,主要通过 DirectConnect 接口接收流量。这将把两条连接终止到同一位置端点的两个不同设备上。如果由于某种原因,DirectConnect 连接失败,流量将切换到通过 VPN 连接传输,作为备份。这种设计模式被认为是一种良好的折衷方案,能够在合理的价格下提供高可用性。如果混合连接需要相同的一致带宽,并且两个链路的配置完全一致,那么将会配置两条 DirectConnect 链路。这样可以最大化关键生产工作负载的弹性。然而,当然这也会带来更高的费用。AWS 建议使用动态路由,以便连接能够自动故障转移,并利用最佳可用路径。此路由功能要求 OpenStack 硬件端点支持动态路由和自动故障转移功能。

现在我们已经介绍了混合云设计中最关键的部分之一——网络,我们将继续讨论设计容器化混合云设置的不同方法。

设计容器化混合云

容器技术是开发现代应用程序的最佳选择,具备可移植性、快速部署和更少操作开销等优势。容器化的发展使得组织能够以几乎零接触、可靠和快速的方式运行和扩展其工作负载。随着 Docker 和 LXD 等多种容器引擎的兴起,Kubernetes、Mesos 和 Docker Swarm 等容器编排系统也应运而生,推动了应用开发的方式。如今,组织部署生产工作负载的信心比以往任何时候都要强。容器编排系统通过微服务架构的演变,改变了应用程序开发的方式。公共云服务商抓住了这个机会,提供了运行完全容器化环境的平台。例如,AWS(截至本文写作时)提供了三大主要的与容器相关的服务,概述如下:

  • 弹性容器服务 (ECS):通过完全托管的容器编排服务,部署和管理容器化工作负载。

  • 弹性 Kubernetes 服务 (EKS):运行和管理 Kubernetes 控制平面,负责容器部署、调度和可用性。

  • Fargate:充当一种无服务器服务,部署和管理应用程序,而无需管理底层基础设施。

Azure 也提供类似的托管容器服务,例如 Azure 容器实例 (ACI)、Azure 容器应用 (ACA) 和 Azure Kubernetes 服务 (AKS)。Kubernetes 对 GCP 来说至关重要,GCP 开发了 Google Kubernetes Engine (GKE),用于可靠且高效地部署和扩展容器化工作负载。Kubernetes 的采用历史足以写成一本书。

在混合云架构中部署容器化应用程序需要对一些设计模式有较好的理解。组织应该选择适合其战略目标的工具,以利用混合模型。在接下来的章节中,我们将探讨几种实现的设计模式,用于使用 Kubernetes 部署混合容器化架构。在处理不同的设计模型之前,我们将选择 Kubernetes 作为容器化平台。选择 Kubernetes 的众多原因之一是它被广泛使用,且其生态系统中有许多功能和工具。采用 Kubernetes 的另一个重要好处是它在设计集群和运行容器方面的灵活性,周围有多个稳定的开源容器管理工具,跨平台使用,并且支持适应混合云架构的联合功能。在深入探讨前面提到的构建混合模型的设计优势之前,让我们简要了解 Kubernetes 的术语。

Kubernetes 简介

今天,Kubernetes 无处不在。八年前,企业对于使用 Kubernetes 开始生产旅程犹豫不决,因为它刚刚由 Google 公布在市场上,还是个新生事物。容器编排引擎的概念在当时并不新鲜,因为 Docker Swarm 和 Mesos 已经相当成熟并被广泛使用。正如预期的那样,Kubernetes 提供了一种不同的引擎概念。理解其基本概念如何运作是自信地在生产环境中运行 Kubernetes 的重要一步。

对于容器爱好者来说,使用云服务将有助于采用基于 Kubernetes 的容器化模型。如前一节所述,云超大规模厂商提供支持 Kubernetes 的托管服务。Kubernetes PaaS 模型简单地消除了管理和安装容器编排引擎的开销。这还包括额外的网络、存储和可用性方面。

如下图所示,Kubernetes 旨在在集群内运行不同类型的节点:

图 11.3 – Kubernetes 引擎架构(高层次)

图 11.3 – Kubernetes 引擎架构(高层次)

节点类别可以总结如下:

  • 主节点 :它负责运行管理 Kubernetes 集群的大多数关键进程,包括以下内容:

    • 调度器 :它运行 kube-scheduler 进程,管理容器根据资源可用性和负载在适当的主机上部署。

    • 控制器管理器 :它运行 kube-controller-manager 进程,负责监控集群活动。

    • API 服务器 :它运行 kube-apiserver 进程,允许 Kubernetes 客户端与集群之间进行通信。可以通过 API 服务器访问主节点。

    • etcd :这是一个键值存储系统,用于处理集群的状态。

  • 工作节点:这是运行容器中的工作负载的节点,包含两个组件:

    • Kubelet 服务:这是运行Kubelet进程的服务,允许集群内部的通信。Kubelet 进程还会从 API 服务器监听,管理工作节点中的容器。

    • Kube-proxy 服务:这是运行kube-proxy服务的组件,负责 Kubernetes 集群中服务之间的网络通信。

Kubernetes 术语引入了几个概念,以及与其基于集群架构描述相关的内容,如下图所示:

图 11.4 – Kubernetes 引擎的低级架构

图 11.4 – Kubernetes 引擎的低级架构

不同的集群组件可以描述如下:

  • Pod:这是定义为 Kubernetes 环境中最小且最基本的组件。Pod 将容器结合在一起并运行,按需附加存储,并为网络通信分配唯一的 IP 地址。

  • 控制器:这是容器编排引擎的主要部分。它管理 Pod 的各个方面,如创建、删除、复制和发布。Kubernetes 控制器跟踪工作负载的位置和分配的资源。控制器有不同的类型,包括ReplicaSetStatefulSetDaemonSetDeploymentJobCronJob。每种控制器类型有不同的用途,针对特定的 Pod 管理需求。例如,ReplicaSet控制器创建一组运行相同应用程序的 Pod。CronJob更专注于创建定时任务。要了解更多关于 Kubernetes 控制器类型的信息,请参考 Kubernetes 官方网站的页面:kubernetes.io/docs/concepts/workloads/controllers/

  • Service:这是暴露在一个或多个 Pod 中运行的应用程序,以便接收传入请求。Kubernetes 服务将每个请求路由到相应的 Pod,并提供额外的功能,如 DNS 和负载均衡来访问 Pod。

  • Namespace:这是一个作用域逻辑层,用于隔离 Kubernetes 资源名称,从而避免在多个用户在同一物理集群中启动多个 Kubernetes 集群时发生名称冲突。

  • Volume:当 Pod 中的工作负载需要时,提供持久存储。Kubernetes 的最新版本支持更多存储和卷功能,以及一个详尽的卷类型列表。可以在kubernetes.io/docs/concepts/storage/volumes/找到受支持的卷类型的完整列表。

现在我们已经涵盖了 Kubernetes 世界中的大部分重要方面,我们可以通过探索两种最广泛采用的部署模型,验证它如何适应混合云架构。

设计去中心化模型

去中心化的 Kubernetes 模型,适用于云混合架构,称为爆发模型。组织采用这种设计,通过利用公共云资源来克服其私有云中资源的过度配置。在这种布局中,每个云环境都有自己的 Kubernetes 基础设施,分别进行部署和管理。在第二次迭代中,操作员需要管理位于两个云环境中的集群之间的网络连接。下图展示了在混合设置中,私有云中运行的 Kubernetes 集群通过接入公共资源(额外的工作节点)来扩展其资源的公共云爆发。

图 11.5 – OpenStack 和公共云提供商的混合爆发模型

图 11.5 – OpenStack 和公共云提供商的混合爆发模型

根据每个公共 Kubernetes 托管服务,操作员需要定义额外的参数,例如 DNS、集群 API 端点和命名空间配置,以便在同一工作负载或应用上下文中使用公共资源。实现这种模型可能并不复杂,但需要额外的调整来正确同步 Kubernetes 集群资源,如服务和部署。操作员必须确保两个集群在配置、身份管理和工作负载部署方面的一致性。

正如本节开头所强调的,AWS 提供了两种托管服务,供基于 Kubernetes 的工作负载使用:EKS 和 Fargate。在设计一个结合 OpenStack 和 AWS 环境的爆发式 Kubernetes 布局之前,必须认识到每个 AWS EKS 和 AWS Fargate 服务的使用场景,如下所示:

  • 如果你需要执行以下操作,请使用 EKS:

    • 由 AWS 提供托管的 Kubernetes 集群,无需管理其控制平面,并且可以操作其底层基础设施及扩展和安全配置。

    • 在网络、存储和扩展选项上有更多的灵活性。

    • 部署复杂和大型工作负载。

    • 更好地控制跨区域、本地部署以及私有云和公共云的部署。

    • 与 AWS 原生服务有更广泛的集成,支持高级配置,如弹性负载均衡和 AWS App Mesh。

  • 如果你需要执行以下操作,请使用 Fargate:

    • 提供 Kubernetes 基础设施及其相关资源

    • 通过任务定义来管理工作负载并提供资源(EC2 实例)。

    • 基于集群和实例大小运行容器,但使用你所需的 CPU 和 RAM 资源。

    • 不专注于管理集群节点,而是专注于管理工作负载。

    • 包括 Kubernetes 引擎附带的额外功能。

如果你需要支持云无关设置和更多网络定制的高级配置,那么 EKS 将是适合混合布局的选择。

另一个关键考虑因素是,在采用 Kubernetes 混合分布式模型时,两个存储(卷)端点应该具有相同的数据。有几种方法可以通过利用一些公共云托管存储服务来确保两个存储端点之间的数据同步。例如,附加到 OpenStack 中 Kubernetes 集群上运行的 Pods 的卷,可以通过私有连接使用 DataSyncaws.amazon.com/datasync/)复制到 AWS。

如下图所示,DataSync 需要一个端点用于从私有云存储端点传入数据。你可以在 AWS VPC 中创建一个 弹性文件系统EFS)作为目标位置。EFS 位置可以在 DataSync 任务中配置,以便从私有云中位于卷上的任何数据都能同步到 EFS 共享。需要注意的是,虽然可以在 Fargate 上挂载 EFS 文件系统,但仅限于卷静态配置,而在 EKS 节点上,则可以使用动态持久卷配置。

图 11.6 – 具有卷同步的混合 Kubernetes 溢出模型

图 11.6 – 具有卷同步的混合 Kubernetes 溢出模型

这种混合模型适用于不要求低延迟和在高峰需求期间动态立即扩展资源的工作负载。在这种模型中,云运营商应该预期需要更多的网络管理,并确保混合云环境中的数据一致性。即使你使用像 EKS 和 Fargate 这样的公共 Kubernetes 托管服务,管理跨不同云环境的多个 Kubernetes 集群也可能会感到压力很大。好消息是,一些基于 Kubernetes 生态系统的开源工具和封装器已经被开发出来,以支持更广泛的设计。Kubernetes 云实例提供商KIP)使你能够通过一个简化的接口管理云实例中的 Pods。下一节将探索一个抽象的布局,展示使用 KIP 在 AWS 和 OpenStack 之间实现去中心化混合 Kubernetes 布局。

混合云溢出

在本节中探讨 KIP 背后的思想之前,有必要简要介绍 Kubelet 这一 Kubernetes 框架中的另一个关键概念。Kubelet 只是一个在节点级别运行 Kubernetes 的代理。它提供了处理 Pods 的各种功能,如部署、管理以及节点与 Pods 之间的通信。Kubelet 可以被看作是 Kubernetes 控制平面与运行在节点上的容器之间的协调者。

重要提示

要了解更多关于 Kubelet 的内容,请参阅官方 Kubernetes 页面:kubernetes.io/docs/reference/command-line-tools-reference/kubelet/

基于相同的 Kubelet 概念,云原生计算基金会CNCF)发起了一个专注于虚拟 Kubelet的开源项目。该项目的官方网站可以在virtual-kubelet.io/找到。它将其定义为“一种开源的 Kubernetes Kubelet 实现,伪装成一个 Kubelet。” 术语伪装具有相当的隐喻性,但理解其概念的一种方式是考虑 Kubelet 和虚拟 Kubelet 之间的区别。虚拟 Kubelet 通过调度在其他云解决方案中提供容器的资源,但不在节点上执行,从而提供比标准 Kubelet 更多的功能。在幕后,虚拟 Kubelet 是高度可定制的,允许用户使用其他云环境并通过自己的 API 部署 Pod。虚拟 Kubelet 的另一个部分是Kubelet 提供者。虚拟 Kubelet 提供者是一个可插拔接口,提供所有必要的操作特性和 Pod 及容器的管理。用于支持云容器平台上 Kubernetes 节点的一些常见提供者包括 AWS Fargate、Azure 容器实例和 OpenStack 的 Zun。一个最新的支持提供者列表可以在virtual-kubelet.io/docs/providers/#current-providers找到。

下图展示了一个简单的云爆发示例,从私有的 OpenStack 云环境到 AWS 公共云。在 OpenStack 租户环境中,一个 Kubernetes 集群与一个虚拟 Kubelet pod 一起运行。

图 11.7 – 通过 KIP 在 OpenStack 和 AWS 之间的混合 Kubernetes 云爆发

图 11.7 – 通过 KIP 在 OpenStack 和 AWS 之间的混合 Kubernetes 云爆发

混合去中心化模型的另一种用途是通过一个单一部署者在多个云环境(私有和公共)中部署不同的 Kubernetes 集群。这种设置需要额外的网络连接来在网络层连接不同的集群。然而,集群的控制和操作是独立执行的。为了集中管理在多个云环境中运行的工作负载,我们需要提供一个公共的控制平面层。这种设计通过在混合模型中加入集中的控制层次,提升了云爆发模型的层次,下一小节将详细探讨这一点。

设计一个集中式模型

第二种混合模型整合了在私有云和公有云中运行的不同 Kubernetes 集群。这种架构被称为Kubernetes 联邦,它主要基于多集群部署,并具有额外的共用控制平面。在 Kubernetes 联邦设置下,单一的工作负载部署源会应用到主集群,作为一个集中部署位置,能够覆盖跨越不同云端点的多个集群。应用的部署随后会传播到所有环境,且视图呈现为单一目标集群。这消除了在每个集群中分别配置或维护应用状态的需求。联邦模型是一个理想的混合选项,特别是在你需要通过单一 API 接口管理多个集群时。应用从单一源打包并部署,且将其部署均匀分布在所有可见集群中。从主集群(主配置主机)的角度来看,所有其视野下的连接集群都被视为成员集群,因此每个已部署的应用将在所有工作节点上按比例拥有副本。Kubernetes 联邦也可以在应用部署过程中进行自定义。一些成员集群属于不同环境,可能需要特定的本地变量,比如网络策略。这类特定于成员集群的配置可以由持有联邦配置的主集群进行补充。

有多种工具可以部署混合 Kubernetes 集中模型。在接下来的部分,我们将专注于使用一些流行的开源解决方案,在 OpenStack 和 AWS 云上部署生产级 Kubernetes 集群。

到处部署 Kubernetes

有多种方式可以编排 Kubernetes 集群的部署。使用PaaSSaaS可以是最快且操作开销最小的方式。开源界也为跨云部署提供了便利,但这涉及到准备工作和理解每种解决方案的底层实现。在接下来的部分,我们将重点介绍 Canonical 提供的一个名为Juju的开源解决方案。

Juju 与混合云部署模型非常契合,尤其是在跨不同云环境的 Kubernetes 工作负载方面。在底层,每个环境应该有一个Juju 控制器主机,而Juju 客户端则执行部署操作和其他功能。如下面的图所示,Juju 云控制器在每个云环境中运行,并支持包括 AWS 和 OpenStack 在内的多个云环境。

图 11.8 – 混合部署模型中的 Juju 工作流

图 11.8 – 混合部署模型中的 Juju 工作流

最新的 Juju 支持的云列表可以在juju.is/docs/juju/juju-supported-clouds找到。这个架构可以与PuppetChef系统管理工具进行比较。Puppet 使用主从架构,其中从组件可以与 Juju 客户端进行比较,主组件则类似于 Juju 云控制器。

重要说明

存在多个支持使用容器的混合云和多云架构的项目和开源解决方案。使用容器的混合部署用例可以在openinfra.dev/hybrid-cloud/找到。

Juju 类似于 Puppet(清单)或 Chef(食谱),使用其自己的脚本操作符,这些操作符被称为charms。Charms 在不同的基础设施资源上部署应用程序,包括容器、虚拟机,甚至裸金属机器。Juju charms 设计得非常灵活,支持多种编程语言进行编写。

以下步骤描述了如何在公有云和私有云之间部署混合 Kubernetes 集群:

  1. 在管理/部署主机上安装 Juju 客户端。

  2. 在管理主机中配置 Juju 客户端,以引导 AWS 和 OpenStack 云。

  3. 在 AWS 公有云中部署 Juju 云控制器。

  4. 在 OpenStack 私有云中部署 Juju 云控制器。

  5. 使用 Juju 在私有云和公有云之间部署 Kubernetes 集群。

  6. 连接两个 Kubernetes 集群。

  7. 配置两个 Kubernetes 集群进行联合。

第 1 步中,我们需要选择一台专门用于 Juju 云管理的主机,并安装 Juju 客户端。这可以是任何一台能够连接 OpenStack 和 AWS 环境的机器。Juju 客户端支持多个操作系统,可以在juju.is/docs/juju/install-juju找到支持的操作系统列表。以下逐步指南展示了如何在运行 macOS 的机器上安装 Juju 客户端:

$ brew install juju

在运行 Ubuntu 操作系统的 Linux 主机上安装 Juju 客户端时,使用以下命令行:

$ sudo add-apt-repository ppa:juju/stable
$ sudo apt update
$ sudo apt install juju

可以通过运行交互式命令行界面来检查 Juju 客户端的安装情况,具体如下:

$ sudo juju

以下是输出:

图 11.9 – 验证 Juju 安装

图 11.9 – 验证 Juju 安装

重要说明

Juju 命令行不会返回任何 Juju 云控制器,因为我们是全新安装的,到目前为止,还没有在任何云中配置云控制器。Juju 会自动注册每个新配置的云控制器,稍后我们将看到。

你还可以通过运行以下命令行列出当前支持的云环境列表:

$ sudo juju list-clouds --all

我们得到以下输出:

图 11.10 – Juju 支持的云服务提供商列表

图 11.10 – Juju 支持的云服务提供商列表

下一步是使用 Juju 引导我们的云环境。为了与 AWS 资源进行交互并引导第一个 Juju 云控制器,我们需要生成 AWS 中 EC2 实例的密钥对,密钥对由访问密钥和密钥 ID 构成。

重要说明

OpenStack 没有列出在此处,因为 Juju 仅列出公共云提供商。包括 OpenStack 在内的私有云将需要通过 Juju 命令行界面添加,这将在接下来的章节中讲解。

以下部分的操作步骤需要你拥有一个 AWS 账户,并且需要一个具有编程访问权限的身份与访问管理IAM)用户。访问你的 AWS 账户,确保你拥有足够的 IAM 权限来创建一个具有编程访问权限的 IAM 用户。从主控制台的服务标签中,点击IAM,然后在控制台左下角的访问管理下拉菜单中选择用户

图 11.11 – AWS IAM 控制台

图 11.11 – AWS IAM 控制台

接下来,点击创建 用户按钮:

图 11.12 – 在 AWS 控制台中创建 IAM 用户

图 11.12 – 在 AWS 控制台中创建 IAM 用户

用户名字段中提供一个 IAM 用户名,然后点击下一步。保持提供用户访问 AWS 管理控制台复选框不选中,因为我们只需要一个具有编程访问权限的用户:

图 11.13 – 在 AWS 控制台中指定用户详细信息

图 11.13 – 在 AWS 控制台中指定用户详细信息

下一步是允许我们的 Juju 用户在 AWS 资源上执行操作。Juju 客户端将在 EC2 实例中引导一个云控制器。为了简单起见,并且基于最小权限原则,我们将通过附加AmazonEC2FullAccess策略来为创建的用户分配对 AWS 中 EC2 资源的完全权限,如下所示:

图 11.14 – 在 AWS 控制台中为 Juju IAM 用户分配 IAM 策略

图 11.14 – 在 AWS 控制台中为 Juju IAM 用户分配 IAM 策略

重要说明

从 AWS 最佳安全实践的角度来看,不建议向 IAM 用户或角色附加一整套权限。自定义策略可以限制对服务和资源的允许操作。作为经验法则,在创建策略和分配权限时,始终遵循最小权限原则。

点击下一步,然后在审查并创建页面上,点击创建用户

图 11.15 – 在 AWS 控制台中审查并创建 Juju IAM 用户

图 11.15 – 在 AWS 控制台中审查并创建 Juju IAM 用户

IAM | 用户仪表板中,选择新创建的 Juju IAM 用户。在摘要标签下,点击创建访问 密钥链接:

图 11.16 – 在 AWS 控制台中为 Juju IAM 用户创建访问密钥

图 11.16 – 在 AWS 控制台中为 Juju IAM 用户创建访问密钥

IAM 用户向导的下一页将要求你选择凭证的使用案例。请选择 在 AWS 外部运行的应用程序 选项:

图 11.17 – 在 AWS 控制台中为 Juju IAM 用户选择访问密钥用例

图 11.17 – 在 AWS 控制台中为 Juju IAM 用户选择访问密钥用例

创建 IAM 用户凭证的最后一步是可选的:为 AWS 凭证资源提供标签值。添加标签值并点击创建 访问密钥

图 11.18 – 在 AWS 控制台中为 Juju IAM 用户添加 AWS 标签资源

图 11.18 – 在 AWS 控制台中为 Juju IAM 用户添加 AWS 标签资源

这将生成一对访问密钥和秘密密钥。你可以将它们复制并保存在安全的位置,或者下载包含凭证的 CSV 文件到本地:

图 11.19 – 在 AWS 控制台中检索为 Juju IAM 用户生成的密钥

图 11.19 – 在 AWS 控制台中检索为 Juju IAM 用户生成的密钥

切换回管理主机中的 Juju 命令行界面,并运行以下命令行,提供一对密钥,包括在前一步中创建的访问密钥和秘密密钥:

$  sudo juju add-credential aws

输出如下:

图 11.20 – 使用 Juju 客户端添加 AWS IAM 用户云凭证

图 11.20 – 使用 Juju 客户端添加 AWS IAM 用户云凭证

之前的命令行将可选地请求提供 Juju 将要操作的区域,通过提供先前生成的访问密钥和秘密密钥。Juju 将创建一个名为 packetpub-kube 的本地 AWS 配置文件。

下一步是通过运行以下命令行,在 AWS 中创建我们的第一个 Juju 云控制器:

$ sudo juju  bootstrap aws juju-controller

我们得到以下输出:

图 11.21 – 在 AWS 中创建 Juju 云控制器

图 11.21 – 在 AWS 中创建 Juju 云控制器

在后台,Juju 执行 API 调用至 AWS 环境,并启动一个 EC2 实例。可以通过 AWS 控制台中的 EC2 仪表盘查看云控制器实例的初始化状态:

图 11.22 – 在 AWS 控制台中创建的 Juju 云控制器 EC2 实例

图 11.22 – 在 AWS 控制台中创建的 Juju 云控制器 EC2 实例

请注意,Juju 使用默认配置引导 Juju 控制器,例如实例的大小(m7g.medium)。确保在 Juju 命令行输出中,启动过程完成,如下图所示:

图 11.23 – Juju 云控制器在 AWS 中引导完成

图 11.23 – Juju 云控制器在 AWS 中引导完成

我们创建的控制器主机被分配了一个公共 IP 地址(34.233.124.117),Juju 客户端与其通信。

重要提示

Juju 引导命令可以通过指定实例大小和云控制器部署的区域来进一步定制。可以通过在 Juju 命令行界面中使用constraint选项来实现,选项采用键值格式。有关 Juju 约束的完整列表,请访问juju.is/docs/juju/constraint

可以通过运行以下命令行列出 Juju 云控制器:

$ juju list-controllers

以下是输出结果:

图 11.24 – 使用 Juju CLI 列出已部署的 Juju 控制器

图 11.24 – 使用 Juju CLI 列出已部署的 Juju 控制器

Juju 部署的另一个惊人优势是支持用户图形界面,提供了多个功能,例如交互式创建控制器系统和部署状态。用户界面链接默认可以通过 EC2 实例分配的公共 IP 访问,该 IP 通过运行 Juju 仪表板命令行生成。如果你运行的是 Juju 版本 3.0 或更高版本,你需要将juju-dashboard魅力添加到已部署的控制器。

重要提示

在版本 3.0.0 之前,Juju 控制器安装时默认会部署 Juju 仪表板魅力,并通过运行$ juju guis命令行生成访问详情。此命令行已从 Juju 3.0.0 及更高版本中删除,取而代之的是$ juju dashboard命令行选项。

由于我们计划公开 Kubernetes 资源,我们将添加 Kubernetes 仪表板魅力。通过运行以下命令行切换到已创建的控制器:

$ juju switch juju-controller

输出结果如下:

图 11.25 – 使用 Juju CLI 切换 Juju 控制器

图 11.25 – 使用 Juju CLI 切换 Juju 控制器

在选定的控制器上部署juju-dashboard魅力以支持 Kubernetes:

$ juju deploy juju-dashboard-k8s dashboard

接下来,通过以下方式将仪表板链接到选定的控制器:

$ juju integrate dashboard juju-controller

最后,通过运行以下命令行使仪表板可访问:

$ juju expose dashboard

Kubernetes 的 Juju 仪表板应部署在控制器实例上,并通过指向前述输出中生成的 URL 及登录凭证进行访问。

重要提示

仪表板链接的输出和相关的登录凭证不再有效。请确保使用自己生成的链接和凭证来访问已部署的仪表板。

一旦 Juju 客户端和云控制器配置完成,我们就可以开始在 AWS 中部署第一个 Kubernetes 集群。Juju 提供了不同的选项,通过简单地部署相应的 charm 来在 AWS 中部署 Kubernetes 集群。可以通过托管的 Kubernetes 服务(例如 EKS)部署集群,或者在 EC2 实例上运行自定义的 Kubernetes 集群。上述任何一种选项都可以通过 Juju charms 轻松部署。在接下来的步骤中,我们将部署一个自管理的 Kubernetes 集群在 AWS 中。Juju charms 提供了一个生产级的 Kubernetes 集群,只需在部署主机上运行以下命令行即可部署:

$ juju deploy charmed-kubernetes

charmed-kubernetes Juju charm 会在 AWS 中部署多个组件,包括以下内容:

  • Kubernetes 主节点

  • Kubernetes 从节点

  • 证书颁发机构

  • etcd

  • Kubernetes API 负载均衡器

  • Containerd 引擎

  • 运行 Calico 的虚拟网络服务

每个组件的完整列表及相应链接可以在 Juju Charmhub 上找到,地址是charmhub.io/charmed-kubernetes。之前的命令行将会在创建的云控制器上部署 Kubernetes 集群。我们可以通过在 Juju 部署主机上运行以下命令来检查每个组件的状态和详细信息:

$ juju status

下面是输出结果:

图 11.26 – 使用 Juju CLI 列出 AWS 中的 K8s 集群状态

图 11.26 – 使用 Juju CLI 列出 AWS 中的 K8s 集群状态

另外,可以通过已安装的仪表板检查新的 Kubernetes 集群。首先,确保在本地安装了kubectl

$ brew install kubectl

安装完成后,在127.0.0.1和端口8001上本地运行kubectl代理命令:

$ kubectl proxy --address='127.0.0.1' --port=8001

在浏览器中输入localhost:8001/api/v1/namespaces/kube-system/services/https:kubernetes-dashboard:/proxy/。这将显示一个图形用户界面,展示不同的 K8s 集群组件,如下所示:

图 11.27 – AWS 中部署的 K8s 集群的 Juju 仪表板

图 11.27 – AWS 中部署的 K8s 集群的 Juju 仪表板

一旦我们在 AWS 中实现了完全部署并正在运行的 Kubernetes 集群,就可以开始在 OpenStack 私有云中执行相同的步骤。

如前所述,juju list-clouds命令默认不会返回 OpenStack 作为支持的云。作为第一步,通过运行以下命令将 OpenStack 私有云添加到 Juju:

$ juju add-cloud

我们得到的输出是:

图 11.28 – 使用 Juju 客户端添加 OpenStack 云

图 11.28 – 使用 Juju 客户端添加 OpenStack 云

一旦添加了 OpenStack 云,使用相同的juju add-credentials命令行对 OpenStack API 进行身份验证:

$ juju add-credential awesome-openstack

运行以下命令行以引导 Juju 中的 OpenStack 云:

$ juju bootstrap awesome-openstack juju-controller2

与 AWS 中的引导过程类似,Juju 将在 OpenStack 中创建一个名为juju-controller2的新云控制器实例。

一旦创建完成,我们可以使用在 AWS 中部署的相同 Juju 魅力部署 Kubernetes 集群。使用以下juju deploy命令行,目标是 OpenStack Juju 模型:

$ juju deploy charmed-kubernetes -m juju-controller2

部署过程可能需要几分钟,可以通过运行带有控制器名称标志的 Juju 状态命令行来检查,如下所示:

$ juju status -m juju-controller2

这将是输出:

图 11.29 – 使用 Juju 客户端检查 OpenStack 中的 K8s 集群状态

图 11.29 – 使用 Juju 客户端检查 OpenStack 中的 K8s 集群状态

由于我们在 OpenStack 中部署的 Kubernetes Juju 魅力与 AWS 中相同,因此在过程成功完成后,应该看到与 AWS 中相同的组件正在运行。之前的命令行提供了 Kubernetes 集群中每个单元的当前状态。当每个单元中的所有代理都显示idle值时,集群即完全部署。

重要提示

部署过程可能需要一些时间,并且可以通过运行watch -c juju status命令行来实时查看部署状态。

一旦集群部署完成,可以从 Kubernetes 主节点或工作节点访问它。要控制集群,我们需要设置客户端和凭证访问权限。在部署工作站中创建一个专用的配置目录:

$ mkdir -p ~/.kube

下一步的目标是通过相同的配置位置,集中管理在 AWS 和 OpenStack 中创建的两个集群。为此,我们将通过scp命令行复制每个在 AWS 和 OpenStack 环境中部署的 Kubernetes 主节点的配置文件。以下命令行将切换 Juju 控制器到相应的 Kubernetes 环境,并将配置文件复制到~/.kube目录。我们从 AWS 的 Juju 控制器开始:

$ juju switch aws
$ juju scp kubernetes-master/0:config ~/.kube/aws-config

运行之前的命令,但切换到 OpenStack Juju 控制器:

$ juju switch awesome-openstack
$ juju scp kubernetes-master/0:config ~/.kube/os-config

要查询两个云环境中的 Kubernetes 资源,我们可以运行默认安装在每个主节点和工作节点中的kubectl本地工具。在管理主机中,确保kubectl已安装(如果之前未安装),可以在 macOS 机器上运行以下命令行:

$ brew install kubectl

提示

其他平台的 Kubectl 设置指南详见 Kubernetes 官网页面:kubernetes.io/docs/tasks/tools/#kubectl

然后,我们可以通过指定每个云环境的相应配置路径,从 Juju 客户端机器查询每个 Kubernetes 集群。以下命令行显示了在 AWS 中部署的 Kubernetes 集群的状态:

$ kubectl cluster-info --kubeconfig=~/.kube/aws-config

这是输出:

图 11.30 – 使用 kubectl 列出在 AWS 中部署的 K8s 集群组件

图 11.30 – 使用 kubectl 列出在 AWS 中部署的 K8s 集群组件

重要提示

或者,您也可以通过在 Juju 客户端机器上运行 $ kubectl proxy 127.0.0.1:8001 来访问 Kubernetes 仪表盘。

现在我们已经在 AWS 和 OpenStack 云中部署了两个完全的 Kubernetes 集群,我们将重点关注如何连接它们。为了使用混合 Kubernetes 术语,我们将依赖于 Federation 功能。

将集群连接在一起

Kubernetes 联邦,一个被称为 KubeFed 的功能,使工作负载可以跨多个集群运行,分布在多个数据中心和地理位置之间。KubeFed 利用从一个中央主机对不同集群的控制,将任何配置更改传播到所有集群或选定的集群成员。从架构的角度来看,联邦控制平面利用一组标准 API 来控制和管理集群范围的操作。由于孤立的集群可以与 DNS 条目关联,KubeFed 会自动配置所有发现的节点的 DNS,负责管理它们。如下图所示(在我们的混合模型中),KubeFed 使得可以通过一个控制平面管理多个集群:

图 11.31 – OpenStack 和 AWS 云中的 Kubernetes 联邦布局

图 11.31 – OpenStack 和 AWS 云中的 Kubernetes 联邦布局

KubeFed 可以协调运行标准 Kubernetes API 的多个集群的状态和配置。在我们的使用案例中,对于 AWS 公有云,任何部署在 EC2、EKS 或 Fargate 上的 Kubernetes 集群都可以进行联合,并与部署在 OpenStack 私有云中的集群链接。

在我们查看联邦实现之前,让我们快速绕道,看看 KubeFed 的一些技术概念。Kubernetes 联邦部分会在 Kubernetes 集群中运行一个常规的 Pod。Federation Pods 完全用于联邦目的,并且存在于创建的联邦服务内。服务部署、健康监控和 DNS 管理等功能由联邦 Pods 处理。

以下步骤将演示如何使用 KubeFed 将 AWS 和 OpenStack 世界连接在一起。

要开始使用 Federation,我们需要在主集群上部署一个专用的 Kubernetes 集群。最简单快捷的方式是通过 Juju 设置一个 Federation 控制器。Kubernetes 的 Federation 集群可以部署在 OpenStack 或 AWS 中。您也可以选择在其他管理环境中部署,并通过稍后可以安装的本地客户端与其交互。为了简单起见,我们将使用 OpenStack 环境来运行 Federation 集群。通过 Juju,我们可以切换到 OpenStack 私有云环境并部署一个新的 Federation 集群,使用与之前相同的 Kubernetes charm,如下所示:

$ juju switch awesome-openstack
$ juju deploy charmed-kubernetes -m juju-controller-fed

确保使用$juju status命令行跟踪集群部署状态。一旦九个组件的集群部署完成,我们就可以继续在本地设置联邦集群。使用我们为 OpenStack 和 AWS Kubernetes 集群所用的相同命令行,使用scp从~/.kube/目录下的任意节点复制集群配置文件:

$ juju scp kubernetes-master/0:config ~/.kube/fed-config

提示

我们通过重命名复制了配置文件,就像我们处理 AWS 和 OpenStack Kube 文件一样,重命名为fed-config

处理多个 Kubernetes 集群时,好的做法是将它们的管理集中在一个命令行中。这将消除每次需要操作特定集群时切换集群的额外开销。实现这一点的一种方法是将所有 Kubernetes 配置文件合并成一个文件。kubectl的最新版本支持管理多个集群视图。如果配置文件尚未存在,请首先创建一个空的配置文件:

$ touch ~/.kube/config

然后,设置KUBECONFIG环境变量,并列出所有配置文件的路径,如下所示:

$ export KUBECONFIG=~/.kube/config:~/.kube/os-config:~/.kube/aws-config: ~/.kube/fed-config

导出后,运行以下命令将所有kubeconfig文件合并为一个:

$ kubectl config view --flatten > ~/.kube/config

使用kubectl get-contexts命令,我们可以显示从合并配置步骤中获取的可用上下文:

$ kubectl config get-contexts

以下是输出:

图 11.32 – Juju 控制器的 K8s 上下文列表

图 11.32 – Juju 控制器的 K8s 上下文列表

提示

我们可以通过运行kubectl config get-clusters命令来显示kubeconfig文件中定义的所有集群。

在构建联邦控制平面之前,我们需要通过 DNS 名称暴露联邦服务控制器。在我们的案例中,我们已在 OpenStack 环境中部署了联邦集群。因此,应该为联邦服务控制器提供一个 DNS 提供商配置。在其他云提供商中部署联邦服务控制器时,如果部署的主机集群与 DNS 提供商相同,则 DNS 提供商配置将自动生成。例如,如果联邦服务控制器在 AWS 上运行,并且已预先配置 Route 53 托管区域,则 DNS 提供商将自动生成并将 DNS 名称传递给联邦服务控制器。在以下设置中,我们将在 OpenStack 联邦集群中将CoreDNS配置为联邦 DNS 提供商。要在juju-controller-fed上启用 CoreDNS,请运行以下命令:

$ juju switch juju-controller-fed
$ juju config kubernetes-master enable-coredns=True

然后,创建一个包含 etcd 服务 IP 地址的coredns-provider.conf文件,该 IP 地址通过juju-controller-fed集群的集群状态和 DNS 区域获得。CoreDNS文件的内容配置如下:

[Global]
etcd-endpoints = http://10.0.0.54:2379
zones = kube-fed.com.

重要提示

本示例中配置的区域基于 OpenStack 环境中的本地 DNS 配置。你可以使用自定义 DNS 提供商或选择一个本地 DNS 提供商来创建和管理私有云资源的区域。公共云提供商也提供托管的 DNS 服务来创建区域和 DNS 记录,例如 AWS 的 Route53 和 Azure 云的 Azure DNS。

现在,是时候在 juju-controller-fed 上部署联邦控制平面了。我们简要讨论了 Kubefed,它是用于 Kubernetes 联邦的工具,但我们还没有安装它。为此,请在 macOS 上运行以下命令行以安装 Kubefed:

$ curl -LO https://github.com/kubernetes-sigs/kubefed/releases/download/v0.10.0/kubefedctl-0.10.0-darwin-amd64.tgz

接下来,将二进制文件提取到其中一个目录并设置 Kubefed 二进制文件所需的可执行权限:

$ tar -xzvf kubefedctl-0.10.0-darwin-amd64.tgz
$ sudo cp kubernetes/client/bin/kubefed /usr/local/bin
$ sudo chmod +x /usr/local/bin/kubefed

运行 kubefed init 命令行来部署并初始化联邦集群中的必要服务:

$ kubefed init hybridfed --host-cluster-context=juju-controllerfed --dns-provider="coredns" --dns-zone-name="kube-fed.com" --dns-provider-config=coredns-provider.conf

这是输出结果:

图 11.33 – 运行 Kubefed 联邦控制平面

图 11.33 – 运行 Kubefed 联邦控制平面

kubefed init 联邦命令行将通过暴露联邦服务来安装一个新的 API 服务器,如前所示。它还会安装联邦控制器管理器,并为主机集群创建一个专用的命名空间,称为 federation-system。现在我们已经准备好使用联邦功能,可以开始控制 Kubernetes 集群进行联邦操作。接下来,切换到联邦上下文:

$ kubectl config use-context hybridfed

接下来,将运行在 OpenStack 和 AWS 云上的 Kubernetes 集群添加到已加入的联邦上下文中。首先从添加 AWS 开始:

$ kubefed join aws --host-cluster-context=juju-controller-fed

输出结果如下:

图 11.34 – 将 AWS K8s 集群加入联邦

图 11.34 – 将 AWS K8s 集群加入联邦

下一条命令行将加入运行在 OpenStack 上的 Kubernetes 集群:

 $ kubefed join awesome-openstack \
    --host-cluster-context=jujucontroller-fed

这是输出结果:

图 11.35 – 将 OpenStack K8s 集群加入联邦

图 11.35 – 将 OpenStack K8s 集群加入联邦

之前的两条命令行将向联邦控制平面中添加必要的配置,以便我们可以通过联邦 API 与新构建的集群进行交互,具体如下:

$ kubectl get clusters

输出结果如下:

图 11.36 – 列出在 OpenStack 和 AWS 上运行的联邦 K8s 集群

图 11.36 – 列出在 OpenStack 和 AWS 上运行的联邦 K8s 集群

在这一层级,我们已经构建了几个运行在公共 AWS 和私有 OpenStack 云上的联邦 Kubernetes 集群。可以使用标准 Kubernetes API 对这两个集群进行进一步操作。该联邦支持部署所有 Kubernetes 基本组件,如命名空间、服务、部署、ConfigMaps 等。例如,通过相同的联邦端点,我们可以部署一个 Kubernetes 命名空间,这个命名空间将跨混合云环境进行扩展。我们来创建一个新的 YAML 命名空间,命名为 fed-ns.yaml,内容如下:

apiVersion: v1
kind: Namespace
metadata:
  name: fed-ns

然后,运行以下命令行,在联邦上下文中创建命名空间,如下所示:

$ kubectl --context= hybridfed create –f fed-ns.yaml

这里是输出结果:

图 11.37 – 创建一个联邦的 K8s 命名空间

图 11.37 – 创建一个联邦的 K8s 命名空间

让我们看看在 AWS 和 OpenStack 环境中创建命名空间的过程。从 AWS 开始,只需通过获取已部署命名空间的列表来切换上下文:

$ kubectl --context=aws get ns

以下是输出结果:

图 11.38 – 列出在 AWS 上运行的 K8s 上下文的命名空间

图 11.38 – 列出在 AWS 上运行的 K8s 上下文的命名空间

类似地,运行相同的命令行,但切换到 OpenStack 上下文:

$ kubectl --context=awesome-openstack get ns

这里是输出结果:

图 11.39 – 列出在 OpenStack 上运行的 K8s 上下文的命名空间

图 11.39 – 列出在 OpenStack 上运行的 K8s 上下文的命名空间

恭喜!我们的联邦已经准备好在混合环境中处理 OpenStack 和 AWS 云上的工作负载。部署服务和 Pods 只需要通过联邦上下文创建,它将由联邦控制器负责在私有云和公有云上共享服务。

总结

本章探讨了使用 OpenStack 的更多云机会。利用容器技术跨多个云环境部署工作负载已经被一些组织采纳,这些组织寻求最佳使用范式。本章重点介绍了部署基于容器的混合云的一些方法。去中心化模型可以看作是集中式模型的简化版本,云运营商可以在多个云环境中部署工作负载。通过集中式模型,从一个地方触发一次部署就能将工作负载传播到多个环境。本章展示了 AWS 和 OpenStack 之间混合模型的用例。这两个世界可以互通,能够在两个云平台之间切换是一个极好的云能力。容器化使公司能够在多个云环境中部署、管理和扩展其工作负载,正如我们在本章中所学到的那样。联邦模式已被证明是一种快速、可靠、无需接触的操作方式,用于管理 Kubernetes 管理的工作负载,这也是我们在本章中了解的内容。我们进一步了解到,OpenStack 再次抓住了机会,随着近年来混合云的普及,OpenStack 已经崭露头角。由于其生态系统的成熟和丰富的 API 集,OpenStack 已成为管理私有云基础设施的需求对象。我们了解到,私有云和公有云的结合到目前为止是一次成功的经验。让我们保持云端,让 OpenStack 一直闪耀

posted @ 2025-07-08 12:24  绝不原创的飞龙  阅读(21)  评论(0)    收藏  举报