Kubernetes-DevOps-完全秘籍-全-

Kubernetes DevOps 完全秘籍(全)

原文:zh.annas-archive.org/md5/2D2322071D8188F9AA9E93F3DAEEBABE

译者:飞龙

协议:CC BY-NC-SA 4.0

前言

Kubernetes 是一个开源的容器编排平台,最初由谷歌开发,并于 2014 年向公众开放。它使得基于容器的复杂分布式系统的部署对开发人员来说更加简单。自诞生以来,社区已经围绕 Kubernetes 构建了一个庞大的生态系统,涵盖了许多开源项目。本书专门设计为快速帮助 Kubernetes 管理员和可靠性工程师找到合适的工具,并快速掌握 Kubernetes。本书涵盖了从在最流行的云和本地解决方案上部署 Kubernetes 集群到帮助您自动化测试并将应用程序移出到生产环境的配方。

Kubernetes – 一个完整的 DevOps 食谱为您提供了清晰的,逐步的说明,以成功安装和运行您的私有 Kubernetes 集群。它充满了实用的配方,使您能够使用 Kubernetes 的最新功能以及其他第三方解决方案,并实施它们。

本书的受众

本书面向开发人员、IT 专业人员、可靠性工程师和 DevOps 团队和工程师,他们希望使用 Kubernetes 在其组织中管理、扩展和编排应用程序。需要对 Linux、Kubernetes 和容器化有基本的了解。

本书涵盖的内容

第一章,构建生产就绪的 Kubernetes 集群,教你如何在不同的公共云或本地配置 Kubernetes 服务,使用当今流行的选项。

第二章,在 Kubernetes 上操作应用程序,教你如何在 Kubernetes 上使用最流行的生命周期管理选项部署 DevOps 工具和持续集成/持续部署(CI/CD)基础设施。

第三章,构建 CI/CD 流水线,教你如何从开发到生产构建、推送和部署应用程序,以及在过程中检测错误、反模式和许可问题的方法。

第四章,在 DevOps 中自动化测试,教你如何在 DevOps 工作流中自动化测试,加快生产时间,减少交付风险,并使用 Kubernetes 中已知的测试自动化工具检测服务异常。

第五章,为有状态的工作负载做准备,教您如何保护应用程序的状态免受节点或应用程序故障的影响,以及如何共享数据和重新附加卷。

第六章,灾难恢复和备份,教您如何处理备份和灾难恢复方案,以保持应用程序在生产中高可用,并在云提供商或基本 Kubernetes 节点故障期间快速恢复服务。

第七章,扩展和升级应用程序,教您如何在 Kubernetes 上动态扩展容器化服务,以处理服务的变化流量需求。

第八章,Kubernetes 上的可观察性和监控,教您如何监控性能分析的指标,以及如何监控和管理 Kubernetes 资源的实时成本。

第九章,保护应用程序和集群,教您如何将 DevSecOps 构建到 CI/CD 流水线中,检测性能分析的指标,并安全地管理秘密和凭据。

第十章,Kubernetes 上的日志记录,教您如何设置集群以摄取日志,以及如何使用自管理和托管解决方案查看日志。

为了充分利用本书

要使用本书,您需要访问计算机、服务器或云服务提供商服务,您可以在其中提供虚拟机实例。为了设置实验室环境,您可能还需要更大的云实例,这将需要您启用计费。

我们假设您正在使用 Ubuntu 主机(在撰写本文时为 18.04,代号 Bionic Beaver);本书提供了 Ubuntu 环境的步骤。

本书涵盖的软件/硬件 操作系统要求
GitLab、Jenkins X、OpenShift、Rancher、kops、cURL、Python、Vim 或 Nano、kubectl、helm Ubuntu/Windows/macOS

您将需要 AWS、GCP 和 Azure 凭据来执行本书中的一些示例。

如果您使用本书的数字版本,我们建议您自己输入代码或通过 GitHub 存储库访问代码(链接在下一节中提供)。这样做将有助于避免与复制/粘贴代码相关的任何潜在错误。

下载示例代码文件

您可以从www.packt.com的帐户中下载本书的示例代码文件。如果您在其他地方购买了本书,您可以访问www.packtpub.com/support并注册,以便文件直接发送到您的邮箱。

您可以按照以下步骤下载代码文件:

  1. 登录或注册www.packt.com

  2. 选择支持选项卡。

  3. 单击代码下载。

  4. 在搜索框中输入书名,并按照屏幕上的说明操作。

下载文件后,请确保使用以下最新版本解压或提取文件夹:

  • Windows 上的 WinRAR/7-Zip

  • Mac 上的 Zipeg/iZip/UnRarX

  • Linux 上的 7-Zip/PeaZip

本书的代码包也托管在 GitHub 上,网址为github.com/k8sdevopscookbook/srcgithub.com/PacktPublishing/Kubernetes-A-Complete-DevOps-Cookbook。如果代码有更新,将在现有的 GitHub 存储库上进行更新。

我们还有其他代码包,来自我们丰富的图书和视频目录,可在github.com/PacktPublishing/上找到。去看看吧!

下载彩色图片

我们还提供了一个 PDF 文件,其中包含本书中使用的屏幕截图/图表的彩色图片。您可以在这里下载:www.packtpub.com/sites/default/files/downloads/9781838828042_ColorImages.pdf

代码实例

访问以下链接,查看代码运行的视频:

bit.ly/2U0Cm8x

使用的约定

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

CodeInText:表示文本中的代码词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 句柄。例如:"将下载的WebStorm-10*.dmg磁盘映像文件挂载为系统中的另一个磁盘。"

一块代码设置如下:

html, body, #map {
 height: 100%; 
 margin: 0;
 padding: 0
}

当我们希望引起您对代码块的特定部分的注意时,相关行或项目将以粗体显示:

[default]
exten => s,1,Dial(Zap/1|30)
exten => s,2,Voicemail(u100)
exten => s,102,Voicemail(b100)
exten => i,1,Voicemail(s0)

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

$ mkdir css
$ cd css

粗体:表示一个新术语,一个重要词,或者您在屏幕上看到的词。例如,菜单或对话框中的单词会以这种形式出现在文本中。这是一个例子:“从管理面板中选择系统信息。”

警告或重要说明会出现在这样的形式中。提示和技巧会出现在这样的形式中。

章节

在这本书中,您会经常看到几个标题(准备工作如何做它是如何工作的还有更多,和另请参阅)。

为了清晰地说明如何完成一个食谱,使用以下章节。

准备工作

这一部分告诉您在食谱中可以期待什么,并描述如何设置任何所需的软件或初步设置。

如何做…

这一部分包含了遵循食谱所需的步骤。

它是如何工作的…

这一部分通常包括了对前一部分发生的事情的详细解释。

还有更多…

这一部分包括了有关食谱的额外信息,以使您对食谱更加了解。

另请参阅

这一部分为食谱提供了其他有用信息的链接。

第一章:构建生产就绪的 Kubernetes 集群

本章提出了最常用的部署方法,这些方法在流行的云服务以及本地都有使用,尽管您肯定会在互联网上找到其他教程,解释其他方法。本章解释了托管/托管云服务与自我管理云或本地 Kubernetes 部署之间的区别,以及一个供应商相对于另一个的优势。

在本章中,我们将涵盖以下示例:

  • 在亚马逊网络服务上配置 Kubernetes 集群

  • 在谷歌云平台上配置 Kubernetes 集群

  • 在 Microsoft Azure 上配置 Kubernetes 集群

  • 在阿里云上配置 Kubernetes 集群

  • 使用 Rancher 配置和管理 Kubernetes 集群

  • 配置 Red Hat OpenShift

  • 使用 Ansible 配置 Kubernetes 集群

  • 故障排除安装问题

技术要求

建议您对 Linux 容器和 Kubernetes 有基本的了解。为了准备您的 Kubernetes 集群,建议使用 Linux 主机。如果您的工作站基于 Windows,则建议您使用Windows 子系统用于 LinuxWSL)。WSL 在 Windows 上提供了一个 Linux 命令行,并允许您在 Windows 上运行 ELF64 Linux 二进制文件。

始终使用相同的环境进行开发是一个良好的实践(这意味着相同的发行版和相同的版本),就像将在生产中使用的一样。这将避免意外的惊喜,比如它在我的机器上运行IWOMM)。如果您的工作站使用不同的操作系统,另一个很好的方法是在您的工作站上设置一个虚拟机。VirtualBox(www.virtualbox.org/)是一个在 Windows、Linux 和 macOS 上运行的免费开源的虚拟化程序。

在本章中,我们假设您正在使用 Ubuntu 主机(18.04,在撰写时的代号为 Bionic Beaver)。由于本章中的所有示例都将部署和运行在云实例上,因此没有特定的硬件要求。以下是在本地主机上完成示例所需的软件包列表:

  • cURL

  • Python

  • Vim 或 Nano(或您喜欢的文本编辑器)

在亚马逊网络服务上配置 Kubernetes 集群

本节中的操作将带您了解如何获得一个功能齐全的 Kubernetes 集群,具有完全可定制的主节点和工作节点,您可以在以下章节或生产中使用。

在本节中,我们将涵盖 Amazon EC2 和 Amazon EKS 的操作步骤,以便我们可以在Amazon Web ServicesAWS)上运行 Kubernetes。

准备工作

这里提到的所有操作都需要一个 AWS 账户和一个具有使用相关服务权限的 AWS 用户。如果您没有,请访问aws.amazon.com/account/并创建一个。

当在 AWS 上运行 Kubernetes 时,AWS 提供了两个主要选项。如果您想完全管理部署并具有特定的强大实例要求,可以考虑使用Amazon Elastic Compute CloudAmazon EC2)。否则,强烈建议考虑使用Amazon Elastic Container Service for KubernetesAmazon EKS)等托管服务。

如何做…

根据您想要使用 AWS EC2 服务还是 EKS,您可以按照以下步骤使用 kops 或 eksctl 工具来启动和运行您的集群:

  • 安装命令行工具以配置 AWS 服务

  • 安装 kops 以配置 Kubernetes 集群

  • 在 Amazon EC2 上配置 Kubernetes 集群 provision a Kubernetes cluster on Amazon EC2.

  • 在 Amazon EKS 上配置托管的 Kubernetes 集群

安装命令行工具以配置 AWS 服务

在这个操作中,我们将获取 AWS 命令行界面CLIawscli和 Amazon EKS CLI eksctl以访问和配置 AWS 服务。

让我们执行以下步骤:

  1. 在您的工作站上安装awscli
$ sudo apt-get update && sudo apt-get install awscli
  1. 配置 AWS CLI 以使用您的访问密钥 ID 和秘密访问密钥:
$ aws configure
  1. 下载并安装 Amazon EKS 命令行界面eksctl
$ curl --silent --location "https://github.com/weaveworks/eksctl/releases/download/latest_release/eksctl_$(uname -s)_amd64.tar.gz" | tar xz -C /tmp
$ sudo mv /tmp/eksctl /usr/local/bin
  1. 验证其版本并确保eksctl已安装:
$ eksctl version

为了能够执行以下操作,eksctl版本应为0.13.0或更高。

安装 kops 以配置 Kubernetes 集群

在这个操作中,我们将获取 Kubernetes 操作工具kops和 Kubernetes 命令行工具kubectl,以便配置和管理 Kubernetes 集群。

让我们执行以下步骤:

  1. 下载并安装 Kubernetes 操作工具kops
$ curl -LO https://github.com/kubernetes/kops/releases/download/$(curl -s https://api.github.com/repos/kubernetes/kops/releases/latest | grep tag_name | cut -d '"' -f 4)/kops-linux-amd64
$ chmod +x kops-linux-amd64 && sudo mv kops-linux-amd64 /usr/local/bin/kops
  1. 运行以下命令以确保kops已安装并确认版本为1.15.0或更高:
$ kops version
  1. 下载并安装 Kubernetes 命令行工具kubectl
$ curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl
$ chmod +x ./kubectl && sudo mv ./kubectl /usr/local/bin/kubectl
  1. 验证其版本并确保kubectl已安装:
$ kubectl version --short

为了能够执行以下操作,kubectl版本应该是v1.15或更高。

在 Amazon EC2 上创建一个 Kubernetes 集群

这个步骤将带您完成如何获得一个完全可定制的主节点和工作节点的完全功能的 Kubernetes 集群,您可以在后续章节或生产中使用。

让我们执行以下步骤:

  1. 为您的集群创建一个域。

按照云管理最佳实践,最好使用子域名,并使用逻辑和有效的 DNS 名称来划分您的集群,以便kops成功地发现它们。

例如,我将使用k8s.containerized.me子域作为我们的托管区域。此外,如果您的域名是在 Amazon Route 53 之外的注册商注册的,您必须更新注册商的名称服务器,并为托管区域添加 Route 53 NS 记录到您的注册商的 DNS 记录中:

$ aws route53 create-hosted-zone --name k8s.containerized.me \
--caller-reference k8s-devops-cookbook \
--hosted-zone-config Comment="Hosted Zone for my K8s Cluster" 
  1. 创建一个 S3 存储桶,用于存储 Kubernetes 配置和集群状态。在我们的示例中,我们将使用s3.k8s.containerized.me作为我们的存储桶名称:
$ aws s3api create-bucket --bucket s3.k8s.containerized.me \
--region us-east-1
  1. 通过列出可用的存储桶来确认您的 S3 存储桶:
$ aws s3 ls
2019-07-21 22:02:58 s3.k8s.containerized.me
  1. 启用存储桶版本控制:
$ aws s3api put-bucket-versioning --bucket s3.k8s.containerized.me \
--versioning-configuration Status=Enabled
  1. 设置kops的环境参数,以便您可以默认使用位置:
$ export KOPS_CLUSTER_NAME=useast1.k8s.containerized.me
$ export KOPS_STATE_STORE=s3://s3.k8s.containerized.me
  1. 如果您还没有创建 SSH 密钥,请创建一个:
$ ssh-keygen -t rsa
  1. 使用您希望主节点运行的区域列表创建集群配置:
$ kops create cluster --node-count=6 --node-size=t3.large \
 --zones=us-east-1a,us-east-1b,us-east-1c \
 --master-size=t3.large \
 --master-zones=us-east-1a,us-east-1b,us-east-1c
  1. 创建集群:
$ kops update cluster --name ${KOPS_CLUSTER_NAME} --yes
  1. 等待几分钟,直到节点启动并验证:
$ kops validate cluster
  1. 现在,您可以使用kubectl来管理您的集群:
$ kubectl cluster-info

默认情况下,kops~/.kube/config下创建和导出 Kubernetes 配置。因此,连接集群使用kubectl不需要额外的步骤。

在 Amazon EKS 上创建托管的 Kubernetes 集群

执行以下步骤,在 Amazon EKS 上使用eksctl启动和运行您的托管 Kubernetes 服务集群:

  1. 使用默认设置创建一个集群:
$ eksctl create cluster
...
[√] EKS cluster "great-outfit-123" in "us-west-2" region is ready

默认情况下,eksctl使用 AWS EKS AMI 在us-west-2地区部署一个带有两个m5.large实例的集群。eksctl~/.kube/config下创建和导出 Kubernetes 配置。因此,连接集群使用kubectl不需要额外的步骤。

  1. 确认集群信息和工作节点:
$ kubectl cluster-info && kubectl get nodes
Kubernetes master is running at https://gr7.us-west-2.eks.amazonaws.com
CoreDNS is running at https://gr7.us-west-2.eks.amazonaws.com/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
NAME                                  STATUS ROLES  AGE   VERSION
ip-1-2-3-4.us-west-2.compute.internal Ready  <none> 5m42s v1.13.8-eks-cd3eb0
ip-1-2-3-4.us-west-2.compute.internal Ready  <none> 5m40s v1.13.8-eks-cd3eb0

现在,您已经有一个运行中的双节点 Amazon EKS 集群。

工作原理...

在亚马逊 EC2 上的第一个配方向您展示了如何提供多个可以在主节点故障以及单个 AZ 故障中生存的主节点副本。虽然与亚马逊 EKS 的第二个配方中具有多 AZ 支持相似,但在 EC2 上的集群给您更高的灵活性。当您使用亚马逊 EKS 时,它为每个集群运行一个单租户 Kubernetes 控制平面,控制平面由至少两个 API 服务器节点和三个etcd节点组成,这些节点跨越区域内的三个 AZ 运行。

让我们看看我们在第 7 步中使用的集群选项,使用 kops create cluster 命令:

  • --node-count=3 设置要创建的节点数。在我们的示例中,这是 6。这个配置将在定义的每个区域部署两个节点,使用--zones=us-east-1a,us-east-1b,us-east-1c,总共有三个主节点和六个工作节点。

  • --node-size 和 --master-size 设置了工作节点和主节点的实例大小。在我们的示例中,工作节点使用 t2.medium,主节点使用 t2.large。对于更大的集群,建议工作节点使用 t2.large

  • --zones 和 --master-zones 设置了集群将在其中运行的区域。在我们的示例中,我们使用了三个区域,分别是 us-east-1aus-east-1b,和 us-east-1c

有关额外区域信息,请查看另请参阅 部分中的 AWS 全球基础设施链接。

AWS 集群不能跨多个区域,所有已定义的主节点和工作节点的区域都应该在同一个区域内。

在部署多主节点集群时,应创建奇数个主实例。还要记住,Kubernetes 依赖于 etcd,一个分布式键/值存储。etcd quorum 要求超过 51%的节点随时可用。因此,有三个主节点时,我们的控制平面只能在单个主节点或 AZ 故障时生存。如果需要处理更多情况,需要考虑增加主实例的数量。

还有更多...

还有以下信息也很有用:

  • 使用 AWS Shell

  • 使用基于 gossip 的集群

  • 在 S3 存储桶中使用不同的区域

  • 编辑集群配置

  • 删除您的集群

  • 使用亚马逊 EKS 仪表板来提供 EKS 集群

  • 部署 Kubernetes 仪表板

使用 AWS Shell

在这里值得一提的另一个有用工具是aws-shell。它是一个与 AWS CLI 一起工作的集成式 shell。它使用 AWS CLI 配置,并通过自动完成功能提高了生产力。

使用以下命令安装aws-shell并运行它:

$ sudo apt-get install aws-shell && aws-shell

您将看到以下输出:

您可以使用aws-shell与更少的输入来使用 AWS 命令。按F10键退出 shell。

使用基于八卦的集群

在这个示例中,我们创建了一个域(可以从亚马逊购买或其他注册商购买)和一个托管区域,因为 kops 使用 DNS 进行发现。虽然它需要是一个有效的 DNS 名称,但从 kops 1.6.2 开始,DNS 配置变成了可选项。可以轻松地创建一个基于八卦的集群,而不是实际的域或子域。通过使用注册的域名,我们使我们的集群更容易共享,并且可以被其他人用于生产。

如果出于任何原因,您更喜欢基于八卦的集群,您可以跳过托管区域的创建,并使用以k8s.local结尾的集群名称:

$ export KOPS_CLUSTER_NAME=devopscookbook.k8s.local
$ export KOPS_STATE_STORE=s3://devops-cookbook-state-store

设置kops的环境参数是可选的,但强烈建议,因为它可以缩短您的 CLI 命令。

为 S3 存储桶使用不同的地区

为了让 kops 存储集群配置,需要一个专用的 S3 存储桶。

eu-west-1地区的示例如下:

$ aws s3api create-bucket --bucket s3.k8s.containerized.me \
--region eu-west-1 --create-bucket-configuration \
LocationConstraint=eu-west-1

这个 S3 存储桶将成为我们 Kubernetes 集群配置的真相来源。为了简单起见,建议使用us-east-1地区;否则,需要指定适当的LocationConstraint以便在所需的地区创建存储桶。

编辑集群配置

kops create cluster命令,我们用来创建集群配置,实际上并不创建集群本身并启动 EC2 实例;相反,它在我们的 S3 存储桶中创建配置文件。

创建配置文件后,您可以使用kops edit cluster命令对配置进行更改。

您可以使用以下命令分别编辑您的节点实例组:

$ kops edit ig nodes 
$ kops edit ig master-us-east-1a

配置文件是从 S3 存储桶的状态存储位置调用的。如果您喜欢不同的编辑器,您可以例如设置$KUBE_EDITOR=nano来更改它。

删除您的集群

要删除您的集群,请使用以下命令:

$ kops delete cluster --name ${KOPS_CLUSTER_NAME} --yes

这个过程可能需要几分钟,完成后,您将收到确认。

使用亚马逊 EKS 管理控制台配置 EKS 集群

在《在 Amazon EKS 上提供托管的 Kubernetes 集群》教程中,我们使用 eksctl 部署了一个集群。作为替代方案,您也可以使用 AWS 管理控制台 Web 用户界面来部署 EKS 集群。

执行以下步骤来在 Amazon EKS 上启动和运行您的集群:

  1. 打开浏览器并转到 Amazon EKS 控制台console.aws.amazon.com/eks/home#/clusters

  2. 输入集群名称并点击“下一步”按钮。

  3. 在创建集群页面上,选择 Kubernetes 版本、角色名称、至少两个或更多可用区的子网列表和安全组。

  4. 点击创建。

  5. 使用 EKS 创建集群大约需要 20 分钟。在 15-20 分钟后刷新页面并检查其状态。

  6. 使用以下命令更新您的kubectl配置:

$ aws eks --region us-east-1 update-kubeconfig \
--name K8s-DevOps-Cookbook  
  1. 现在,使用kubectl来管理您的集群:
$ kubectl get nodes

现在您的集群已配置好,您可以配置kubectl来管理它。

部署 Kubernetes 仪表板

最后但并非最不重要的是,在 AWS 集群上部署 Kubernetes 仪表板应用程序,您需要按照以下步骤进行操作:

  1. 在我写这个教程的时候,Kubernetes Dashboard v.2.0.0 仍处于测试阶段。由于 v.1.x 版本很快就会过时,我强烈建议您安装最新版本,即 v.2.0.0。新版本带来了许多功能和对 Kubernetes v.1.16 及更高版本的支持。在部署仪表板之前,请确保删除之前的版本(如果有)。通过以下信息框中的链接检查最新发布,并使用最新发布进行部署,类似于以下操作:
$ kubectl delete ns kubernetes-dashboard
# Use the latest version link from https://github.com/kubernetes/dashboard/releases
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.0-beta5/aio/deploy/recommended.yaml

随着 Kubernetes 版本的升级,仪表板应用程序也经常会更新。要使用最新版本,请在发布页面github.com/kubernetes/dashboard/releases上找到 YAML 清单的最新链接。如果您在使用仪表板的最新版本时遇到兼容性问题,您可以始终使用以下命令部署以前的稳定版本:$ kubectl apply -f

https://raw.githubusercontent.com/kubernetes/dashboard/v1.10.1/src/depl

oy/recommended/kubernetes-dashboard.yaml

  1. 默认情况下,kubernetes-dashboard服务使用ClusterIP类型进行公开。如果您想从外部访问它,请使用以下命令编辑服务,并将ClusterIP类型替换为LoadBalancer;否则,请使用端口转发进行访问:
$ kubectl edit svc kubernetes-dashboard -n kubernetes-dashboard
  1. kubernetes-dashboard服务中获取仪表板的外部 IP:
$ kubectl get svc kubernetes-dashboard -n kubernetes-dashboard
NAME                 TYPE          CLUSTER-IP    EXTERNAL-IP PORT(S) AGE
kubernetes-dashboard LoadBalancer 100.66.234.228 myaddress.us-east-1.elb.amazonaws.com 443:30221/TCP 5m46s
  1. 在浏览器中打开外部 IP 链接。在我们的示例中,它是https://myaddress.us-east-1.elb.amazonaws.com

  2. 我们将使用令牌选项来访问 Kubernetes 仪表板。现在,让我们使用以下命令在我们的集群中找到令牌。在这个例子中,该命令返回kubernetes-dashboard-token-bc2w5作为令牌名称:

$ kubectl get secrets -A | grep dashboard-token
kubernetes-dashboard kubernetes-dashboard-token-bc2w5 kubernetes.io/service-account-token 3 17m
  1. 用前一个命令的输出替换密钥名称。从 Secret 的描述中获取令牌详细信息:
$ kubectl describe secrets kubernetes-dashboard-token-bc2w5 -nkubernetes-dashboard
  1. 从前面命令的输出中复制令牌部分,并将其粘贴到 Kubernetes 仪表板中以登录到仪表板:

现在,您可以访问 Kubernetes 仪表板来管理您的集群。

另请参阅

在 Google Cloud Platform 上配置 Kubernetes 集群

本节将逐步指导您在 GCP 上配置 Kubernetes 集群。您将学习如何在不需要配置或管理主节点和 etcd 实例的情况下运行托管的 Kubernetes 集群,使用 GKE。

准备工作

这里提到的所有操作都需要启用计费的 GCP 帐户。如果您还没有,请转到console.cloud.google.com并创建一个帐户。

在 Google Cloud Platform(GCP)上,运行 Kubernetes 有两个主要选项。如果您想完全管理部署并具有特定的强大实例要求,可以考虑使用 Google Compute Engine(GCE)。否则,强烈建议使用托管的 Google Kubernetes Engine(GKE)。

如何做…

本节进一步分为以下小节,以使此过程更易于跟进:

  • 安装命令行工具以配置 GCP 服务

  • 在 GKE 上配置托管的 Kubernetes 集群

  • 连接到 GKE 集群

安装命令行工具以配置 GCP 服务

在这个教程中,我们将安装 Google 云平台的主要 CLI,gcloud,以便我们可以配置 GCP 服务:

  1. 运行以下命令以下载gcloud CLI:
$ curl https://sdk.cloud.google.com | bash
  1. 初始化 SDK 并按照给定的说明进行操作:
$ gcloud init
  1. 在初始化期间,当询问时,请选择您有权限的现有项目或创建一个新项目。

  2. 为项目启用 Compute Engine API:

$ gcloud services enable compute.googleapis.com
Operation "operations/acf.07e3e23a-77a0-4fb3-8d30-ef20adb2986a" finished successfully.
  1. 设置默认区域:
$ gcloud config set compute/zone us-central1-a
  1. 确保您可以从命令行启动 GCE 实例:
$ gcloud compute instances create "devops-cookbook" \
--zone "us-central1-a" --machine-type "f1-micro"
  1. 删除测试 VM:
$ gcloud compute instances delete "devops-cookbook"

如果所有命令都成功,您可以配置您的 GKE 集群。

在 GKE 上配置托管的 Kubernetes 集群

让我们执行以下步骤:

  1. 创建一个集群:
$ gcloud container clusters create k8s-devops-cookbook-1 \
--cluster-version latest --machine-type n1-standard-2 \
--image-type UBUNTU --disk-type pd-standard --disk-size 100 \
--no-enable-basic-auth --metadata disable-legacy-endpoints=true \
--scopes compute-rw,storage-ro,service-management,service-control,logging-write,monitoring \
--num-nodes "3" --enable-stackdriver-kubernetes \ --no-enable-ip-alias --enable-autoscaling --min-nodes 1 \
--max-nodes 5 --enable-network-policy \
--addons HorizontalPodAutoscaling,HttpLoadBalancing \
--enable-autoupgrade --enable-autorepair --maintenance-window "10:00"

集群创建需要 5 分钟或更长时间才能完成。

连接到 Google Kubernetes Engine(GKE)集群

要访问您的 GKE 集群,您需要按照以下步骤进行操作:

  1. 配置kubectl以访问您的k8s-devops-cookbook-1集群:
$ gcloud container clusters get-credentials k8s-devops-cookbook-1
  1. 验证您的 Kubernetes 集群:
$ kubectl get nodes

现在,您有一个运行中的三节点 GKE 集群。

工作原理...

这个教程向您展示了如何使用一些默认参数快速配置 GKE 集群。

步骤 1 中,我们使用了一些默认参数创建了一个集群。虽然所有参数都非常重要,但我想在这里解释其中一些。

--cluster-version 设置要用于主节点和节点的 Kubernetes 版本。只有在想要使用与默认值不同的版本时才使用它。您可以使用 gcloud container get-server-config 命令获取可用版本信息。

我们使用 --machine-type 参数设置了实例类型。如果没有设置,默认值是 n1-standard-1。您可以使用 gcloud compute machine-types list 命令获取预定义类型的列表。

默认镜像类型是 COS,但我个人偏好 Ubuntu,所以我使用 --image-type UBUNTU 来将 OS 镜像设置为 UBUNTU。如果没有设置,服务器会选择默认镜像类型,即 COS。您可以使用 gcloud container get-server-config 命令获取可用镜像类型的列表。

GKE 提供了高级集群管理功能,并配备了节点实例的自动扩展、自动升级和自动修复功能,以维护节点的可用性。--enable-autoupgrade 启用了 GKE 的自动升级功能,用于集群节点,--enable-autorepair 启用了自动修复功能,该功能在使用 --maintenance-window 参数定义的时间开始。这里设置的时间是 UTC 时区,并且必须以 HH:MM 格式。

还有更多...

以下是在上一节描述的教程之外可以采用的一些替代方法:

  • 使用 Google 云 Shell

  • 使用自定义网络配置部署

  • 删除您的集群

  • 查看工作负载仪表板

使用 Google 云 Shell

作为 Linux 工作站的替代方案,您可以在浏览器上获得 CLI 接口,以管理您的云实例。

转到 cloud.google.com/shell/ 获取 Google 云 Shell。

使用自定义网络配置部署

以下步骤演示了如何使用自定义网络配置来配置您的集群:

  1. 创建 VPC 网络:
$ gcloud compute networks create k8s-devops-cookbook \
--subnet-mode custom
  1. 在您的 VPC 网络中创建一个子网。在我们的示例中,这是 10.240.0.0/16
$ gcloud compute networks subnets create kubernetes \
--network k8s-devops-cookbook --range 10.240.0.0/16
  1. 创建防火墙规则以允许内部流量:
$ gcloud compute firewall-rules create k8s-devops-cookbook-allow-int \
--allow tcp,udp,icmp --network k8s-devops-cookbook \
--source-ranges 10.240.0.0/16,10.200.0.0/16
  1. 创建防火墙规则以允许外部 SSH、ICMP 和 HTTPS 流量:
$ gcloud compute firewall-rules create k8s-devops-cookbook-allow-ext \
--allow tcp:22,tcp:6443,icmp --network k8s-devops-cookbook \
--source-ranges 0.0.0.0/0
  1. 验证规则:
$ gcloud compute firewall-rules list
 NAME                          NETWORK             DIRECTION PRIORITY ALLOW  DENY    DISABLED
 ...
 k8s-devops-cookbook-allow-ext k8s-devops-cookbook INGRESS   1000     tcp:22,tcp:6443,icmp      False
 k8s-devops-cookbook-allow-int k8s-devops-cookbook INGRESS   1000     tcp,udp,icmp              False
  1. --network k8s-devops-cookbook--subnetwork kubernetes参数添加到您的container clusters create命令并运行它。

删除您的集群

要删除您的k8s-devops-cookbook-1集群,请使用以下命令:

$ gcloud container clusters delete k8s-devops-cookbook-1

这个过程可能需要几分钟,完成后,您将收到确认消息。

查看工作负载仪表板

在 GCP 上,您可以使用内置的工作负载仪表板并通过 Google Marketplace 部署容器化应用程序,而不是使用 Kubernetes 仪表板应用程序。按照以下步骤:

  1. 要从 GCP 仪表板访问工作负载仪表板,请选择您的 GKE 集群并单击工作负载。

  2. 单击“显示系统工作负载”以查看已部署在kube-system命名空间中的现有组件和容器。

另请参阅

在 Microsoft Azure 上配置 Kubernetes 集群

在本节中,我们将使用 Microsoft Azure Kubernetes ServiceAKS)创建 Microsoft Azure 云上的 Kubernetes 集群。

准备就绪

这里提到的所有操作都需要 Microsoft Azure 订阅。如果您还没有,请转到portal.azure.com并创建一个免费帐户。

如何做…

本节将带您了解如何在 Microsoft Azure 上配置 Kubernetes 集群。本节进一步分为以下子节,以使此过程更容易:

  • 安装命令行工具以配置 Azure 服务

  • 在 AKS 上配置托管的 Kubernetes 集群

  • 连接到 AKS 集群

安装命令行工具以配置 Azure 服务

在这个配方中,我们将安装名为azkubectl的 Azure CLI 工具。

让我们执行以下步骤:

  1. 安装必要的依赖项:
$ sudo apt-get update && sudo apt-get install -y libssl-dev \
libffi-dev python-dev build-essential
  1. 下载并安装az CLI 工具:
$ curl -L https://aka.ms/InstallAzureCli | bash
  1. 验证您正在使用的az版本:
$ az --version
  1. 如果尚未安装,请安装kubectl
$ az aks install-cli

如果所有命令都成功,您可以开始配置您的 AKS 集群。

在 AKS 上配置托管的 Kubernetes 集群

让我们执行以下步骤:

  1. 登录到您的帐户:
$ az login
  1. 在您喜欢的区域创建一个名为k8sdevopscookbook的资源组:
$ az group create --name k8sdevopscookbook --location eastus
  1. 创建服务主体并记下您的appIdpassword以进行下一步:
$ az ad sp create-for-rbac --skip-assignment
{
 "appId": "12345678-1234-1234-1234-123456789012",
 "displayName": "azure-cli-2019-05-11-20-43-47",
 "name": "http://azure-cli-2019-05-11-20-43-47",
 "password": "12345678-1234-1234-1234-123456789012",
 "tenant": "12345678-1234-1234-1234-123456789012"
  1. 创建一个集群。用前面命令的输出替换appIdpassword
$ az aks create  --resource-group k8sdevopscookbook \  --name AKSCluster \ --kubernetes-version 1.15.4 \
 --node-vm-size Standard_DS2_v2 \ --node-count 3 \ --service-principal <appId> \ --client-secret <password> \ --generate-ssh-keys

集群创建大约需要 5 分钟。当成功完成时,您将看到"provisioningState": Succeeded"

连接到 AKS 集群

让我们执行以下步骤:

  1. 收集一些凭据并配置kubectl以便您可以使用它们:
$ az aks get-credentials --resource-group k8sdevopscookbook \
--name AKSCluster
  1. 验证您的 Kubernetes 集群:
$ kubectl get nodes

现在,您有一个运行中的三节点 GKE 集群。

它是如何工作的…

本教程向您展示了如何使用一些常见选项快速创建 AKS 集群。

步骤 3中,命令以az aks create开头,后面跟着-g--resource-group,这样您就可以选择资源组的名称。您可以使用az configure --defaults group=k8sdevopscookbook来配置默认组,并在下次跳过这个参数。

我们使用--name AKSCluster参数来设置托管集群的名称为AKSCluster。其余的参数是可选的;--kubernetes-version-k设置要用于集群的 Kubernetes 版本。您可以使用az aks get-versions --location eastus --output table命令来获取可用选项的列表。

我们使用--node-vm-size来设置 Kubernetes 工作节点的实例类型。如果没有设置,默认值为Standard_DS2_v2

接下来,我们使用--node-count来设置 Kubernetes 工作节点的数量。如果没有设置,默认值为3。可以使用az aks scale命令来更改这个值。

最后,使用--generate-ssh-keys参数来自动生成 SSH 公钥和私钥文件,这些文件存储在~/.ssh目录中。

还有更多…

尽管 Kubernetes 现在支持基于 Windows 的容器,但要能够运行 Windows Server 容器,您需要运行基于 Windows Server 的节点。AKS 节点目前在 Linux OS 上运行,不支持基于 Windows Server 的节点。但是,您可以使用 Virtual Kubelet 在容器实例上调度 Windows 容器,并将其作为集群的一部分进行管理。在本节中,我们将看一下以下内容:

  • 删除您的集群

  • 查看 Kubernetes 仪表板

删除您的集群

要删除您的集群,请使用以下命令:

$ az aks delete --resource-group k8sdevopscookbook --name AKSCluster

这个过程将需要几分钟,完成后,您将收到确认信息。

查看 Kubernetes 仪表板

要查看 Kubernetes 仪表板,您需要按照以下步骤进行:

  1. 要启动 Kubernetes 仪表板,请使用以下命令:
$ az aks browse --resource-group k8sdevopscookbook --name AKSCluster
  1. 如果您的集群启用了 RBAC,则创建Clusterrolebinding
$ kubectl create clusterrolebinding kubernetes-dashboard \
--clusterrole=cluster-admin \
--serviceaccount=kube-system:kubernetes-dashboard
  1. 打开浏览器窗口,转到代理运行的地址。在我们的示例中,这是http://127.0.0.1:8001/

另请参阅

在阿里巴巴云上配置 Kubernetes 集群

阿里巴巴云(也称为阿里云)提供了多个模板,您可以使用这些模板来提供 Kubernetes 环境。有四个主要的服务类别:

  • Kubernetes:在单个区域的 ECS 实例上部署的具有三个主节点的自管理 Kubernetes。工作节点可以是 ECS 或裸金属。

  • 托管的 Kubernetes:类似于 Kubernetes 集群选项,只是主节点由阿里巴巴云管理。

  • 多 AZ Kubernetes:类似于 Kubernetes 集群选项,只是自管理的主节点和工作节点可以部署在不同的可用区。

  • 无服务器 Kubernetes:一种 Kubernetes 服务提供,您可以在其中部署容器应用程序,而无需管理和维护集群实例:

在本节中,我们将介绍如何在不需要配置或管理主节点和 etcd 实例的情况下,提供一个高可用的多 AZ Kubernetes 集群。

做好准备

这里提到的所有操作都需要阿里巴巴云账户(也称为阿里云)和 AccessKey。如果您还没有,请转到account.alibabacloud.com并创建一个账户。

如何做到…

本节将带您了解如何在阿里巴巴云上配置 Kubernetes 集群。本节进一步分为以下子节,以使此过程更加简单:

  • 安装命令行工具以配置阿里巴巴云服务

  • 在阿里巴巴云上提供一个高可用的 Kubernetes 集群

  • 连接到阿里巴巴容器服务集群

安装命令行工具以配置阿里巴巴云服务

对于此示例,我们将使用阿里巴巴云控制台,并从仪表板生成 API 请求参数,该参数将与 CLI 一起使用。您还需要安装阿里巴巴云 CLI aliyunkubectl

  1. 运行以下命令以下载aliyun工具:
$ curl -O https://aliyuncli.alicdn.com/aliyun-cli-linux-3.0.15-amd64.tgz

您可以在此处找到最新版本的链接:github.com/aliyun/aliyun-cli

  1. 提取文件并安装它们:
$ tar –zxvf aliyun-cli*.tgz && sudo mv aliyun /usr/local/bin/.
  1. 验证您正在使用的aliyun CLI 版本:
$ aliyun --version
  1. 如果您还没有创建 AccessKey,请转到您的帐户中的安全管理并创建一个(usercenter.console.aliyun.com/#/manage/ak)。

  2. 通过输入您的 AccessKey ID、AccessKey Secret 和区域 ID 完成 CLI 配置:

$ aliyun configure
Configuring profile '' in '' authenticate mode...
Access Key Id []: <Your AccessKey ID>
Access Key Secret []: <Your AccessKey Secret>
Default Region Id []: us-west-1
Default Output Format [json]: json (Only support json))
Default Language [zh|en] en: en
Saving profile[] ...Done.
  1. 启用bash/zsh自动完成:
$ aliyun auto-completion
  1. 转到容器服务控制台(cs.console.aliyun.com),为容器服务授予权限访问云资源。在这里,选择AliyunCSDefaultRoleAliyunCSServerlessKuberentesRoleAliyunCSClusterRoleAliyunCSManagedKubernetesRole,然后点击“确认授权策略”。

确保已启用资源编排服务(ROS)和自动伸缩服务,因为它们是部署 Kubernetes 集群所需的。ROS 用于根据您的模板自动提供和配置资源以进行自动部署、操作和维护,而自动伸缩用于根据需求调整计算资源。

在阿里云上部署高可用的 Kubernetes 集群

让我们执行以下步骤:

  1. 打开浏览器窗口,转到阿里云虚拟私有云控制台vpc.console.aliyun.com

  2. 确保选择至少有三个区域的区域(中国大陆的大多数区域都有三个以上的区域),然后点击“创建 VPC”。

  3. 为您的 VPC 指定一个唯一名称并选择一个 IPv4 CIDR 块。在我们的示例中,这是10.0.0.0/8

  4. 为您的第一个 VSwitch(k8s-1)输入一个名称,并选择一个区域(北京 A 区)。

  5. 设置一个 IPv4 CIDR 块。在我们的示例中,我们使用了10.10.0.0./16

  6. 点击“添加”按钮,然后重复步骤 4步骤 5以获取不同的区域。使用以下 CIDR 块信息:

VSwitch 2 VSwitch 3
名称: k8s-2 k8s-3
区域: 北京 B 区 北京 E 区
IPv4 CIDR 块: 10.20.0.0/16 10.30.0.0/16
  1. 点击“确定”创建您的 VPC 和 VSwitches。

  2. 在您的 Web 浏览器上打开阿里云 Web 控制台(cs.console.aliyun.com。)。

  3. 点击“创建 Kubernetes 集群”。

  4. 选择标准托管集群。

  5. 点击“多可用区 Kubernetes”选项卡,为您的集群命名,并选择与创建 VPC 和 VSwitches 时相同的区域。

  6. 如果您选择了相同的区域,VPC 下拉菜单将显示为k8s-devops-cookbook-vpc。现在,选择我们创建的所有三个 VSwitches:

  1. 在每个区域的 Master 节点配置中设置实例类型。

  2. 在每个区域的 Worker 节点配置中设置实例类型,并将每个区域的节点数设置为3。否则,请使用默认设置。

  3. 选择 Kubernetes 版本(1.12.6-aliyun.1,在撰写时)。

  4. 从下拉菜单中选择“密钥对名称”,或者点击“创建新密钥对”来创建一个:

  1. 阿里巴巴提供两种 CNI 选项:Flannel 和 Terway。区别在本食谱的更多内容…部分有解释。使用Flannel保留默认网络选项。默认参数支持集群中最多 512 台服务器。

  2. 监控和日志记录将在第八章 Kubernetes 上的可观察性和监控和第十章 Kubernetes 上的日志记录中进行解释。因此,此步骤是可选的。勾选“在您的 ECS 上安装云监控插件”和“使用日志服务”选项以启用监控和日志记录。

  3. 现在,点击“创建”以配置您的多可用区 Kubernetes 集群。此步骤可能需要 15-20 分钟才能完成。

连接到阿里巴巴容器服务集群

要访问阿里巴巴云上的集群,您需要按照以下步骤进行:

  1. 要获取集群的凭据,请转到“集群”菜单,然后单击要访问的“集群名称”:

  1. 复制 KubeConfig 选项卡中显示的内容到您本地机器的$HOME/.kube/config文件中:

  1. 验证您的 Kubernetes 集群:
$ kubectl get nodes

作为替代方案,请参阅查看 Kubernetes 仪表板部分下的说明,以管理您的集群。

工作原理…

本食谱向您展示了如何使用集群模板在阿里巴巴云上配置托管的 Kubernetes 集群。

在容器服务菜单下,阿里巴巴云提供了一些 Kubernetes 集群,其中提供了七个集群模板。我们在这里使用了标准托管集群。此选项只允许您管理工作节点,并为您节省了主节点的资源和管理成本:

默认情况下,帐户支持最多 20 个集群和每个集群 40 个节点。您可以通过提交支持工单来请求配额增加。

还有更多...

作为使用阿里巴巴云控制台的替代方法,您可以通过aliyuncli使用 REST API 调用来创建 ECS 实例和您的集群。按照以下步骤操作:

  1. 在阿里巴巴云控制台上配置了集群选项后,点击“创建”按钮下方的“生成 API 请求参数”以生成用于aliyun CLI 的 POST 请求主体内容。

  2. 将内容保存到文件中。在我们的案例中,这个文件被称为cscreate.json

  3. 有关本节中列出的其他参数的解释,请参阅www.alibabacloud.com/help/doc-detail/87525.htm中的创建 Kubernetes部分。

  4. 使用以下命令创建您的集群:

$ aliyun cs POST /clusters --header "Content-Type=application/json" \
--body "$(cat cscreate.json)"

阿里巴巴云容器服务为其 Kubernetes 集群提供了两种网络插件选项:Terway 和 Flannel。

Flannel 基于社区 Flannel CNI 插件。Flannel 是一个非常常见和稳定的网络插件,提供基本的网络功能。除了不支持 Kubernetes NetworkPolicy 之外,它是大多数用例的推荐选项。Terway 是阿里巴巴云 CS 开发的网络插件。它与 Flannel 完全兼容。Terway 可以根据 Kubernetes NetworkPolicy 定义容器之间的访问策略。Terway 还支持对容器进行带宽限制。

使用 Rancher 配置和管理 Kubernetes 集群

Rancher 是一个容器管理平台,具有使用Rancher Kubernetes EngineRKE)或基于云的 Kubernetes 服务(如 GKE、AKS 和 EKS)创建 Kubernetes 集群的灵活性,这些我们在前面的章节中讨论过。

在本节中,我们将介绍配置 Rancher 的方法,以便部署和管理 Kubernetes 服务。

准备工作

Rancher 可以安装在 Ubuntu、RHEL/CentOS、RancherOS 甚至 Windows Server 上。您可以在高可用配置或单节点中启动 Rancher 服务器。请参考另请参阅...部分,获取替代安装说明的链接。在本教程中,我们将在单个节点上运行 Rancher。

如何做...

本节将带您了解如何使用 Rancher 配置和管理 Kubernetes 集群。为此,本节进一步分为以下子节,以使此过程更加简单:

  • 安装 Rancher 服务器

  • 部署 Kubernetes 集群

  • 导入现有集群

  • 启用集群和节点提供程序

安装 Rancher 服务器

按照以下步骤安装 Rancher 服务器:

  1. 安装支持的 Docker 版本。如果您已经安装了 Docker,则可以跳过此步骤:
$ sudo apt-get -y install apt-transport-https ca-certificates curl \
software-properties-common
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
$ sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
$ sudo apt-get -y install docker-ce && docker --version
  1. 将用户添加到 Docker 组:
$ sudo usermod -a -G docker $USER
  1. 要安装 Rancher 服务器,请运行以下命令:
docker run -d --restart=unless-stopped \
-p 80:80 -p 443:443 rancher/rancher:latest
  1. 打开浏览器窗口,转到https://localhost。如有必要,请将localhost替换为您主机的 IP。

  2. 设置新密码,然后单击继续。

  3. 设置 Rancher 服务器的公共 IP 地址,并单击保存 URL。这个 IP 地址需要从您的集群外部访问。

部署 Kubernetes 集群

要部署一个新的集群,您需要按照以下步骤进行:

  1. 单击添加集群。

  2. 选择提供程序。在我们的示例中,我们将使用 GKE。其他提供程序的一些设置可能略有不同:

  1. 输入集群名称。

如果您有我们之前保存的 GCP 服务帐户 JSON 文件,请跳至步骤 10

  1. 从 GCP 导航菜单中,转到 IAM,然后单击服务帐户链接。

  2. 单击创建服务帐户。

  3. 输入服务帐户名称,然后单击创建。

  4. 添加所需的最低权限;即,Compute Viewer、Viewer、Kubernetes Engine Admin 和 Service Account User,然后单击继续。

  5. 单击创建密钥。使用 JSON 作为密钥类型,以保存您的服务帐户。

  6. 在 Rancher UI 上,单击从文件读取,并加载您之前保存的服务帐户 JSON 文件。

  7. 根据需要自定义集群选项;否则,使用默认设置,然后单击创建以部署您的 Kubernetes 集群:

您的集群将被列出,并立即可以在 Rancher 仪表板上进行管理。

导入现有集群

要导入现有集群,您需要按照以下步骤进行:

  1. 单击添加集群

  2. 单击导入:

  1. 输入集群名称,然后单击“创建”。

  2. 按照显示的说明,复制并运行显示在屏幕上的kubectl命令到现有的 Kubernetes 集群。如果您使用的是不受信任/自签名的 SSL 证书,则此命令看起来类似于以下内容:

  1. 点击“完成”后,您的集群将被列出,并且可以立即在 Rancher 仪表板上进行管理:

最后一步可能需要一分钟的时间来完成。最终,当准备就绪时,您的集群状态将从待定变为活动。

启用集群和节点提供者

为了支持多个提供者,Rancher 使用集群和节点驱动程序。如果您在列表中找不到您的提供者,则很可能是未启用。

要启用其他提供者,请按照以下步骤操作:

  1. 从“工具”中,单击“驱动程序”。

  2. 在列表中找到您的提供者,然后单击“激活”:

从同一页,您还可以停用您不打算使用的提供者。

它是如何工作的...

这个教程向您展示了如何快速运行 Rancher 服务器来管理您的 Kubernetes 集群。

步骤 1中,我们使用了默认的自签名证书方法进行单节点安装。出于安全目的,与集群交互需要 SSL。因此,需要证书。

如果您更喜欢使用由认可的 CA 签名的自己的证书,可以使用以下命令,并提供路径以将它们挂载到容器中,通过用您的签名证书替换FULLCHAIN.pemPRIVATEKEY.pem文件:

$ docker run -d --restart=unless-stopped \
 -p 80:80 -p 443:443 \
 -v /<CERTDIRECTORY>/<FULLCHAIN.pem>:/etc/rancher/ssl/cert.pem \
 -v /<CERTDIRECTORY>/<PRIVATEKEY.pem>:/etc/rancher/ssl/key.pem \
 rancher/rancher:latest --no-cacerts

使用认可的证书将消除登录页面上的安全警告。

还有更多...

还有以下信息也很有用:

  • 绑定挂载主机卷以保留数据

  • 保持用户卷持久

  • 在主机卷上保持数据持久

  • 在相同的 Kubernetes 节点上运行 Rancher

绑定挂载主机卷以保留数据

在使用单节点安装时,持久数据保存在容器中的/var/lib/rancher路径上。

要在主机上保留数据,可以使用以下命令将主机卷绑定到位置:

$ docker run -d --restart=unless-stopped \
 -p 80:80 -p 443:443 \
 -v /opt/rancher:/var/lib/rancher \
 -v /var/log/rancher/auditlog:/var/log/auditlog \
 rancher/rancher:latest 

与卷相比,绑定挂载具有有限的功能。当使用绑定挂载启动 Rancher 时,主机上的目录将被挂载到容器中的指定目录。

保持用户卷持久

在使用 RancherOS 时,只有特定目录才能使user-volumes参数定义的数据持久。

要添加额外的持久user-volumes,例如,添加/var/openebs目录:

$ ros config set rancher.services.user-volumes.volumes \[/home:/home,/opt:/opt,/var/lib/kubelet:/var/lib/kubelet,/etc/kubernetes:/etc/kubernetes,/var/openebs]
$ system-docker rm all-volumes
$ reboot

重新启动后,指定目录中的数据将是持久的。

在相同的 Kubernetes 节点上运行 Rancher

要将运行 Rancher 服务器的节点添加到集群中,请将默认端口-p 80:80 -p 443:443替换为以下内容,并使用以下命令启动 Rancher:

$ docker run -d --restart=unless-stopped \
 -p 8080:80 -p 8443:443 rancher/rancher:latest

在这种情况下,Rancher 服务器将通过https://localhost:8443而不是标准的443端口访问。

另请参阅

配置 Red Hat OpenShift

在这个教程中,我们将学习如何在 AWS、裸金属或 VMware vSphere VM 上部署 Red Hat OpenShift。

部署 OpenShift 集群教程中的步骤可以应用于在虚拟化环境上运行的 VM 或裸金属服务器上部署 OpenShift。

准备就绪

这里提到的所有操作都需要具有活动 Red Hat Enterprise Linux 和 OpenShift Container Platform 订阅的 Red Hat 帐户。如果您还没有,请转到access.redhat.com并创建一个帐户。

在部署 VM 时,请确保计划在 Kubernetes 节点上创建的区域实际上位于单独的 hypervisor 节点上。

对于这个教程,我们需要至少有六个节点,上面安装了 Red Hat Enterprise CoreOS。这些节点可以是裸金属、VM 或裸金属和 VM 的混合体。

如何做…

本节将带您了解如何配置 Red Hat OpenShift。为此,本节进一步分为以下子节,以使此过程更加简单:

  • 下载 OpenShift 二进制文件

  • 部署 OpenShift 集群

  • 连接到 OpenShift 集群

下载 OpenShift 二进制文件

确保您在第一个主节点的终端上,并且具有 root 访问权限的帐户,或者正在以超级用户身份运行。按照以下步骤操作:

  1. 转到 cloud.redhat.com/openshift/install 并下载最新的 OpenShift Installer

  1. 在您的工作站上提取安装程序文件:
$ tar -xzf openshift-install-linux-*.tar.gz

上述命令将在同一文件夹中创建一个名为 openshift-install 的文件。

配置 OpenShift 集群

在此教程中,我们将使用 AWS 平台部署 OpenShift:

  1. 要启动您的 OpenShift 集群,请使用以下命令:
$ ./openshift-install create cluster
  1. 选择 aws 作为您的平台,并输入您的 AWS Access Key IDSecret Access Key

  2. 选择您的地区。在我们的示例中,这是 us-east-1

  3. 选择一个基础域。在我们的示例中,这是 k8s.containerized.me

  4. 输入一个集群名称。

  5. 从 Red Hat 网站复制 Pull Secret,并将其粘贴到命令行中:

  1. 安装完成后,您将看到控制台 URL 和访问新集群的凭据,类似于以下内容:
INFO Install complete!
INFO To access the cluster as the system:admin user when using 'oc', run 'export KUBECONFIG=/home/ubuntu/auth/kubeconfig'
INFO Access the OpenShift web-console here: https://console-openshift-console.apps.os.k8s.containerized.me
INFO Login to the console with user: kubeadmin, password: ABCDE-ABCDE-ABCDE-ABCDE
  1. 转到 Red Hat 网站,单击 Download Command-Line Tools 链接以下载 openshift-client

  2. 在您的工作站上提取 openshift-client 文件:

$ tar -xzf openshift-client-linux-*.tar.gz && sudo mv oc /usr/local/bin

上述命令将在同一文件夹中创建 kubectloc 文件,并将 oc 二进制文件移动到 PATH。

连接到 OpenShift 集群

要连接到 OpenShift 集群,请按照以下步骤操作:

  1. 要访问您的 OpenShift 集群,请使用以下命令:
$ export KUBECONFIG=~/auth/kubeconfig
  1. 替换 passwordcluster address 后登录到您的 OpenShift 集群:
$ oc login -u kubeadmin -p ABCDE-ABCDE-ABCDE-ABCDE \
https://api.openshift.k8s.containerized.me:6443 \
--insecure-skip-tls-verify=true

如果您更喜欢使用 Web 控制台,可以在 配置 OpenShift 集群 教程中的步骤 7 中打开 Web 控制台 URL 地址。

工作原理…

此教程向您展示了如何在 AWS 上快速部署 OpenShift 集群。

步骤 1 中,我们使用安装程序提供的基础设施的默认配置创建了一个集群。

安装程序询问了一系列关于用户信息的问题,并且大多数其他配置选项都使用了默认值。如果需要,这些默认值可以通过 install-config.yaml 文件进行编辑和自定义。

要查看部署时使用的默认值,让我们创建一个 install-config.yaml 文件并查看它:

$ ./openshift-install create install-config && cat install-config.yaml

如您从以下输出中所见,文件的默认配置创建了一个由三个主节点和三个工作节点组成的集群:

apiVersion: v1
baseDomain: k8s.containerized.me
compute:
- hyperthreading: Enabled
 name: worker
 platform: {}
 replicas: 3
controlPlane:
 hyperthreading: Enabled
 name: master
 platform: {}
 replicas: 3
...

根据需要编辑install-config.yaml。下次创建集群时,将使用新参数。

还有更多...

还有以下信息也是有用的:

  • 删除您的集群

删除您的集群

要删除您的集群,请使用以下命令:

$ ./openshift-install destroy cluster

此过程将需要几分钟时间,完成后将收到确认消息。

另请参阅

使用 Ansible 配置 Kubernetes 集群

强大的 IT 自动化引擎,如 Ansible,可用于自动化几乎任何日常 IT 任务,包括在裸机集群上部署 Kubernetes 集群。在本节中,我们将学习如何使用 Ansible playbook 部署一个简单的 Kubernetes 集群。

准备工作

在本食谱中,我们将使用一个 Ansible playbook。这些食谱中将使用的示例可通过k8sdevopscookbook GitHub 存储库访问。

在执行本节食谱中的命令之前,请使用以下命令克隆 Ansible playbook 示例:

$ git clone https://github.com/k8sdevopscookbook/src.git

您将在k8sdevopscookbook/src目录下找到示例存储。

如何做…

本节将带您了解如何使用 Ansible 配置 Kubernetes 集群。为此,本节进一步分为以下子节,以使此过程更加简单:

  • 安装 Ansible

  • 使用 Ansible playbook 提供 Kubernetes 集群

  • 连接到 Kubernetes 集群

安装 Ansible

为了使用 Ansible playbook 提供 Kubernetes 集群,请按照以下步骤进行:

  1. 要在 Linux 工作站上安装 Ansible,首先需要添加必要的存储库:
$ sudo apt-get install software-properties-common
$ sudo apt-add-repository --yes --update ppa:ansible/ansible
  1. 使用以下命令安装 Ansible:
$ sudo apt-get update && *sudo apt-get install ansible -y*
  1. 验证其版本并确保已安装 Ansible:
$ ansible --version

在撰写本食谱时,最新的 Ansible 版本是2.9.4

使用 Ansible playbook 提供 Kubernetes 集群

为了使用 Ansible playbook 提供 Kubernetes 集群,请按照以下步骤进行:

  1. 编辑hosts.ini文件,并用您想要配置 Kubernetes 的节点 IP 地址替换主节点和节点 IP 地址:
$ cd src/chapter1/ansible/ && vim hosts.ini
  1. hosts.ini文件应如下所示:
[master]
192.168.1.10
[node]
192.168.1.[11:13]
[kube-cluster:children]
master
node
  1. 编辑groups_vars/all.yml文件以自定义您的配置。以下是如何执行此操作的示例:
kube_version: v1.14.0
token: b0f7b8.8d1767876297d85c
init_opts: ""
kubeadm_opts: ""
service_cidr: "10.96.0.0/12"
pod_network_cidr: "10.244.0.0/16"
calico_etcd_service: "10.96.232.136"
network: calico
network_interface: ""
enable_dashboard: yes
insecure_registries: []
systemd_dir: /lib/systemd/system
system_env_dir: /etc/sysconfig
network_dir: /etc/kubernetes/network
kubeadmin_config: /etc/kubernetes/admin.conf
kube_addon_dir: /etc/kubernetes/addon
  1. 运行site.yaml playbook 来创建您的集群:
$ ansible-playbook site.yaml

您的集群将根据您的配置部署。

连接到 Kubernetes 集群

要访问您的 Kubernetes 集群,您需要按照以下步骤进行操作:

  1. master1节点复制配置文件:
$ scp root@master:/etc/kubernetes/admin.conf ~/.kube/config
  1. 现在,使用kubectl来管理您的集群。

另请参阅

故障排除安装问题

Kubernetes 由许多松散耦合的组件和 API 组成。基于环境的不同,您可能会遇到需要更多关注才能使一切正常运行的问题。幸运的是,Kubernetes 提供了许多指出问题的方法。

在本节中,我们将学习如何获取集群信息,以便排除潜在问题。

如何执行…

按照以下步骤收集集群信息,以便排除潜在问题:

  1. 创建名为cluster-state的集群状态文件转储:
$ kubectl cluster-info dump --all-namespaces \
 --output-directory=$PWD/cluster-state
  1. 显示主节点和服务地址:
$ kubectl cluster-info
Kubernetes master is running at https://172.23.1.110:6443
Heapster is running at https://172.23.1.110:6443/api/v1/namespaces/kube-system/services/heapster/proxy
KubeDNS is running at https://172.23.1.110:6443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy
  1. 显示us-west-2.compute.internal节点的资源使用情况:
$ kubectl top node us-west-2.compute.internal
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
us-west-2.compute.internal 42m 2% 1690Mi 43%
  1. us-west-2.compute.internal节点标记为不可调度:
$ kubectl cordon us-west-2.compute.internal
  1. 安全地从us-west-2.compute.internal节点中撤出所有的 pod 以进行维护:
$ kubectl drain us-west-2.compute.internal
  1. 在维护后,将us-west-2.compute.internal节点标记为可调度:
$ kubectl uncordon us-west-2.compute.internal

工作原理…

这个教程向您展示了如何快速排除常见的 Kubernetes 集群问题。

在第 1 步中,当使用kubectl cluster-info命令执行--output-directory参数时,Kubernetes 将集群状态的内容转储到指定文件夹下。您可以使用以下命令查看完整列表:

$ tree ./cluster-state
./cluster-state
├── default
│ ├── daemonsets.json
│ ├── deployments.json
│ ├── events.json
│ ├── pods.json
│....

在第 4 步中,我们使用kubectl cordon命令将节点标记为不可用。Kubernetes 有一个调度应用程序的概念,这意味着它会将 pod 分配给可用的节点。如果您事先知道集群中的实例将被终止或更新,您不希望在特定节点上安排新的 pod。 Cordoning 意味着使用node.Spec.Unschedulable=true对节点进行修补。当节点设置为不可用时,不会在该节点上安排新的 pod。

在第 5 步中,我们使用kubectl drain命令驱逐现有的 pod,因为仅使用 cordoning 不会对当前已安排的 pod 产生影响。驱逐 API 会考虑中断预算。如果所有者设置了中断预算,中断预算将限制复制应用程序中同时处于自愿中断状态的 pod 数量。如果不支持或设置了中断预算,驱逐 API 将在宽限期后简单地删除节点上的 pod。

还有更多...

以下信息也很有用:

  • 设置日志级别

设置日志级别

在使用kubectl命令时,您可以使用--v标志设置输出详细程度,后面跟着日志级别的整数,该整数介于 0 和 9 之间。 Kubernetes 文档中描述了一般的 Kubernetes 日志约定和相关的日志级别:kubernetes.io/docs/reference/kubectl/cheatsheet/#kubectl-output-verbosity-and-debugging

将输出详细信息以特定格式获取是有用的,方法是在命令中添加以下参数之一:

  • -o=wide 用于获取资源的附加信息。示例如下:
$ kubectl get nodes -owide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE KERNEL-VERSION CONTAINER-RUNTIME
ip-192-168-41-120.us-west-2.compute.internal Ready <none> 84m v1.13.8-eks-cd3eb0 192.168.41.120 34.210.108.135 Amazon Linux 2 4.14.133-113.112.amzn2.x86_64 docker://18.6.1
ip-192-168-6-128.us-west-2.compute.internal Ready <none> 84m v1.13.8-eks-cd3eb0 192.168.6.128 18.236.119.52 Amazon Linux 2 4.14.133-113.112.amzn2.x86_64 docker://18.6.1
  • -o=yaml 用于以 YAML 格式返回输出。示例如下:
$ kubectl get pod nginx-deployment-5c689d88bb-qtvsx -oyaml
apiVersion: v1
kind: Pod
metadata:
 annotations:
 kubernetes.io/limit-ranger: 'LimitRanger plugin set: cpu request for container
 nginx'
 creationTimestamp: 2019-09-25T04:54:20Z
 generateName: nginx-deployment-5c689d88bb-
 labels:
 app: nginx
 pod-template-hash: 5c689d88bb
 name: nginx-deployment-5c689d88bb-qtvsx
 namespace: default
...

正如您所看到的,-o=yaml参数的输出也可以用来从现有资源创建清单文件。

另请参阅

第二章:在 Kubernetes 上操作应用程序

在本章中,我们将讨论可用于在 Kubernetes 上部署云原生应用程序的供应工具。您将学习如何使用最流行的生命周期管理选项在 Kubernetes 上部署 DevOps 工具和 CI/CD(持续集成/持续交付或持续部署)基础设施。您将掌握执行第 1 天和第 2 天的操作的技能,例如安装、升级和版本控制部署,排除新应用程序,并在不再需要时删除部署。

在本章中,我们将涵盖以下主题:

  • 使用 YAML 文件部署工作负载

  • 使用自定义部署工作负载

  • 使用 Helm 图表部署工作负载

  • 使用 Kubernetes 运算符部署和操作应用程序

  • 部署和管理 Jenkins X 的生命周期

  • 部署和管理 GitLab 的生命周期

技术要求

本节中的配方假设您已部署了一个功能齐全的 Kubernetes 集群,遵循第一章中描述的推荐方法之一。

Kubernetes 操作工具 kubectl 将用于本节中其余的配方,因为它是针对 Kubernetes 集群运行命令的主要命令行界面。如果您使用 Red Hat OpenShift 集群,可以将 kubectl 替换为 oc,并且所有命令预计将类似地运行。

使用 YAML 文件部署工作负载

在本节中,我们将创建在 Kubernetes 中部署应用程序所需的资源配置。您将学习如何创建 Kubernetes 清单,部署工作负载,并使用 YAML 文件推出新版本。

准备工作

在开始之前,请克隆本章中使用的示例存储库:

$ git clone https://github.com/k8sdevopscookbook/src.git

确保您已准备好一个 Kubernetes 集群,并配置 kubectl 以管理集群资源。

操作步骤

本节进一步分为以下子节,以便简化流程:

  • 创建部署

  • 验证部署

  • 编辑部署

  • 回滚部署

  • 删除部署

创建部署

这个教程将带您按照说明创建一个使用清单文件的部署,该文件保持一组 pod 运行。部署用于声明应该运行多少个 pod 的副本。部署可以进行扩展和缩减;我们将在第七章中更多地了解这个主题,扩展和升级 应用程序

让我们执行以下步骤:

  1. 切换到src/chapter2/yaml/目录,这里是本教程的示例文件所在的位置:
$ cd src/chapter2/yaml/
  1. 查看部署清单:
$ cat deployment-nginx.yaml
apiVersion: apps/v1
kind: deployment
metadata:
 name: nginx-deployment
 labels:
 app: nginx
spec:
 replicas: 2
 selector:
 matchLabels:
 app: nginx
# actual file is longer, shortened to show structure of the file only

YAML 是对空格敏感的。查看示例文件以了解文件的结构。您会发现 YAML 文件不使用制表符,而是使用空格字符。

如果有疑问,请使用 YAML 文件的 linter。

  1. 通过应用 YAML 清单创建一个部署:
$ kubectl apply -f deployment-nginx.yaml

在运行了上述命令之后,YAML 清单中提到的容器镜像将从容器注册表中拉取,并且应用程序将按照部署清单中定义的方式在您的 Kubernetes 集群中安排。现在您应该能够通过以下教程来验证部署。

验证部署

这个教程将带您按照说明验证部署的状态,并在需要时进行故障排除。

让我们执行以下步骤:

  1. 通过观察部署状态来确认部署状态显示了一个“成功部署”消息:
$ kubectl rollout status deployment nginx-deployment
deployment "nginx-deployment" successfully rolled out
  1. 验证DESIREDCURRENT值的数量是否相等,在我们的情况下是2
$ kubectl get deployments
NAME             DESIRED CURRENT UP-TO-DATE AVAILABLE AGE
nginx-deployment 2       2       2          2         2m40s
  1. 最后,还要检查作为部署的一部分部署的 ReplicaSets(rs)和pods
$ kubectl get rs,pods
NAME                              DESIRED CURRENT READY AGE
nginx-deployment-5c689d88bb       2       2       2      28m
NAME                              READY STATUS  RESTARTS AGE
nginx-deployment-5c689d88bb-r2pp9 1/1   Running 0        28m
nginx-deployment-5c689d88bb-xsc5f 1/1   Running 0        28m

现在您已经验证了新的部署成功部署并运行。在生产环境中,您还需要编辑、更新和扩展现有的应用程序。在下一个教程中,您将学习如何对现有的部署执行这些修改操作。

编辑部署

这个教程将带您按照说明编辑现有的 Kubernetes 对象,并学习在需要时如何更改部署对象的参数。

让我们执行以下步骤:

  1. 编辑部署对象并将容器镜像从 nginx 1.7.9 更改为 nginx 1.16.0:
$ kubectl edit deployment nginx-deployment
  1. 您可以看到,部署首先进入挂起终止状态,然后在运行以下命令后,部署状态显示了一个“成功部署”的消息:
$ kubectl rollout status deployment nginx-deployment
Waiting for deployment "nginx-deployment" rollout to finish: 1 old replicas are pending termination...
deployment "nginx-deployment"
  1. 确认您的部署通过创建新的 ReplicaSet 并将旧的 ReplicaSet 从2缩减到0来启动新的 pod:
$ kubectl get rs
NAME                        DESIRED CURRENT READY AGE
nginx-deployment-5c689d88bb 0       0       0     36m
nginx-deployment-f98cbd66f  2       2       2     46s
  1. 我们将创建一个更改原因注释。以下命令将向您当前的部署添加在kubernetes.io/change-cause参数中定义的描述:
$ kubectl annotate deployment nginx-deployment kubernetes.io/change-cause="image updated to 1.16.0"
  1. 现在,作为编辑部署的另一种替代方法,编辑deployment-nginx.yaml文件,并将副本从replicas: 2更改为replicas: 3,将nginx:1.7.9更改为image: nginx:1.17.0
$ nano deployment-nginx.yaml
  1. 通过应用更新后的 YAML 清单来更新部署。此步骤将应用用于部署的镜像标记的更改以及我们在步骤 5中增加的副本数:
$ kubectl apply -f deployment-nginx.yaml
  1. 通过创建新的 ReplicaSet 并将旧的 pod 缩减到新的 pod 来确认您的部署正在启动新的 pod:
$ kubectl get rs
NAME                        DESIRED CURRENT READY AGE
nginx-deployment-5c689d88bb 0       0       0     56m
nginx-deployment-5d599789c6 3       3       3     15s
nginx-deployment-f98cbd66f  0       0       0     20m
  1. 通过定义我们使用kubernetes.io/change-cause参数所做的更改来创建另一个更改原因注释:
$ kubectl annotate deployment nginx-deployment kubernetes.io/change-cause="image updated to 1.17.0 and scaled up to 3 replicas"

现在您已经学会了如何编辑、扩展,并使用 ReplicaSet 发布应用程序的新版本。

回滚部署

本教程将带您按照说明审查所做的更改,并通过比较注释回滚部署到旧的修订版本。

让我们执行以下步骤:

  1. 检查部署的详细信息和事件,并注意最近的ScalingReplicaSet事件:
$ kubectl describe deployments
  1. 现在,显示部署的发布历史。输出将显示修订版本以及我们创建的注释:
$ kubectl rollout history deployment nginx-deployment
deployment.extensions/nginx-deployment
REVISION CHANGE-CAUSE
1        <none>
2        image updated to 1.16.0
3        image updated to 1.17.0 and scaled up to 3 replicas
  1. 回滚最后一次发布。此命令将使您的部署回到上一个修订版本,在本示例中为修订版本 2:
$ kubectl rollout undo deployment nginx-deployment
deployment.apps/nginx-deployment rolled back
  1. 确认部署已回滚到上一个版本:
$ kubectl get rs
NAME                        DESIRED CURRENT READY AGE
nginx-deployment-5c689d88bb 0       0       0     69m
nginx-deployment-5d599789c6 0       0       0     12m
nginx-deployment-f98cbd66f  3       3       3     33m

请注意,回滚命令只会将部署回滚到不同的镜像版本发布,并不会撤消其他规范更改,例如副本的数量。

  1. 现在,回滚到特定的修订版本。此命令将使您的部署回到使用--to-revision参数定义的特定修订版本:
$ kubectl rollout undo deployment nginx-deployment --to-revision=1

现在您已经学会了如何查看发布历史并在需要时回滚更改。

删除部署

Kubernetes 根据资源的可用性在工作节点上调度资源。如果您使用的是 CPU 和内存资源有限的小集群,您可能会很容易耗尽资源,这将导致新的部署无法在工作节点上调度。因此,除非在配方的要求中提到,否则在继续下一个配方之前始终清理旧的部署。

让我们执行以下步骤来删除nginx-deployment

  1. 在继续下一个步骤之前,请删除部署:
$ kubectl delete deployment nginx-deployment

上述命令将立即终止部署并从集群中删除应用程序。

工作原理...

创建部署的步骤向您展示了如何使用 YAML 清单文件将您的 Pod 和 ReplicaSets 的期望状态应用到部署控制器。

在第 2 步中,我们使用了kubectl apply命令,这是声明性管理方法的一部分,它进行增量更改而不是覆盖它们。第一次创建资源意图时,您可以使用kubectl create命令,这被认为是一种命令式管理方法。

我更喜欢使用apply命令,因为它允许声明性模式,而不是create,因为它更适合创建 CI 脚本,并且如果资源已经存在,则不会引发错误。

现在您已经学会了在 Kubernetes 中运行单个部署的基本步骤,我们可以继续进行更复杂的部署用例,使用 Kustomize、Helm 和 Operator 框架来组成一系列对象。

另请参阅

使用 Kustomize 部署工作负载

在本节中,我们将向您展示如何从文件生成资源,并在 Kubernetes 中组成和自定义资源集合。您将了解使用 Kustomize 进行 Kubernetes 对象的声明性管理。

做好准备

确保您已准备好一个 Kubernetes 集群,并配置了kubectl来管理集群资源。

本节中创建的源文件可以在我的 GitHub 存储库中找到,位于github.com/k8sdevopscookbook/src/tree/master/chapter2/kustomize。建议您按照说明创建和编辑它们,并且只在遇到问题时使用存储库中的文件与您的文件进行比较。

操作步骤如下…

本节进一步分为以下小节,以便简化流程:

  • 验证 Kubernetes 集群版本

  • 从文件生成 Kubernetes 资源

  • 为开发和生产部署创建一个基础

验证 Kubernetes 集群版本

为了使 Kustomize 正常运行,需要 Kubernetes 集群版本 1.14.0 或更高版本,因为 Kustomize 支持仅包含在 kubectl v.1.14.0 及更高版本中。

  1. 列出节点以确认您的 Kubernetes 集群版本,并确保其为 1.14.0 或更高版本:
$ kubectl get nodes
 NAME STATUS ROLES AGE VERSION
 ip-172-20-112-25.ec2.internal Ready master 7h19m v1.15.0
 ip-172-20-126-108.ec2.internal Ready node 7h18m v1.15.0
 ip-172-20-51-209.ec2.internal Ready node 7h18m v1.15.0
 ip-172-20-92-89.ec2.internal Ready node 7h19m v1.15.0

在上面的例子中,版本显示为v1.15.0

从文件生成 Kubernetes 资源

让我们学习如何使用 Kustomize 定制我们在上一个配方中做的 nginx 滚动:

  1. 创建一个名为nginx的目录:
$ mkdir nginx
  1. 将您在“使用 YAML 文件部署工作负载”配方中创建的deployment-nginx.yaml文件复制到nginx目录下。这个文件仍然使用image: nginx:1.7.9作为容器镜像:
$ cp deployment-nginx.yaml ./nginx/
  1. 通过指定新的镜像版本创建一个kustomization.yaml文件:
$ cat <<EOF >./nginx/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment-nginx.yaml
images:
 - name: nginx
 newName: nginx
 newTag: 1.16.0
commonAnnotations:
 kubernetes.io/change-cause: "Initial deployment with 1.16.0"
EOF
  1. 通过运行以下命令检查新版本是否被注入到您的部署中。在输出中,您将看到image: nginx:1.16.0,而不是我们之前在deployment-nginx.yaml文件中使用的原始镜像版本nginx:1.7.9
$ kubectl kustomize ./nginx/
  1. 使用-k参数应用定制的部署:
$ kubectl apply -k nginx
  1. 通过指定一个更新的镜像版本创建一个新的kustomization.yaml文件:
$ cat <<EOF > nginx/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
 - deployment-nginx.yaml
images:
 - name: nginx
 newName: nginx
 newTag: 1.17.0
commonAnnotations:
 kubernetes.io/change-cause: "image updated to 1.17.0"
EOF
  1. 使用-k参数应用定制的部署:
$ kubectl apply -k nginx
  1. 现在,显示部署的滚动历史:
$ kubectl rollout history deployment nginx-deployment
deployment.extensions/nginx-deployment
REVISION CHANGE-CAUSE
1        Initial deployment with 1.16.0
2        image updated to 1.17.0

现在您已经学会了如何使用 Kustomize 编辑、扩展,并通过 Kustomize 推出应用的新版本。

为开发和生产部署创建一个基础

让我们执行以下步骤来创建一个本地 Docker 镜像注册表部署的基础,我们将在本章后面使用:

  1. 创建一个名为registry的目录,并在其下创建一个名为base的目录:
$ mkdir registry && mkdir registry/base
  1. registry/base下,从示例存储库中下载名为deployment-registry.yaml的部署文件:
$ cd registry/base/
$ wget https://raw.githubusercontent.com/k8sdevopscookbook/src/master/chapter2/kustomize/registry/base/deployment-registry.yaml
  1. 查看文件以了解其结构。您将看到它是一个包含两个名为registryregistryui的容器的Deployment清单。您将看到注册表容器有一个名为registry-storagevolumeMount,这个卷是由名为registry-pvc的持久卷声明提供的:
$ cat deployment-registry.yaml
apiVersion: extensions/v1beta1
kind: Deployment
# actual file is longer, shortened to highlight important structure of the file only
 - image: registry:2
#....#
 - name: registry-storage
 mountPath: /var/lib/registry
#....#
 - name: registryui
 image: hyper/docker-registry-web:latest
#....#
 - name: registry-storage
 persistentVolumeClaim:
 claimName: registry-pvc
  1. 在相同的registry/base下,从示例存储库中下载名为service-registry.yaml的服务清单文件:
$ wget https://raw.githubusercontent.com/k8sdevopscookbook/src/master/chapter2/kustomize/registry/base/service-registry.yaml
  1. 查看文件以了解其结构。您将看到这是一个服务清单,它在每个节点的 IP 上以静态端口暴露服务;在这个示例中,registry服务的端口为5000registry-ui服务的端口为80
$ cat <<EOF > registry/base/service-registry.yaml
kind: Service
# actual file is longer, shortened to highlight important structure of the file only
 type: NodePort
 ports:
 - name: registry
 port: 5000
 protocol: TCP 
 nodePort: 30120
 - name: registry-ui
 port: 80
 protocol: TCP
 nodePort: 30220 
#....#
  1. 创建一个名为pvc-registry.yamlPersistentVolumeClaim清单文件,内容如下:
$ cat <<EOF > registry/base/pvc-registry.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
 name: registry-pvc
 labels:
 app: kube-registry-pv-claim
spec:
 accessModes:
 - ReadWriteOnce
 resources:
 requests:
 storage: 10G
EOF

此时,您可以使用kubectl apply -f registry/base来部署registry目录下的所有资源文件。但是,每当您需要更改资源中的参数,比如applabel时,您需要编辑这些文件。使用 Kustomize 的整个目的是利用重用文件而无需修改文件的源。

  1. 最后,创建kustomization.yaml文件。以下命令将创建 Kustomize 资源内容,其中包括我们之前创建的三个单独的清单文件:
$ cat <<EOF >./registry/base/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
 - deployment-registry.yaml
 - service-registry.yaml
 - pvc-registry.yaml
EOF
  1. 现在,创建两个用于开发和生产部署的叠加层。第一个是用于开发的:
$ mkdir registry/overlays && mkdir registry/overlays/dev 
$ cat <<EOF >./registry/overlays/dev/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
bases:
 - ../../base
namePrefix: dev-
commonAnnotations:
 note: Hello, I am development!
EOF
  1. 第二个清单将为生产创建叠加层:
$ mkdir registry/overlays/prod
$ cat <<EOF >./registry/overlays/prod/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
bases:
 - ../../base
namePrefix: prod-
commonAnnotations:
 note: Hello, I am production!
EOF
  1. 检查devprod前缀是否注入到您的部署中。当您指向prod文件夹时,注释说明将显示“你好,我是生产!”:
$ kubectl kustomize ./registry/overlays/prod/
# result shortened to highlight the annotation
metadata:
 annotations:
 note: Hello, I am production!
 labels:
 app: kube-registry-pv-claim
 name: prod-registry-pvc
#...#
  1. 当您指向dev文件夹时,注释说明将显示“你好,我是开发!”:
$ kubectl kustomize ./dev/
... # removed
metadata:
 annotations:
 note: Hello, I am development!
 labels:
 app: kube-registry-pv-claim
 name: dev-registry-pvc
... # removed
  1. 现在,部署您应用的dev版本:
$ kubectl apply -k ./registry/overlays/dev

同样,您可以注入标签,修补图像版本,更改副本的数量,并将资源部署到不同的命名空间。

它是如何工作的...

这个示例向您展示了如何使用 Git 管理和实现配置文件的基本版本控制。

为开发和生产部署创建基础配方中,我们在base目录下创建的资源代表应用程序/工作负载的上游存储库,而在overlay目录下在第 8 步和第 10 步之间创建的自定义内容是您在存储库中控制和存储的更改。

稍后,如果您需要查看变体的差异,可以使用以下diff参数:

$ kubectl diff -k registry/overlays/prod/

通过将更改与基础分离,我们能够为多种目的定制无模板的 YAML 文件,保持原始 YAML 文件不变,从而实现源和更改的版本控制。

另请参阅

使用 Helm 图表部署工作负载

在本节中,我们将向您展示如何在 Kubernetes 中使用 Helm 图表。Helm 是 Kubernetes 的软件包管理器,可帮助开发人员和 SRE 轻松打包、配置和部署应用程序。

您将学习如何在集群上安装 Helm 并使用 Helm 来管理第三方应用程序的生命周期。

准备工作

确保您已准备好 Kubernetes 集群,并配置了kubectl来管理集群资源。

如何做…

本节进一步分为以下子节,以便简化流程:

  • 安装 Helm 2.x

  • 使用 Helm 图表安装应用程序

  • 在 Helm 存储库中搜索应用程序

  • 使用 Helm 更新应用程序

  • 使用 Helm 回滚应用程序

  • 添加新的 Helm 存储库

  • 使用 Helm 删除应用程序

  • 构建 Helm 图表

安装 Helm 2.x

让我们执行以下步骤来配置先决条件并安装 Helm:

  1. 使用以下命令创建ServiceAccount
$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
 name: tiller
 namespace: kube-system
EOF
  1. 使用以下命令创建ClusterRoleBinding
$ cat <<EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
 name: tiller
roleRef:
 apiGroup: rbac.authorization.k8s.io
 kind: ClusterRole
 name: cluster-admin
subjects:
 - kind: ServiceAccount
 name: tiller
 namespace: kube-system
EOF
  1. 下载 Helm 安装脚本。此install-helm.sh脚本将检测系统的架构并获取最新的正确二进制文件以安装 Helm:
$ curl https://raw.githubusercontent.com/kubernetes/helm/master/scripts/get > install-helm.sh
  1. 运行脚本安装 Helm。以下命令将安装运行 Helm 所需的两个重要二进制文件 Helm 和 Tiller:
$ chmod u+x install-helm.sh && ./install-helm.sh
  1. 运行init参数以使用我们在第 1 步创建的服务帐户配置 Helm。--history-max参数用于清除和限制 Helm 历史记录,因为如果没有此设置,历史记录可能会无限增长并引起问题:
$ helm init --service-account tiller --history-max 200

此过程将在您的集群中安装 Helm 服务器端组件 Tiller。

如果收到Tiller 已经安装在集群中的消息,可以在命令的末尾添加--upgrade参数运行相同的命令,并强制升级现有版本。

  1. 通过运行以下命令确认 Helm 版本:
$ helm version --short

在撰写本文时,Helm 的最新稳定版本是 v2.15.1,下一个版本 Helm 3 仍处于测试阶段。在接下来的章节和配方中,我们将基于 Helm 2.x 版本进行指导。

使用 Helm 图表安装应用程序

让我们执行以下步骤,从官方 Helm 存储库位置安装 Helm 图表:

  1. 在安装图表之前,始终同步存储库以获取最新内容。否则,您可能会得到旧版本的 Helm 图表:
$ helm repo update
  1. 安装示例图表,例如stable/mysql
$ helm install --name my-mysqlrelease stable/mysql

同样,您可以从 Helm 图表稳定存储库安装其他应用程序,或者添加自己的存储库以获取自定义图表。

每次安装图表时,都会创建一个具有随机名称的新发布,除非使用--name参数指定。现在,列出发布:

$ helm ls
NAME            REVISION UPDATED                 STATUS   CHART         APP VERSION NAMESPACE
my-mysqlrelease 1        Thu Aug 8 02:30:27 2019 DEPLOYED mysql-1.3.0 5.7.14        default
  1. 检查发布状态,在我们的示例中是my-mysqlrelease
$ helm status my-mysqlrelease

您将获得部署状态和所有资源的信息。

在 Helm 存储库中搜索应用程序

让我们执行以下步骤,从 Helm 图表存储库中搜索要在 Kubernetes 上部署的应用程序:

  1. 在存储库中搜索图表。以下命令将在您可以访问的 Helm 存储库中查找您搜索的词语:
$ helm search redis
NAME CHART VER APP VER DESCRIPTION 
stable/prometheus-redis-exporter 3.0.0 1.0.3 Prometheus export
stable/redis 9.0.1 5.0.5 Open source, adva
stable/redis-ha 3.6.2 5.0.5 Highly available 
stable/sensu 0.2.3 0.28 Sensu monitoring 

您可以在 helm/stable 中找到所有工作负载的完整列表,并在以下 GitHub 链接的存储库中找到源代码:github.com/helm/charts/tree/master/stable 

  1. 您的search关键字不一定要是项目的确切名称。您还可以搜索关键字,如StorageMQDatabase
$ helm search storage
NAME                 CHART VERSION APP VERSION DESCRIPTION ...
stable/minio         2.5.4 RELEASE.2019-07-17T22-54-12Z MinIO is a hi
stable/nfs-server-pr 0.3.0 2.2.1-k8s1.12 nfs-server-provisioner is an
stable/openebs       1.0.0 1.0.0 Containerized Storage for Containers

默认情况下,您的存储库列表仅限于helm/stable位置,但稍后在添加新的 Helm 存储库配方中,您还将学习如何添加新的存储库以扩展您的搜索范围到其他存储库。

使用 Helm 升级应用程序

有几种使用升级的方法。让我们执行以下步骤:

  1. 升级发布,在我们的例子中是my-mysqlrelease,使用更新的图表版本:
$ helm upgrade my-mysqlrelease stable/mysql
  1. 在将来,您可能会发现应用程序的特定版本在您的环境中更加稳定,或者在多个集群中保持安装的一致。在这种情况下,您可以使用以下命令使用您偏好的图表版本更新图表版本:
$ helm upgrade my-mysqlrelease stable/mysql --version 1.2.0
  1. 使用以下命令确认图表版本更改。在第 2 步升级版本后,您应该期望看到mysql --version 1.2.0
$ helm ls
NAME            REVISION UPDATED                  STATUS   CHART       APP VERSION NAMESPACE
my-mysqlrelease 3        Tue Jul 30 22:44:07 2019 DEPLOYED mysql-1.2.0 5.7.14      default
  1. 使用以下命令查看修订历史。由于我们最近更新了图表版本,您应该在历史记录中看到至少两个修订版本:
$ helm history my-mysqlrelease stable/mysql
REV UPDATED             STATUS     CHART       DESCRIPTION
1   Oct 1 22:47:37 2019 SUPERSEDED mysql-1.3.3 Install complete
2   Oct 1 22:57:32 2019 SUPERSEDED mysql-1.3.3 Upgrade complete
3   Oct 1 23:00:44 2019 DEPLOYED   mysql-1.2.0 Upgrade complete
  1. 使用helm upgrade函数通过使用--set key=value[,key=value]参数指定参数来更新现有发布上的参数。以下命令将使用--set mysqlRootPassword参数设置两个 MySQL 密码:
$ helm upgrade my-mysqlrelease stable/mysql --version 1.2.0 --set mysqlRootPassword="MyNevvPa55w0rd"
  1. 确认密码实际上已更新。您应该期望得到与第 4 步设置的相同密码:
$ kubectl get secret --namespace default my-mysqlrelease -o jsonpath="{.data.mysql-root-password}" | base64 --decode; echo
MyNevvPa55w0rd

现在您已经学会了如何使用新参数升级 Helm 发布。

使用 Helm 回滚应用程序

让我们执行以下步骤,撤消升级并将应用程序状态恢复到先前的修订版本:

  1. 列出您的发布的修订历史,例如coy-jellyfish
$ helm history my-mysqlrelease
REV UPDATED                 STATUS     CHART       DESCRIPTION
1   Tue Oct 1 22:47:37 2019 SUPERSEDED mysql-1.3.3 Install complete
2   Tue Oct 1 22:57:32 2019 SUPERSEDED mysql-1.3.3 Upgrade complete
3   Tue Oct 1 23:00:44 2019 SUPERSEDED mysql-1.2.0 Upgrade complete
4   Tue Oct 1 23:07:23 2019 SUPERSEDED mysql-1.3.3 Upgrade complete
5   Tue Oct 1 23:10:39 2019 DEPLOYED   mysql-1.2.0 Upgrade complete
  1. 假设您需要从最后一次升级回滚到修订版本4。回滚到特定的修订版本:
$ helm rollback my-mysqlrelease 4
Rollback was a success.
  1. 修订历史将更新以反映您的回滚:
$ helm history my-mysqlrelease
 REV UPDATED                  STATUS     CHART       DESCRIPTION
...
 5   Tue Jul 30 22:44:07 2019 SUPERSEDED mysql-1.2.0 Upgrade complete
 6   Tue Jul 30 23:11:52 2019 DEPLOYED   mysql-1.3.0 Rollback to 4

现在您已经学会了如何查看发布历史并在需要时回滚 Helm 发布。

使用 Helm 删除应用程序

让我们执行以下步骤,从您的 Kubernetes 集群中使用 Helm 删除部署的应用程序:

  1. 使用helm ls命令和--all参数列出所有发布,包括已删除的修订版本:
helm ls --all
NAME REVISION UPDATED STATUS CHART APP VERSION NAMESPACE
my-mysqlrelease 6 Thu Aug 8 02:34:13 2019 DEPLOYED mysql-1.3.0 5.7.14 default
  1. 使用--purge参数删除一个发布。以下命令将完全从您的集群中删除应用程序:
helm delete --purge my-mysqlrelease

上述命令将立即终止部署并从集群中删除 Helm 发布。

添加新的 Helm 存储库

默认情况下,Helm 只使用官方的 Helm/stable 存储库进行查找,通常在接下来的章节中,我们需要使用本教程中解释的方法从第三方供应商那里添加额外的存储库。

让我们执行以下步骤来将额外的 Helm 存储库添加到你的源列表中:

  1. 检查现有存储库的列表。你应该只能看到列表上的stablelocal
$ helm repo list
 NAME   URL
 stable https://kubernetes-charts.storage.googleapis.com
 local  http://127.0.0.1:8879/charts
  1. 我们需要为我们的存储库服务器配置一个持久卷和认证。使用以下内容创建一个名为customhelmrepo.yaml的文件:
cat <<EOF >customhelmrepo.yaml
env:
 open:
 STORAGE: local
persistence:
 enabled: true
 accessMode: ReadWriteOnce
 size: 10Gi
 secret:
 BASIC_AUTH_USER: helmcurator
 BASIC_AUTH_PASS: myhelmpassword
EOF
  1. 使用持久卷创建一个存储库服务器:
$ helm install --name my-chartmuseum -f customhelmrepo.yaml stable/chartmuseum
  1. 获取chartmuseum的服务 IP。以下命令将返回一个 IP 地址,在我们的例子中是10.3.0.37
$ kubectl get svc --namespace default -l "app=chartmuseum" -l \
"release=my-chartmuseum" -o jsonpath="{.items[0].spec.clusterIP}"; echo
10.3.0.37
  1. 将新的 Helm 存储库添加到你的存储库列表中;在我们的例子中,IP 是10.3.0.37
$ helm repo add chartmuseum http://10.3.0.37:8080
  1. 检查现有存储库的列表:
$ helm repo list
NAME        URL
stable      https://kubernetes-charts.storage.googleapis.com
local       http://127.0.0.1:8879/charts
chartmuseum http://10.3.0.37:8080

有许多选项可用于托管你的图表存储库。你可以使用一个名为 ChartMuseum 的开源 Helm 存储库服务器部署一个本地存储库,也可以使用 S3 存储桶、GitHub 页面或经典的 Web 服务器。为了简单起见,我们使用 Helm 本身来部署服务器。你可以在另请参阅部分找到 Helm 图表的替代托管方法。

构建一个 Helm 图表

让我们执行以下步骤来构建一个自定义的 Helm 图表,以便发布到你的本地chartmuseum存储库中:

  1. 创建一个名为mychart的图表:
$ helm create mychart
  1. 根据你的喜好编辑你的图表结构并测试模板可能出现的错误:
$ helm lint ./mychart
==> Linting ./mychart
[INFO] Chart.yaml: icon is recommended
1 chart(s) linted, no failures
  1. 使用--dry-run测试你的应用程序:
$ helm install ./mychart --debug --dry-run
  1. 构建 Helm 图表。通过运行以下命令,你将从mychart位置生成一个 Helm 存储库的 tarball 包:
$ helm package .
  1. 用你的 Helm 服务器替换 Helm 存储库服务器地址,并使用 URL 上传这个 Helm 图表包:
$ cd mychart && curl --data-binary "@mychart-0.1.0.tgz" http://10.3.0.37:8080/api/charts

现在你已经学会了如何创建、清理、测试、打包和上传你的新图表到本地基于 ChartMuseum 的 Helm 存储库。

它是如何工作的...

这个教程向你展示了如何安装 Helm 包管理器并构建你的第一个 Helm 图表。

当我们在构建 Helm 图表教程中构建 Helm 图表时,在第 1 步中,helm create命令在chart文件夹下创建了一些文件作为模板。你可以通过编辑这些文件或者在你对结构更加熟悉时从头开始创建它们。

helm create命令创建了构建我们 Helm 图表的模板。这里解释了内容及其功能:

mychart 
├── Chart.yaml          --> Description of the chart
├── charts              --> Directory for chart dependencies
├── mychart-0.1.0.tgz   --> Packaged chart following the SemVer 2 standard
├── templates           --> Directory for chart templates
│   ├── NOTES.txt       --> Help text displayed to users
│   ├── _helpers.tpl    --> Helpers that you can re-use 
│   ├── deployment.yaml --> Application - example deployment
│   ├── service.yaml    --> Application - example service endpoint
└── values.yaml         --> Default values for a chart

构建 Helm 图表的步骤中,在第 3 步helm install中,当与--dry-run参数一起使用时,会将图表发送到服务器,并返回渲染的模板,而不是安装它。这通常用于测试 Helm 图表。

在同一步骤中,在第 4 步中,helm package命令将您的完整图表打包成图表存档,基本上是一个 tarball。

在第 5 步中,我们使用curl命令将打包的 tarball 二进制文件发送到我们的 ChartMuseum 服务器,一个 HTTP 服务器,以便在接收到helm命令的GET请求时为我们提供 Helm 图表存档。

现在您已经学会了如何安装 Helm 图表并在本地存储库中创建您自己的 Helm 图表,您将能够安装下一章节中所需的第三方图表,以及在 CI/CD 流水线中构建您自己的构件。

另请参阅

使用 Kubernetes 操作员部署和操作应用程序

Kubernetes 操作员是另一种在 Kubernetes 上打包、部署和管理应用程序的方法。操作员比 Helm 等包管理器更复杂。操作员有助于消除手动步骤、特定于应用程序的准备工作和部署后步骤,甚至自动化用户的二天操作,如扩展或升级。

例如,一个应用程序的要求可能会根据其安装的平台而有所不同,或者可能需要更改其配置并与外部系统进行交互。

在本节中,我们将部署两个基于两种不同操作员框架的热门有状态应用程序的操作员,并了解它们提供了哪些功能。

准备工作

确保您已经准备好一个 Kubernetes 集群,并配置了kubectl来管理集群资源。

如何做…

该部分进一步分为以下子部分以简化流程:

  • 安装KUDOKubernetes 通用声明运算符)和 KUDO kubectl 插件

  • 使用 KUDO 安装 Apache Kafka 运算符

  • 安装 Operator Lifecycle Manager

  • 安装 Zalando PostgreSQL 运算符

安装 KUDO 和 KUDO kubectl 插件

在使用 KUDO 运算符安装应用程序之前,您需要安装 KUDO。我们将使用brew来安装 KUDO,这是 Linux 上用于简单安装二进制文件的软件包管理器;因此,如果您还没有安装brew,您也需要安装它:

  1. 按照使用 Helm 图表部署工作负载中的 Helm 说明来运行 Helm。

  2. 使用以下命令安装brew

$ sh -c "$(curl -fsSL https://raw.githubusercontent.com/Linuxbrew/install/master/install.sh)"
$ PATH=/home/linuxbrew/.linuxbrew/bin/:$PATH
  1. 通过运行以下命令使用brew install安装 KUDO 和kudo kubectl插件:
$ brew tap kudobuilder/tap && brew install kudo-cli
  1. 按照以下方式安装 KUDO:
$ kubectl kudo init

值得一提的是,Kubernetes 运算符是 Kubernetes 社区中一个不断发展的概念。有多个运算符框架,例如 Red Hat Operator Framework、D2iQ 的 KUDO 等。此外,对于每个工作负载,您会发现社区开发了许多运算符。我建议在决定使用运算符之前测试几种不同的运算符,以找到适合您用例的运算符。

现在您已经安装了 KUDO 控制器,可以使用 Kubernetes Operators 测试一些有状态的运行应用程序。

使用 KUDO 安装 Apache Kafka Operator

另请参阅部分列出了多个 Kafka 运算符,例如 Strimzi、Banzai Cloud、Confluent、krallistic 等。虽然在本文中我没有偏好,但作为示例,我们将基于 KUDO Operator 部署 Apache Kafka Operator。

让我们执行以下步骤:

  1. Kafka 需要 ZooKeeper。让我们创建一个 ZooKeeper 集群:
$ kubectl kudo install zookeeper --instance=zk
  1. 使用 KUDO Kafka Operator 创建 Kafka 集群:
$ kubectl kudo install kafka --instance=kafka
  1. 通过查询Operators CRD API 列出 KUDO 运算符如下。在部署 Kafka 之后,您还应该看到kafkazookeeper运算符:
$ kubectl get Operators
NAME      AGE
kafka     9s
zookeeper 17s
  1. 列出 KUDO 实例:
$ kubectl get instances
NAME  AGE
kafka 25s
zk    33s

现在您已经学会了如何使用 KUDO Operator 部署 ZooKeeper 和 Kafka。

安装 Operator Lifecycle Manager

在使用 Red Hat Operator Framework 运算符安装应用程序之前,您需要安装Operator Lifecycle ManagerOLM)。请注意,OLM 在 OpenShift 4.0 及更高版本中默认安装。

  1. 安装 OLM。这是我们下一个配方安装 Zalando PostgreSQL Operator所需的:
$ kubectl create -f https://raw.githubusercontent.com/Operator-framework/Operator-lifecycle-manager/master/deploy/upstream/quickstart/crds.yaml
$ kubectl create -f https://raw.githubusercontent.com/Operator-framework/Operator-lifecycle-manager/master/deploy/upstream/quickstart/olm.yaml

现在您已经安装了 OLM 来测试使用 Operator Framework 运行一些有状态的应用程序。

安装 Zalando PostgreSQL Operator

另请参阅部分列出了多个 PostgreSQL Operators,例如 CrunchyDB 和 Zalando。在本示例中,我们将部署 Zalando PostgreSQL Operator 来管理 Kubernetes 集群中的 PostgreSQL 部署的生命周期。

让我们执行以下步骤来使用 Operator Hub 部署 Zalando PostgreSQL Operator:

  1. 从 Operator Hub 安装postgres-Operator
$ kubectl create -f https://Operatorhub.io/install/postgres-Operator.yaml
  1. 验证postgres-Operator是否正在运行:
$ kubectl get pods -n Operators
NAME                               READY STATUS  RESTARTS AGE
postgres-Operator-5cd9d99494-5nl5r 1/1   Running 0        3m56s
  1. 现在 PostgreSQL Operator 已经启动运行,让我们部署 Postgres Operator UI:
$ kubectl apply -f https://raw.githubusercontent.com/k8sdevopscookbook/src/master/chapter2/postgres-Operator/ui/postgres-ui.yaml
  1. 部署 PostgreSQL。以下命令将创建一个小的两实例 PostgreSQL 集群:
$ kubectl create -f https://raw.githubusercontent.com/zalando/postgres-Operator/master/manifests/minimal-postgres-manifest.yaml
  1. 列出由 Zalando Operator 管理的 PostgreSQL 实例。它将显示一个名为acid-minimal-cluster的集群:
$ kubectl get postgresql
NAME                 TEAM VERSION PODS VOLUME CPU-REQUEST MEMORY-REQUEST AGE STATUS
acid-minimal-cluster acid 11      2    1Gi                               7s
  1. 首先获取您的集群凭据,并使用psql交互式 PostgreSQL 终端连接到您的 PostgreSQL,如下所示:
$ export PGPASSWORD=$(kubectl get secret postgres.acid-minimal-cluster.credentials -o 'jsonpath={.data.password}' | base64 -d)
$ export PGSSLMODE=require
$ psql -U postgres
  1. 删除您的 PostgreSQL 集群:
$ kubectl delete postgresql acid-minimal-cluster

现在您已经学会了如何简单地使用流行的 Kubernetes Operators 在 Kubernetes 上部署和管理工作负载。您可以稍后应用这些知识,以简化您在开发和生产环境中使用的有状态工作负载的生命周期管理。

另请参阅

部署和管理 Jenkins X 的生命周期

Jenkins X 是一个开源解决方案,为软件开发人员提供管道自动化、内置 GitOps、CI、自动化测试和 CD,即 CI/CD,在 Kubernetes 中。Jenkins X 专注于利用 Kubernetes 生态系统加速大规模软件交付。

在本节中,我们将专注于 Jenkins X 示例,并在您的云提供商上创建具有 CI/CD 功能的 Kubernetes 集群。

准备工作

在以下示例中,您将学习如何创建一个静态的 Jenkins 服务器,以部署具有管道自动化和自动 CI/CD 的 Kubernetes 集群,并使用 GitOps 推广和预览环境。

此示例需要 kubectl 和 Helm。对于此示例,我们将使用GKEGoogle Kubernetes Engine的缩写),因此还需要安装 gcloud CLI 工具。您还需要创建一个适当的 GitHub 组织和 GitHub 帐户。

如何做到...

本节进一步分为以下小节,以便简化流程:

  • 安装 Jenkins X CLI

  • 创建 Jenkins X Kubernetes 集群

  • 验证 Jenkins X 组件

  • 切换 Kubernetes 集群

  • 验证集群一致性

安装 Jenkins X CLI

Jenkins X CLI jx 与您首选的云提供商 CLI 一起用于编排 Kubernetes 集群的部署。Jenkins X 支持 Azure、AWS、GCPGoogle Cloud Platform的缩写)、IBM Cloud、Oracle Cloud、Minikube、Minishift 和 OpenShift 作为部署的提供者。对于此示例,我们将使用 GKE。请参阅 Jenkins X 文档以获取其他供应商的说明。

让我们执行以下步骤来安装 Jenkins X CLI 工具:

  1. 访问 JX 发布站点github.com/jenkins-x/jx/releases并注意最新的发布版本。在撰写本文时,最新的发布版本是 v2.0.905。

  2. 在以下命令中更新发布版本。下载并安装最新版本的 Jenkins X CLI:

$ curl -L https://github.com/jenkins-x/jx/releases/download/v2.0.905/jx-linux-amd64.tar.gz | tar xzv 
$ sudo mv jx /usr/local/bin

现在你已经安装了 Jenkins X CLI,你可以继续下一个步骤了。

创建一个 Jenkins X Kubernetes 集群

你可能更喜欢其他云供应商或本地部署。在这个示例中,我们将使用 GKE。查看 Jenkins X 文档以获取其他供应商的说明。

让我们执行以下步骤来使用jx创建你的第一个 Jenkins X Kubernetes 集群:

  1. 使用以下命令和gke参数创建一个 GKE 的 Kubernetes 集群:
$ jx create cluster gke --skip-login
  1. 选择你的 Google Cloud 项目;在我们的例子中是devopscookbook

  2. 选择us-central1-a当被要求选择一个 Google Cloud 区域时。

  3. 选择静态 Jenkins 服务器和 Jenkinsfiles 作为安装类型。

  4. 输入你的 GitHub 用户名:

Creating a local Git user for GitHub server
? GitHub username:
  1. 输入你的 GitHub API 令牌。前往 GitHub Token 页面github.com/settings/tokens/new?scopes=repo,read:user,read:org,user:email,write:repo_hook,delete_repo获取你的 API 令牌:
Please click this URL and generate a token
https://github.com/settings/tokens/new?scopes=repo,read:user,read:org,user:email,write:repo_hook,delete_repo
Then COPY the token and enter it following:
? API Token:
  1. 默认情况下,Jenkins X 会设置入口规则来使用魔术 DNS nip.io 域:
? Domain [? for help] (your_IP.nip.io)
  1. 对以下问题输入Yes
? Do you wish to use GitHub as the pipelines Git server: (Y/n)
  1. 选择你想要创建环境仓库的 GitHub 组织;在我们的例子中是k8devopscookbook

  2. 当你的部署成功时,你会看到类似以下的消息:

Jenkins X installation completed successfully
 ********************************************************
 NOTE: Your admin password is: your_password
 ********************************************************
...
Context "gke_devopscookbook_us-central1-a_slayersunset" modified.
NAME            HOSTS                             ADDRESS PORTS AGE
chartmuseum     chartmuseum.jx.your_IP.nip.io     your_IP 80    7m43s
docker-registry docker-registry.jx.your_IP.nip.io your_IP 80    7m43s
jenkins         jenkins.jx.your_IP.nip.io         your_IP 80    7m43s
nexus           nexus.jx.your_IP.nip.io           your_IP 80    7m43s

你也可以在前面的输出中找到你的管理员密码。

验证 Jenkins X 组件

让我们执行以下步骤来验证所有 Jenkins X 组件是否按预期运行:

  1. 确认所有的 pod 都在运行。jx命名空间中的所有 pod 都应该处于运行状态:
$ kubectl get pods -n jx
NAME                                          READY STATUS  RESTARTS AGE
jenkins-956c58866-pz5vl                       1/1   Running 0       11m
jenkins-x-chartmuseum-75d45b6d7f-5bckh        1/1   Running 0       11m
jenkins-x-controllerrole-bd4d7b5c6-sdkbg      1/1   Running 0       11m
jenkins-x-controllerteam-7bdd76dfb6-hh6c8     1/1   Running 0       11m
jenkins-x-controllerworkflow-7545997d4b-hlvhm 1/1   Running 0       11m
jenkins-x-docker-registry-6d555974c7-sngm7    1/1   Running 0       11m
jenkins-x-heapster-7777b7d7d8-4xgb2           2/2   Running 0       11m
jenkins-x-nexus-6ccd45c57c-btzjr              1/1   Running 0       11m
maven-brcfq                                   2/2   Running 0       63s
maven-qz0lc                                   2/2   Running 0       3m
maven-vqw9l                                   2/2   Running 0       32s
  1. 获取我们需要连接的 Jenkins X 服务 URL 列表。你将会得到类似以下的jenkinschartmuseumdocker-registrynexus的 URL 列表:
$ jx get urls
NAME                      URL
jenkins                   http://jenkins.jx.your_IP.nip.io
jenkins-x-chartmuseum     http://chartmuseum.your_IP.nip.io
jenkins-x-docker-registry http://docker-registry.jx.your_IP.nip.io
nexus                     http://nexus.jx.your_IP.nip.io

现在你可以通过访问jx get urls命令的前面输出中的第一个 URL 连接到 Jenkins UI。

切换 Kubernetes 集群

让我们执行以下步骤来在 Jenkins X 中切换你可以访问的 Kubernetes 集群:

  1. 通过列出上下文来获取现有的 Kubernetes 集群:
$ jx context
  1. 选择您想要使用的集群。在我们的情况下,我们切换到使用 Jenkins X 创建的 gke_devopscookbook 集群:
Change Kubernetes context: [Use arrows to move, space to select, type to filter]
> gke_devopscookbook_us-central1-a_slayersunset
eks_devopscookbook_us-west
openshift_cluster

现在您知道如何使用 Jenkins X CLI 切换上下文了。

验证集群符合性

如果您在现有的 Kubernetes 集群之间切换,建议在运行流水线之前验证集群配置。让我们执行以下步骤:

  1. 验证您的集群是否合规。这些测试通常需要一个小时:
jx compliance run
  1. 检查状态。此命令仅在测试完成后返回“合规性测试已完成”消息:
$ jx compliance status
Compliance tests completed.
  1. 查看结果。如果您的集群符合规定,所有执行的测试结果应显示为“通过”:
$ jx compliance results

现在您知道如何检查集群符合性结果了。

工作原理...

《创建 Jenkins X Kubernetes 集群》的教程向您展示了如何为流水线自动化和自动化 CI/CD 提供 Kubernetes 集群。

在《创建 Jenkins X Kubernetes 集群》的教程中,在第 1 步,我们使用 Jenkins X CLI 创建了集群。默认情况下,Jenkins X 在 GKE 上使用 n1-standard-2 作为机器类型,并创建一个最小为三个、最大为五个节点的集群。请记住,您也可以使用现有的 Kubernetes 集群,而不是创建新的集群。大多数设置将在下次运行 create cluster 命令时保存和记住。

Jenkins X 部署了一些服务,包括 Jenkins、私有 Docker 注册表、私有 Helm 仓库 ChartMuseum、用于管理 Helm 图表的 Monocular,以及名为 Nexus 的 Maven 和 npm 仓库。

安装后,您将在存储库中找到,Jenkins X 创建了两个 Git 存储库,一个用于暂存环境,一个用于生产环境。Jenkins X 使用 GitOps 方法通过 Git 拉取请求(PR)从一个存储库推广代码到另一个存储库。因此,每个存储库都包含一个 Jenkins 流水线来处理推广。

在《创建 Jenkins X Kubernetes 集群》的教程中,在第 7 步,Jenkins X 使用魔术 DNS 服务,并通过 nip.io 服务将您的 GKE 集群的 IP 地址转换为可通过 DNS 发现的主机名。如果您拥有自己的域并且 DNS 配置为指向您的集群,您可以使用 jx upgrade ingress --cluster 命令稍后更新设置。

稍后,在第 10 步,您将获得分配给您的管理员用户的默认密码。当您首次通过本步骤提供的 URL 连接到 Jenkins UI 时,将要求您更改此密码。

还有更多...

了解以下信息也很有用:

  • 导入应用程序

  • 升级 Jenkins X

  • 删除 Jenkins X Kubernetes 集群

导入应用程序

让我们执行以下步骤来将现有应用程序导入 Jenkins X 环境:

  1. 克隆或使用现有应用程序。例如,我们将创建hello-world示例的克隆:
$ mkdir import && cd import
$ git clone https://github.com/k8sdevopscookbook/hello-world.git
  1. cloned目录中删除 Git 文件。这将从目录中删除 Git 历史记录:
$ cd hello-world & sudo rm -r .git/
  1. 在文件夹中运行以下命令以将源代码导入 Jenkins X:
$ jx import

升级 Jenkins X 应用程序

让我们执行以下步骤来升级 Jenkins X 应用程序及其组件:

  1. 首先,升级jx CLI。如果远程存储库中有新版本可用,此命令将升级应用程序:
$ jx upgrade cli
  1. 一旦您使用最新的 CLI,使用以下命令升级平台。如果存在新版本,新的jx CLI 命令将升级平台组件:
$ jx upgrade platform

删除 Jenkins X Kubernetes 集群

删除托管的 Kubernetes 集群可能会很棘手,特别是如果不是您创建它们的人。由于我们使用 GKE 创建它们,使用 gcloud CLI 工具更快地删除它们。让我们执行以下步骤来删除我们使用 Jenkins X 创建的 Kubernetes 集群:

  1. 使用您的云提供商的说明来删除 Kubernetes 集群。在我们的情况下,我们使用 GKE 来进行操作。首先,列出集群:
$ gcloud container clusters list
NAME LOCATION MASTER_VERSION MASTER_IP MACHINE_TYPE NODE_VERSION NUM_NODES STATUS
clustername us-central1-a 1.12.8-gke.10 your_IP n1-standard-2 1.12.8-gke.10 3 RUNNING
  1. 使用步骤 1 的输出中的clustername删除集群:
$ gcloud container clusters delete <clustername>

现在您已经学会了如何使用 Jenkins X 来创建您的集群。这些知识已经为您准备好了第三章,构建 CI/CD 流水线,在那里您将继续使用这个环境,并学会在 Jenkins X 中将应用程序导入为流水线。

另请参阅

部署和管理 GitLab 的生命周期

GitLab 是一个完整的 DevOps 工具链,提供在单个应用平台中交付。GitLab 提供了您管理、计划、创建、验证、打包、发布、配置、监视和保护应用程序所需的所有工具。

在本节中,我们将使用 Helm 图表来覆盖 GitLab 的部署和生命周期管理。

准备工作

在下一个步骤中,您将学习如何在现有的 Kubernetes 集群上安装 GitLab,从而可以管理整个 DevOps 生命周期。

此步骤需要 kubectl 和 Helm,以及现有的 Kubernetes 集群。对于此步骤,我们将使用在第一章中部署的 AWS 集群,构建生产就绪的 Kubernetes 集群。您应该能够在任何 Kubernetes 集群版本 1.11 或更高版本上运行相同的步骤,最低要求为 6vCPU 和 16GB RAM。

操作步骤:

本节进一步分为以下小节,以便简化流程:

  • 使用 Helm 安装 GitLab

  • 连接到 GitLab 仪表板

  • 创建第一个 GitLab 用户

  • 升级 GitLab

  • 删除 GitLab

使用 Helm 安装 GitLab

对于此步骤,我们将使用在第一章中部署的 Amazon EC2 上的 Kubernetes 集群,构建生产就绪的 Kubernetes 集群下的在 Amazon Web Services 上配置 Kubernetes 集群*部分:

  1. 将 GitLab Helm 图表存储库添加到本地存储库:
$ helm repo add gitlab https://charts.gitlab.io/
$ helm repo update
  1. 用您的域名替换以下externalUrl,并在gitlab命名空间中使用 Helm 部署 GitLab:
$ helm upgrade --install gitlab gitlab/gitlab --namespace gitlab \
--timeout 600 \
--set global.edition=ce \
--set certmanager-issuer.email=youremail@domain.com \
--set global.hosts.domain=yourdomain.com

为简单起见,我建议您在使用自动生成的自签名证书部分使用您自己的证书。然后,您可以使用CNAME记录将您的 DNS 名称映射到创建的 ELB。

  1. 部署可能需要大约 10-15 分钟。确认服务状态并注意gitlab-gitlab-ce服务的外部 IP:
$ kubectl get svc -n gitlab

连接到 GitLab 仪表板

让我们执行以下步骤,以获取 GitLab 服务地址,以便使用您的 Web 浏览器连接:

  1. 获取 GitLab 服务的外部地址:
$ echo http://$(kubectl get svc --namespace gitlab \
gitlab-nginx-ingress-controller \
-o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
  1. 在浏览器中打开上一个命令返回的地址。

  2. 通过运行以下命令获取 GitLab 创建的默认 root 密码:

$ kubectl get secret gitlab-gitlab-initial-root-password \
-ojsonpath='{.data.password}' | base64 --decode ; echo
  1. 设置新密码并使用root用户和新密码登录。

  2. 要使用自定义 URL,请在 DNS 上创建一个CNAME记录,将别名指向第 1 步中使用的外部 URL。

创建第一个 GitLab 用户

默认情况下,我们使用 root 帐户来管理 GitLab 部署。所有新用户都需要使用自己的凭据登录 GitLab。

让我们执行以下步骤来创建新用户:

  1. root用户身份登录。

  2. 登录到 GitLab 仪表板后,您将看到类似以下内容的欢迎屏幕。在 GitLab 欢迎屏幕上点击添加人员

  1. 新用户菜单下,至少输入姓名、用户名和电子邮件字段,然后点击创建用户以保存更改。

升级 GitLab

GitLab 经常发布具有额外功能的新版本。偶尔,您可能还需要升级以获得错误修复。升级可以使用 Helm upgrade 轻松完成。让我们执行以下步骤来升级 GitLab 到新版本:

  1. 首先,使用helm get values命令将当前使用的参数导出到 YAML 文件中,如下所示:
$ helm get values gitlab > gitlab.yaml
  1. 升级图表存储库以获取远程存储库中可用的新版本:
$ helm repo update
  1. 列出可用的图表版本:
$ helm search -l gitlab/gitlab
NAME CHART VERSION APP VERSION DESCRIPTION
gitlab/gitlab 2.1.7 12.1.6 Web-based Git-repository manager with wiki and issue-trac...
gitlab/gitlab 2.1.6 12.1.4 Web-based Git-repository manager with wiki and issue-trac...
...
  1. 使用相同的参数升级新版本:
$ helm upgrade gitlab gitlab/gitlab --version 2.1.7 -f gitlab.yaml

工作原理...

使用 Helm 安装 GitLab配方向您展示了如何使用所有内置组件和外部依赖项来配置 GitLab。

使用 Helm 安装 GitLab配方中,在第 1 步中,我们确保将官方最新的 GitLab Helm 图表存储库添加到本地存储库列表中。否则,将使用来自 stable/gitlab 存储库的旧版本的 GitLab 图表。

在相同的配方中,在第 2 步中,我们使用 Helm 图表在gitlab命名空间中使用--namespace gitlab参数部署了 GitLab。这个命令不仅部署了 GitLab 组件,还部署了 Redis、PostgreSQL、Minio 对象存储用于数据持久性、Cert Manager、本地容器注册表和 nginx ingress 控制器。

要使用现有的 PostgreSQL、Redis、Gitaly、S3 存储和 ingress 控制器的部署,请按照此处描述的高级配置说明:docs.gitlab.com/charts/advanced/

默认情况下,GitLab Helm 图表部署 GitLab 的企业版。通过使用--set global.edition=ce参数,我们将部署切换到了免费的社区版。

使用 Helm 安装 GitLab教程中执行了命令后,在第 2 步,Helm 图表假定我们有一个现有的默认存储类,并使用默认存储类为有状态应用创建 PVCs 和 PVs。

还有更多...

还有以下信息也很有用:

  • 使用您自己的通配符证书

  • 使用自动生成的自签名证书

  • 启用 GitLab Operator

  • 删除 GitLab

使用您自己的通配符证书

GitLab 的 Helm 图表安装支持使用 nginx 控制器进行 TLS 终止。当您安装 GitLab 时,您有选择。为了提高安全性,您可以使用 Cert Manager 和 Let's Encrypt,或者选择使用您自己的通配符证书。在本教程中,我们将解释如何使用您自己的通配符证书选项,具体如下:

  1. 将您的证书和密钥添加到集群作为一个密钥:
$ kubectl create secret tls mytls --cert=cert.crt --key=key.key
  1. 使用以下附加参数从 Helm 图表部署 GitLab:
$ helm upgrade --install gitlab gitlab/gitlab --namespace gitlab \
--timeout 600 \
--set global.edition=ce \
--version 2.1.6 \
--set certmanager.install=false \
--set global.ingress.configureCertmanager=false \
--set global.ingress.tls.secretName=mytls

使用自动生成的自签名证书

如果您无法使用自己的通配符证书,但仍希望快速测试或小规模使用 GitLab,您也可以使用自动生成的自签名证书。在本教程中,我们将解释如何使用自签名证书,这在 Let's Encrypt 不可用但仍需要 SSL 安全的环境中非常有用:

  1. 在您的域名无法从 Let's Encrypt 服务器访问的情况下,您可以提供一个自动生成的自签名通配符证书:
$ helm upgrade --install gitlab gitlab/gitlab --namespace gitlab \
--timeout 600 \
--set global.edition=ce \
--version 2.1.6 \
--set certmanager.install=false \
--set global.ingress.configureCertmanager=false \
--set gitlab-runner.install=false
  1. 检索证书,稍后可以导入到 Web 浏览器或系统存储中:
$ kubectl get secret gitlab-wildcard-tls-ca -n gitlab \
-ojsonpath='{.data.cfssl_ca}' | base64 --decode > gitlab.mydomain.com.ca.pem

启用 GitLab Operator

GitLab 提供了一个实验性的 Operator。这个 Operator 控制升级过程,并帮助执行无停机的滚动升级。让我们执行以下步骤,使 GitLab Operator 运行起来:

  1. 首先,通过使用以下 Helm 参数来确保 CRD 已经就位:
$ helm upgrade --install gitlab . --set global.Operator.enabled=true \
--set global.Operator.bootstrap=true 
  1. 使用 Helm 图表部署 GitLab Operator:
$ helm upgrade gitlab . --set global.Operator.enabled=true \
--set global.Operator.bootstrap=false 

删除 GitLab

让我们执行以下步骤,完全删除我们在本节中创建的 GitLab 部署:

  1. 使用 Helm 删除 GitLab 的现有发布:
$ helm delete --purge gitlab
  1. 您可能还想删除命名空间,以确保没有留下任何东西:
$ kubectl delete ns gitlab

现在您已经学会了如何在 Kubernetes 上启动和运行 GitLab。这些知识将在第三章“构建 CI/CD 流水线”中的 GitLab 部分中需要,您将学习如何在 GitLab 中导入应用程序并创建流水线。

另请参阅

第三章:构建 CI/CD 流水线

在本章中,我们将讨论使用最流行的 CI/CD 工具在自托管公共云和 Kubernetes 的 SaaS 解决方案上配置端到端持续集成/持续交付CI/CD)流水线。在遵循本章的配方之后,您将掌握构建、部署和推广应用程序从开发到生产环境所需的技能。您将能够使用我们在这些配方中实施的工具来在持续集成过程中检测错误、反模式和许可问题。

在这一章中,我们将涵盖以下的配方:

  • 在 Jenkins X 中创建 CI/CD 流水线

  • 在 GitLab 中创建 CI/CD 流水线

  • 使用 CircleCI 创建 CI/CD 流水线

  • 使用 GitHub Actions 设置 CI/CD 流水线

  • 在 Amazon Web Services 上设置 CI/CD 流水线

  • 在 Google Cloud Build 上使用 Spinnaker 设置 CI/CD 流水线

  • 在 Azure DevOps 上设置 CI/CD 流水线

技术要求

本节的配方假定您在遵循第一章中描述的推荐方法之一后部署了一个功能性的 Kubernetes 集群,构建生产就绪的 Kubernetes 集群

Kubernetes 的命令行界面kubectl将在本节的其余配方中使用,因为它是针对 Kubernetes 集群运行命令的主要命令行界面。如果您使用的是 Red Hat OpenShift 集群,您可以用oc替换kubectl。所有命令都预计会有类似的功能。

本节的配方需要一个带有容器化项目的 Git 存储库。

在 Jenkins X 中创建 CI/CD 流水线

Jenkins X 是一个相当新的开源解决方案,它扩展了 Jenkins 生态系统,并解决了在使用 Kubernetes 在云中自动化 CI/CD 的问题。

在本节中,我们将学习如何将您的应用程序作为一个流水线进入 Jenkins X,您可以通过遵循第二章中的部署和管理 Jenkins X 的生命周期配方说明来部署。有了这个,您将学会如何使用简单的命令创建具有自动化 GitOps 的 CI/CD 流水线,并将应用程序从暂存推广到生产。

准备工作

确保你已经按照第二章,在 Kubernetes 上操作应用程序中的说明,并且已经准备好一个功能齐全的 Kubernetes 集群和一个部署好的 Jenkins X。你也可以在那一章中找到安装helm的说明。

在下面的示例中,你将学习如何使用 GitOps 推广创建流水线。

这个示例需要kubectlhelm、Jenkins X CLI、jx以及你安装 Kubernetes 集群的首选云提供商 CLI。

Jenkins X 支持 Azure、AWS、GCP、IBM Cloud、Oracle Cloud、minikube、minishift 和 OpenShift 作为部署过程的提供商。你还需要拥有一个 GitHub 组织和 GitHub 账户。

如何操作…

这一部分进一步分为以下子部分,以使这个过程更容易:

  • 连接到 Jenkins 流水线控制台

  • 将应用程序导入为流水线

  • 检查应用程序状态

  • 将应用程序推广到生产环境

  • 使用快速启动应用程序创建流水线

连接到 Jenkins 流水线控制台

让我们执行以下步骤来访问 Jenkins 流水线控制台 Web 界面:

  1. 切换到部署了 Jenkins X 的jx命名空间:
$ jx ns
? Change namespace: [Use arrows to move, space to select, type to filter]
 default
> jx
 jx-production
 jx-staging
 kube-public
 kube-system
  1. 使用以下命令获取 Jenkins(Blue Ocean)控制台地址,并在浏览器中打开链接。在这个示例中,控制台地址是以下jx console命令的输出,即http://jenkins.jx.your_ip.nip.io/blue
$ jx console
Jenkins Console: http://jenkins.jx.your_ip.nip.io/blue
  1. 在你从步骤 2的输出中打开 Jenkins 控制台链接后,点击列表中的一个流水线。例如,你可以在我们的演示环境中看到两个流水线:

  1. 选择最后一次运行,并确保两个流水线都正常,这意味着你的环境是正常工作的。类似于以下截图,你应该在验证环境和更新环境阶段看到绿色的勾号:

现在我们已经验证了环境是正常的,我们可以开始为我们自己的应用程序添加新的流水线。

将应用程序导入为流水线

大多数情况下,你需要将本地项目或 Git 仓库导入到 Jenkins 中。让我们执行以下步骤来创建现有仓库的本地克隆并将其导入为流水线:

  1. 首先,将示例代码的副本分叉到您的帐户。在浏览器中转到github.com/k8sdevopscookbook/python-flask-docker,并单击右上角的 Fork 按钮。

  2. 将存储库克隆到本地计算机。确保您将your_github_username替换为您分叉示例的 GitHub 用户名:

$ git clone https://github.com/your_github_username/python-flask-docker.git
  1. 现在,您应该有python-flash-docker应用程序的本地副本。使用以下命令导入项目:
$ cd python-flask-docker
$ jx import
  1. 现在,您可以从 Jenkins Blue Ocean 视图或 CLI 观察流水线活动。以下屏幕截图显示了 Jenkins Blue Ocean 仪表板上的流水线活动:

  1. 作为替代方案,您可以使用jx get activity命令在 CLI 上观察活动:
$ jx get activity -f python-flask-docker -w
STEP STARTED AGO DURATION STATUS
muratkars/python-flask-docker/master #1 1m3s Running
 Checkout Source 22s 5s Succeeded
 CI Build and push snapshot 17s NotExecuted
 Build Release 17s Pending
...
 Promoted 2m5s 2m0s Succeeded Application is at: http://python-flask-docker.jx-staging.35.188.140.152.nip.io
 Clean up 1s 0s Succeeded

检查应用程序状态

创建了流水线后,您需要确认其状态。在将应用程序移入生产之前,让我们执行以下步骤确保应用程序已在暂存中部署:

  1. 如果流水线构建成功,您应该在暂存环境中有版本 0.0.1。在流水线完成时列出应用程序:
$ jx get applications
APPLICATION STAGING PODS URL
python-flask-docker 0.0.1 1/1 http://python-flask-docker.jx-staging.35.188.140.152.nip.io
  1. 在这里,您可以看到应用程序已部署。访问 URL 以查看应用程序:

  1. 我们的 pod 当前正在jx-staging命名空间中运行。确认jx-stagingjx-production命名空间中的 pod。在将应用程序推广到生产之前,第二个命名空间不应返回任何内容:
$ kubectl get pods -n jx-staging
NAME READY STATUS RESTARTS AGE
jx-python-flask-docker-8564f5b4cb-ff97f 1/1 Running 0 21m
$ kubectl get pods -n jx-production
No resources found.

将应用程序推广到生产

一旦应用程序在暂存中部署,下一步就是将其推广到生产环境。让我们执行以下步骤,将应用程序从暂存推广到生产:

  1. 确认应用程序稳定后,下一步是将其推广到生产。让我们使用以下命令将当前版本从staging推送到production
$ jx promote python-flask-docker --version 0.0.1 --env production
  1. 出于各种原因,主要是环境限制,成功将应用程序部署到暂存中并不保证成功将其部署到生产中。在推广应用程序后,使用以下命令检查生产部署的进度。运行此命令后,您需要看到Succeeded消息:
$ jx get activity -f python-flask-docker -w
  1. 我们的 pod 已经被提升到jx-production命名空间。确认 pod 现在也在jx-production命名空间中运行:
$ kubectl get pods -n jx-production
NAME                                    READY STATUS  RESTARTS AGE
jx-python-flask-docker-8564f5b4cb-fhcpm 1/1   Running 0        104m
  1. 列出应用程序。您将获得相同应用程序的暂存和生产链接:
$ jx get applications
APPLICATION         STAGING PODS URL                                                         PRODUCTION PODS URL
python-flask-docker 0.0.1   1/1  http://python-flask-docker.jx-staging.35.188.140.152.nip.io 0.0.1      1/1  http://python-flask-docker.jx-production.35.188.140.152.nip.io

使用 QuickStart 应用程序创建管道

如果您没有要导入的项目,则可以从 QuickStart 创建一个新应用程序,并通过以下步骤将新生成的代码导入 Git 和 Jenkins 进行 CI/CD:

  1. 从标准化模板创建一个构建。此命令将显示您可以使用的应用程序模板来创建新应用程序:
$ jx create quickstart
  1. 选择您的 GitHub 用户名和组织:
? Git user name? 
? Which organisation do you want to use?
  1. 输入一个新的仓库名称。在本示例中,这是chapter2-jx-tutorial
Enter the new repository name: chapter2-jx-tutorial
  1. 选择您希望创建的 QuickStart 示例。在我们的示例中,这是golang-http

  2. 对以下问题指定

Would you like to initialise git now? (Y/n) y
  1. 管道需要一些时间才能完成。使用以下命令列出可用的管道:
$ jx get pipelines

它是如何工作的...

本节的第二个示例,将应用程序导入为管道,向您展示了如何使用现有项目创建 Jenkins 管道。

步骤 3中,当您使用jx import命令导入应用程序时,会发生以下情况:

  1. 首先,从仓库检出项目源代码并应用新的语义版本号。然后,借助 Skaffold,一个便于 Kubernetes 应用程序持续开发的命令行工具,创建 Git 标签 v0.0.1 并执行单元测试(在我们的示例中,没有单元测试)。

  2. 在单元测试执行完毕后,将创建一个 Docker 镜像并推送到本地容器注册表。您可以在以下代码中看到这个过程:

Starting build... Building [devopscookbook/python-flask-docker]...
Sending build context to Docker daemon    127kB Step 1/8 : FR
OM python:3.6 3.6: Pulling from library/python 
4ae16bd47783: Pulling fs layer 
bbab4ec87ac4: Pulling fs layer 
...
  1. 容器镜像推送到注册表后,您可以在 Docker 注册表中找到它:

  1. 在推广到环境阶段,将执行 Helm 构建。在图表被推送到本地的chartmuseum仓库后,您可以在仓库中找到 Helm 图表:
$ helm search python-flask-docker
NAME CHART VERSION APP VERSION DESCRIPTION
jenkins-x-chartmuseum/python-flask-docker 0.0.1 0.0.1 A Helm chart for Kubernetes
  1. 最后,暂存管道从主分支运行,并将我们的 pod 从 Helm 仓库部署到jx-staging命名空间。在此步骤之后,暂存和应用程序管道将完成。

在 GitLab 中创建一个 CI/CD 管道

GitLab 是一个完整的 DevOps 工具链,以单一应用程序平台的形式提供。GitLab 提供了您管理、规划、创建、验证、打包、发布、配置、监控和保护应用程序所需的所有必要工具。

在这一部分,我们将专注于 GitLab 的 CI/CD 流水线功能,这些功能可以作为 SaaS 或自托管服务使用。我们将导入一个应用程序并在 GitLab 中创建一个流水线。您将学习如何使用 Auto DevOps 创建一个 CI/CD 流水线,并将一个应用程序从暂存推广到生产环境。

准备工作

在下面的步骤中,您将学习如何使用 Auto DevOps 创建一个流水线。这个步骤需要 GitLab(自托管或 SaaS)和您在 GitLab 中安装 Kubernetes 集群的首选云供应商的帐户。

GitLab 的社区版包括自动构建、自动测试、自动审阅应用程序、自动部署和自动监控功能。除了这些功能之外,基于订阅的 GitLab 的 SaaS 版本还根据您的订阅计划提供自动代码质量、自动静态应用程序安全测试(SAST)、自动依赖扫描、自动许可合规性、自动容器扫描、自动动态应用程序安全测试(DAST)和自动浏览器性能测试功能。

确保您已经按照第二章在 Kubernetes 上操作应用程序中的说明进行操作,并部署了自托管的 GitLab。

如果您愿意,您也可以使用 GitLab 提供的 SaaS 服务。在这种情况下,请访问 GitLab 网站about.gitlab.com/free-trial/并登录您的帐户。

GitLab Auto DevOps 支持 GKE 在任何公共或私有云上创建新的 Kubernetes 集群,以及现有集群。

如何做…

这一部分进一步分为以下子部分,以使这个过程更容易:

  • 使用模板创建项目

  • 从 GitHub 导入现有项目

  • 启用 Auto DevOps

  • 启用 Kubernetes 集群集成

  • 使用 Auto DevOps 创建流水线

  • 逐步将应用程序推向生产环境

使用模板创建项目

GitLab 上的大部分操作都是在项目上完成的。当您第一次启动项目时,您有几个选项。您可以使用项目模板之一创建项目,导入现有项目,或者启动一个空白项目。在本教程中,您将学习如何使用项目模板创建项目,具体步骤如下:

  1. 使用非根用户账户登录 GitLab。

  2. 在欢迎使用 GitLab 屏幕上点击“创建项目”按钮:

  1. 选择“从模板创建”选项卡,并通过点击“使用模板”按钮选择列出的代码模板之一。在本例中,我们将使用以下 Pages/GitBook 模板:

  1. GitLab 项目可以是私有的、内部的或公开的。项目访问级别由项目中的可见性字段确定。给您的新项目命名,并将可见性级别设置为公开:

  1. 点击“创建项目”按钮。

现在,您将看到模板项目已成功导入。

从 GitHub 导入现有项目

并非总是可以从干净的项目模板开始。通常情况下,您需要为现有项目创建一个流水线。让我们执行以下步骤,将一些现有项目源代码添加到 GitLab 环境中:

  1. 使用非根用户账户登录 GitLab。

  2. 如果您还没有项目,请在欢迎使用 GitLab 屏幕上点击“创建项目”按钮。如果您之前创建过项目,请在以下视图的右上角点击“新项目”按钮:

  1. GitLab 可以从各种 Git 仓库导入项目,包括 GitHub、Bitbucket、Google Code、Fogbugz、Gitea 和 GitLab 本身。在这里,选择“导入项目”选项卡,并选择 GitHub:

  1. 在新窗口中打开github.com/settings/tokens,然后转到您的 GitHub 账户。

  2. 在您的 GitHub 账户上点击“生成新令牌”。

  3. 为了让 GitLab 能够访问您的 GitHub 账户,需要创建一个访问令牌。在新的个人访问令牌页面上,选择 repo 范围,然后点击“生成令牌”按钮。该页面显示了您可以使用令牌分配的权限:

  1. 复制在 GitHub 上创建的新个人访问令牌,粘贴到 GitLab 中,并单击“列出您的 GitHub 存储库”按钮:

  1. GitLab 将访问并发现您的 GitHub 存储库位置中的项目。导入您想要与此配方一起使用的存储库。在此示例中,我们将使用来自github.com/k8sdevopscookbook/auto-devops-example存储库的项目。这是本书中所有示例的位置:

导入完成后,状态将显示“完成”。最后,单击“转到项目”按钮以在 GitLab 中查看您的项目。

启用 Auto DevOps

GitLab 的 Auto DevOps 功能提供了预定义的 CI/CD 配置,可以自动检测、构建、测试、部署和监控您的应用程序。让我们执行以下步骤,为现有项目启用 Auto DevOps 选项:

  1. 使用您的项目用户帐户登录。

  2. 在 GitLab 欢迎屏幕上,您将看到一些链接,可以帮助您入门。在这里,单击“配置 GitLab”按钮以访问配置选项:

  1. 只有具有维护者和管理员权限的项目用户才能访问项目设置。从屏幕左侧的管理区域菜单中,选择设置|CI/CD 菜单以访问 CI/CD 选项。以下屏幕截图显示了 CI/CD 设置的位置:

  1. 在以下持续集成和部署页面下,确保为所有项目默认使用 Auto DevOps 流水线的复选框已被选中。如果要使用自动审阅应用程序和自动部署功能,可以选择输入基本域:

  1. 单击“保存更改”按钮。

启用 Kubernetes 集成

GitLab 与 Kubernetes 一起工作或在其中以多种方式。让我们执行以下步骤,并添加 Kubernetes 自动化,以便我们可以在多个项目之间共享集群:

  1. 以 root 用户身份登录。

  2. 在“您的项目”页面下选择一个项目。

  3. 从项目的详细信息页面,单击“添加 Kubernetes 集群”按钮:

  1. 您可以在 GKE 上创建一个新的集群,也可以添加一个现有的集群。假设您已经按照第一章中的配方创建了一个集群,构建生产就绪的 Kubernetes 集群,我们将添加一个现有的集群。在下面截图中显示的视图上,选择“添加现有集群”选项卡:

  1. 输入 Kubernetes 集群名称。在我们的示例中,这是AWSCluster

  2. 从已配置kubectl实例的命令行中,以便您可以访问现有的 Kubernetes 集群,使用以下命令获取 API URL:

$ kubectl cluster-info | grep 'Kubernetes master' | awk '/http/ {print $NF}'
  1. 为了让 GitLab 能够使用 API 访问您的集群,需要一个认证令牌。Kubernetes 将default-token存储为一个秘密。使用以下命令列出您集群上的秘密来找到该令牌:
$ kubectl get secrets | grep default-token
default-token-75958 kubernetes.io/service-account-token 3 4d12h
  1. 使用前一个命令返回的令牌名称并获取 CA 证书:
$ kubectl get secret <secret name> -o jsonpath="{['data']['ca\.crt']}" | base64 --decode
-----BEGIN CERTIFICATE-----
MID...h5x
-----END CERTIFICATE-----
  1. 在您的集群上创建名为ServiceAccount的 GitLab 管理员:
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
 name: gitlab-admin
 namespace: kube-system
EOF
  1. 在您的集群上创建名为ClusterRoleBinding的 GitLab 管理员:
cat <<EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
 name: gitlab-admin
roleRef:
 apiGroup: rbac.authorization.k8s.io
 kind: ClusterRole
 name: cluster-admin
subjects:
- kind: ServiceAccount
 name: gitlab-admin
 namespace: kube-system
EOF
  1. 获取服务账户令牌。以下命令将在“令牌”部分返回您的令牌:
$ kubectl -n kube-system describe secret $(kubectl -n kube-system get secret | grep gitlab-admin | awk '{print $1}')

Name: gitlab-admin-token-xkvss
...
Data
====
ca.crt: 1119 bytes
namespace: 11 bytes
token: 
<your_token_here>
  1. 一旦您从步骤 11的输出中复制了令牌信息,请在同一窗口上点击“添加 Kubernetes 集群”按钮。您应该看到类似以下视图的东西,这是我们将集群添加到 GitLab 的地方:

  1. 接下来,输入您的基础域名。在我们的示例中,我们使用k8s.containerized.me子域作为我们托管区域,我们在第一章中创建了构建生产就绪的 Kubernetes 集群中的在 Amazon EC2 上配置 Kubernetes 集群配方。

  2. 单击 Helm Tiller 旁边的“安装”按钮。此选项将在您的集群中部署 Helm 服务器:

  1. 安装 Helm 后,通过单击这些选项旁边的“安装”按钮来安装 Ingress、Cert-Manager、Prometheus 和 GitLab Runner。

  2. 所有 GitLab 管理的应用都安装在gitlab-managed-apps命名空间下。验证它们在您的 Kubernetes 集群上处于Running状态。您应该看到类似以下的 Pod 列表:

$ kubectl get pods -n gitlab-managed-apps
NAME                                                   READY STATUS  RESTARTS AGE
certmanager-cert-manager-574b6d6cdd-s87kn              1/1   Running 0        3m39s
ingress-nginx-ingress-controller-7d44688bf-8x7ld       1/1   Running 0        4m39s
ingress-nginx-ingress-default-backend-66645696bf-sz545 1/1   Running 0        4m39s
prometheus-kube-state-metrics-744949b679-2rwnh         1/1   Running 0        2m8s
prometheus-prometheus-server-646888949c-j4wn7          2/2   Running 0        2m8s
runner-gitlab-runner-84fc959dcf-4wxfc                  1/1   Running 0        56s
tiller-deploy-5d76d4796c-fdtxz                         1/1   Running 0        7m13s

使用 Auto DevOps 创建流水线

启用 Auto DevOps 后,它简化了软件开发生命周期的设置和执行。让我们执行以下步骤来利用 Auto DevOps 并创建我们的第一个自动化流水线:

  1. 如果您有多个项目,您需要选择目标项目,您想要在其中运行您的流水线。首先,在“您的项目”页面中选择您的项目。

  2. 在 CI/CD 菜单下点击流水线。此选项将带您到可以查看现有流水线的页面。在此页面上,单击“运行流水线”按钮。此选项将帮助我们手动运行流水线:

  1. 在这里,您可以选择在不同分支上运行流水线的选项。在本例中,选择主分支来运行流水线。在下面的截图中,您可以看到流水线阶段已完成:

当流水线完成时,您将看到已执行的每个作业的结果,并且您的应用程序应该可以在http://application_name.your_domain.com访问。在我们的案例中,这个地址是http://murat-auto-devops.k8s.containerized.me

逐步将应用程序部署到生产环境

默认情况下,Auto DevOps 使用连续部署到生产策略。如果您想将该设置更改为执行增量部署,请执行以下步骤:

  1. 在“您的项目”页面中选择您的项目。

  2. 在设置菜单中点击 CI/CD。

  3. 通过单击“展开”按钮展开 Auto DevOps 部分。

  4. 将部署策略更改为自动部署到暂存,手动部署到生产,并单击“保存更改”按钮。您还将看到其他 Auto DevOps 选项:

  1. 在 CI/CD 菜单下点击流水线。单击“运行流水线”按钮手动运行流水线。

  2. 当暂存作业完成时,流水线将被暂停。您将看到已执行的每个作业的结果,并且您的应用程序应该可以在http://application-name-staging.your_domain.com访问。在我们的案例中,这个地址是http://murat-auto-devops-staging.k8s.containerized.me

  3. 现在,在运维菜单下点击“环境”。

  4. 一旦您的应用程序处于暂存环境中,您可以逐渐将其移入生产环境。在暂存环境中,单击“部署到”按钮(看起来像播放按钮的那个)并选择要推出的百分比,如下视图所示。在下拉菜单中,您将看到 10%、25%、50%和 100%的选项:

它是如何工作的...

前面的教程使用 Auto DevOps 创建流水线向您展示了如何利用 Auto DevOps 的功能来简化流水线的创建。

步骤 2中,运行流水线后,当项目中找不到.gitlab-ci.yml文件时,GitLab Auto DevOps 会为您节省时间和精力,因为它会自动创建阶段和作业。这个文件由 GitLab 创建,为所有没有该文件的项目提供 CI/CD 配置。

如果您喜欢使用.gitlab-ci.yaml文件,可以禁用 Auto DevOps,并在项目上使用“设置 CI/CD”按钮来从模板创建您的 GitLab CI/CD YAML 文件。请参阅创建一个简单的.gitlab-ci.yaml文件部分中的链接,以了解更多关于创建 YAML 文件的信息。

步骤 3中,Auto DevOps 使用 Herokuish Buildpacks,这是一个在容器中模拟 Heroku 构建和运行任务的工具。通过使用 Herokuish,GitLab 可以检测项目所使用的语言,并自动创建流水线。

还有更多...

您还将受益于了解以下内容:

  • GitLab Web IDE

  • 监控环境

GitLab Web IDE

GitLab 不仅是一个 CI/CD 解决方案,它还具有许多其他功能,并为您提供类似 GitHub 的私人代码存储库。您可以使用 GitLab Web IDE 来编辑和提交更改,并将其推送到生产环境。要在不克隆到自己的机器上编辑代码,请执行以下步骤:

  1. 在“您的项目”页面上选择您的项目。

  2. 单击 Web IDE 按钮。

  3. 从存储库中选择一个文件进行编辑。

  4. 编辑文件,完成后,单击“提交...”按钮,如下截图所示:

  1. 创建提交消息,然后单击“暂存并提交”按钮,如下截图所示:

您的提交将触发新的流水线。因此,GitLab 将构建、测试和部署您的更改。

监控环境

使用 GitLab,您可以监控 Kubernetes 集群资源使用情况和应用程序响应指标。如果您还没有在 Kubernetes 集群上启用 Prometheus,请按照启用 Kubernetes 集群集成的说明进行操作,然后执行以下步骤:

  1. 在 Your Projects 页面上选择您的项目。

  2. 在操作菜单中点击 Metrics。

  3. 从下拉菜单中选择 Production 环境。在下拉菜单上,您将有生产和暂存环境:

  1. GitLab 将显示一个类似以下内容的页面,其中包含您的应用程序性能数据和 Kubernetes 资源利用率指标的最近 8 小时。在这个视图中,您将能够看到应用程序的历史平均 CPU 和内存利用率以及总利用率:

现在,您知道如何在 GitLab 上创建项目,并使用 Auto DevOps 功能来自动创建 CI/CD 流水线。

另请参阅

在 CircleCI 中创建 CI/CD 流水线

在本节中,我们将介绍使用 CircleCI 部署和管理 Kubernetes 服务的初始配置和要求。您将学习如何创建一个流水线,以便构建容器镜像并将其存储在容器注册表中。

准备工作

这个教程需要一个活跃的 GitHub 账户和一个要构建的项目。我们将使用 AWS EKS 来演示与 CircleCI 的 CI。

首先,访问我们的演示应用程序项目的以下 GitHub 页面,并将其复制到您的 GitHub 帐户中:

$ git clone https://github.com/k8sdevopscookbook/circleci-demo-aws-eks.git

克隆k8sdevopscookbook/circleci-demo-aws-eks存储库到您的工作站,以便在github.com/k8sdevopscookbook/circleci-demo-aws-eks上使用circleci-demo-aws-eks示例。

如何做...

该部分进一步分为以下子部分,以使该过程更容易:

  • 开始使用 CircleCI

  • 将更改部署到 Amazon EKS 上的 Kubernetes 集群

开始使用 CircleCI

Circle CI 是一个持续集成平台,可以在干净的容器或虚拟机中自动运行您的构建,从而可以直接测试存储在您的存储库中的代码以进行每次提交。 CircleCI 可以作为 SaaS 解决方案在云中使用,也可以作为自托管解决方案安装在您的环境中。让我们执行以下步骤来开始使用 CircleCI 的云版本:

  1. 使用您的 GitHub 帐户在circleci.com/signup/注册 CircleCI。

  2. 注册后,在仪表板视图的左侧点击“添加项目”按钮:

  1. 从左上角的下拉菜单中,选择要构建项目的 GitHub 帐户。

将更改部署到 EKS 上的 Kubernetes 集群

在这个示例中,我们将使用 Amazon EKS。让我们执行以下步骤来开始:

  1. 为 CircleCI 创建一个新的 AWS IAM 用户,并注意您的新用户的访问密钥 ID 和秘密访问密钥。

  2. 在 AWS 弹性容器注册表 ECR 上创建名为eks_orb_demo_app的存储库。注意您的 ECR URL。它应该类似于1234567890.dkr.ecr.us-east-2.amazonaws.com

  3. 确保您已登录 Circle CI。点击“添加项目”按钮,搜索demo-aws关键字,然后点击其旁边的“设置项目”按钮:

  1. 点击构建。构建将失败,因为缺少访问您的 AWS 帐户的环境变量。

  2. 点击项目设置。转到“构建设置”下的“环境变量”页面。通过单击“添加变量”按钮创建以下四个变量:

AWS_DEFAULT_REGION = us-east-2
AWS_ACCESS_KEY_ID = [Enter your Access key ID here]
AWS_SECRET_ACCESS_KEY = [Enter your Secret Access Key here]
AWS_ECR_URL = [Enter your ECR URL here**]** 

此输出可以在以下截图中看到:

  1. 设置环境变量将允许您的流水线访问 AWS 资源。在定义了云变量之后,点击“构建”按钮开始构建。

  2. 如果您的 AWS 用户没有所需的权限,构建可能会失败;否则,这应该在 35-40 分钟内成功完成。

它是如何工作的...

这个教程向您展示了如何快速创建一个在 Kubernetes 集群上运行的演示应用程序的 CI/CD 流水线。

步骤 2中的在 EKS 上部署 Kubernetes 集群的更改教程中,我们在 AWS ECR 上创建了一个存储库,用于推送由 CircleCI 构建的容器映像。构建成功后,这些映像将被保存并可以通过私有注册表位置访问。

步骤 6中,当我们运行流水线时,CircleCI 将按顺序执行六个作业。第一个作业(build-and-push-image)将启动一个虚拟机,检出我们的代码,安装任何先决条件,并从代码构建镜像。第二个作业(aws-eks/create-cluster)将使用 CloudFormation 堆栈创建一个 EKS 集群,并验证该集群。第三个作业(deploy-application)将部署应用程序。第四个作业(test-application)将使用kubectl get service demoapp命令获取服务的外部 IP,并连接到服务以验证返回。服务将返回一个类似于以下内容的页面:

Hello World! (Version info: 63d25fd14ef8dfb1c718cf81a815b36d80138d19, build date: 20190820224253)

最后,第五个(undeploy-application)和第六个(aws-eks/delete-cluster)作业将分别删除应用程序并再次使用 CloudFormation 销毁 EKS 集群。

通过这样,您已经学会了如何使用在 CircleCI 上部署的预定义容器环境轻松构建您的应用程序。

另请参阅

使用 GitHub Actions 设置 CI/CD 流水线

GitHub Actions 使您能够直接在 GitHub 存储库中创建自定义软件开发工作流程。如果您已经将 GitHub 作为您的代码存储库,内置的 CI/CD 功能使这个选项非常具有吸引力。

在本节中,我们将介绍 GitHub Actions 工作流配置和内置的 CI/CD 功能。您将学习如何管理工作流程并创建新的 GitHub Actions。

准备工作

在下一个示例中,您将学习如何通过添加 Dockerfile 在您拥有的存储库中创建一个基本的操作示例。此示例需要一个活跃的 GitHub 帐户和一个要构建的项目。我们将使用 AWS EKS 来演示与 GitHub 的 CI。

如何做...:

此部分进一步分为以下子部分,以使此过程更加简单:

  • 创建工作流文件

  • 创建基本的 Docker 构建工作流程

  • 构建并将镜像发布到 Docker Registry

  • 添加工作流状态徽章

创建一个工作流文件

GitHub flow 是 GitHub 最近推出的一个轻量级分支。让我们执行以下步骤来创建我们的第一个工作流程:

  1. 登录到github.com/的 GitHub 帐户。

  2. 选择一个您拥有维护者访问权限的存储库。在我们的示例中,我们正在使用k8sdevopscookbook/python-flask-docker项目的分支。

  3. .github/workflows目录中创建一个ci.yml文件,内容如下:

name: My Application
on:
 pull_request:
 branches:
 - master
jobs:
 build:
 runs-on: ubuntu-16.04
 steps:
 - uses: actions/checkout@v1
 - name: Set up Python 3.7
 uses: actions/setup-python@v1
 with:
 python-version: 3.7
  1. 添加以下行以安装任何依赖项:
 - name: Install dependencies
 run: |
 python -m pip install --upgrade pip
 pip install -r requirements.txt 
  1. 在使用计算机编程语言时,会使用 lint 工具对源代码进行静态分析,以检查语义差异。在我们的示例中,我们将使用flake8来使用以下命令对我们的 Python 代码进行 lint:
 - name: Lint with flake8
 run: |
 pip install flake8
 # stop the build if there are Python syntax errors or undefined names
 flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics
 # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
 flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
  1. 如果您有单元测试,请添加以下行来使用pytest测试您的应用程序,pytest是 Python 编程中用于编写小型测试的框架:
- name: Test with pytest
 run: |
 pip install pytest
 pytest
  1. 配置完成后,向存储库发送拉取请求以触发流水线:

流水线完成后,您将能够在拉取请求PR)上看到一个绿色的复选标记。在上面的屏幕截图中,您可以看到所有检查都已通过,并且拉取请求成功。

创建基本的 Docker 构建工作流程

让我们执行以下步骤,直接从我们的 GitHub 存储库自动化 Docker 镜像构建:

  1. 登录到您的 GitHub 帐户。

  2. 选择一个你有维护者访问权限的存储库。在我们的示例中,我们正在使用k8sdevopscookbook/python-flask-docker项目的分支。

  3. 点击“Actions”选项卡。

  4. 在这里,点击“添加新的工作流程”。

  5. .github/workflows目录下创建一个dockerimage.yml文件,内容如下:

name: Docker Image CI
on: [push]
jobs:
 build: 
 runs-on: ubuntu-latest 
 steps:
 - uses: actions/checkout@v1
 - name: Build the Docker image
 run: docker build . --file Dockerfile --tag my-image-name:$(date +%s)

每次将新代码推送到存储库时,工作流都会创建一个新的 Docker 图像。

构建并发布图像到 Docker Registry

您可以使用一个操作一次性完成构建、标记、登录和推送到 Docker 存储库,而不是创建多个操作。让我们执行以下步骤:

  1. 登录到您的 GitHub 帐户。

  2. 选择一个你有维护者访问权限的存储库。在我们的示例中,我们正在使用k8sdevopscookbook/python-flask-docker项目的分支。

  3. 点击“Actions”选项卡。

  4. 从这里,点击“添加新的工作流程”。

  5. .github/workflows目录下创建一个dockerpush.yml文件,内容如下。确保更改MyDockerRepo/repository,以便使用您想要推送的图像的名称:

name: Build and Push to DockerHub
on: [push]
jobs:
 build:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@master
    - name: Publish to Registry
      uses: elgohr/Publish-Docker-Github-Action@master
      with:
        name: MyDockerRepo/repository
        username: ${{ secrets.DOCKER_USERNAME }}
        password: ${{ secrets.DOCKER_PASSWORD }} 
  1. 点击“Settings”选项卡,转到“Secrets”菜单。

  2. 创建一个DOCKER_USERNAME秘密,其值等于您用于登录到 Docker Registry 的用户名。

  3. 创建一个DOCKER_PASSWORD秘密,其值等于您用于登录到 Docker Registry 的密码。创建了这两个秘密后,您应该能够在“Secrets”菜单中看到它们,如下截图所示:

作为秘密存储的环境变量将被加密,并且仅对选定的操作可用。

添加工作流状态徽章

许多在 GitHub 上的优秀源代码存储库在其主页上使用徽章来显示已在存储库上完成的各种测试的状态。同样,在这个教程中,我们将向我们的存储库添加一个操作状态摘要,以通知我们的访问者和用户当前的工作流状态:

  1. 登录到您的 GitHub 帐户,并选择一个您有维护者访问权限的存储库。在我们的示例中,我们正在使用k8sdevopscookbook/python-flask-docker项目的分支。

  2. 编辑存储库顶级目录中的README.md文件。

  3. 按照以下示例中显示的格式https://github.com/{owner}/{repo}/workflows/{workflow_name}/badge.svg添加徽章的链接:

[![Actions Status](https://github.com/muratkars/python-flask-docker/workflows/.github/workflows/dockerpush.yml/badge.svg)

另请参阅

在亚马逊网络服务上设置 CI/CD 流水线

在本节中,我们将介绍 AWS 上的 CI/CD 流水线构建工作流程和内置的 CI/CD 功能。您将学习如何管理流水线,如何在流水线步骤中运行构建命令,以及如何将构建结果图像存储在 Amazon 弹性容器注册表(ECR)上。

准备工作

在以下食谱中,您将学习如何基于 AWS 服务构建、测试和部署示例服务。这里提到的所有操作都需要一个 AWS 账户和一个具有使用相关服务权限的 AWS 用户策略,分配了 CodeCommit 的 HTTPS Git 凭据,并使用 AWS EKS 部署了 Kubernetes 集群。如果您没有,请访问aws.amazon.com/account/并创建一个。

如何做...

本节进一步分为以下子节,以使此过程更容易:

  • 创建 AWS CodeCommit 代码存储库

  • 使用 AWS CodeBuild 构建项目

  • 创建 AWS CodeDeploy 部署

  • 使用 AWS CodePipeline 创建流水线

创建 AWS CodeCommit 代码存储库

AWS CodeCommit 服务是一个托管的源代码控制服务,它在 AWS 平台上托管安全的基于 Git 的存储库。在这个食谱中,我们将学习如何在 CodeCommit 上创建我们的第一个存储库:

  1. 登录到您的 AWS 账户,并在us-west-2.console.aws.amazon.com/codesuite上打开 AWS 开发人员工具。

  2. 从开发人员工具菜单中,展开“源”菜单,然后单击“存储库”。您可以在以下截图中看到完整的菜单内容:

  1. 在存储库页面,单击“创建存储库”按钮,以在 CodeCommit 上启动您的代码存储库。

  2. 输入存储库名称,然后单击“创建”按钮。在本示例中,存储库名称为k8sdevopscookbook

  1. 从 AWS 管理控制台,转到 IAM 服务。

  2. 从现有用户列表中,选择一个您想要使用的 IAM 用户。

  3. 在用户摘要页面上,点击安全凭据选项卡。以下截图显示了选项卡的位置:

  1. 在 AWS CodeCommit 的 HTTPS Git 凭据下,点击生成按钮。这将创建一个我们稍后用于身份验证的用户名和密码:

  1. 在生成的 Git 凭据窗口中,点击下载凭据按钮以记录您的 CodeCommit 凭据。以下截图显示了为我创建的用户名和密码。这是您查看或复制凭据的唯一机会:

  1. 从 AWS 管理控制台,转到 CodeCommit 服务。

  2. 在克隆 URL 列下,选择 HTTPS。在本教程中,我们的示例存储库位于git-codecommit.us-west-2.amazonaws.com/v1/repos/k8sdevopscookbook

  3. 在您的 Linux 工作站上,克隆空的存储库:

$ git clone <your_new_repo>
  1. 使用您的 CodeCommit 凭据克隆存储库。

  2. 下载我们的示例应用程序并解压缩:

$ wget https://github.com/k8sdevopscookbook/python-flask-docker/archive/master.zip && unzip master.zip
  1. 现在,将示例应用程序复制到您的存储库克隆中:
$ cp -r python-flask-docker-master/. k8sdevopscookbook/.
$ cd k8sdevopscookbook
  1. 将所有文件进行分阶段。以下命令将在项目目录中找到所有新的和更新的文件,并将它们添加到暂存区,然后将其推送到目标存储库之前:
$ git add -A
  1. 用消息提交文件。以下命令在使用-m参数时添加提交:
$ git commit -m "Add example application files"
  1. 将文件从本地存储库文件夹推送到 CodeCommit 存储库:
$ git push

现在,您将能够查看 CodeCommit 存储库中的文件。

使用 AWS CodeBuild 构建项目

让我们执行以下步骤,从前面的教程中创建的 CodeCommit 存储库构建项目:

  1. 登录到您的 AWS 账户并打开 AWS 开发者工具us-west-2.console.aws.amazon.com/codesuite

  2. 从开发者工具菜单中,展开构建菜单并点击构建项目。以下截图显示了菜单的位置:

  1. 在构建项目页面上,点击创建构建项目按钮。以下截图显示了其他可用菜单选项和创建构建项目按钮的位置:

  1. 输入项目名称。

  2. 现在,我们将设置项目的主要来源。在源框中,选择 AWS CodeCommit 作为源提供程序。选择您在创建 AWS CodeCommit 代码存储库中创建的存储库。选择主分支。在我们的示例中,存储库的名称是k8sdevopscookbook

  1. 在环境框中,选择托管映像和 Ubuntu 作为您的操作系统。

  2. 选择新服务角色:

  1. 展开附加配置设置。添加AWS_DEFAULT_REGIONAWS_ACCOUNT_IDIMAGE_TAGIMAGE_REPO_NAME环境变量,如下截图所示:

永远不要将环境变量存储在存储库位置。在构建过程中始终使用环境参数来提供值。

  1. 在 Buildspec 框中,选择使用 buildspec 文件。确保buildspec.yaml文件存在于代码存储库的根目录中。此文件应该看起来像这样:
version: 0.2
phases:
 install:
 runtime-versions:
 docker: 18
 pre_build:
 commands:
 - echo Logging in to Amazon ECR...
 - $(aws ecr get-login --no-include-email --region $AWS_DEFAULT_REGION)
 build:
 commands:
 - echo Build started on `date`
 - echo Building the Docker image...
 - docker build -t $IMAGE_REPO_NAME:$IMAGE_TAG .
...
  1. 最后,单击创建构建项目。

  2. 身份和访问管理(IAM)中找到您在步骤 7中创建的服务角色,并将此语句添加到附加到 CodeBuild 服务角色的策略中:

{
  "Version": "2012-10-17"
  "Statement": [ *### BEGIN ADDING STATEMENT HERE ###* {       "Action": [
         "ecr:BatchCheckLayerAvailability",
         "ecr:CompleteLayerUpload",
         "ecr:GetAuthorizationToken",
         "ecr:InitiateLayerUpload",
         "ecr:PutImage",
         "ecr:UploadLayerPart"       ],
       "Resource": "*",
       "Effect": "Allow"
     }, *### END ADDING STATEMENT HERE ###* ...   ],
 }
  1. 现在项目准备就绪,单击页面右上角的开始构建按钮。在下图中,您可以在启动后的构建历史选项卡下查看其状态。在我们的示例中,它显示构建成功:

如果您的构建失败,请确保AmazonEC2ContainerRegistryPowerUser策略已分配给您的 IAM 角色。

创建 AWS CodeDeploy 部署

让我们执行以下步骤来从 CodeBuild 构建创建部署:

  1. 登录到您的 AWS 帐户,并在us-west-2.console.aws.amazon.com/codesuite上打开 AWS 开发人员工具。

  2. 从开发者工具菜单中,展开部署菜单,然后单击应用程序。

  3. 单击创建应用程序按钮:

  1. 输入应用程序名称。

  2. 选择 AWS Lambda 作为计算平台。

使用 AWS CodePipeline 构建流水线

最后,我们已经到达了 AWS 开发人员工具的最后阶段。让我们执行以下步骤,使用 AWS CodePipeline 服务构建管道:

  1. 登录到您的 AWS 帐户,并在us-west-2.console.aws.amazon.com/codesuite中打开 AWS 开发人员工具。

  2. 从开发人员工具菜单中,展开“管道”菜单,然后单击“管道”。

  3. 输入管道名称。

  4. 选择“新服务角色”,然后单击“下一步”。

  5. 现在,我们将设置管道的主要来源。选择 AWS CodeCommit 作为源提供程序。选择您在“创建 AWS CodeCommit 代码存储库”配方中创建的存储库。单击“下一步”以确认这些更改。以下屏幕截图显示,在我们的示例中,源是k8sdevopscookbook

  1. 选择 AWS CodeBuild 作为构建提供程序。选择您在“使用 AWS CodeBuild 构建项目”配方中创建的项目名称(或创建一个新项目)。单击“下一步”以确认这些更改。以下屏幕截图显示,在我们的示例中,区域是“美国西部”,项目名称是 DevOpsCookbookExample:

  1. 单击“跳过部署阶段”。作为部署替代方案,您可以调用一个 Lambda 函数来调用 CloudFormation 模板并部署 Kubernetes 集群。您可以在“另请参阅”部分中找到显示如何执行此操作的 AWS CodeSuite 示例。

  2. 单击“创建管道”。

  3. 当管道执行完毕时,您将看到类似以下的构建:

通过这样,您已成功使用 AWS CodePipeline 服务构建了一个管道。

它是如何工作的...

这个配方向您展示了如何快速使用 AWS 开发人员工具创建管道。

在“使用 AWS CodePipeline 构建管道”配方中,在创建管道之后,AWS CodePipeline 会监视 AWS CodeCommit 中的更改。当新的 PR 合并到存储在您的 CodeCommit 存储库中的主分支时,CodePipeline 会自动检测到分支的更改并触发管道。

在构建作业期间,CodeBuild 将代码和 Docker 文件中描述的任何依赖项打包到 Docker 镜像中。此 Docker 镜像将推送到您在配方中指定的 Amazon ECR 容器注册表中。

该管道也是完全可扩展的。实际上,您还可以选择通过 AWS Lambda 调用无服务器函数,以创建 Kubernetes 集群或在现有 Kubernetes 集群上部署代码,以便进行测试。您可以在另请参阅部分提供的 AWS 博客链接中找到其他示例。

另请参阅

在 Google Cloud Build 上使用 Spinnaker 设置 CI/CD 管道

Google Cloud Build 是一个托管的 CI/CD 和部署平台,可让您在云中构建,测试和部署。在本节中,我们将介绍使用 Spinnaker 功能的 Google Cloud Build 配置的 CI/CD 管道,Spinnaker 是一个开源的多云持续交付平台。

准备工作

k8sdevopscookbook/src存储库克隆到您的工作站,以使用chapter3目录下的清单文件:

$ git clone https://github.com/k8sdevopscookbook/src.git
$ cd /src/chapter3

确保您有使用 GCP 服务的必要凭据,并且可以访问当前项目。如果您还没有,请转到console.cloud.google.com并创建一个帐户。

如何做...

本节进一步分为以下子节,以使这个过程更容易:

  • 安装和配置 Spin CLI

  • 为 CI/CD 配置服务账户

  • 配置事件以触发流水线

  • 使用 Helm 安装 Spinnaker

  • 创建 Google Cloud 源代码仓库

  • 使用 Google Cloud Build 构建项目

  • 配置 Spinnaker 流水线

  • 将应用程序部署到生产环境

安装和配置 Spin CLI

以下配方中提到的操作需要spin CLI、gcloud和启用计费的 GCP 项目的账户。我们将使用gcloud CLI 来启用相关的 API:

  1. 运行以下命令下载gcloud CLI。如果您已经安装了gcloud CLI 并且已经有一个项目,请跳到步骤 4
$ curl https://sdk.cloud.google.com | bash
  1. 初始化 SDK 并按照给定的说明进行操作:
$ gcloud init
  1. 选择您有权限的项目或创建一个新项目。

  2. 为项目启用 Kubernetes Engine API、Cloud Build API 和 Cloud Source Repositories API:

$ gcloud services enable compute.googleapis.com cloudapis.googleapis.com sourcerepo.googleapis.com
Operation "operations/acf.d1f2c714-9258-4784-a8a9-6648ab4c59fe" finished successfully.
  1. 下载并安装spin CLI:
$ curl -LO \
https://storage.googleapis.com/spinnaker-artifacts/spin/$(curl -s \
https://storage.googleapis.com/spinnaker-artifacts/spin/latest)/linux/amd64/spin
$ chmod +x spin
$ sudo mv spin /usr/local/bin/spin

现在您已经启用了 GCP 服务并安装了spin CLI。

为 CI/CD 配置服务账户

要在 Google Cloud 上使用 CI/CD 服务,您的用户需要被分配正确的权限。让我们执行以下步骤来为 CI/CD 配置服务账户:

  1. 按照第一章中在 GKE 上配置托管的 Kubernetes 集群配方中的说明,部署一个 GKE 集群。如果您已经有一个,请跳到步骤 2创建一个稍后流水线将使用的服务账户
$ gcloud iam service-accounts create cicd-account \
--display-name "My CICD Service Account"
  1. 在两个地方用您的项目名称替换以下的devopscookbook,并将存储管理员角色绑定到您的服务账户:
$ gcloud projects \
 add-iam-policy-binding \
 devopscookbook --role \
 roles/storage.admin --member \
 serviceAccount:cicd-account@devopscookbook.iam.gserviceaccount.com
  1. 存储您的cicd-account密钥:
$ gcloud iam service-accounts keys \
 create cicd-key.json \
 --iam-account cicd-account@devopscookbook.iam.gserviceaccount.com

通过这样,您已经为您的服务账户分配了权限。

配置事件以触发流水线

Google Pub/Sub 是一个云服务,最好描述为 Kafka 或 Rabbit MQ 的托管版本。我们将使用 Google Pub/Sub 在容器注册表中检测到变化时发送通知。让我们执行以下步骤:

  1. 使用以下gcloud命令创建 Cloud Pub/Sub 主题:
$ gcloud pubsub topics create projects/devopscookbook/topics/gcrgcloud pubsub topics create projects/devopscookbook/topics/gcr
Created topic [projects/devopscookbook/topics/gcrgcloud].
Created topic [projects/devopscookbook/topics/pubsub].
Created topic [projects/devopscookbook/topics/topics].
Created topic [projects/devopscookbook/topics/create].
Created topic [projects/devopscookbook/topics/gcr].
  1. 创建一个pubsub订阅。以下命令应返回一个类似于Created subscription的消息:
$ gcloud pubsub subscriptions create gcr-triggers --topic projects/devopscookbook/topics/gcr
Created subscription [projects/devopscookbook/subscriptions/gcr-triggers].
  1. 在两个地方用您的项目名称替换以下的devopscookbook,并为您的 CI/CD 服务帐户cicd-account添加权限:
$ gcloud pubsub subscriptions add-iam-policy-binding \
 gcr-triggers --role roles/pubsub.subscriber \
 --member serviceAccount:cicd-account@devopscookbook.iam.gserviceaccount.com

有了这个,您已经学会了如何配置事件来触发管道。

使用 Helm 部署 Spinnaker

让我们执行以下步骤,使用 Helm 图表部署 Spinnaker 工具:

  1. 验证helm是否已安装并在您的 GKE 集群上初始化。如果没有,请按照第二章中的说明,在使用 Helm 图表部署工作负载中安装 Helm。如果在您的集群上安装了 Helm,以下命令将返回 Helm 的客户端和服务器:
$ helm version --short
Client: v2.14.3+g0e7f3b6
Server: v2.14.3+g0e7f3b6
  1. ci-admin服务帐户创建clusterrolebinding
$ kubectl create clusterrolebinding \
 --clusterrole=cluster-admin \
 --serviceaccount=default:default \
 ci-admin
  1. 使用以下命令创建一个管道配置存储桶。确保用唯一名称替换devopscookbook-ci-config存储桶名称。这将在 Google Cloud 存储上创建一个对象存储桶:
$ gsutil mb -c regional -l us-central1 gs://devopscookbook-ci-config
  1. 创建一个包含cicd-account密钥内容的变量:
$ export CICDKEY_JSON=$(cat cicd-key.json)
  1. 编辑cd /src/chapter3/gcp目录中的spinnaker-config.yaml文件,并用您在步骤 3中使用的存储桶名称替换以下存储桶名称:
gcs:
 enabled: true
 bucket: devopscookbook-ci-config
 project: devopscookbok
 jsonKey: '$CICDKEY_JSON'
...
  1. 使用自定义的spinnaker-config.yaml文件在K 步骤 5上部署 Spinnaker 到您的 Kubernetes 集群:
$ helm install -n cd stable/spinnaker -f \
 spinnaker-config.yaml --timeout 600 --wait
  1. 创建端口转发隧道以访问 Spinnaker UI:
$ export DECK_POD=$(kubectl get pods --namespace default -l "cluster=spin-deck" -o jsonpath="{.items[0].metadata.name}")
$ kubectl port-forward --namespace default $DECK_POD 8080:9000 >> /dev/null &
$ export GATE_POD=$(kubectl get pods --namespace default -l "cluster=spin-gate" -o jsonpath="{.items[0].metadata.name}")
$ kubectl port-forward --namespace default $GATE_POD 8084

为了能够访问 Spinnaker UI,我们为我们的工作站创建了端口转发隧道。我们也可以创建一个云负载均衡器来向互联网开放端口,但端口转发更安全。

创建 Google Cloud 源代码存储库

让我们执行以下步骤,在 Google Cloud 源代码服务上创建一个代码存储库:

  1. 下载我们的示例应用并提取它:
$ wget https://github.com/k8sdevopscookbook/src/raw/master/chapter3/gcp/sample-app-v2.tgz && tar xzfv sample-app-v2.tgz  
  1. 提取示例代码后,切换到我们的源代码目录:
$ cd sample-app
  1. 使用以下命令对您的存储库进行初始提交:
$ git init && git add . && git commit -m "Initial commit"
  1. 创建名为sample-app的 Google Cloud 代码存储库:
$ gcloud source repos create sample-app
  1. 为 Google Cloud 存储库设置credential.helper
$ git config credential.helper gcloud.sh
  1. 用您的项目名称替换devopscookbook。将您的新存储库添加为remote并推送您的代码:
$ git remote add origin https://source.developers.google.com/p/devopscookbook/r/sample-app
$ git push origin master
  1. 现在,您将能够在 Google Cloud 源代码存储库中查看sample-app存储库中的文件,如下面的屏幕截图所示:

通过这样,您已经学会了如何在 Google Cloud Source 上创建代码存储库。在下一个步骤中,我们将使用 Cloud Source 存储库位置来构建我们的项目。

使用 Google Cloud Build 构建项目

让我们执行以下步骤,从我们在上一个步骤中创建的 Cloud Source 存储库构建项目:

  1. 在这里,我们将使用 Cloud Build 产品来构建我们的项目。首先,登录到您的 GCP 帐户。从主产品菜单中,点击 Cloud Build。如下截图所示,它位于 TOOLS 下:

  1. 在 Cloud Build 菜单中,选择“触发器”,然后点击“创建触发器”按钮,如下截图所示:

  1. 我们的代码在 Cloud Source 存储库中,所以选择 Cloud Source 存储库,然后点击“继续”按钮。如您所见,其他选项是 Bitbucket 和 GitHub:

  1. 您的帐户上的存储库将被自动检测到。选择 sample-app 存储库,然后点击“继续”按钮:

  1. 设置以下设置,其他保持不变:
Name: devopscookbook-trigger-1
Trigger type: Tag
Tag (regex): v.*
Build configuration: Cloud Build configuration file (yaml or json)
  1. 点击“创建触发器”按钮。

  2. 切换回已配置为访问您的 Kubernetes 集群的kubectl命令行,并创建一个存储桶。在创建之前,请将devopscookbook-kubernetes-manifests存储桶名称更改为唯一的存储桶名称:

$ gsutil mb -l us-central1 gs://devopscookbook-kubernetes-manifests
  1. 步骤 6中创建的存储桶上启用存储桶版本控制。以下命令将在 Cloud Storage 上启用版本控制,并让存储桶保留对象的旧版本:
$ gsutil versioning set on gs://devopscookbook-kubernetes-manifests
  1. 如果您还没有在源代码文件夹中,切换到我们的源代码目录:
$ cd sample-app
  1. 将我们的 Kubernetes 部署清单文件中的项目 ID 更改为您的项目:
$ sed -i s/PROJECT/devopscookbook/g k8s/deployments/*
  1. 提交更改,并使用类似以下的有意义的提交消息:
$ git commit -a -m "Change placeholder project ID to devopscookbook"
  1. 为发布创建一个 Git 标签,并推送该标签:
$ git tag v1.0.0 && git push --tags
  1. 切换回浏览器,点击 Cloud Code 菜单中的“历史”,确认构建已被触发并成功:

通过这样,您已经学会了如何使用 Google Cloud Build 构建项目。

配置 Spinnaker 管道

让我们执行以下步骤,将您的配置上传到 Spinnaker:

  1. owner-email部分用您的电子邮件替换以下电子邮件,并使用以下命令在 Spinnaker 中创建所提供的应用程序:
$ spin application save \
--application-name sample \
--owner-email \
youremail@domain.com \
--cloud-providers kubernetes \
--gate-endpoint \
http://localhost:8080/gate
  1. 将示例流水线上传到 Spinnaker:
$ sed s/PROJECT/devopscookbook/g spinnaker/pipeline-deploy.json > pipeline.json
$ spin pipeline save --gate-endpoint http://localhost:8080/gate -f pipeline.json

上述命令将配置导出到名为pipeline.json的文件中,并将其上传到 Spinnaker。

将应用程序部署到生产环境

一旦应用程序部署到了暂存环境,下一步就是将其推广到生产环境。让我们执行以下步骤,将应用程序从暂存推广到 Spinnaker 上的生产环境:

  1. 在 Spinnaker UI 中,选择我们在配置 Spinnaker 流水线中创建的sample应用程序:

  1. 单击以下截图中显示的 PIPELINES 选项卡:

  1. 将鼠标悬停在橙色框上,然后单击“继续”按钮。如下截图所示,绿色框表示流水线的已完成部分,而橙色框表示流水线暂停的位置:

  1. 在 INFRASTRUCTURE 菜单下选择 LOAD BALANCERS。以下截图显示了 INFRASTRUCTURE 菜单:

  1. 单击服务 sample-frontend-production 负载均衡器下的 DEFAULT 按钮:

  1. 在详细信息窗格的右侧,找到 Ingress IP,并通过单击 IP 地址旁边的复制图标将其复制到剪贴板:

  1. 在浏览器中打开 IP 地址,确认生产应用程序是否可访问。您将看到一个类似以下视图的屏幕,显示 Pod 名称、节点名称及其版本:

有了这个,您就知道如何使用 Google Cloud Platform 服务和 Spinnaker 在 GKE 上创建您的 CI/CD 流水线。

另请参阅

在 Azure DevOps 上设置 CI/CD 流水线

Azure DevOps 提供版本控制、报告、自动构建以及项目/实验室/测试和发布管理功能。Azure DevOps 可作为 SaaS 或本地服务器产品提供。在本节中,我们将介绍 Azure DevOps 工作流配置和使用 SaaS 产品的内置 CI/CD 功能。您将学习如何管理工作流程并创建 Azure 管道。

做好准备

在以下示例中,您将学习如何通过添加一个 YAML 文件在您拥有的存储库中创建一个管道示例。此示例需要一个准备好进行构建的项目的活动 GitHub 帐户。我们将使用 AKS 来演示 Azure 管道的持续交付。

这里提到的所有操作都需要 Azure DevOps 帐户。如果您没有,请转到azure.microsoft.com/services/devops/并创建一个。在 Azure Kubernetes 服务上部署应用程序还需要活动的 Azure 云订阅。

如何做...

本节进一步分为以下子节,以使此过程更加简单:

  • 开始使用 Azure DevOps

  • 配置 Azure 管道

  • 将更改部署到 AKS 集群

开始使用 Azure DevOps

Azure DevOps 是由微软提供的一组 DevOps 工具,包括 CI/CD 和项目管理服务,如 Azure 管道、Azure 看板、Azure 工件、Azure 存储库和 Azure 测试计划。

在使用 Azure 管道之前,让我们执行以下步骤来创建我们的第一个项目:

  1. 登录到azure.microsoft.com/en-us/services/devops/的 Azure DevOps。

  2. 创建一个项目名称。

  3. 选择可见性。在我们的示例中,这被设置为公共:

  1. 单击“创建项目”按钮。

配置 Azure 管道

Azure 管道允许您使用任何语言、平台和云提供商进行 CI/CD 构建、测试和部署。让我们执行以下步骤,首次配置 Azure 管道:

  1. 登录到 Azure DevOps 帐户后,您将在左侧概述菜单中看到主要功能的链接。从概述菜单中,单击“管道”菜单。以下屏幕截图显示了“欢迎来到项目!”页面:

  1. 单击“创建管道”按钮。

  2. 作为管道创建过程的一部分,您需要设置代码存储库位置。您可以从任何 Git 存储库导入项目。在我们的示例中,我们将使用 GitHub 作为我们的存储库。以下截图显示了所有其他可用选项:

  1. 单击“授权 AzurePipelines”:

  1. 选择一个存储库并单击“批准并安装”:

  1. 现在,选择要配置管道的存储库。

  2. 选择 Docker 构建并推送镜像到 Azure 容器注册表。此选项将上传容器构件到 Azure 容器注册表服务。以下截图显示了我们将使用的 Docker 选项:

  1. 审查您的管道 YAML 并单击“保存并运行”以批准它。

  2. 您将看到管道。单击“构建作业”以查看其详细信息:

有了这个,您已经学会了如何配置 Azure 管道。

部署更改到 AKS 集群

让我们执行以下步骤:

  1. 登录到 Azure DevOps 帐户后,您将在左侧概述菜单中看到主要功能的链接。这次,从概述菜单中选择“管道”选项。如下截图所示,它是从顶部数起的第四个选项:

  1. 接下来,您需要创建一个管道。如下截图所示,显示了“管道”菜单。单击页面右上角的“新管道”按钮:

  1. 选择 GitHub 作为您的存储库。同样,在以下截图中,所有其他存储库选项都是可见的:

  1. 选择一个存储库并单击“批准并安装”。如下截图所示,我的存储库已被选中。在您的情况下,存储库名称将不同:

  1. 现在,选择要配置管道的存储库。

  2. 如下截图所示,您将获得预定义的配置管道的替代方案。在本例中,选择“部署到 Azure Kubernetes 服务”以构建并推送镜像到 Azure 容器注册表,并部署到 AKS:

  1. 选择您的 Azure 云订阅。

  2. 选择现有的 AKS 集群。

  3. 选择现有并在命名空间字段中选择默认。

  4. 输入您的容器注册表的名称。在下面的屏幕截图中,您可以看到我选择的选项。在您的情况下,容器注册表和镜像名称将不同:

  1. 单击“验证和配置”按钮。

  2. 审查您的流水线 YAML 并单击“保存并运行”以批准它。

  3. 您将看到流水线。单击“构建作业”以查看其详细信息:

在前面的屏幕截图中,我们简单的流水线只包括两个阶段。这些将在它是如何工作的...部分进行解释。

它是如何工作的...

这个教程向您展示了如何快速创建一个在 AKS 集群上运行的演示应用程序的 Azure DevOps CI/CD 流水线。

将更改部署到 AKS 集群教程中,在步骤 9之后,当我们构建作业时,Azure Pipelines 将创建您的流水线。它将创建以下两个阶段:

  1. 在第 1 阶段,即构建阶段,它创建一个 Docker 镜像并将图像推送到您的 Azure 容器注册表中。当成功时,您可以在 Azure 门户中找到存储在现有注册表中的新图像。例如,以下屏幕截图显示了作为我的流水线结果创建的图像在 Azure 容器注册表下以及其详细信息:

  1. 在第 2 阶段,即部署阶段,它创建图像拉取凭据以访问您的注册表,并将您的应用程序部署为部署。

应用程序将部署到您在流水线创建期间指定的命名空间中。

稍后,您可以创建多个环境,用于应用程序的不同阶段(预览、暂存和生产),并更改应用程序需要部署到流水线中的位置。

另请参阅

第四章:在 DevOps 中自动化测试

在本章中,我们将讨论在 DevOps 工作流中自动化测试,以加快生产时间,减少交付风险的损失,并使用已知的测试自动化工具在 Kubernetes 上检测服务异常。在本章的配方之后,您将学会预防已知缺陷,以及快速发现新缺陷,以减少服务停机时间。

在本章中,我们将涵盖以下配方:

  • 使用 StackStorm 构建事件驱动的自动化

  • 使用 Litmus 框架自动化测试

  • 使用 Gremlin 进行混沌工程自动化

  • 使用 Codacy 自动化您的代码审查

  • 使用 SonarQube 进行静态代码分析检测错误和反模式

  • 使用 Fossa 检测许可合规问题

技术要求

本节中的配方假定您已经通过遵循第一章中描述的推荐方法之一部署了一个功能性的 Kubernetes 集群,构建生产就绪的 Kubernetes 集群

Kubernetes 命令行工具kubectl将在本章的其余配方中使用,因为它是针对 Kubernetes 集群运行命令的主要命令行界面。我们还将使用helm,其中 Helm 图表可用于部署解决方案。

使用 StackStorm 构建事件驱动的自动化

StackStorm 是一个开源的、事件驱动的自动化平台。使用 GitOps 方法,它可以根据事件运行工作流。在本节中,我们将使用 Helm 图表在 Kubernetes 上以高可用配置部署 StackStorm,并开始部署规则、自定义传感器、操作和工作流的示例,执行任意自动化或补救任务。

准备就绪

确保您已经准备好一个 Kubernetes 集群,以及已经配置好kubectlhelm,以便您可以管理集群资源。

如何做…

本节进一步分为以下子节,以使这个过程更容易:

  • 安装 StackStorm

  • 访问 StackStorm UI

  • 使用 st2 CLI

  • 定义规则

  • 部署规则

安装 StackStorm

尽管 StackStorm 可以作为 Linux 系统的Red Hat Package Manager/Debian(RPM/Deb)分发,并作为 Docker 镜像,但如果您计划运行业务关键的自动化任务,建议在 Kubernetes 上部署 StackStorm 高可用性(HA)集群。

在本教程中,我们将学习如何按照以下步骤在 Kubernetes 上部署 StackStorm:

  1. 将 Helm 存储库添加到本地图表列表中:
$ helm repo add stackstorm https://helm.stackstorm.com/
  1. 使用 Helm 图表安装 StackStorm HA 集群。以下命令将部署 StackStorm 及其依赖项,如 MongoDB 和 RabbitMQ:
$ helm install stackstorm/stackstorm-ha --name=st2 --namespace=stackstorm
  1. 安装过程可能需要 2 到 3 分钟。确认已部署并运行发布:
$ helm ls st2
NAME REVISION  UPDATED                  STATUS   CHART                APP VERSION NAMESPACE
st2  1         Wed Oct 30 23:06:34 2019 DEPLOYED stackstorm-ha-0.22.0 3.2dev      stackstorm

现在,您的集群中正在运行 StackStorm。接下来,我们将访问 UI 或使用 CLI 与 StackStorm 进行交互。

访问 StackStorm UI

StackStorm Helm 安装假定您正在单节点 Minikube 集群中运行,并且随附的说明适用于较小的部署。我们正在一个具有多个节点的大型集群上运行 StackStorm。我们将外部公开 Web 服务器以访问 StackStorm UI。

让我们执行以下步骤来创建云负载均衡器,以便我们可以访问 StackStorm Web 界面:

  1. 创建负载均衡器。以下命令将通过您的云提供商创建负载均衡器并在端口80上公开 Web 服务:
$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
 name: st2-service
 namespace: stackstorm
spec:
 type: LoadBalancer
 ports:
 - port: 80
 targetPort: 80
 protocol: TCP
 selector:
 app: st2web
EOF
  1. 查找外部服务 IP。在以下示例中,我们使用了部署在 AWS 上的 Kubernetes 集群。尽管输出可能不同,但在其他平台上,以下命令应该产生相同的结果:
$ kubectl get svc st2-service -nstackstorm
NAME        TYPE         CLUSTER-IP    EXTERNAL-IP PORT(S) AGE
st2-service LoadBalancer 100.68.68.243 a022d6921df2411e9bd5e0a92289be87-2114318237.us-east-1.elb.amazonaws.com 80:31874/TCP 6m38s
  1. 在浏览器中打开步骤 2中的外部 IP 地址:

  1. 使用必要的凭据登录,即用户名为st2admin,密码为Ch@ngeMe

现在,您可以访问StackStorm界面。现在,我们将点击菜单项并在定义规则教程中创建我们的第一个规则之前探索操作。

使用 st2 CLI

如果我们想熟悉产品,StackStorm Web 界面很有用,但是,如果您要在生产中使用 StackStorm,则需要学习 CLI 命令。现在,执行以下步骤以从 pod 访问 st2 CLI:

  1. 查找 st2 客户端的 pod 名称:
$ export ST2CLIENT=$(kubectl get --namespace stackstorm pod -l app=st2client -o jsonpath="{.items[0].metadata.name}")
  1. 通过 st2 CLI 执行以下命令。此命令将从 pod 执行st2 --version命令:
$ kubectl exec -it ${ST2CLIENT} -n stackstorm -- st2 --version
st2 3.2dev (a643ba7), on Python 2.7.12
  1. 使用以下 CLI 命令对 StackStorm 进行身份验证,并使用-w参数保存密码。如果不想保存密码,则可以在末尾删除-w参数:
$ kubectl exec -it ${ST2CLIENT} -n stackstorm -- st2 login st2admin -p 'Ch@ngeMe' -w
Logged in as st2admin
  1. 列出核心包中可用的操作:
$ kubectl exec -it ${ST2CLIENT} -n stackstorm -- st2 action list --pack=core
  1. 列出核心包中的操作。您还可以尝试 Linux、ChatOps 和其他包选项:
$ kubectl exec -it ${ST2CLIENT} -n stackstorm -- st2 action list --pack=core

所有 StackStorm CLI 操作都可以通过 REST API、Python 和 JavaScript 绑定进行。您可以在另请参阅部分的StackStorm CLI 和 Python 客户端参考链接中找到更多信息。

定义规则

StackStorm 使用规则在事件发生时运行可用的操作。StackStorm 带有默认操作,并且可以通过从社区添加新操作来增加操作目录。按照以下步骤创建您的第一个规则:

  1. 规则以熟悉的 YAML 格式创建,由三个部分组成:触发器、条件和操作。在创建规则文件之前,我们将熟悉可以在规则中使用的可用触发器。使用以下命令列出可用的触发器:
$ kubectl exec -it ${ST2CLIENT} -n stackstorm -- st2 trigger list
  1. 检查 webhook 触发器的详细信息。以下命令将返回触发器的描述、参数和有效负载模式。检查parameters_schema,因为我们稍后将在示例规则中使用它:
$ kubectl exec -it ${ST2CLIENT} -n stackstorm -- st2 trigger get core.st2.webhook
...
| parameters_schema | {                                   |
|                   |      "additionalProperties": false, |
|                   |      "type": "object",              |
|                   |      "properties": {                |
|                   |          "url": {                   |
|                   |              "required": true,      |
|                   |              "type": "string"       |
...
  1. 使用以下命令列出可用的操作:
$ kubectl exec -it ${ST2CLIENT} -n stackstorm -- st2 action list
  1. 检查core.local操作的详细信息。此操作在本地主机上执行任意 Linux 命令。以下命令返回它可以接受的参数,如下所示:
$ kubectl exec -it ${ST2CLIENT} -n stackstorm -- st2 action get core.local
...
| parameters    | {                                               |
|               | "cmd": {                                        |
|               |     "required": true,                           |
|               |     "type": "string",                           |
|               |     "description": "Arbitrary Linux command to  |
|               | be executed on the local host."                 |
|               |     },                                          |
|               |     "sudo": {                                   |
|               |         "immutable": true                       |
|               |     }                                           |
|               | }                                               |
| metadata_file | actions/local.yaml                              |
...
  1. 让我们在规则中使用前面的触发器和操作,并设置一个 webhook 来监听https://{host}/api/v1/webhooks/sample的 URL,使用以下规则并创建一个first_rule.yaml文件。完成后,将文件复制到容器中。当向此 URL 发出 POST 请求时,操作将被触发:
$ cat > first_rule.yaml <<EOF
 name: "sample_rule_with_webhook"
 pack: "examples"
 description: "Sample rule dumping webhook payload to a file."
 enabled: true
 trigger:
 type: "core.st2.webhook"
 parameters:
 url: "sample"
 criteria:
 trigger.body.name:
 pattern: "st2"
 type: "equals"
 action:
 ref: "core.local"
 parameters:
 cmd: "echo \"{{trigger.body}}\" >> ~/st2.webhook_sample.out ; sync"
EOF

通过这样,您已经学会了如何查找和使用可用的操作和触发器来构建规则。接下来,我们将学习如何在 StackStorm 中运行它。

部署规则

StackStorm 规则可以通过其 UI、CLI 或 API 部署。在本教程中,我们将使用之前定义的规则,并使用以下步骤部署它:

  1. 使用我们在定义规则教程中创建的 YAML 文件创建规则:
$ kubectl exec -it ${ST2CLIENT} -n stackstorm -- st2 rule create first_rule.yaml
  1. 列出规则并确认新规则已创建。您应该在列表中看到examples.sample_rule_with_webhook规则,如下所示:
$ kubectl exec -it ${ST2CLIENT} -n stackstorm -- st2 rule list
+------------------+----------+-------------------------+---------+
| ref | pack | description | enabled |
+------------------+----------+-------------------------+---------+
| chatops.notify | chatops | Notification rule to | True |
| | | send results of action | |
| | | executions to stream | |
| | | for chatops | |
| examples.sample | examples | Sample rule dumping | True |
| rule_with_webhook| | webhook payload to a | |
| | | file. | |
+------------------+----------+-------------------------+---------+

通过我们在这里创建的新规则,webhook 已开始监听https://{host}/api/v1/webhooks/sample

另请参见

使用 Litmus 框架自动化测试

Litmus 是一个开源工具集,用于在 Kubernetes 中运行混沌实验。Litmus 为云原生开发人员和 SRE 提供了混沌中央注册库(CRD),以便在生产环境中实时注入、编排和监视混沌,以发现 Kubernetes 部署中的潜在弱点。在本节中,我们将运行一些这些混沌实验,以验证系统的弹性。您将学习如何构建 CI 和端到端测试的流水线,以验证和认证新的 Kubernetes 版本。

准备工作

k8sdevopscookbook/src存储库克隆到您的工作站,以便能够使用chapter4目录下的清单文件:

$ git clone https://github.com/k8sdevopscookbook/src.git
$ cd src/chapter4

确保您已准备好 Kubernetes 集群,并配置了kubectlhelm,以便您可以管理集群资源。

如何做…

本节进一步分为以下子节,以使这个过程更容易:

  • 安装 Litmus Operator

  • 使用 Chaos Charts 进行 Kubernetes

  • 创建一个容器杀死混沌实验

  • 审查混沌实验结果

  • 查看混沌实验日志

安装 Litmus Operator

Litmus 混沌工程工具可以使用 Helm 图表进行安装。Books 被定义为 Kubernetes 作业。

让我们执行以下步骤来在我们的集群中安装 Litmus:

  1. 安装 Litmus 混沌操作员:
$ kubectl apply -f https://litmuschaos.github.io/pages/litmus-operator-latest.yaml
  1. 验证 Litmus 混沌操作员 pod 是否正在运行:
$ kubectl get pods -n litmus
NAME                               READY STATUS  RESTARTS AGE
chaos-operator-ce-554d6c8f9f-46kf6 1/1   Running 0        50s
  1. 验证集群角色和集群角色绑定已应用:
$ kubectl get clusterroles,clusterrolebinding,crds | grep "litmus\|chaos"

现在,我们在集群中运行了 Litmus 混沌操作员。接下来,我们需要部署混沌实验来测试集群资源的弹性。

使用 Chaos Charts 进行 Kubernetes

与工作负载 Helm 图表类似,Litmus 混沌图表用于安装混沌实验包。混沌实验包含实际的混沌细节。在本食谱中,我们将学习如何列出混沌实验包并下载 Kubernetes 混沌实验包。让我们执行以下步骤来为 Litmus Operator 安装混沌图表:

  1. 在浏览器上打开 Kubernetes 混沌图表网站hub.litmuschaos.io,并在搜索框中搜索generic

  1. 点击“通用混沌”图表:

  1. 点击“安装所有实验”按钮:

  1. 复制混沌实验清单链接:

  1. 安装混沌实验:
$ kubectl create -f https://hub.litmuschaos.io/api/chaos?file=charts/generic/experiments.yaml
  1. 获取已创建的混沌实验列表:
$ kubectl get chaosexperiments
NAME                 AGE
container-kill       19s
pod-delete           19s
pod-network-latency  19s
pod-network-loss     19s

通用混沌图表下提供了诸如 pod 删除、网络延迟、网络丢失和容器杀死等混沌实验场景。您还可以安装或构建自己的特定于应用程序的混沌图表来运行特定于应用程序的混沌。

创建一个 pod 删除混沌实验

混沌实验捆绑了可复现的混沌情况,以便将它们作为 Kubernetes 作业运行。在这个教程中,我们将部署一个示例应用程序,并在应用程序上使用 Kubernetes 混沌实验。让我们执行以下步骤来测试在我们的集群中删除 pod 的影响:

  1. 部署一个示例应用程序:
$ kubectl apply -f litmus/nginx/nginx.yaml
  1. 列出 pod 并确认它们正在运行:
$ kubectl get pods |grep nginx
nginx-deployment-5c689d88bb-24n4m 1/1 Running 0 4m31s
nginx-deployment-5c689d88bb-qtvsx 1/1 Running 0 4m31s
  1. 使用litmuschaos.io/chaos="true"为混沌注释部署:
$ kubectl annotate deploy nginx-deployment litmuschaos.io/chaos="true"
deployment.extensions/nginx-deployment annotated
  1. 为混沌执行器创建一个ServiceAccount
$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
 name: nginx
 labels:
 app: nginx
EOF
  1. 创建一个集群角色:
$ cat <<EOF | kubectl apply -f -
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
 name: nginx
rules:
- apiGroups: ["", "extensions", "apps", "batch", "litmuschaos.io"]
 resources: ["daemonsets", "deployments", "replicasets", "jobs", "pods", "pods/exec", "events", "chaosengines", "chaosexperiments", "chaosresults"]
 verbs: ["*"]
EOF
  1. 创建一个ClusterRoleBinding
$ cat <<EOF | kubectl apply -f -
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
 name: nginx
subjects:
- kind: ServiceAccount
 name: nginx
 namespace: default
roleRef:
 kind: ClusterRole
 name: nginx
 apiGroup: rbac.authorization.k8s.io
EOF
  1. 审阅实验 CRs 以查看混沌参数。在这种情况下,让我们审阅pod-deletecontainer-kill实验:
$ kubectl get chaosexperiment pod-delete -o yaml
$ kubectl get chaosexperiment container-kill -o yaml
  1. 使用前面两个你已经审阅过的实验创建一个混沌引擎:
cat <<EOF | kubectl apply -f -
apiVersion: litmuschaos.io/v1alpha1
kind: ChaosEngine
metadata:
 name: engine-nginx
spec:
 appinfo: 
 appns: default
 applabel: "app=nginx"
 appkind: deployment
 chaosServiceAccount: nginx
 experiments:
 - name: pod-delete
 spec:
 rank: 1
 - name: container-kill
 spec:
 components:
EOF

通过这样,您已经学会了如何基于预定义的混沌图表创建混沌实验。

审阅混沌实验结果

混沌实验是作为 Kubernetes 作业执行的,受影响的 pod 将根据实验定义被混沌执行器关闭。

让我们执行以下步骤来审阅我们混沌实验的结果:

  1. 观察实验进行中:
$ watch kubectl get pods
Every 2.0s: kubectl get pods ip-172-20-50-43: Wed Sep 25 05:17:55 2019
NAME                              READY STATUS       RESTARTS AGE
container-kill-klfr5-rgddd        0/1   Completed    0        2m39s
engine-nginx-runner               1/2   Running      0        4m53s
nginx-deployment-5c689d88bb-qtvsx 1/1   Terminating  1        23m
nginx-deployment-5c689d88bb-rwtk9 1/1   Running      0        3m12s
pod-delete-wzj6w-x6k5t            0/1   Completed    0        4m8s
  1. 获取结果列表:
$ kubectl get chaosresults
NAME                        AGE
engine-nginx-container-kill 9m
engine-nginx-pod-delete     10m
  1. 查看engine-nginx-container-kill实验结果:
$ kubectl describe chaosresults engine-nginx-container-kill
...
Spec:
 Experimentstatus:
 Phase: <nil>
 Verdict: pass
Events: <none>

  1. 查看engine-nginx-pod-delete实验结果:
$ kubectl describe chaosresults engine-nginx-pod-delete
...
Spec:
 Experimentstatus:
 Phase: <nil>
 Verdict: pass
Events: <none>

在这个教程中,我们已经测试并审阅了一个简单的场景。您可以结合现有的混沌图表来创建您自己的实验,并使用 Litmus 框架编写应用程序混沌实验。

查看混沌实验日志

日志始终由您的集群上使用的标准 Kubernetes 日志框架收集和存储。在需要快速查看它们的情况下,您可以访问kubelet日志。

让我们执行以下步骤,深入了解在混沌实验期间执行的任务:

  1. 获取由已完成的作业创建的 Pod 列表:
$ kubectl get pods |grep Completed
container-kill-klfr5-rgddd 0/1 Completed 0 35m
pod-delete-wzj6w-x6k5t     0/1 Completed 0 37m
  1. 使用kubectl logs命令查看日志:
$ kubectl logs container-kill-klfr5-rgddd
...
TASK [Force kill the application pod using pumba] ******************************
...
TASK [Verify restartCount] ***************************************************
...
PLAY RECAP *******************************************************************
127.0.0.1 : ok=29 changed=18 unreachable=0 failed=0
2019-09-25T05:15:56.151497 (delta: 1.254396) elapsed: 35.944704 *******

在日志中,您将能够看到已执行的各个任务以及通过或失败任务的摘要。

它是如何工作的...

这个步骤向您展示了如何在运行在 Kubernetes 上的应用程序上快速运行预定义的混沌实验。

Litmus 实验可以很容易地从头开始创建,并集成到应用程序开发人员的 CI 流水线中,在构建和单元/集成测试阶段之后,对 Kubernetes 集群上的混沌行为进行测试。

运行 Litmus 混沌实验步骤中,在步骤 8中,我们创建了一个 Chaos Engine 来测试一个 Pod 删除实验,然后是一个容器杀死实验。这两个实验使用 Chaoskube,这是一个定期在您的 Kubernetes 集群中杀死随机 Pod 的工具,以及 Pumba,一个混沌测试和网络仿真工具,作为混沌的最终注入器。

另请参阅

使用 Gremlin 自动化混沌工程

Gremlin 是一个混沌工程服务,可以防止停机,并构建更可靠的系统。在本节中,我们将在生产环境中运行混沌攻击,以验证使用 Gremlin 的系统的弹性。您将学习如何创建 CPU 和节点关闭攻击,以测试基础设施的弹性。

准备工作

对于这个步骤,我们需要安装 Kubernetes 命令行工具kubectlhelm

这里提到的所有操作都需要 Gremlin 帐户。如果您没有帐户,请访问app.gremlin.com/signup并创建一个。

如何做…

这一部分进一步分为以下子部分,以使这个过程更容易:

  • 设置 Gremlin 凭据

  • 在 Kubernetes 上安装 Gremlin

  • 对 Kubernetes 工作节点进行 CPU 攻击

  • 针对 Kubernetes 工作节点创建节点关闭攻击

  • 运行预定义的基于场景的攻击

  • 从您的集群中删除 Gremlin

设置 Gremlin 凭据

要从我们的 Kubernetes 集群连接到 Gremlin 服务,我们需要将 Gremlin 凭据存储为 Kubernetes 秘密。

让我们执行以下步骤来配置我们的 Gremlin 凭据:

  1. 登录到 Gremlin 服务app.gremlin.com/

  2. 从帐户菜单中,点击“公司设置”:

  1. 点击“团队”选项卡并选择您的团队:

  1. 点击“配置”选项卡并下载您的证书:

  1. certificates.zip文件复制到已配置 kubectl 的主机上。

  2. 提取文件:

$ unzip certificate.zip
  1. 相应地重命名证书文件:
$ mv Me-client.pub_cert.pem gremlin.cert && mv Me-client.priv_key.pem gremlin.key
  1. 在您的集群中创建一个秘密资源:
$ kubectl create secret generic gremlin-team-cert --from-file=./gremlin.cert --from-file=./gremlin.key

有了这个,我们已经将我们的凭据转换为 Kubernetes 中的秘密资源。这个秘密将在稍后用于将 Gremlin 连接到我们的集群。

在 Kubernetes 上安装 Gremlin

在 Kubernetes 上安装 Gremlin 的最简单方法是使用 Helm 图表。在继续之前,请确保您已经创建了一个 gremlin 团队证书秘密,如“设置 Gremlin 凭据”中所述。

让我们执行以下步骤来使用 Helm 图表安装 Gremlin:

  1. 添加 Gremlin Helm 存储库:
$ helm repo add gremlin https://helm.gremlin.com
  1. 更新存储库:
$ helm repo update
  1. 使用您的团队 ID 安装 Gremlin 客户端:
$ helm install --name gremlin --set gremlin.teamID=abc1234-a12b-1234-1234-abcdefgh gremlin/gremlin
  1. Gremlin 将创建一个在集群中的每个节点上运行的 DaemonSet。验证DESIREDAVAILABLE pod 是否相等:
$ kubectl get daemonsets
NAME    DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
gremlin 3       3       3     3          3         <none>        11m

Gremlin 正在您的集群中运行。接下来,我们需要通过我们的 Gremlin 帐户触发一些混乱。

针对 Kubernetes 工作节点创建 CPU 攻击

Gremlin 可以生成各种影响核心、工作节点和内存的基础设施攻击。

让我们执行以下步骤来攻击 CPU:

  1. 部署一个示例应用程序:
$ kubectl apply -f ./src/chapter4/gremlin/nginx.yaml
  1. 列出 pod 并确认它们正在运行:
$ kubectl get pods |grep nginx
nginx-deployment-5c689d88bb-24n4m 1/1 Running 0 4m31s
nginx-deployment-5c689d88bb-rwtk9 1/1 Running 0 4m31s
  1. 获取一个 pod 的节点名称:
$ kubectl get pod nginx-deployment-5c689d88bb-rwtk9 -o jsonpath="{.spec.nodeName}"
ip-172-20-50-43.ec2.internal
  1. 观察pods状态:
$ watch kubectl get pods
  1. 登录到您的 Gremlin 帐户app.gremlin.com/

  2. 从攻击菜单中,点击基础设施。

  3. 点击“新攻击”按钮:

  1. 在“选择目标主机”选项卡下,从“步骤 3”中选择节点的本地主机名:

  1. 在“选择 Gremlin”选项卡下,单击“资源”,选择 CPU 攻击,将 CPU 容量设置为90,并消耗所有 CPU 核心:

  1. 单击“释放 Gremlin”以运行攻击:

现在,您在 Gremlin 帐户上触发的操作将通过代理在您的集群上执行。

针对 Kubernetes 工作节点执行节点关闭攻击

Gremlin 可以生成影响核心、工作节点和内存的各种基础设施攻击。

让我们执行以下步骤来攻击 CPU:

  1. 登录到您的 Gremlin 帐户app.gremlin.com/

  2. 从“攻击”菜单中,单击“基础设施”。

  3. 单击“新攻击”按钮:

  1. 在“选择目标主机”选项卡下,选择节点的本地主机名

  1. 在“选择 Gremlin”选项卡下,单击“状态”并选择“关闭”:

  1. 单击“释放 Gremlin”以运行攻击:

  1. 获取我们对其执行了关闭攻击的节点上的 Pod:
$ kubectl get pod -owide |grep ip-172-20-50-43.ec2.internal
NAME                READY STATUS  RESTARTS AGE IP          NODE NOMINATED NODE
engine-nginx-runner 1/2   Running 1        24h 100.96.0.65 ip-172-20-50-43.ec2.internal <none>
gremlin-rpp22       1/1   Running 1        88m 100.96.0.60 ip-172-20-50-43.ec2.internal <none>
nginx-deployment-5c689d88bb-rwtk9 1/1 Running 1 24h 100.96.0.63 ip-172-20-50-43.ec2.internal <none>

您将注意到 Pod 被重新启动。

运行预定义场景攻击

Gremlin 混沌场景帮助捆绑攻击以生成真实世界的故障场景。在这个教程中,我们将学习可以用来验证系统如何响应常见故障的预定义场景。

让我们执行以下步骤来验证自动缩放:

  1. 登录到您的 Gremlin 帐户app.gremlin.com/

  2. 单击“场景”菜单并查看推荐的场景:

  1. 确保您的 Kubernetes 集群上启用了自动缩放,并选择“验证自动缩放”场景。

  2. 单击“添加目标并运行”按钮:

  1. 单击“运行场景”以执行攻击。

因此,Gremlin 将对现有节点执行 CPU 攻击,以对集群施加压力,这理想情况下应触发集群的自动缩放功能以减少 CPU 压力。

从您的集群中删除 Gremlin

让我们执行以下步骤来从您的 Kubernetes 集群中删除 Gremlin 的组件:

  1. 列出 Gremlin Helm 发布:
$ helm ls |grep gremlin
gremlin 1 Thu Sep 26 04:37:05 2019 DEPLOYED gremlin-0.1.3 2.11.8
  1. 使用发布名称删除 Helm 发布:
$ helm delete gremlin --purge

Helm 将从您的集群中删除发布。

它是如何工作的...

这个配方向您展示了如何快速在 Kubernetes 调度应用程序的工作节点上运行预定义的混沌攻击。

请记住,尽管我们正在寻找创建 CPU 攻击创建节点关闭攻击配方对特定 pod 的影响,但整个节点都受到了攻击,因此节点上的其他 pod 也受到了影响。

特别是在小集群中,建议限制爆炸半径,并开始针对一个 pod 的单个容器进行攻击。这可以通过使用网络延迟攻击和指定与您希望看到攻击效果的容器相关的端口来完成。

参见

使用 Codacy 自动化您的代码审查

在本节中,我们将使用 Codacy 自动化代码审查,而无需对我们的存储库进行任何其他代码更改,并生成有关代码质量和安全问题的通知。您将学习如何自动化在开发代码审查和检查时最被低估的任务之一。

准备就绪

这里提到的所有操作都需要 Codacy 帐户。如果您没有帐户,请转到www.codacy.com/pricing并创建一个。

如何做…

本节进一步分为以下子节,以使这个过程更容易:

  • 访问项目仪表板

  • 审查提交和 PR

  • 按类别查看问题

  • 将 Codacy 徽章添加到您的存储库

访问项目仪表板

让我们执行以下步骤来访问 Codacy 项目仪表板:

  1. 登录到 Codacy 网站app.codacy.com,这将带您到您的组织仪表板。

  2. 在左侧菜单中单击项目:

  1. 单击特定项目以进入项目视图:

  1. 在项目仪表板上找到项目评分选项。在我们的示例中,以下项目已被评为 A:

  1. 查找质量演变图,并查看问题数量与行业平均值的比较。如果您的平均值高于行业标准,则需要审查提交并减少问题数量:

审查提交和 PR

让我们执行以下步骤来审查 Codacy 仪表板上的代码提交:

  1. 在项目仪表板上,单击“提交”菜单。

  2. 从下拉菜单中选择主分支:

  1. 在提交列表中,找到其中一个标有新问题的提交标记为红色的提交:

  1. 单击提交以查看其详细信息:

  1. 实施建议的修复以清除问题,或者为开发团队打开 GitHub 问题以进行修复。

  2. 现在,单击“打开”拉取请求菜单:

  1. 重复步骤 35,以查看问题和推荐的解决方案,以在代码合并之前清除它们。这将提高代码质量。

按类别查看问题

并非所有问题都相同,也不需要相同数量的工作来解决。大多数情况下,安全问题应该是首要关注的问题,代码样式应该是持续的工程努力,以便通过改进内部审查流程来解决它们。

让我们执行以下步骤来查看问题分解:

  1. 登录到app.codacy.com,这将带您到您的组织仪表板。

  2. 在左侧菜单上单击“项目”。

  3. 选择要分析的项目。

  4. 向下滚动仪表板,直到看到问题分解图表:

  1. 单击具有问题的类别,并使用代码审查中提供的问题信息:

  1. 如果您正在进行同行评审或检查自己的代码,您可以通过单击“所有作者”过滤器并将其更改为名称来过滤来自作者的问题。

将 Codacy 徽章添加到您的存储库

徽章用于表示高级项目状态及其对来到您的存储库或网站的用户的稳定性。由于 Codacy 可以显示您的代码质量,因此您可能希望在README.MD文件中显示它。

让我们执行以下步骤来向您的 GitHub 存储库添加 Codacy 徽章:

  1. 登录到app.codacy.com,这将带您到您的组织仪表板。

  2. 在左侧菜单上单击“项目”。

  3. 选择要分析的项目。

  4. 单击项目名称旁边的徽章图标:

  1. 单击“添加徽章到存储库”以创建一个 PR 到您的存储库:

  1. 审查 PR 的内容并合并它。一旦合并,您将在存储库概述页面上看到代码质量分数,类似于以下截图所示:

徽章用于突出显示存储库访问者的重要测试和信息。

另请参阅

使用 SonarQube 检测错误和反模式

SonarQube 是一个流行的开发工具,用于在软件开发中捕捉应用程序中的错误和漏洞。在本节中,我们将学习如何自动化静态代码分析,以检测您可以在 CI/CD 流水线中使用的错误和反模式。

准备工作

克隆k8sdevopscookbook/src存储库到您的工作站,以便使用chapter4目录下的清单文件:

$ git clone https://github.com/k8sdevopscookbook/src.git
$ cd src/chapter4

确保您已经准备好一个 Kubernetes 集群,并且已经配置了 kubectl 和 helm,以便您可以管理集群资源。

如何做…

这一部分进一步分为以下子部分,以使这个过程更容易:

  • 使用 Helm 安装 SonarQube

  • 访问 SonarQube 仪表板

  • 创建新用户和令牌

  • 启用质量配置文件

  • 添加项目

  • 分析项目

  • 按类别查看问题

  • 向您的存储库添加 SonarQube 徽章

  • 添加市场插件

  • 从您的集群中删除 SonarQube

使用 Helm 安装 SonarQube

SonarQube 是一个领先的开源解决方案,用于采用代码质量的 CI/CD 中的代码质量和安全分析。它可以作为一个独立的解决方案从二进制文件安装。在这个示例中,我们将使用 Helm 图表在 Kubernetes 集群上安装它。

让我们执行以下步骤来启动和运行 SonarQube:

  1. 更新您的存储库:
$ helm repo update
  1. 安装 SonarQube:
$ helm install stable/sonarqube --name sonar --namespace sonarqube
  1. 验证 PostgreSQL 和 SonarQube pod 是否就绪:
$ kubectl get pods -n sonarqube
NAME                              READY STATUS  RESTARTS AGE
sonar-postgresql-68b88ddc77-l46wc 1/1   Running 0        16m
sonar-sonarqube-995b9cc79-9vzjn   1/1   Running 1        16m

通过这样,您已经学会了如何在 Kubernetes 集群上部署 SonarQube。

访问 SonarQube 仪表板

使用 Helm 图表安装 SonarQube 会创建一个负载均衡器并公开外部 IP 以进行连接。我们将首先发现 IP 并使用服务 IP 连接到 SonarQube 仪表板。

让我们执行以下步骤通过云负载均衡器公开 SonarQube:

  1. 获取 SonarQube 负载均衡器的外部 IP:
$ export SONAR_SVC=$(kubectl get svc --namespace sonarqube sonar-sonarqube -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
$ echo http://$SONAR_SVC:9000
  1. 在浏览器中打开地址:

  1. 点击“登录”,并使用admin作为用户名和密码登录到仪表板:

  1. 点击屏幕右上角的账户配置标志,然后选择“我的账户”:

  1. 选择“安全”选项卡:

  1. 通过点击“更改密码”按钮来更改默认管理员密码并保存:

由于服务端口可以从外部访问,重要的是更改 SonarQube 的默认凭据。

创建新用户和令牌

团队成员需要拥有自己的用户帐户来访问仪表板。建议您生成令牌以管理帐户。您可以使用它们来运行分析或调用 Web 服务,而无需访问用户的实际凭据。这样,您对用户密码的分析不会通过网络传输。

让我们执行以下步骤来创建可以访问 SonarQube 的新用户:

  1. 从顶部菜单中,点击“管理”。

  2. 点击“安全”选项卡,然后选择“用户”:

  1. 点击“创建用户”按钮:

  1. 输入用户的“名称”、“电子邮件”和“密码”,然后点击“创建”:

  1. 在“用户”表上,点击“令牌”列下的“更新令牌”按钮:

  1. 设置一个令牌名称,然后点击“生成”按钮。

  2. 确保复制令牌并记下它,以备后续使用。

启用质量配置

要能够分析一个项目,首先需要安装特定的编程语言插件。让我们执行以下步骤来安装我们将在下一个示例“添加项目”中使用的 Java 插件:

  1. 点击“质量配置”。如果看到消息“没有可用的语言”,则需要安装语言插件:

  1. 点击“管理”菜单,切换到“市场”选项卡:

  1. 在市场搜索栏中,搜索您想要启用的语言。对于这个示例,这是java

  1. 通过点击相应插件旁边的“安装”按钮,为 SonarQube、Checkstyle、Findbugs、Java i18n 规则、PMD 和 SonarJava 插件添加Adobe Experience ManagerAEM)规则:

  1. 此操作需要重新启动。点击“重新启动服务器”,并在重新启动后登录到仪表板:

  1. 一旦您重新登录到仪表板,点击“质量配置文件”。这次,您应该看到 Java 配置文件:

对于您想安装的其他语言,请重复步骤 15

添加一个项目

在第一次分析时,SonarQube 会自动创建一个项目。在我们扫描项目之前,我们需要选择一种分析方法。在这个教程中,我们将启动一个 Gradle 分析。其他可用的方法列在另请参阅部分中。

让我们执行以下步骤将新项目添加到 SonarQube 中:

  1. 克隆一个示例存储库进行扫描:
$ git clone https://github.com/javajon/code-analysis.git
$ cd code-analysis/microservice/
  1. 对于这个示例,我们还需要在我们的节点上安装 Java 1.8。如果您已经安装了,跳到步骤 4
$ sudo apt install openjdk-8-jre-headless default-jdk
  1. 确认您正在使用的 Java 版本:
$ java -version openjdk version "1.8.0_222"
OpenJDK Runtime Environment (build 1.8.0_222-8u222-b10-1~deb9u1-b10)
OpenJDK 64-Bit Server VM (build 25.222-b10, mixed mode)
  1. 获取 SonarQube 服务的外部 IP:
$ export SONAR_SVC=$(kubectl get svc --namespace sonarqube sonar-sonarqube -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
  1. 运行分析。分析将在几分钟内完成:
$ ./gradlew -Dsonar.host.url=http://$SONAR_SVC:9000 sonarqube
....
BUILD SUCCESSFUL in 13s
6 actionable tasks: 1 executed, 5 up-to-date
  1. 切换回 SonarQube 门户,查看新项目:

现在,您将能够在 SonarQube 门户上看到您的新项目。

审查项目的质量

SonarQube 的分析因所扫描的语言而异,但在大多数情况下,它会生成高质量的度量、问题报告,并找出编码规则被违反的地方。在这个教程中,您将学习如何查找问题类型,并按严重程度查看问题。

确保您通过遵循添加项目教程将示例项目添加到 SonarQube 中。现在,执行以下步骤:

  1. 点击“问题”菜单:

  1. 已知漏洞被视为阻碍因素,需要立即解决。在过滤器下,展开严重性并选择阻碍因素:

  1. 在示例代码中检测到了一个硬编码凭据,这是一个严重的漏洞。要将此问题分配给团队成员,请点击“未分配”下拉菜单,并输入该人的名字以将其分配给他们:

  1. 最终,所有问题都需要确认和分配,或者解决为已修复、误报或不会修复。可以通过单击“打开”下拉菜单并将其更改为新的状态值来设置状态。

添加市场插件

让我们执行以下步骤,从市场上添加新的插件到 SonarQube 中:

  1. 单击“管理”菜单,切换到“市场”选项卡:

  1. 在市场上,除了代码分析器,您还可以找到替代的身份验证方法、语言包和其他有用的集成。例如,让我们搜索 GitHub 身份验证:

  1. 单击插件旁边的“安装”按钮。

  2. 现在,单击“重新启动服务器”,并在重新启动后登录仪表板。

  3. 使用 SonarQube,转到“管理”|“配置”|“常规设置”|“GitHub”。

  4. 将 Enabled 设置为 true:

  1. client IDclient secret设置为 GitHub 开发人员应用程序提供的值。通过转到github.com/settings/applications/new在 GitHub 上注册一个新的 OAuth 应用程序。

  2. 保存设置并从 SonarQube 注销:

新用户将被要求使用 GitHub 用户登录。

从集群中删除 SonarQube

让我们执行以下步骤,从您的 Kubernetes 集群中删除 SonarQube:

  1. 列出 SonarQube Helm 发布:
$ helm ls |grep sonarqube
sonar 1 Thu Sep 26 22:01:24 2019 DEPLOYED sonarqube-2.3.0 7.9 sonarqube
  1. 使用发布名称删除 Helm 发布:
$ helm delete sonar --purge

Helm 将从您的集群中删除 SonarQube 发布及其组件。

它是如何工作的...

这个教程向您展示了如何快速检测项目中的安全漏洞和错误。

在“添加项目”教程中,在“第 5 步”中,当我们开始分析我们的示例时,提供给分析的文件在服务器端进行分析,并将分析结果作为报告发送回服务器。这个报告在服务器端以异步方式进行分析。

报告被添加到队列中,并按顺序由服务器处理。如果将多个报告发送回服务器,结果可能需要一些时间才能显示在 SonarQube 仪表板上。

默认情况下,只有安装的代码分析器可以检测到的文件才会加载到项目中。这意味着如果你只有用 C 或 Go 编写的 SonarJava 代码和在 Kubernetes 世界中非常常见的 YAML 文件,它们将被忽略。

另请参阅

使用 FOSSA 检测许可合规问题

FOSSA 是一个开源软件许可合规工具,允许现代团队成功开发开源软件。在本节中,我们将使用 FOSSA 框架扫描软件许可证。您将学习如何自动化许可合规性和漏洞检查。

准备工作

所有在这里提到的操作都需要一个 FOSSA 账户。如果你没有,请访问app.fossa.com/account/register并创建一个。

如何做…

该部分进一步分为以下子部分,以使该过程更加简单:

  • 将项目添加到 FOSSA

  • 处理许可问题

  • 向您的项目添加 FOSSA 徽章

将项目添加到 FOSSA

让我们执行以下步骤将项目添加到 FOSSA:

  1. 登录 FOSSA 网站app.fossa.com/projects

  2. 单击“添加项目”按钮:

  1. 选择 QUICK IMPORT,然后继续:

  1. 选择存储库位置。在本教程中,我们将使用 Gitlab:

  1. 单击“连接服务”按钮。

  2. 选择您想要扫描的存储库,然后单击“导入”按钮:

FOSSA 将导入并自动扫描许可合规问题。

处理许可问题

FOSSA 不需要任何额外的步骤或代码来扫描您的项目。一旦将您的存储库添加到 FOSSA 帐户中,它就会运行许可证扫描。让我们来看一下:

  1. 登录app.fossa.com/projects

  2. 选择项目。

  3. “摘要”选项卡将显示已检测到的任何“标记的依赖项”:

  1. 单击“问题”选项卡:

  1. 从左侧菜单中选择一个问题线程。

  2. 查看问题和推荐的解决方案:

根据问题需要采取的行动,您可以选择创建一个工单,留下一条评论与团队成员讨论,或者解释并解决问题。

向您的项目添加 FOSSA 徽章

让我们执行以下步骤将 FOSSA 许可证检查徽章添加到我们的 GitHub 存储库页面:

  1. 登录 FOSSA 网站app.fossa.com/projects

  2. 选择项目以生成徽章。

  3. 切换到“设置”选项卡。

  4. 选择 SHIELD 作为徽章格式:

  1. 将 MARKDOWN 内容复制到剪贴板。

  2. 在您扫描的 GitHub 存储库上编辑README.md文件。将您在步骤 5中复制的 MARKDOWN 徽章代码粘贴到文件的开头:

  1. 保存文件后,FOSSA 扫描的结果将显示在存储库的徽章上。

第五章:为有状态的工作负载做准备

在本章中,我们将讨论在 Kubernetes 上使用流行的开源存储解决方案,以及如何保护应用程序的状态免受节点或应用程序故障,并共享相同的数据,或者如何在 Pod 被重新调度到不同节点时处理重新附加卷。在本章的示例中,您将学会在自管理基础设施或私有云中使用块和文件存储选项的技能。

在本章中,我们将涵盖以下示例:

  • 在 Kubernetes 中管理 Amazon EBS 卷

  • 在 Kubernetes 中管理 GCE PD 卷

  • 在 Kubernetes 中管理 Azure Disk 卷

  • 使用 Rook 配置和管理持久存储

  • 使用 OpenEBS 配置和管理持久存储

  • 在 Kubernetes 上设置 NFS 共享存储

  • 故障排除存储问题

技术要求

本节的示例假定您已根据第一章中描述的推荐方法之一部署了功能性 Kubernetes 集群,构建生产就绪的 Kubernetes 集群

Kubernetes 的命令行工具kubectl将在本节的其余示例中使用,因为它是针对 Kubernetes 集群运行命令的主要命令行界面。我们还将使用helm在可用 helm 图表的情况下部署解决方案。

在 Kubernetes 中管理 Amazon EBS 卷

Amazon Elastic Block Store(Amazon EBS)为在 AWS 中使用的 Amazon EC2 实例提供持久的块级存储卷,这些实例用于kops创建的 Kubernetes 集群和 Amazon EKS 集群。在本节中,我们将为在 AWS 中运行的 Kubernetes 应用程序创建存储类。您将学习如何在 Kubernetes 中创建StorageClass资源,了解 EBS 卷类型性能差异的参数,并使用新的容器存储接口CSI)来消耗 EBS 卷。

准备就绪

克隆k8sdevopscookbook/src存储库到您的工作站,以便能够使用chapter5目录下的清单文件:

$ git clone https://github.com/k8sdevopscookbook/src.git
$ cd chapter5

确保您已准备好一个 Kubernetes 集群,并配置了kubectl来管理集群资源。

如何做到…

本节进一步细分为以下子节,以便促进流程:

  • 创建 EBS 存储类

  • 更改默认存储类

  • 使用 EBS 卷进行持久存储

  • 使用 EBS 存储类动态创建持久卷

  • 删除 EBS 持久卷

  • 安装 EBS CSI 驱动程序以管理 EBS 卷

创建 EBS 存储类

让我们执行以下步骤来学习构建 EBS 存储类所需的存储类参数,我们可以使用它来动态请求 AWS Cloud 中的新持久卷:

  1. 创建一个基本的存储类,指定提供程序kubernetes.io/aws-ebs和类型gp2
$ cat <<EOF | kubectl apply -f -
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
 name: aws-gp2
provisioner: kubernetes.io/aws-ebs
parameters:
 type: gp2
 fsType: ext4 
reclaimPolicy: Retain
allowVolumeExpansion: true
mountOptions:
 - debug
volumeBindingMode: Immediate
EOF

此处还接受其他类型值,包括io1sc1st1。您可以在另请参阅部分的 AWS EBS 卷类型链接中找到不同卷类型的定义和用例。

在 Amazon EKS 集群上,默认的 EBS 卷类型是gp2。对于数据库工作负载,如 MongoDB、Cassandra 和 PostgreSQL,建议使用io1-type高性能 SSD。

  1. 列出存储类。确认列表中是否有新的aws-gp2。根据云提供商或 Kubernetes 部署工具,您可能会在列表中看到类似以下的其他存储类:
$ kubectl get sc
NAME                      PROVISIONER                    AGE
aws-gp2                   kubernetes.io/aws-ebs          8s
default                   kubernetes.io/aws-ebs          25h
gp2 (default)             kubernetes.io/aws-ebs          25h
openebs-hostpath          openebs.io/local               175m
openebs-jiva-default      openebs.io/provisioner-iscsi   175m

存储类是动态配置的基础。正如我们在示例中所看到的,您的集群中可能有多个存储类。理想情况下,存储类应该根据应用程序的需求创建,因为某些应用程序需要更快的卷,而其他应用程序可能会利用 Rook 和 OpenEBS 等解决方案提供的多可用区复制。

更改默认存储类

动态存储配置是扩展应用程序的关键部分。当未指定存储类时,Kubernetes 会使用默认选项。让我们执行以下步骤来将我们首选的存储类设置为默认选项:

  1. 通过将is-default-class值设置为true,同时创建一个新的存储类并将其定义为默认存储类。我们的示例在此处使用io1卷类型,并将iopsPerGB限制为10。它还将reclaimPolicy设置为Retain,这意味着,如果用户删除相关的 PVC,卷将被保留(其他两个保留策略选项是RecycleDelete):
$ cat <<EOF | kubectl apply -f -
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
 name: aws-io1-slow
 annotations:
 storageclass.kubernetes.io/is-default-class: "true"
provisioner: kubernetes.io/aws-ebs
parameters:
 type: io1
 iopsPerGB: "10"
 fsType: ext4
reclaimPolicy: Retain
allowVolumeExpansion: true
EOF
  1. 在创建存储类后更改现有存储类的状态之前,首先选择一个存储类:
$ kubectl get sc
NAME                   PROVISIONER           AGE
aws-gp2                kubernetes.io/aws-ebs 6m28s
aws-io1-slow (default) kubernetes.io/aws-ebs 4m29s
  1. 让我们将现有的存储类aws-io1-slow设置为非默认选项:
$ kubectl patch storageclass aws-io1-slow -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"false"}}}'
  1. 现在,再次将aws-gp2定义为默认存储类:
$ kubectl patch storageclass aws-gp2 -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
  1. 确认新的默认存储类:
$ kubectl get sc
NAME               PROVISIONER           AGE
aws-gp2 (default)  kubernetes.io/aws-ebs 10m
aws-io1-slow       kubernetes.io/aws-ebs 8m

确保始终只有一个默认存储类,否则没有定义存储类但期望默认存储类的 PVC 将失败。

使用 EBS 卷进行持久存储

作为创建 PVC 和动态创建卷的替代方案,您还可以手动创建卷并将其直接附加到您的应用程序作为持久卷,执行以下步骤:

  1. 通过以下aws CLI 在与您的工作节点相同的区域创建 EBS 卷:
$ aws ec2 create-volume --availability-zone=us-west-2a --size=10 --volume-type=gp2
  1. 使用您在步骤 1中创建的 EBS volumeID 部署一个测试应用程序:
$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
 name: test-server
spec:
 containers:
 - image: gcr.io/google_containers/test-webserver
 name: test-container
 volumeMounts:
 - mountPath: /test-ebs
 name: test-volume
 volumes:
 - name: test-volume
 awsElasticBlockStore:
 volumeID: vol-02f4bc9b938604f72
 fsType: ext4
EOF
  1. 验证您的 pod 处于Running状态:
$ kubectl get pods
NAME        READY STATUS  RESTARTS AGE
test-server 1/1   Running 0        4m32s

手动创建持久卷(PV)的主要优势在于 PV 不附加到单个集群或命名空间。它们作为您 AWS 云账户上的资源存在,甚至可以跨集群共享,而动态创建的 PVC 只存在于创建的命名空间中,并且只能被同一命名空间内的 pod 使用。

使用 EBS 存储类动态创建持久卷

作为 StatefulSet 的一部分,volumeClaimTemplates可以使用您选择的PersistentVolume提供持久存储。在这个示例中,我们将使用 StorageClass 动态为您的应用程序创建 PV。让我们从以下步骤开始:

  1. 在应用程序部署清单的volumeClaimTemplates部分下添加aws-gp2存储类行,类似于以下示例:
...
  volumeClaimTemplates:
  - metadata:
      name: datadir
      annotations:
        volume.beta.kubernetes.io/storage-class: aws-gp2
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 1G
...
  1. 在这个示例中,我们将使用aws-gp2存储类部署 Redis StatefulSet。在执行之前,请查看示例存储库中src/chapter5/aws目录下的 YAML 清单:
$ cat aws/redis-statefulset.yml
  1. 使用以下示例创建 Redis StatefulSet:
$ kubectl apply -f aws/redis-statefulset.yml
  1. 验证已创建 pod。在这个示例中,我们的示例有带有三个副本的 StatefulSet。因此,您应该看到三个运行的副本,类似于以下输出:
$ kubectl get pods
NAME READY STATUS  RESTARTS AGE
rd-0 1/1   Running 0        9m9s
rd-1 1/1   Running 0        7m56s
rd-2 1/1   Running 0        6m47s
  1. 列出已创建的 PVC 和 PV。您应该期望看到创建的三个 PVC 和三个 PV,类似于我们这里的示例输出:
$ kubectl get pvc,pv
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
datadir-rd-0 Bound pvc-8a538aa3-7382-4147-adde-1ea3dbaaafb4 1Gi RWO aws-gp2 10m
datadir-rd-1 Bound pvc-171fbee3-39bf-4450-961f-6c1417ff3897 1Gi RWO aws-gp2 9m1s
datadir-rd-2 Bound pvc-b40df89b-5349-4f02-8510-917012579746 1Gi RWO aws-gp2 7m52s$ 
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-171fbee3-39bf-4450-961f-6c1417ff3897 1Gi RWO Retain Bound default/datadir-rd-1 aws-gp2 9m18s
pvc-8a538aa3-7382-4147-adde-1ea3dbaaafb4 1Gi RWO Retain Bound default/datadir-rd-0 aws-gp2 10m
pvc-b40df89b-5349-4f02-8510-917012579746 1Gi RWO Retain Bound default/datadir-rd-2 aws-gp2 8m10s

现在,您知道如何在部署中动态创建持久卷了。

删除 EBS 持久卷

当回收策略设置为保留卷时,需要通过以下步骤单独删除卷:

  1. 请记住,删除您的工作负载不会删除 PVC 和 PV,除非 PVC 清单包含在清单中:
$ kubectl delete -f redis-statefulset.yml
  1. 列出剩余的 PV:
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-171fbee3-39bf-4450-961f-6c1417ff3897 1Gi RWO Retain Bound default/datadir-rd-1 aws-gp2 13m
pvc-8a538aa3-7382-4147-adde-1ea3dbaaafb4 1Gi RWO Retain Bound default/datadir-rd-0 aws-gp2 15m
pvc-b40df89b-5349-4f02-8510-917012579746 1Gi RWO Retain Bound default/datadir-rd-2 aws-gp2 12m
  1. 删除 PVC。您可以通过在单个命令中添加它们的名称来一次删除多个 PVC,类似于以下内容:
$ kubectl delete pvc datadir-rd-0 datadir-rd-1 datadir-rd-2
  1. 删除 PV。您可以通过在单个命令中添加它们的名称来一次删除多个 PV,类似于以下内容:
$ kubectl delete pv <pv-name-1> <pv-name-2> <pv-name-3>

尽管我们删除了 PVC 和 PV,但我们的 EBS 卷仍然保留。现在让我们也删除这些:

  1. 打开您的 AWS 管理控制台,然后在“计算”选项下单击 EC2:

  1. 在“资源”部分下,单击“卷”:

  1. 选择可用且未使用的卷。从使用 EBS 存储类创建动态持久卷中,我们有三个未使用的卷:

  1. 从“操作”下拉菜单中,选择“删除卷”:

我们已成功删除了与作为 Redis StatefulSet 资源的一部分创建的应用程序相关的所有存储资源。

安装 EBS CSI 驱动程序以管理 EBS 卷

Amazon EBS CSI 驱动程序提供了一个允许 Amazon EKS 集群简单管理 Amazon EBS 卷的生命周期的 Kubernetes CSI 接口。在本教程中,我们将学习如何通过以下步骤安装 EBS CSI 驱动程序:

  1. EBS CSI 与您的 AWS 卷通信,以按需创建卷。因此,它需要访问凭据。请在此处用您的 AWS 凭据替换key_idaccess_key的值,并使用秘密资源配置 CSI 驱动程序权限:
$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Secret
metadata:
 name: aws-secret
 namespace: kube-system
stringData:
 key_id: "YOUR_KEY_ID_HERE"
 access_key: "YOUR_ACCESS_KEY_HERE"
EOF
  1. 从其存储库位置部署 AWS EBS CSI 驱动程序。以下命令将创建 ClusterRoleBindings、CSI 控制器部署和将在每个工作节点上运行的ebs-csi-node DaemonSet:
$ kubectl apply -k "github.com/kubernetes-sigs/aws-ebs-csi-driver/deploy/kubernetes/overlays/stable/?ref=master"
  1. 验证驱动程序是否正在运行:
$ kubectl get pods -n kube-system | grep ebs-csi
ebs-csi-controller-8579f977f4-ljfhm 4/4 Running 0 2m37s
ebs-csi-controller-8579f977f4-qw6ld 4/4 Running 0 2m37s
ebs-csi-node-5x8nh 3/3 Running 0 2m37s
ebs-csi-node-cfghj 3/3 Running 0 2m37s
ebs-csi-node-xp569 3/3 Running 0 2m37s
ebs-csi-node-z45hn 3/3 Running 0 2m37s
  1. 现在,创建一个新的存储类,该存储类将使用ebs.csi.aws.com作为提供者:
$ cat <<EOF | kubectl apply -f -
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
 name: aws-csi-ebs
provisioner: ebs.csi.aws.com
volumeBindingMode: WaitForFirstConsumer
EOF
  1. 创建 PVC:
$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
 name: csi-ebs-pvc
spec:
 accessModes:
 - ReadWriteOnce
 storageClassName: aws-csi-ebs
 resources:
 requests:
 storage: 4Gi
EOF
  1. 创建一个将使用 PVC 并写入/data/out.txt文件的 pod:
$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
 name: app
spec:
 containers:
 - name: app
 image: centos
 command: ["/bin/sh"]
 args: ["-c", "while true; do echo $(date -u) >> /data/out.txt; sleep 5; done"]
 volumeMounts:
 - name: persistent-storage
 mountPath: /data
 volumes:
 - name: persistent-storage
 persistentVolumeClaim:
 claimName: csi-ebs-pvc
EOF
  1. 验证我们的mytestapp pod 是否将数据写入卷:
$ kubectl exec -it mytestapp cat /data/out.txt
Mon Sep 9 17:40:25 UTC 2019
  1. 通过使用以下命令删除 pod 和 PVC 来删除资源:
$ kubectl delete pod mytestapp && kubectl delete pvc csi-ebs-pvc

现在您知道如何使用 CSI 驱动程序来配置 EBS 卷。CSI 驱动程序提供了一个统一的接口来响应 Kubernetes 上的存储请求。只要驱动程序已安装并且具有驱动程序实现的功能,无论底层存储系统如何,用户都可以使用它。

另请参阅

在 Kubernetes 中管理 GCE PD 卷

Google Cloud Platform(GCP)为 Google Kubernetes Engine(GKE)实例提供持久的块级存储卷。在本节中,我们将为在 GKE 中运行的 Kubernetes 应用程序创建存储类。您将学习在 Kubernetes 中创建 StorageClass 资源,了解 GCP PD 卷类型性能变化的参数,并使用新的 CSI。

准备工作

k8sdevopscookbook/src存储库克隆到您的工作站:

$ git clone https://github.com/k8sdevopscookbook/src.git
$ cd src/chapter5

确保您有一个区域性的 GKE 集群准备就绪,并配置kubectl来管理集群资源。

操作步骤…

本节进一步细分为以下子节,以便进行操作:

  • 创建 GCE 持久磁盘存储类

  • 更改默认存储类

  • 使用 GCE PD 卷进行持久存储

  • 使用 GCE PD 存储类创建动态持久卷

  • 删除 GCE PD 持久卷

  • 安装 GCP Compute PD CSI 驱动程序来管理 PD 卷

创建 GCE 持久磁盘存储类

让我们执行以下步骤来学习存储类参数,以构建一个 GCE PD 存储类,我们可以用来动态请求新的持久卷:

  1. 基于 GKE 的 Kubernetes 集群创建时会有默认的存储类。列出存储类如下:
$ kubectl get sc
NAME               PROVISIONER          AGE
standard (default) kubernetes.io/gce-pd 81s
  1. 描述standard存储类:
$ kubectl describe sc standard
Name: standard
IsDefaultClass: Yes
Annotations: storageclass.beta.kubernetes.io/is-default-class=true
Provisioner: kubernetes.io/gce-pd
Parameters: type=pd-standard
AllowVolumeExpansion: <unset>
MountOptions: <none>
ReclaimPolicy: Delete
VolumeBindingMode: Immediate
Events: <none>
  1. 创建基本的存储类,指定kubernetes.io/gce-pd的 provisioner 和pd-standard类型:
$ cat <<EOF | kubectl apply -f -
kind: StorageClass 
apiVersion: storage.k8s.io/v1 
metadata:
 name: gce-pd 
provisioner: kubernetes.io/gce-pd 
parameters:
 type: pd-standard
volumeBindingMode: WaitForFirstConsumer
allowedTopologies:
- matchLabelExpressions:
 - key: failure-domain.beta.kubernetes.io/zone
 values:
 - us-central1-a
 - us-central1-b
EOF

您可以在GCE PD 卷类型链接中找到不同卷类型的定义和用例,位于另请参阅部分。

在 GKE 集群上,默认的 PD 卷类型是pd-standard。对于 MongoDB、Cassandra 和 PostgreSQL 等数据库工作负载,建议使用pd-ssd-type高性能 SSD。

  1. 列出存储类:
$ kubectl get sc
NAME                      PROVISIONER                    AGE
gce-pd                    kubernetes.io/gce-pd           3s
standard (default)        kubernetes.io/gce-pd           17m

GKE 带有一个名为standard的默认存储类。您的集群中可能有多个存储类。理想情况下,存储类应根据应用程序的要求创建,因为某些应用程序需要更快的卷,而其他应用程序可能利用其他解决方案提供的多可用区复制。

更改默认存储类

动态存储配置是扩展应用程序的关键部分。当 PVC 未指定存储类时,Kubernetes 将使用默认选项。让我们执行以下步骤,将我们首选的存储类设置为默认值:

  1. 让我们创建一个新的存储类,并通过将is-default-class设置为true来同时将其定义为默认选项:
$ cat <<EOF | kubectl apply -f -
kind: StorageClass 
apiVersion: storage.k8s.io/v1 
metadata:
 name: gce-pd-ssd 
 annotations:
 storageclass.kubernetes.io/is-default-class: "true"
provisioner: kubernetes.io/gce-pd 
parameters:
 type: pd-ssd
reclaimPolicy: Retain
allowVolumeExpansion: true
volumeBindingMode: WaitForFirstConsumer
allowedTopologies:
- matchLabelExpressions:
 - key: failure-domain.beta.kubernetes.io/zone
 values:
 - us-central1-a
 - us-central1-b
EOF
  1. 拥有多个默认存储类将会导致问题。您需要删除一个。要更改已创建的存储类的状态,请首先选择一个存储类:
$ kubectl get sc
NAME                 PROVISIONER AGE
gce-pd               kubernetes.io/gce-pd 3m52s
gce-pd-ssd (default) kubernetes.io/gce-pd 4s
standard (default)   kubernetes.io/gce-pd 21m
  1. 让我们将standardgce-pd-ssd存储类设置为非默认值:
$ kubectl patch storageclass standard -p '{"metadata": {"annotations":{"storageclass.beta.kubernetes.io/is-default-class":"false"}}}'
$ kubectl patch storageclass gce-pd-ssd -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"false"}}}'
  1. 现在让我们再次将gce-pd定义为默认存储类:
$ kubectl patch storageclass gce-pd -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
  1. 确认新的默认存储类:
$ kubectl get sc
NAME             PROVISIONER          AGE
gce-pd (default) kubernetes.io/gce-pd 8m25s
gce-pd-ssd       kubernetes.io/gce-pd 4m37s
standard         kubernetes.io/gce-pd 25m

现在您已经学会了如何用新的存储类替换默认存储类。确保始终只有一个默认存储类;否则,没有定义存储类的 PVC 将失败。

使用 GCE PD 卷进行持久存储

作为创建 PVC 和动态创建卷的替代方案,您还可以手动创建卷,并将其直接附加到应用程序作为持久卷,观察以下步骤:

  1. 在与工作节点相同的区域创建 GCE PD 卷:
$ gcloud beta compute disks create gce-disk-1 --region us-central1 --replica-zones us-central1-b,us-central1-c 
Created [https://www.googleapis.com/compute/beta/projects/devopscookbook/regions/us-central1/disks/gce-disk-1].
NAME       ZONE SIZE_GB TYPE        STATUS
gce-disk-1      500     pd-standard READY
  1. 使用现有卷名gce-disk-1创建 PV:
$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolume
metadata:
 name: gce-disk-1
spec:
 storageClassName: ""
 capacity:
 storage: 500G
 accessModes:
 - ReadWriteOnce
 gcePersistentDisk:
 pdName: gce-disk-1
 fsType: ext4
EOF
  1. 使用 PV 名称gce-disk-1创建 PVC:
$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
 name: pvc-gcedisk1
spec:
 storageClassName: ""
 volumeName: gce-disk-1
 accessModes:
 - ReadWriteOnce
 resources:
 requests:
 storage: 500G
EOF
  1. 使用您在步骤 1中创建的volumeMounts名称gce-disk-1部署测试应用程序。
$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
 name: test-server
spec:
 containers:
 - image: gcr.io/google_containers/test-webserver
 name: test-container
 volumeMounts:
 - mountPath: /test-ebs
 name: test-volume
 volumes:
 - name: test-volume
 persistentVolumeClaim:
 claimName: pvc-gcedisk1
EOF
  1. 验证您的 pod 处于Running状态:
$ kubectl get pods
NAME        READY STATUS  RESTARTS AGE
test-server 1/1   Running 0        4m32s

手动创建 PV 的主要优势在于 PV 不附加到单个集群或命名空间。它们作为您的 GCP 帐户上的资源存在,甚至可以跨集群共享。另一方面,动态创建的 PVC 仅存在于创建的命名空间中,并且只能被同一命名空间内的 pod 使用。

使用 GCE PD 存储类创建动态持久卷

作为 StatefulSet 的一部分,volumeClaimTemplates可以使用您选择的PersistentVolume提供程序提供持久存储。在这个示例中,我们将使用 StorageClass 为您的应用程序动态创建 PV:

  1. 在应用程序部署清单的volumeClaimTemplates部分下添加gce-pd存储类行,类似于以下示例:
...
 volumeClaimTemplates:
 - metadata:
 name: datadir
 annotations:
 volume.beta.kubernetes.io/storage-class: gce-pd
 spec:
 accessModes: [ "ReadWriteOnce" ]
 resources:
 requests:
 storage: 1G
...
  1. 在这个示例中,我们将使用gce-pd存储类部署 Redis Statefulset。在执行之前,请查看示例存储库中src/chapter5/gcp目录下的 YAML 清单:
$ cat gcp/redis-statefulset.yml
  1. 创建 Redis StatefulSet:
$ kubectl apply -f redis-statefulset.yml
  1. 验证已创建了 Pod:
$ kubectl get pods
NAME READY STATUS  RESTARTS AGE
rd-0 1/1   Running 0        2m27s
rd-1 1/1   Running 0        81s
rd-2 0/1   Running 0        19s
  1. 列出已创建的 PVC 和 PV:
$ kubectl get pvc, pv
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
datadir-rd-0 Bound pvc-3481b73c-d347-11e9-b514-42010a80005e 1Gi RWO gce-pd 3m1s
datadir-rd-1 Bound pvc-5b8cc2d6-d347-11e9-b514-42010a80005e 1Gi RWO gce-pd 115s
datadir-rd-2 Bound pvc-80d826b9-d347-11e9-b514-42010a80005e 1Gi RWO gce-pd 53s
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-3481b73c-d347-11e9-b514-42010a80005e 1Gi RWO Delete Bound default/datadir-rd-0 gce-pd 3m16s
pvc-5b8cc2d6-d347-11e9-b514-42010a80005e 1Gi RWO Delete Bound default/datadir-rd-1 gce-pd 2m11s
pvc-80d826b9-d347-11e9-b514-42010a80005e 1Gi RWO Delete Bound default/datadir-rd-2 gce-pd 68s

现在您知道如何在应用程序部署的一部分动态创建 GCE PD 持久卷。

删除 GCE PD 持久卷

当回收策略设置为保留卷时,需要通过以下步骤单独删除它们:

  1. 请记住,删除工作负载不会删除 PVC 和 PV,除非清单中包含 PVC 清单:
$ kubectl delete -f redis-statefulset.yml
statefulset.apps "rd" deleted
service "redis" deleted
  1. 列出剩余的 PV:
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-171fbee3-39bf-4450-961f-6c1417ff3897 1Gi RWO Retain Bound default/datadir-rd-1 aws-gp2 13m
pvc-8a538aa3-7382-4147-adde-1ea3dbaaafb4 1Gi RWO Retain Bound default/datadir-rd-0 aws-gp2 15m
pvc-b40df89b-5349-4f02-8510-917012579746 1Gi RWO Retain Bound default/datadir-rd-2 aws-gp2 12m
  1. 删除 PVC。您可以通过在单个命令中添加它们的名称一次性删除多个 PVC,类似于以下内容:
$ kubectl delete pvc datadir-rd-0 datadir-rd-1 datadir-rd-2

我们已成功删除了与 Redis StatefulSet 资源一起创建的应用程序相关的所有存储资源。

安装 GCP Compute PD CSI 驱动程序来管理 PD 卷。

GCP Compute PD CSI 驱动程序提供了一个 Kubernetes CSI 接口,允许 GKE 集群简单地管理持久卷的 GKE 卷的生命周期。在这个示例中,我们将学习安装 GCP Compute PD CSI 驱动程序所需的步骤,通过以下步骤观察:

  1. 克隆 GCP CSI 驱动程序项目:
$ git clone https://github.com/kubernetes-sigs/gcp-compute-persistent-disk-csi-driver.git
$ cd gcp-compute-persistent-disk-csi-driver/
  1. PROJECT名称替换为您的 GCP 项目名称,在存储服务帐户私钥文件的位置设置GCE_PD_SA_DIR,并设置 GCP 服务帐户变量:
$ EXPORT PROJECT="DevOpsCookBook"
$ GCE_PD_SA_NAME=my-gce-pd-csi-sa 
$ GCE_PD_SA_DIR=/my/safe/credentials/directory 
$ ./deploy/setup-project.sh
  1. 部署 GCP Compute PD CSI 驱动程序:
$ GCE_PD_SA_DIR=/my/safe/credentials/directory
$ GCE_PD_DRIVER_VERSION=stable
$ ./deploy/kubernetes/deploy-driver.sh
  1. 验证驱动程序是否正在运行:
$ kubectl get pods -n kube-system | grep ebs-csi
csi-gce-pd-controller   4/4 Running 0 31s
csi-gce-pd-node-f8w8w   3/3 Running 0 31s
csi-gce-pd-node-g8qn5   3/3 Running 0 31s
csi-gce-pd-node-n2fhp   3/3 Running 0 31s
  1. 现在,使用pd.csi.storage.gke.io提供程序创建一个新的区域性存储类:
$ cat <<EOF | kubectl apply -f -
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
 name: gcp-csi-pd
provisioner: pd.csi.storage.gke.io
parameters:
 type: pd-standard
 replication-type: regional-pd
volumeBindingMode: WaitForFirstConsumer
EOF
  1. 创建 PVC:
$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
 name: csi-gcp-pd-pvc
spec:
 accessModes:
 - ReadWriteOnce
 storageClassName: gcp-csi-pd
 resources:
 requests:
 storage: 4Gi
EOF
  1. 创建一个将使用 PVC 并写入/data/out.txt文件的 Pod:
$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
 name: mytestapp
spec:
 containers:
 - name: app
 image: centos
 command: ["/bin/sh"]
 args: ["-c", "while true; do echo $(date -u) >> /data/out.txt; sleep 5; done"]
 volumeMounts:
 - name: persistent-storage
 mountPath: /data
 volumes:
 - name: persistent-storage
 persistentVolumeClaim:
 claimName: csi-gcp-pd-pvc
EOF
  1. 验证我们的mytestapp Pod 是否将数据写入卷:
$ kubectl exec -it mytestapp cat /data/out.txt
Mon Sep 9 18:20:38 UTC 2019
  1. 删除资源:
$ kubectl delete pod mytestapp && kubectl delete pvc csi-gcp-pd-pvc 

现在您知道如何利用 CSI 驱动程序在 GKE 集群上部署 GCE PD 卷。

它是如何工作的...

本食谱向您展示了如何使用 Kubernetes 存储类、PVC 和 PV 概念快速提供动态持久卷。

创建 GCP 持久磁盘存储类食谱中,在步骤 3中,您使用allowedTopologies参数创建了gce-pd存储类,并设置了两个 GKE 区域,us-central1-aus-central1-b

当在存储类中定义了allowedTopologies时,GCP 会创建一个区域性持久磁盘,并在同一区域的两个区域之间复制数据,以提高可用性。

使用此选项创建的卷也会以类似于此处标签的方式进行标记:failure-domain.beta.kubernetes.io/region : us-central1failure-domain.beta.kubernetes.io/region : us-central1-a

区域性 PD 有助于在区域性故障中存活。在这种情况下,您的 Kubernetes 集群将使用卷故障转移工作负载到另一个区域。

在构建高可用状态工作负载的 GKE 集群上,建议使用此选项。

另请参阅

在 Kubernetes 中管理 Azure Disk 卷

Azure Cloud 为与Azure Kubernetes EngineAKS)一起使用的持久块级存储卷提供支持。在本节中,我们将为在 AKS 中运行的 Kubernetes 应用程序创建存储类。您将学习如何在 Kubernetes 中创建 StorageClass 资源,了解 Azure Disk 卷类型性能变化的参数,以及如何使用新的 CSI。

准备就绪

克隆k8sdevopscookbook/src存储库到您的工作站,以便使用chapter5目录下的清单文件:

$ git clone https://github.com/k8sdevopscookbook/src.git
$ cd src/chapter5

确保您有一个区域性的 GKE 集群,并配置kubectl来管理集群资源。

如何做…

本节进一步细分为以下子节,以便促进流程:

  • 创建 Azure Disk 存储类

  • 将默认存储类更改为 ZRS

  • 使用 Azure Disk 存储类创建动态 PV

  • 删除 Azure Disk 持久卷

  • 安装 Azure Disk CSI 驱动程序

创建 Azure Disk 存储类

让我们执行以下步骤,以了解构建 Azure 磁盘存储类所需的存储类参数,我们可以使用这些参数从 AKS 动态请求新的持久卷:

  1. 基于 AKS 的 Kubernetes 集群默认创建两个本地冗余(LRS)存储类。让我们列出 AKS 集群上的存储类:
$ kubectl get sc
NAME PROVISIONER AGE
default (default) kubernetes.io/azure-disk 13m
managed-premium kubernetes.io/azure-disk 13m
  1. 描述default存储类:
$ kubectl describe sc default
Name: default
IsDefaultClass: Yes
...
Provisioner: kubernetes.io/azure-disk
Parameters: cachingmode=ReadOnly,kind=Managed,storageaccounttype=Standard_LRS
AllowVolumeExpansion: <unset>
MountOptions: <none>
ReclaimPolicy: Delete
VolumeBindingMode: Immediate
Events: <none>
  1. 使用提供程序kubernetes.io/azure-disk和指定Standard_ZRS skuName 创建区域冗余存储类:
$ cat <<EOF | kubectl apply -f -
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
 name: azure-zrs
provisioner: kubernetes.io/azure-disk
parameters:
 storageaccounttype: Standard_ZRS
 kind: Shared
reclaimPolicy: Retain
allowVolumeExpansion: true
volumeBindingMode: Immediate
EOF

您可以在“Azure 磁盘卷类型”链接中找到不同卷类型的定义和用例。

在 Azure 云集群上,默认的 Azure 磁盘卷类型是Standard_LRS。对于数据库工作负载,如 MongoDB、Cassandra 和 PostgreSQL,建议使用Premium_LRS类型的高性能 SSD。

  1. 列出存储类:
$ kubectl get sc
NAME              PROVISIONER              AGE
azure-zrs         kubernetes.io/azure-disk 4s
default (default) kubernetes.io/azure-disk 18m
managed-premium   kubernetes.io/azure-disk 18m

如您在我们的示例中所见,AKS 集群配备了两个预定义的存储类。

将默认存储类更改为 ZRS

动态存储配置是扩展应用程序的关键部分。当 PVC 未指定存储类时,Kubernetes 使用默认选项。让我们执行以下步骤,将我们首选的存储类设置为默认值:

  1. 将现有的default存储类设置为非默认选项:
$ kubectl patch storageclass default -p '{"metadata": {"annotations":{"storageclass.beta.kubernetes.io/is-default-class":"false"}}}'
  1. 现在,再次将azure-zrs定义为默认存储类:
$ kubectl patch storageclass azure-zrs -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'
  1. 确认新的默认存储类。您应该看到新的azure-zrs作为默认值,类似于以下输出:
$ kubectl get sc
NAME                PROVISIONER AGE
azure-zrs (default) kubernetes.io/azure-disk 4m38s
default             kubernetes.io/azure-disk 23m
managed-premium     kubernetes.io/azure-disk 23m

现在您知道如何在 AKS 集群上将首选的存储类设置为默认值。

使用 Azure 磁盘存储类创建动态 PV

作为 StatefulSet 的一部分,volumeClaimTemplates可以使用您选择的PersistentVolume提供程序提供的PersistentVolumes来提供持久存储。在这个示例中,我们将使用 Azure 存储类为您的应用程序动态创建 PV:

  1. 在应用程序部署清单的volumeClaimTemplates部分下添加azure-zrs存储类行,类似于以下示例:
...
  volumeClaimTemplates:
  - metadata:
      name: datadir
      annotations:
        volume.beta.kubernetes.io/storage-class: azure-zrs
    spec:
      accessModes: [ "ReadWriteOnce" ]
      resources:
        requests:
          storage: 1G
...
  1. 在这个示例中,我们将使用azure-zrs存储类部署 Redis Statefulset。在执行之前,请查看示例存储库中src/chapter5/azure目录下的 YAML 清单:
$ cat azure/redis-statefulset.yml
  1. 创建 Redis StatefulSet:
$ kubectl apply -f redis-statefulset.yml
  1. 验证已创建 Pod。在这个示例中,我们的示例有三个副本的 StatefulSet。因此,您应该看到三个副本正在运行,类似于以下输出:
$ kubectl get pods
NAME READY STATUS  RESTARTS AGE
rd-0 1/1   Running 0        6m24s
rd-1 1/1   Running 0        4m14s
rd-2 1/1   Running 0        2m13s
  1. 列出创建的 PVC 和 PV。您应该期望看到创建了三个 PVC 和三个 PV,类似于我们这里的示例输出:
$ kubectl get pvc, pv
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
datadir-rd-0 Bound pvc-afaafb97-d376-11e9-88a2-a2c82783dcda 1Gi RWO azure-zrs 4m31s
datadir-rd-1 Bound pvc-fc9f3a35-d376-11e9-88a2-a2c82783dcda 1Gi RWO azure-zrs 2m22s
datadir-rd-2 Bound pvc-453d185d-d377-11e9-88a2-a2c82783dcda 1Gi RWO azure-zrs 20s
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-453d185d-d377-11e9-88a2-a2c82783dcda 1Gi RWO Delete Bound default/datadir-rd-2 azure-zrs 22s
pvc-afaafb97-d376-11e9-88a2-a2c82783dcda 1Gi RWO Delete Bound default/datadir-rd-0 azure-zrs 4m42s
pvc-fc9f3a35-d376-11e9-88a2-a2c82783dcda 1Gi RWO Delete Bound default/datadir-rd-1 azure-zrs 2m38s

现在您知道如何在 AKS 集群上动态创建持久卷作为应用程序部署的一部分。

删除 Azure 磁盘持久卷

当回收策略设置为保留卷时,需要按照以下步骤单独删除卷:

  1. 请记住,除非 PVC 清单包含在清单中,否则删除工作负载不会删除 PVC 和 PV:
$ kubectl delete -f redis-statefulset.yml
statefulset.apps "rd" deleted
service "redis" deleted
  1. 列出剩余的 PV:
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-171fbee3-39bf-4450-961f-6c1417ff3897 1Gi RWO Retain Bound default/datadir-rd-1 aws-gp2 13m
pvc-8a538aa3-7382-4147-adde-1ea3dbaaafb4 1Gi RWO Retain Bound default/datadir-rd-0 aws-gp2 15m
pvc-b40df89b-5349-4f02-8510-917012579746 1Gi RWO Retain Bound default/datadir-rd-2 aws-gp2 12m
  1. 删除 PVC。您可以通过将它们的名称添加到单个命令中一次删除多个 PVC,类似于以下操作:
$ kubectl delete pvc datadir-rd-0 datadir-rd-1 datadir-rd-2

我们现在已成功删除了与 Redis StatefulSet 资源的创建相关的应用程序的所有存储资源。

安装 Azure Disk CSI 驱动程序

Azure Disk CSI 驱动程序提供了一个 Kubernetes CSI,允许 AKS 集群简单地管理 Azure 磁盘卷的生命周期,用于持久卷。在这个教程中,我们将学习安装 Azure Disk CSI 驱动程序所需的步骤,观察以下步骤:

  1. 部署 Azure Disk CSI 驱动程序:
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/azuredisk-csi-driver/master/deploy/crd-csi-driver-registry.yaml
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/azuredisk-csi-driver/master/deploy/crd-csi-node-info.yaml
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/azuredisk-csi-driver/master/deploy/rbac-csi-azuredisk-controller.yaml
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/azuredisk-csi-driver/master/deploy/csi-azuredisk-controller.yaml
$ kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/azuredisk-csi-driver/master/deploy/csi-azuredisk-node.yaml
  1. 验证驱动程序正在运行控制器,并且azuredisk-node DaemonSet 正在运行:
$ kubectl get po -o wide -n kube-system | grep csi-azuredisk
csi-azuredisk-controller-9bc7f4d77-cbgxs 6/6 Running 0 5m31s 10.244.2.4 aks-agentpool-40109510-2 <none> <none>
csi-azuredisk-node-7kqzm 3/3 Running 0 5m27s 10.240.0.5 aks-agentpool-40109510-1 <none> <none>
csi-azuredisk-node-gm6dr 3/3 Running 0 5m27s 10.240.0.4 aks-agentpool-40109510-2 <none> <none>
csi-azuredisk-node-wqsls 3/3 Running 0 5m27s 10.240.0.6 aks-agentpool-40109510-0 <none> <none>
  1. 现在,创建一个新的存储类:
$ cat <<EOF | kubectl apply -f -
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
 name: disk.csi.azure.com
provisioner: disk.csi.azure.com
parameters:
 skuname: Standard_LRS 
 kind: managed 
 cachingMode: ReadOnly
reclaimPolicy: Delete
volumeBindingMode: Immediate
EOF
  1. 使用存储类名称disk.csi.azure.com创建 PVC:
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
 name: csi-azure-pvc
spec:
 accessModes:
 - ReadWriteOnce
 storageClassName: disk.csi.azure.com
 resources:
 requests:
 storage: 4Gi
EOF
  1. 创建一个将使用csi-azure-pvc PVC 并写入/data/out.txt文件的 pod:
$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
 name: mytestapp
spec:
 containers:
 - name: app
 image: centos
 command: ["/bin/sh"]
 args: ["-c", "while true; do echo $(date -u) >> /data/out.txt; sleep 5; done"]
 volumeMounts:
 - name: persistent-storage
 mountPath: /data
 volumes:
 - name: persistent-storage
 persistentVolumeClaim:
 claimName: csi-azure-pvc
EOF
  1. 验证我们的mytestapp pod 是否将数据写入卷:
$ kubectl exec -it mytestapp cat /data/out.txt
Mon Sep 9 19:23:29 UTC 2019

现在您知道如何在 AKS 集群上使用 Azure Disk CSI 驱动程序来提供持久卷。

参见

使用 Rook 配置和管理持久存储

Rook 是一个面向 Kubernetes 的云原生开源存储编排器。Rook 在 Kubernetes 中提供自管理、自扩展和自愈的分布式存储系统。在本节中,我们将使用 Rook 存储编排器为 Kubernetes 中的应用程序创建多个存储提供程序。您将学习为需要持久存储的有状态应用程序创建 Ceph 提供程序。

准备工作

确保你已经准备好一个 Kubernetes 集群,并且kubectl已配置好以管理集群资源。

如何做…

这一部分进一步细分为以下子部分,以便进行流程:

  • 使用 Rook 安装 Ceph 提供程序

  • 创建一个 Ceph 集群

  • 验证 Ceph 集群的健康状态

  • 创建一个 Ceph 块存储类

  • 使用 Ceph 块存储类创建动态 PVs

使用 Rook 安装 Ceph 提供程序

让我们执行以下步骤,使用 Rook 项目来运行 Ceph 扩展存储解决方案:

  1. 克隆 Rook 存储库:
$ git clone https://github.com/rook/rook.git
$ cd rook/cluster/examples/kubernetes/ceph/
  1. 部署 Rook Operator:
$ kubectl create -f common.yaml 
$ kubectl create -f operator.yaml 
  1. 验证 Rook Operator:
$ kubectl get pod -n rook-ceph
NAME                                READY STATUS  RESTARTS AGE
rook-ceph-operator-6b66859964-vnrfx 1/1   Running 0        2m12s
rook-discover-8snpm                 1/1   Running 0        97s
rook-discover-mcx9q                 1/1   Running 0        97s
rook-discover-mdg2s                 1/1   Running 0        97s

现在你已经学会了如何在 Kubernetes 上运行 Ceph 提供程序的 Rook 编排组件。

创建一个 Ceph 集群

让我们执行以下步骤,使用 Rook Operator 部署 Ceph 集群:

  1. 创建一个 Ceph 集群:
$ cat <<EOF | kubectl apply -f -
apiVersion: ceph.rook.io/v1
kind: CephCluster
metadata:
 name: rook-ceph
 namespace: rook-ceph
spec:
 cephVersion:
 image: ceph/ceph:v14.2.3-20190904
 dataDirHostPath: /var/lib/rook
 mon:
 count: 3
 dashboard:
 enabled: true
 storage:
 useAllNodes: true
 useAllDevices: false
 directories:
 - path: /var/lib/rook
EOF
  1. 验证所有的 pod 是否正在运行:
$ kubectl get pod -n rook-ceph

在一分钟内,一个完全功能的 Ceph 集群将被部署并准备好使用。你可以在参见部分的Rook Ceph 存储文档链接中了解更多关于 Ceph 的信息。

验证 Ceph 集群的健康状态

Rook 工具箱是一个包含常用工具的容器,用于 Rook 调试和测试。让我们执行以下步骤来部署 Rook 工具箱以验证集群健康状态:

  1. 部署 Rook 工具箱:
$ kubectl apply -f toolbox.yaml
  1. 验证工具箱是否正在运行:
$ kubectl -n rook-ceph get pod -l "app=rook-ceph-tools"
NAME                             READY STATUS  RESTARTS AGE
rook-ceph-tools-6fdfc54b6d-4kdtm 1/1   Running 0        109s
  1. 连接到工具箱:
$ kubectl -n rook-ceph exec -it $(kubectl -n rook-ceph get pod -l "app=rook-ceph-tools" -o jsonpath='{.items[0].metadata.name}') bash
  1. 验证集群是否处于健康状态(HEALTH_OK):
# ceph status
 cluster:
 id: 6b6e4bfb-bfef-46b7-94bd-9979e5e8bf04
 health: HEALTH_OK
 services:
 mon: 3 daemons, quorum a,b,c (age 12m)
 mgr: a(active, since 12m)
 osd: 3 osds: 3 up (since 11m), 3 in (since 11m)
 data:
 pools: 0 pools, 0 pgs
 objects: 0 objects, 0 B
 usage: 49 GiB used, 241 GiB / 291 GiB avail
 pgs:
  1. 当你完成故障排除后,使用以下命令删除部署:
$ kubectl -n rook-ceph delete deployment rook-ceph-tools

现在你知道如何部署 Rook 工具箱及其常用工具,用于调试和测试 Rook。

创建一个 Ceph 块存储类

让我们执行以下步骤,为 Ceph 存储创建一个存储类:

  1. 创建CephBlockPool
$ cat <<EOF | kubectl apply -f -
apiVersion: ceph.rook.io/v1
kind: CephBlockPool
metadata:
 name: replicapool
 namespace: rook-ceph
spec:
 failureDomain: host
 replicated:
 size: 3
EOF
  1. 创建一个 Rook Ceph 块存储类:
$ cat <<EOF | kubectl apply -f -
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
 name: rook-ceph-block
provisioner: rook-ceph.rbd.csi.ceph.com
parameters:
 clusterID: rook-ceph
 pool: replicapool
 imageFormat: "2"
 imageFeatures: layering
 csi.storage.k8s.io/provisioner-secret-name: rook-ceph-csi
 csi.storage.k8s.io/provisioner-secret-namespace: rook-ceph
 csi.storage.k8s.io/node-stage-secret-name: rook-ceph-csi
 csi.storage.k8s.io/node-stage-secret-namespace: rook-ceph
 csi.storage.k8s.io/fstype: xfs
reclaimPolicy: Delete
EOF
  1. 确认存储类已创建:
$ kubectl get sc
NAME              PROVISIONER                AGE
default (default) kubernetes.io/azure-disk   6h27m
rook-ceph-block   rook-ceph.rbd.csi.ceph.com 3s

从前面的提供者名称rook-ceph.rbd.csi.ceph.com可以看出,Rook 还使用 CSI 与 Kubernetes API 进行交互。该驱动程序针对 RWO pod 访问进行了优化,其中只有一个 pod 可以访问存储。

使用 Ceph 块存储类创建动态 PVs

在这个示例中,我们将使用 Rook Ceph 块存储提供程序创建动态持久卷来部署 Wordpress。让我们执行以下步骤:

  1. 克隆示例存储库:
$ git clone https://github.com/k8sdevopscookbook/src.git
$ cd src/chapter5/rook/
  1. 查看mysql.yamlwordpress.yaml。注意 PVC 正在使用rook-ceph-block存储类:
$ cat mysql.yaml && cat wordpress.yaml
  1. 部署 MySQL 和 WordPress:
$ kubectl apply -f mysql.yaml 
$ kubectl apply -f wordpress.yaml
  1. 确认已创建持久卷:
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-eb2d23b8-d38a-11e9-88a2-a2c82783dcda 20Gi RWO Delete Bound default/mysql-pv-claim rook-ceph-block 38s
pvc-eeab1ebc-d38a-11e9-88a2-a2c82783dcda 20Gi RWO Delete Bound default/wp-pv-claim rook-ceph-block 38s
  1. 获取 WordPress 服务的外部 IP:
$ kubectl get service
NAME            TYPE         CLUSTER-IP  EXTERNAL-IP  PORT(S)      AGE
kubernetes      ClusterIP    10.0.0.1    <none>       443/TCP      6h34m
wordpress       LoadBalancer 10.0.102.14 13.64.96.240 80:30596/TCP 3m36s
wordpress-mysql ClusterIP    None        <none>       3306/TCP     3m42s
  1. 在浏览器中打开 WordPress 服务的外部 IP 以访问您的 WordPress 部署:

现在您知道如何获取流行的 WordPress 服务,并在基于 Rook 的 Ceph 存储上存储持久存储。

另请参阅

使用 OpenEBS 配置和管理持久存储

OpenEBS 是一个受欢迎的开源、云原生存储(CNS)项目,拥有庞大的社区。在本节中,我们将安装 OpenEBS 持久存储提供程序。您将学习如何在 Kubernetes 上为有状态工作负载使用不同类型的存储引擎选项创建卷。

准备工作

对于这个步骤,我们需要安装helmkubectl。确保您已经准备好一个 Kubernetes 集群,并且kubectl配置好以管理集群资源。

操作步骤

本节进一步细分为以下子节,以便促进流程:

  • 安装 iSCSI 客户端先决条件

  • 安装 OpenEBS

  • 使用临时存储创建持久卷

  • 创建存储池

  • 创建 OpenEBS 存储类

  • 使用 OpenEBS 存储类创建动态 PV

安装 iSCSI 客户端先决条件

OpenEBS 存储提供程序要求 iSCSI 客户端在所有工作节点上运行:

  1. 在所有工作节点上,按照安装和启用open-iscsi的步骤进行操作:
$ sudo apt-get update && sudo apt-get install open-iscsi && sudo service open-iscsi restart
  1. 验证 iSCSI 服务是否在运行:
$ systemctl status iscsid
● iscsid.service - iSCSI initiator daemon (iscsid)
 Loaded: loaded (/lib/systemd/system/iscsid.service; enabled; vendor preset: enabled)
 Active: active (running) since Sun 2019-09-08 07:40:43 UTC; 7s ago
 Docs: man:iscsid(8)
  1. 如果服务状态显示为非活动状态,则启用并启动 iscsid 服务:
$ sudo systemctl enable iscsid && sudo systemctl start iscsid

安装 iSCSI 服务后,您可以在集群上安装 OpenEBS。

安装 OpenEBS

让我们执行以下步骤,快速安装 OpenEBS 控制平面:

  1. 使用运算符安装 OpenEBS 服务:
$ kubectl apply -f https://openebs.github.io/charts/openebs-operator.yaml
  1. 确认所有 OpenEBS pod 都在运行:
$ kubectl get pods --namespace openebs
NAME                                        READY STATUS  RESTARTS AGE
maya-apiserver-dcbc87f7f-k99fz              0/1   Running 0        88s
openebs-admission-server-585c6588d-j29ng    1/1   Running 0        88s
openebs-localpv-provisioner-cfbd49877-jzjxl 1/1   Running 0        87s
openebs-ndm-fcss7                           1/1   Running 0        88s
openebs-ndm-m4qm5                           1/1   Running 0        88s
openebs-ndm-operator-bc76c6ddc-4kvxp        1/1   Running 0        88s
openebs-ndm-vt76c                           1/1   Running 0        88s
openebs-provisioner-57bbbd888d-jb94v        1/1   Running 0        88s
openebs-snapshot-operator-7dd598c655-2ck74  2/2   Running 0        88s

OpenEBS 由以下核心组件组成。Node Disk Manager (NDM)是 OpenEBS 的重要组成部分之一,负责检测磁盘更改,并作为 DaemonSet 在您的工作节点上运行。

使用临时存储创建持久卷

OpenEBS 目前提供三种存储引擎选项(Jiva、cStor 和 LocalPV)。第一个存储引擎选项Jiva可以在临时存储之上创建复制存储。让我们执行以下步骤来使用临时存储配置存储:

  1. 列出默认存储类:
$ kubectl get sc
NAME                      PROVISIONER                                              AGE
openebs-device            openebs.io/local                                         25m
openebs-hostpath          openebs.io/local                                         25m
openebs-jiva-default      openebs.io/provisioner-iscsi                             25m
openebs-snapshot-promoter volumesnapshot.external-storage.k8s.io/snapshot-promoter 25m
  1. 描述openebs-jiva-default存储类:
$ kubectl describe sc openebs-jiva-default
Name: openebs-jiva-default
IsDefaultClass: No
Annotations: cas.openebs.io/config=- name: ReplicaCount
 value: "3"
- name: StoragePool
 value: default
  1. 使用openebs-jiva-default创建持久卷声明:
$ cat <<EOF | kubectl apply -f -
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
 name: demo-vol1-claim
spec:
 storageClassName: openebs-jiva-default
 accessModes:
 - ReadWriteOnce
 resources:
 requests:
 storage: 5G
EOF
  1. 确认 PVC 状态为BOUND
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
demo-vol1-claim Bound pvc-cb7485bc-6d45-4814-adb1-e483c0ebbeb5 5G RWO openebs-jiva-default 4s
  1. 现在,使用 PVC 动态提供持久卷:
$ kubectl apply -f https://raw.githubusercontent.com/openebs/openebs/master/k8s/demo/percona/percona-openebs-deployment.yaml
  1. 现在列出 Pod,并确保您的工作负载、OpenEBS 控制器和副本都处于运行状态:
$ kubectl get pods
NAME                                                          READY STATUS  RESTARTS AGE
percona-767db88d9d-2s8np                                      1/1   Running 0        75s
pvc-cb7485bc-6d45-4814-adb1-e483c0ebbeb5-ctrl-54d7fd794-s8svt 2/2   Running 0        2m23s
pvc-cb7485bc-6d45-4814-adb1-e483c0ebbeb5-rep-647458f56f-2b9q4 1/1   Running 1        2m18s
pvc-cb7485bc-6d45-4814-adb1-e483c0ebbeb5-rep-647458f56f-nkbfq 1/1   Running 0        2m18s
pvc-cb7485bc-6d45-4814-adb1-e483c0ebbeb5-rep-647458f56f-x7s9b 1/1   Running 0        2m18s

现在您知道如何为 Kubernetes 上的有状态应用程序配置高可用的云原生存储。

创建存储池

在这个示例中,我们将使用附加到您的节点的原始块设备来创建存储池。这些设备可以是 AWS EBS 卷、GCP PD、Azure 磁盘、虚拟磁盘或 vSAN 卷。设备可以附加到您的工作节点 VM,或者如果您使用裸金属 Kubernetes 集群,则可以是基本物理磁盘。让我们执行以下步骤来从原始块设备创建存储池:

  1. 列出节点上未使用和未声明的块设备:
$ kubectl get blockdevices -n openebs
NAME NODENAME SIZE CLAIMSTATE STATUS AGE
blockdevice-24d9b7652893384a36d0cc34a804c60c ip-172-23-1-176.us-west-2.compute.internal 107374182400 Unclaimed Active 52s
blockdevice-8ef1fd7e30cf0667476dba97975d5ac9 ip-172-23-1-25.us-west-2.compute.internal 107374182400 Unclaimed Active 51s
blockdevice-94e7c768ef098a74f3e2c7fed6d82a5f ip-172-23-1-253.us-west-2.compute.internal 107374182400 Unclaimed Active 52s

在我们的示例中,我们在 AWS EC2 上有一个三节点的 Kubernetes 集群,每个节点附加了一个额外的 EBS 卷。

  1. 使用未声明的设备从步骤 1创建存储池:
$ cat <<EOF | kubectl apply -f -
apiVersion: openebs.io/v1alpha1
kind: StoragePoolClaim
metadata:
 name: cstor-disk-pool
 annotations:
 cas.openebs.io/config: |
 - name: PoolResourceRequests
 value: |-
 memory: 2Gi
 - name: PoolResourceLimits
 value: |-
 memory: 4Gi
spec:
 name: cstor-disk-pool
 type: disk
 poolSpec:
 poolType: striped
 blockDevices:
 blockDeviceList:
 - blockdevice-24d9b7652893384a36d0cc34a804c60c
 - blockdevice-8ef1fd7e30cf0667476dba97975d5ac9
 - blockdevice-94e7c768ef098a74f3e2c7fed6d82a5f
EOF
  1. 列出存储池声明:
$ kubectl get spc
NAME AGE
cstor-disk-pool 29s
  1. 验证是否已创建 cStor 池并且其状态为“健康”:
$ kubectl get csp
NAME                 ALLOCATED FREE  CAPACITY STATUS  TYPE    AGE
cstor-disk-pool-8fnp 270K      99.5G 99.5G    Healthy striped 3m9s
cstor-disk-pool-nsy6 270K      99.5G 99.5G    Healthy striped 3m9s
cstor-disk-pool-v6ue 270K      99.5G 99.5G    Healthy striped 3m10s
  1. 现在我们可以使用存储类中的存储池来提供动态卷。

创建 OpenEBS 存储类

让我们执行以下步骤来创建一个新的存储类来使用之前创建的 StoragePool:

  1. 使用 cStor StoragePoolClaim名称cstor-disk-pool创建一个 OpenEBS cStor 存储类,带有三个副本:
$ cat <<EOF | kubectl apply -f -
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
 name: openebs-cstor-default
 annotations:
 openebs.io/cas-type: cstor
 cas.openebs.io/config: |
 - name: StoragePoolClaim
 value: "cstor-disk-pool"
 - name: ReplicaCount
 value: "3"
provisioner: openebs.io/provisioner-iscsi
EOF
  1. 列出存储类:
$ kubectl get sc
NAME                  PROVISIONER                  AGE
default               kubernetes.io/aws-ebs        25m
gp2 (default)         kubernetes.io/aws-ebs        25m
openebs-cstor-default openebs.io/provisioner-iscsi 6s
openebs-device        openebs.io/local             20m
openebs-hostpath      openebs.io/local             20m
openebs-jiva-default  openebs.io/provisioner-iscsi 20m
openebs-snapshot-promoter volumesnapshot.external-storage.k8s.io/snapshot-promoter 20m
ubun
  1. gp2 AWS EBS 存储类设置为非默认选项:
$ kubectl patch storageclass gp2 -p '{"metadata": {"annotations":{"storageclass.beta.kubernetes.io/is-default-class":"false"}}}'
  1. openebs-cstor-default定义为默认存储类:
$ kubectl patch storageclass openebs-cstor-default -p '{"metadata": {"annotations":{"storageclass.kubernetes.io/is-default-class":"true"}}}'

确保以前的存储类不再设置为默认,并且您只有一个默认存储类。

使用 OpenEBS 存储类创建动态 PVs

让我们执行以下步骤来使用 OpenEBS 存储提供程序动态创建持久卷:

  1. 克隆示例存储库:
$ git clone https://github.com/k8sdevopscookbook/src.git
$ cd src/chapter5/openebs/
  1. 审查minio.yaml,注意 PVC 正在使用openebs-stor-default存储类。

  2. 部署 Minio:

$ kubectl apply -f minio.yaml
deployment.apps/minio-deployment created
persistentvolumeclaim/minio-pv-claim created
service/minio-service created
  1. 获取 Minio 服务负载均衡器的外部 IP:
$ kubectl get service
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.3.0.1 <none> 443/TCP 54m
minio-service LoadBalancer 10.3.0.29 adb3bdaa893984515b9527ca8f2f8ca6-1957771474.us-west-2.elb. amazonaws.com 9000:32701/TCP 3s
  1. 在地址末尾添加端口9000,并在浏览器中打开 Minio 服务的外部 IP:

  2. 使用用户名minio和密码minio123登录由持久 OpenEBS 卷支持的 Minio 部署:

您现在已成功部署了一个部署在 OpenEBS cStor 存储引擎上的有状态应用程序。

它是如何工作的...

这个配方向您展示了如何快速使用 OpenEBS 提供持久存储。

使用临时存储创建持久卷配方中,在步骤 6中,当我们使用openebs-jiva-default存储类部署工作负载时,OpenEBS 启动了具有三个副本的 OpenEBS 卷。

要设置一个副本,就像单节点 Kubernetes 集群一样,您可以创建一个新的存储类(类似于我们在创建 OpenEBS 存储类配方中创建的存储类),并将ReplicaCount变量值设置为1

apiVersion: openebs.io/v1alpha1
kind: StoragePool
metadata:
  name: my-pool
  type: hostdir
spec:
  path: "/my/openebs/folder"

当使用临时存储时,OpenEBS Jiva 存储引擎使用每个可用节点上的/var/openebs目录来创建副本稀疏文件。如果您想要更改默认值或创建新的 StoragePool 资源,您可以创建一个新的存储池并设置自定义路径。

另请参阅

为 Kubernetes 设置 NFS 共享存储

尽管它不是最佳性能的解决方案,但 NFS 仍然与需要多节点写访问的云原生应用程序一起使用。在本节中,我们将为这种类型的应用程序创建基于 NFS 的持久存储。您将学习如何使用 OpenEBS 和 Rook 为需要在 Kubernetes 上共享存储的有状态工作负载提供ReadWriteManyRWX)可访问的持久卷。

准备就绪

对于本教程,我们需要安装rookopenebs作为编排器。确保您已准备好 Kubernetes 集群,并配置了kubectl以管理集群资源。

如何做…

在提供 NFS 服务时,有两种常用的选择。本节进一步细分为以下子节,以解释使用 Rook 和 OpenEBS 的过程:

  • 安装 NFS 先决条件

  • 使用 Rook NFS 运算符安装 NFS 提供程序

  • 使用 Rook NFS 运算符存储类创建动态 NFS PV

  • 使用 OpenEBS 安装 NFS 提供程序

  • 使用 OpenEBS 运算符存储类创建动态 NFS PV

安装 NFS 先决条件

要能够挂载 NFS 卷,需要在计划挂载 NFS 的所有工作节点上预先安装 NFS 客户端软件包:

  1. 如果您使用 Ubuntu,在所有工作节点上安装nfs-common
$ sudo apt install -y nfs-common
  1. 如果使用 CentOS,在所有工作节点上安装nfs-common
$ yum install nfs-utils

现在我们在工作节点上安装了nfs-utils,准备部署 NFS 服务器。

使用 Rook NFS 运算符安装 NFS 提供程序

让我们执行以下步骤,使用 Rook NFS 提供程序选项使 NFS 提供程序功能正常:

  1. 克隆 Rook 存储库:
$ git clone https://github.com/rook/rook.git
$ cd rook/cluster/examples/kubernetes/nfs/
  1. 部署 Rook NFS 运算符:
$ kubectl create -f operator.yaml
  1. 确认运算符正在运行:
$ kubectl get pods -n rook-nfs-system
NAME READY STATUS RESTARTS AGE
rook-nfs-operator-54cf68686c-f66f5 1/1 Running 0 51s
rook-nfs-provisioner-79fbdc79bb-hf9rn 1/1 Running 0 51s
  1. 创建一个命名空间rook-nfs
$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Namespace
metadata:
 name: rook-nfs
EOF
  1. 确保您已将首选存储提供程序定义为默认存储类。在本教程中,我们使用在 OpenEBS 教程中定义的openebs-cstor-default

  2. 创建 PVC:

$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
 name: nfs-default-claim
 namespace: rook-nfs
spec:
 accessModes:
 - ReadWriteMany
 resources:
 requests:
 storage: 1Gi
EOF
  1. 创建 NFS 实例:
$ cat <<EOF | kubectl apply -f -
apiVersion: nfs.rook.io/v1alpha1
kind: NFSServer
metadata:
 name: rook-nfs
 namespace: rook-nfs
spec:
 serviceAccountName: rook-nfs
 replicas: 1
 exports:
 - name: share1
 server:
 accessMode: ReadWrite
 squash: "none"
 persistentVolumeClaim:
 claimName: nfs-default-claim
 annotations:
 # key: value
EOF
  1. 验证 NFS pod 处于“运行”状态:
$ kubectl get pod -l app=rook-nfs -n rook-nfs 
NAME       READY  STATUS  RESTARTS AGE
rook-nfs-0 1/1    Running 0        2m

通过观察上述命令,将创建一个 NFS 服务器实例类型。

使用 Rook NFS 运算符存储类创建动态 NFS PV

由于 NFS 具有对 Kubernetes 环境中的ReadWriteMany功能,因此需要同时访问相同数据的应用程序。在本教程中,我们将执行以下步骤,动态创建基于 NFS 的持久卷:

  1. 使用来自使用 Rook NFS 运算符安装 NFS 提供程序教程的exportNamenfsServerNamenfsServerNamespace创建 Rook NFS 存储类:
$ cat <<EOF | kubectl apply -f -
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
 labels:
 app: rook-nfs
 name: rook-nfs-share1
parameters:
 exportName: share1
 nfsServerName: rook-nfs
 nfsServerNamespace: rook-nfs
provisioner: rook.io/nfs-provisioner
reclaimPolicy: Delete
volumeBindingMode: Immediate
EOF
  1. 现在,您可以使用rook-nfs-share1存储类为需要ReadWriteMany访问的应用程序创建 PVC:
$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
 name: rook-nfs-pv-claim
spec:
 storageClassName: "rook-nfs-share1"
 accessModes:
 - ReadWriteMany
 resources:
 requests:
 storage: 1Mi
EOF

通过观察上述命令,将创建一个 NFS PV。

使用 OpenEBS 安装 NFS 提供程序

OpenEBS 提供了一个 NFS 提供程序,该提供程序受到 OpenEBS 的基础存储引擎选项的保护。让我们执行以下步骤来启动并运行 OpenEBS 的 NFS 服务:

  1. 克隆示例存储库:
$ git clone https://github.com/k8sdevopscookbook/src.git
$ cd src/chapter5/openebs
  1. 在这个示例中,我们使用了openebs-jiva-default存储类。查看目录内容,并在 NFS 目录下应用YAML文件:
$ kubectl apply -f nfs
  1. 列出 PVC,并确认是否创建了名为openebspvc的 PVC:
$ kubectl get pvc
NAME       STATUS VOLUME                                   CAPACITY ACCESS MODES STORAGECLASS         AGE
openebspvc Bound  pvc-9f70c0b4-efe9-4534-8748-95dba05a7327 110G     RWO          openebs-jiva-default 13m

使用 OpenEBS NFS 提供程序存储类创建动态 NFS PV

让我们执行以下步骤来动态部署由 OpenEBS 存储提供程序保护的 NFS PV:

  1. 列出存储类,并确认openebs-nfs是否存在:
$ kubectl get sc
NAME                            PROVISIONER                  AGE
openebs-cstor-default (default) openebs.io/provisioner-iscsi 14h
openebs-device                  openebs.io/local             15h
openebs-hostpath                openebs.io/local             15h
openebs-jiva-default            openebs.io/provisioner-iscsi 15h
openebs-nfs                     openebs.io/nfs               5s
openebs-snapshot-promoter       volumesnapshot.external-storage.k8s.io/snapshot-promoter 15h
  1. 现在,您可以使用openebs-nfs存储类为需要ReadWriteMany访问的应用程序创建 PVC:
$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
 name: openebs-nfs-pv-claim
spec:
 storageClassName: "openebs-nfs"
 accessModes:
 - ReadWriteMany
 resources:
 requests:
 storage: 1Mi
EOF

另请参阅

故障排除存储问题

在本节中,您将学习如何解决与 Kubernetes 相关的最常见存储问题。在本章的示例中,您将获得解决持久卷挂起或终止状态所需的基本技能。

做好准备

确保您已准备好 Kubernetes 集群,并配置了kubectl以管理集群资源。

如何做…

这一部分进一步细分为以下子部分,以便促进流程:

  • 持久卷处于挂起状态

  • 一旦 PVC 被删除,PV 就会卡住

持久卷处于挂起状态

您已部署了一个应用程序,但是 pod 和持久卷声明都卡在挂起状态,类似于以下情况:

$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
mysql-pv-claim Pending rook-ceph-block 28s

让我们执行以下步骤来开始故障排除:

  1. 首先,描述 PVC 以了解根本原因:
$ kubectl describe pvc mysql-pv-claim
...
Events:
 Type Reason Age From Message
 ---- ------ ---- ---- -------
 Warning ProvisioningFailed 3s (x16 over 3m42s) persistentvolume-controller storageclass.storage.k8s.io "rook-ceph-block" not found
  1. 由于存储类不正确或不存在,PVC 被卡住。我们需要用有效的资源更改存储类。列出存储类如下:
$ kubectl get sc
NAME                             PROVISIONER                                              AGE
default                          kubernetes.io/aws-ebs                                    102m
gp2                              kubernetes.io/aws-ebs                                    102m
openebs-cstor-default (default)  openebs.io/provisioner-iscsi                             77m
openebs-device                   openebs.io/local                                         97m
openebs-hostpath                 openebs.io/local                                         97m
openebs-jiva-default             openebs.io/provisioner-iscsi                             97m
openebs-snapshot-promoter        volumesnapshot.external-storage.k8s.io/snapshot-promoter 97m
  1. 使用kubectl delete -f <deployment.yaml>删除部署。

  2. 编辑部署并用前一步骤输出的有效存储类替换storageClassName字段,我们的情况下是openebs-cstor-default

  3. 重新部署应用程序使用kubectl apply -f <deployment.yaml>

  4. 确认 PVC 状态为“已绑定”:

$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
mysql-pv-claim Bound pvc-bbf2b01e-2a69-4c4c-b9c2-48921959c363 20Gi RWO openebs-cstor-default 5s

现在您已成功排除了由于缺少 StorageClass 资源而引起的 PVC 问题。

一旦删除了 PVC,PV 就会卡住

您已删除了一个 PVC。但是,无论是 PVC 还是 PV 的删除都卡在终止状态,类似于以下情况:

$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
pvc-bbf2b01e-2a69-4c4c-b9c2-48921959c363 20Gi RWO Delete Terminating default/mysql-pv-claim gp2 7m45s

编辑卡在终止状态的 PV 或 PVC:

$ kubectl edit pv <PV_Name>

删除类似于- kubernetes.io/pv-protection的 finalizers,并保存更改。

第六章:灾难恢复和备份

在本章中,我们将专注于备份和灾难恢复方案,以保持生产中的应用程序高度可用,并允许它们在云提供商或基本 Kubernetes 节点故障期间快速恢复服务。在本章中遵循配方后,您将掌握用于灾难恢复DR)的工具,并能够在集群和云之间实时迁移应用程序。

本章中,我们将涵盖以下配方:

  • 使用 MinIO 配置和管理 S3 对象存储

  • 管理 Kubernetes 卷快照和恢复

  • 使用 Velero 进行应用程序备份和恢复

  • 使用 Kasten 进行应用程序备份和恢复

  • 跨云应用程序迁移

技术要求

本章的配方假定您已通过第一章中描述的推荐方法之一部署了功能性 Kubernetes 集群,构建生产就绪的 Kubernetes 集群

Kubernetes 操作工具kubectl将在本章的其余配方中使用,因为它是针对 Kubernetes 集群运行命令的主要命令行界面。如果您正在使用 Red Hat OpenShift 集群,可以用oc替换kubectl。所有命令都预计以类似的方式运行。

使用 MinIO 配置和管理 S3 对象存储

在本节中,我们将使用 MinIO 创建 S3 对象存储,以存储 Kubernetes 中您的应用程序创建的工件或配置文件。您将学习如何创建部署清单文件,部署 S3 服务,并为其他应用程序或用户提供外部 IP 地址以使用该服务。

准备工作

k8sdevopscookbook/src存储库克隆到您的工作站,以便在chapter6目录下使用清单文件,如下所示:

$ git clone https://github.com/k8sdevopscookbook/src.git
$ cd src/chapter6

确保您已准备好一个 Kubernetes 集群,并配置了kubectl,以便您可以管理集群资源。

如何做…

本节进一步分为以下子节,以使此过程更容易:

  • 创建部署 YAML 清单

  • 创建 MinIO S3 服务

  • 访问 MinIO Web 用户界面

创建部署 YAML 清单

所有 Kubernetes 资源都是通过使用 YAML 清单文件以声明方式创建的。让我们执行以下步骤来创建一个示例文件,稍后我们将在 Kubernetes 中部署应用程序时使用它:

  1. 对于这个配方,我们将使用 MinIO 创建一些资源,以便我们可以了解文件格式,并在以后帮助我们部署完全功能的应用程序。通过访问min.io/download#/kubernetes打开 MinIO 下载网站。

  2. 在 MinIO 网站上,从可用下载选项列表中,单击 Kubernetes 按钮,然后选择 Kubernetes CLI 选项卡。此页面将帮助我们根据我们的偏好生成 MinIO 应用程序所需的 YAML 内容:

  1. 输入您的访问密钥和秘密密钥对。在我们的示例中,我们使用了minio/minio123。当您访问 MinIO 服务时,这将代替用户名和密码。选择分布式作为部署模型,并输入4作为节点数。此选项将创建一个具有四个副本的 StatefulSet。输入10GB 作为大小。在我们的示例中,我们将使用以下配置屏幕上显示的值:

  1. 单击“生成”按钮并检查文件内容。您将注意到存储在 YAML 清单中的三种不同资源,包括服务、StatefulSet 和第二个服务,它将创建一个云负载均衡器来将第一个服务端口暴露给外部访问。

  2. 复制内容,并将其保存为minio.yaml在您的工作站上。

创建 MinIO S3 服务

让我们执行以下步骤来创建必要的资源,以使用 MinIO 获得功能齐全的 S3 服务:

  1. 使用您在创建部署 YAML 清单配方中创建的 YAML 清单部署 MinIO:
$ kubectl apply -f minio.yaml

作为替代方法,您可以使用示例存储库中/src/chapter6/minio目录下保存的示例 YAML 文件,使用$ kubectl apply -f minio/minio.yaml命令。

  1. 验证 StatefulSet。您应该看到 4 个 4 个副本部署,类似于以下输出。请注意,如果您以独立方式部署,您将没有 StatefulSets:
$ kubectl get statefulsets
NAME  READY AGE
minio 4/4   2m17s

现在,您已经部署了一个 MinIO 应用程序。在下一个配方中,我们将学习如何发现其外部地址以访问该服务。

访问 MinIO Web 用户界面

作为部署过程的一部分,我们让 MinIO 创建一个云负载均衡器来将服务暴露给外部访问。在这个配方中,我们将学习如何访问 MinIO 界面,以上传和下载文件到 S3 后端。为此,我们将执行以下步骤:

  1. 使用以下命令获取minio-service LoadBalancer 的外部 IP。您将在EXTERNAL-IP列下看到公开的服务地址,类似于以下输出:
$ kubectl get service
NAME          TYPE         CLUSTER-IP EXTERNAL-IP                     PORT(S)  AGE
minio         ClusterIP    None       <none>                          9000/TCP 2m49s
minio-service LoadBalancer 10.3.0.4   abc.us-west-2.elb.amazonaws.com 9000:30345/TCP 2m49s
  1. 正如您所看到的,输出服务是通过端口9000公开的。要访问该服务,我们还需要将端口9000添加到地址的末尾(http://[externalIP]:9000),并在浏览器中打开 MinIO 服务的公共地址。

  2. 您需要有权限访问仪表板。使用我们之前创建的默认用户名minio和默认密码minio123登录到 Minio 部署。登录后,您将能够访问 MinIO 浏览器,如下面的屏幕截图所示:

MinIO 与亚马逊 S3 云存储服务兼容,最适合存储照片、日志文件和备份等非结构化数据。现在您可以访问 MinIO 用户界面,创建 buckets,上传文件,并通过 S3 API 访问它们,类似于访问标准的亚马逊 S3 服务来存储您的备份。您可以通过转到另请参阅部分中的MinIO 文档链接来了解更多关于 MinIO 的信息。

工作原理...

这个配方向您展示了如何在 Kubernetes 上部署 MinIO 来提供完全兼容 Amazon S3 API 的服务。此服务将在以后用于灾难恢复和备份在 Kubernetes 上运行的应用程序。

创建 MinIO S3 服务配方中,在步骤 1中,当我们部署 MinIO 时,它会在端口9000创建一个 LoadBalancer 服务。由于我们将节点数设置为4,将创建一个具有四个副本的 StatefulSet。每个副本将使用volumeClaimTemplates部分设置的信息来创建 PVC。如果未明确定义storageClassName,则将使用默认存储类。结果,您将在集群上看到创建了四个PersistentVolumesClaim(PVC)实例,以提供高可用的 MinIO 服务。

另请参阅

管理 Kubernetes 卷快照和恢复

在本节中,我们将在 Kubernetes 中从我们的持久卷创建卷快照。通过按照这个步骤,您将学习如何启用卷快照功能,创建快照存储类,并从现有的卷快照中恢复。

准备工作

确保您有一个准备好的 Kubernetes 集群,并配置kubectl来管理集群资源。

k8sdevopscookbook/src存储库克隆到您的工作站,以便使用chapter6目录下的清单文件,如下所示:

$ git clone https://github.com/k8sdevopscookbook/src.git
$ cd src/chapter6

确保您首选存储供应商的容器存储接口CSI)驱动程序已安装在您的 Kubernetes 集群上,并且已实现了快照功能。我们在第五章中介绍了 AWS EBS、GCP PD、Azure Disk、Rook 和 OpenEBS CSI 驱动程序的安装,为有状态的工作负载做准备

本节中的说明与其他支持通过 CSI 进行快照的供应商类似。您可以在 Kubernetes CSI 文档网站上找到这些额外的驱动程序:kubernetes-csi.github.io/docs/drivers.html

如何做…

本节进一步分为以下子节,以使这个过程更容易:

  • 启用功能门

  • 通过 CSI 创建卷快照

  • 通过 CSI 从快照还原卷

  • 通过 CSI 克隆卷

启用功能门

这里将讨论的一些功能目前可能处于不同的阶段(alpha、beta 或 GA)。如果遇到问题,请执行以下步骤:

  1. kube-apiserverkubelet设置以下feature-gates标志为true
- --feature-gates=VolumeSnapshotDataSource=true
- --feature-gates=KubeletPluginsWatcher=true
- --feature-gates=CSINodeInfo=true
- --feature-gates=CSIDriverRegistry=true
- --feature-gates=BlockVolume=true
- --feature-gates=CSIBlockVolume=true

您可以通过转到参见部分中的Kubernetes 功能门链接,找到功能及其状态的最新状态。

通过 CSI 创建卷快照

卷快照是从 Kubernetes 集群中的 PVC 中获取的状态的副本。它是一个有用的资源,可以使用现有数据启动有状态的应用程序。让我们按照以下步骤使用 CSI 创建卷快照:

  1. 创建 PVC 或选择现有的 PVC。在我们的食谱中,我们将使用 AWS EBS CSI 驱动程序和我们在第五章中创建的aws-csi-ebs存储类,为有状态的工作负载做准备,在安装 EBS CSI 驱动程序来管理 EBS 卷食谱中:
$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
 name: csi-ebs-pvc
spec:
 accessModes:
 - ReadWriteOnce
 storageClassName: aws-csi-ebs
 resources:
 requests:
 storage: 4Gi
EOF
  1. 创建一个 pod,它将写入PersistentVolumePV)内的/data/out.txt文件:
$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
 name: app
spec:
 containers:
 - name: app
 image: centos
 command: ["/bin/sh"]
 args: ["-c", "while true; do echo $(date -u) >> /data/out.txt; sleep 5; done"]
 volumeMounts:
 - name: persistent-storage
 mountPath: /data
 volumes:
 - name: persistent-storage
 persistentVolumeClaim:
 claimName: csi-ebs-pvc
EOF
  1. 创建VolumeSnapshotClass。确保快照提供程序设置为您的 CSI 驱动程序名称。在这个食谱中,这是ebs.csi.aws.com
$ cat <<EOF | kubectl apply -f -
apiVersion: snapshot.storage.k8s.io/v1alpha1
kind: VolumeSnapshotClass
metadata:
 name: csi-ebs-vsc
snapshotter: ebs.csi.aws.com
EOF
  1. 必须使用存储供应商的 CSI 驱动程序创建 PVC。在我们的食谱中,我们将使用我们在安装 EBS CSI 驱动程序来管理 EBS 卷食谱中创建的 PVC。现在,使用我们在步骤 1中设置的 PVC 名称(csi-ebs-pvc)创建VolumeSnapshot
$ cat <<EOF | kubectl apply -f -
apiVersion: snapshot.storage.k8s.io/v1alpha1
kind: VolumeSnapshot
metadata:
 name: ebs-volume-snapshot
spec:
 snapshotClassName: csi-ebs-vsc
 source:
 name: csi-ebs-pvc
 kind: PersistentVolumeClaim
EOF
  1. 列出卷快照:
$ kubectl get volumesnapshot
NAME AGE
ebs-volume-snapshot 18s
  1. 在检查以下命令的输出时,验证状态是否为Ready To Use: true
$ kubectl describe volumesnapshot ebs-volume-snapshot

通过 CSI 从快照还原卷

我们可以创建快照以尝试还原其他快照。让我们执行以下步骤来还原我们在上一个食谱中创建的快照:

  1. 使用以下命令从快照中还原卷,并使用 PVC。如您所见,将基于ebs-volume-snapshot快照创建一个名为csi-ebs-pvc-restored的新 PVC:
$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
 name: csi-ebs-pvc-restored
spec:
 accessModes:
 - ReadWriteOnce
 storageClassName: aws-csi-ebs
 resources:
 requests:
 storage: 4Gi
 dataSource:
 name: ebs-volume-snapshot
 kind: VolumeSnapshot
 apiGroup: snapshot.storage.k8s.io
EOF
  1. 创建另一个 pod,它将继续写入 PV 内的/data/out.txt文件。此步骤将确保卷在创建后仍然可以访问:
$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
 name: newapp
spec:
 containers:
 - name: app
 image: centos
 command: ["/bin/sh"]
 args: ["-c", "while true; do echo $(date -u) >> /data/out.txt; sleep 5; done"]
 volumeMounts:
 - name: persistent-storage
 mountPath: /data
 volumes:
 - name: persistent-storage
 persistentVolumeClaim:
 claimName: csi-ebs-pvc-restored
EOF
  1. 确认newapp pod 包含恢复的数据和创建卷快照食谱中的时间戳:
$ kubectl exec -it newapp cat /data/out.txt

通过这个,您已经学会了如何从现有快照中提供持久卷。这是 CI/CD 流水线中非常有用的一步,这样您就可以节省时间来排查失败的流水线。

通过 CSI 克隆卷

虽然快照是 PV 的某个状态的副本,但这并不是创建数据副本的唯一方法。CSI 还允许从现有卷创建新卷。在这个食谱中,我们将执行以下步骤,使用现有 PVC 创建一个 PVC:

  1. 获取 PVC 列表。您可能有多个 PVC。在这个例子中,我们将使用我们在创建卷快照食谱中创建的 PVC。只要已经使用支持VolumePVCDataSource API 的 CSI 驱动程序创建了另一个 PVC,您就可以使用另一个 PVC:
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
csi-ebs-pvc Bound pvc-574ed379-71e1-4548-b736-7137ab9cfd9d 4Gi RWO aws-csi-ebs 23h
  1. 使用现有的 PVC(在本示例中为csi-ebs-pvc)作为dataSource创建 PVC。数据源可以是VolumeSnapshot或 PVC。在本例中,我们使用PersistentVolumeClaim来克隆数据:
$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
 name: clone-of-csi-ebs-pvc
spec:
 accessModes:
 - ReadWriteOnce
 resources:
 requests:
 storage: 4Gi
 dataSource:
 kind: PersistentVolumeClaim
 name: csi-ebs-pvc
EOF

通过这个,您已经学会了从现有数据源克隆持久数据的简单方法。

工作原理...

本示例向您展示了如何创建快照,从快照中恢复数据,以及如何在 Kubernetes 上立即克隆持久卷。

通过 CSI 从快照还原卷通过 CSI 克隆卷的示例中,我们向 PVC 添加了dataSource,引用了现有的 PVC,以便创建一个完全独立的新 PVC。生成的 PVC 可以独立附加、克隆、快照或删除,即使源被删除。主要区别在于,在为 PVC 进行供应之后,后端设备会提供指定卷的精确副本,而不是空 PV。

重要的是要注意,对于已经实现了这一功能的 CSI 驱动程序,动态供应商可以使用本地克隆支持。CSI 项目正在不断发展和成熟,因此并非每个存储供应商都提供完整的 CSI 功能。

另请参阅

使用 Velero 进行应用程序备份和恢复

在本节中,我们将使用 VMware Velero(前身为 Heptio Ark)在 Kubernetes 中创建灾难恢复备份,并迁移 Kubernetes 应用程序及其持久卷。

您将学习如何安装 Velero,创建标准和计划备份,并将它们恢复到 Kubernetes 集群中的 S3 目标。

准备工作

确保您有一个准备好的 Kubernetes 集群,并且kubectl配置为管理集群资源。

克隆k8sdevopscookbook/src存储库到您的工作站,以便在chapter6目录下使用清单文件,如下所示:

$ git clone https://github.com/k8sdevopscookbook/src.git
$ cd src/chapter6

这个配方需要一个具有可呈现数据的现有有状态工作负载,以便我们可以模拟灾难,然后恢复数据。为此,我们将使用在第五章的安装 EBS CSI 驱动程序来管理 EBS 卷配方中创建的mytestapp应用程序,为有状态的工作负载做准备

Velero 还需要 S3 兼容的对象存储来存储备份。在这个配方中,我们将使用在使用 Minio 配置和管理 S3 对象存储配方中部署的 MinIO S3 目标来存储我们的备份。

如何做…

这一部分进一步分为以下子部分,以使这个过程更容易:

  • 安装 Velero

  • 备份应用程序

  • 恢复应用程序

  • 创建计划备份

  • 备份整个命名空间

  • 使用 MinIO 查看备份

  • 删除备份和计划

安装 Velero

Velero 是一个开源项目,用于备份、执行灾难恢复、恢复和迁移 Kubernetes 资源和持久卷。在这个配方中,我们将学习如何通过以下步骤在我们的 Kubernetes 集群中部署 Velero:

  1. 下载 Velero 的最新版本:
$ wget https://github.com/vmware-tanzu/velero/releases/download/v1.1.0/velero-v1.1.0-linux-amd64.tar.gz

在撰写本书时,Velero 的最新版本是 v1.1.0。检查 Velero 存储库github.com/vmware-tanzu/velero/releases,如果自本书发布以来已更改,请使用最新的下载链接更新链接。

  1. 提取 tarball:
$ tar -xvzf velero-v1.1.0-linux-amd64.tar.gz
$ sudo mv velero-v1.1.0-linux-amd64/velero /usr/local/bin/ 
  1. 确认velero命令可执行:
$ velero version
Client:
 Version: v1.1.0
 Git commit: a357f21aec6b39a8244dd23e469cc4519f1fe608
<error getting server version: the server could not find the requested resource (post serverstatusrequests.velero.io)>
  1. 创建credentials-velero文件,其中包含您在使用 Minio 配置和管理 S3 对象存储配方中使用的访问密钥和秘钥:
$ cat > credentials-velero <<EOF
[default]
aws_access_key_id = minio
aws_secret_access_key = minio123
EOF
  1. 使用 MinIO 服务的外部 IP 更新s3Url并安装 Velero 服务器:
$ velero install \
 --provider aws \
 --bucket velero \
 --secret-file ./credentials-velero \
 --use-restic \
 --backup-location-config region=minio,s3ForcePathStyle="true",s3Url=http://ac76d4a1ac72c496299b17573ac4cf2d-512600720.us-west-2.elb.amazonaws.com:9000
  1. 确认部署成功:
$ kubectl get deployments -l component=velero --namespace=velero
NAME READY UP-TO-DATE AVAILABLE AGE
velero 1/1 1 1 62s

有了这个,Velero 已经在您的 Kubernetes 集群上使用 MinIO 作为备份目标进行配置。

备份应用程序

让我们执行以下步骤,使用 Velero 备份应用程序及其卷。我们在这里创建的所有 YAML 清单文件都可以在/src/chapter6/velero目录下找到:

  1. 如果您已经为要备份的应用程序和卷打上标签,可以跳到步骤 5。否则,使用以下命令创建一个命名空间和一个 PVC:
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Namespace
metadata:
 name: backup-example
 labels:
 app: app2backup
EOF
  1. backup-example命名空间中使用您首选的storageClass创建一个 PVC。在我们的示例中,这是aws-csi-ebs
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
 name: pvc2backup
 namespace: backup-example
 labels:
 app: app2backup
spec:
 accessModes:
 - ReadWriteOnce
 storageClassName: aws-csi-ebs
 resources:
 requests:
 storage: 4Gi
EOF
  1. src/chapter6/velero目录中查看myapp.yaml文件,并使用它创建一个将使用 PVC 并写入/data/out.txt文件的 pod:
$ kubectl apply -f myapp.yaml
  1. 验证我们的myapp pod 是否将数据写入卷:
$ kubectl exec -it myapp cat /data/out.txt -nbackup-example
Thu Sep 12 23:18:08 UTC 2019
  1. 为所有具有app=app2backup标签的对象创建备份:
$ velero backup create myapp-backup --selector app=app2backup
  1. 确认备份阶段已经完成:
$ velero backup describe myapp-backup
Name: myapp-backup
Namespace: velero
Labels: velero.io/storage-location=default
Annotations: <none>
Phase: Completed
...
  1. 列出所有可用的备份:
$ velero backup get
NAME         STATUS    CREATED                       EXPIRES STORAGE LOCATION SELECTOR
myapp-backup Completed 2019-09-13 05:55:08 +0000 UTC 29d     default app=app2backup

通过这样,您已经学会了如何使用标签创建应用程序的备份。

恢复应用程序

让我们执行以下步骤来从备份中恢复应用程序:

  1. 删除应用程序及其 PVC 以模拟数据丢失的情况:
$ kubectl delete pvc pvc2backup -nbackup-example
$ kubectl delete pod myapp -nbackup-example
  1. 从名为myapp-backup的先前备份中恢复您的应用程序:
$ velero restore create --from-backup myapp-backup
  1. 确认您的应用程序正在运行:
$ kubectl get pod -nbackup-example
NAME  READY STATUS  RESTARTS AGE
myapp 1/1   Running 0        10m
  1. 确认我们的myapp pod 将数据写入卷:
$ kubectl exec -it myapp cat /data/out.txt -nbackup-example

通过这样,您已经学会了如何使用 Velero 从备份中恢复应用程序及其卷。

创建定期备份

Velero 支持 cron 表达式来安排备份任务。让我们执行以下步骤来为我们的应用程序安排备份:

  1. 创建一个定期的每日备份:
$ velero schedule create myapp-daily --schedule="0 0 1 * * ?" --selector app=app2backup

如果您不熟悉 cron 表达式,可以使用另请参阅部分中的Cron 表达式生成器链接创建不同的计划。

请注意,前面的计划使用了 cron 表达式。作为替代,您可以使用简写表达式,如--schedule="@daily",或者使用在线 cron 生成器创建 cron 表达式。

  1. 获取当前已安排的备份作业列表:
$ velero schedule get
 NAME        STATUS  CREATED                       SCHEDULE    BACKUP TTL LAST BACKUP SELECTOR
 myapp-daily Enabled 2019-09-13 21:38:36 +0000 UTC 0 0 1 * * ? 720h0m0s   2m ago      app=app2backup
  1. 确认已经通过定期备份作业创建了备份:
$ velero backup get
NAME                       STATUS    CREATED                       EXPIRES STORAGE LOCATION SELECTOR
myapp-daily-20190913205123 Completed 2019-09-13 20:51:24 +0000 UTC 29d     default app=app2backup

通过这样,您已经学会了如何使用 Velero 创建应用程序的定期备份。

备份整个命名空间

在进行备份时,您可以使用不同类型的选择器,甚至可以在所选命名空间中使用完整的资源。在本教程中,我们将通过以下步骤包括命名空间中的资源:

  1. 使用以下命令对整个命名空间进行备份。此示例包括backup-example命名空间。如果需要,请替换此命名空间。在执行以下命令之前,命名空间和资源应该存在:
$ velero backup create fullnamespace --include-namespaces backup-example
  1. 如果需要从备份中排除特定资源,请向它们添加backup: "false"标签,并运行以下命令:
$ velero backup create fullnamespace --selector 'backup notin (false)'

通过这个,你学会了如何使用 Velero 在给定命名空间中创建资源备份。

使用 MinIO 查看备份

让我们执行以下步骤来查看 MinIO 界面上备份的内容:

  1. 按照访问 MinIO Web 用户界面食谱中的说明,访问 MinIO 浏览器。

  2. 点击velero桶:

  1. 打开backups目录以查找 Velero 备份列表:

  1. 点击备份名称以访问备份的内容:

通过这个,你学会了如何定位和查看 Velero 备份的内容。

删除备份和计划

如果没有正确维护,Velero 备份的大小会迅速增长。让我们执行以下步骤来删除现有的备份资源和清理定期备份:

  1. 删除名为myapp-backup的现有备份:
$ velero backup delete myapp-backup
  1. 删除所有现有备份:
$ velero backup delete --all
  1. 删除名为myapp-daily的定期备份作业:
$ velero schedule delete myapp-daily

它是如何工作的...

这个食谱向你展示了如何创建灾难恢复备份,从 S3 目标还原你的应用程序及其数据,以及如何在 Kubernetes 上创建定期备份作业。

备份应用程序食谱中,在步骤 4中,当你运行velero backup create myapp-backup --selector app=app2backup时,Velero 客户端会调用 Kubernetes API 服务器并创建一个备份对象。

你可以通过运行kubectl get crds |grep velero命令来获取 Velero 创建的自定义资源定义CRD)列表。

Velero 的 BackupController 会监视新对象,一旦检测到,它会执行标准验证并处理备份。Velero 的 BackupController 通过向 API 服务器请求资源来收集备份信息。然后,它会调用默认存储提供程序并上传备份文件。

另请参阅

使用 Kasten 进行应用程序备份和恢复

在本节中,我们将使用 Kasten(K10)创建灾难恢复备份,并在 Kubernetes 中迁移 Kubernetes 应用程序及其持久卷。

您将学习如何安装和使用 K10,创建标准和定期备份到 S3 目标的应用程序,并将它们恢复到 Kubernetes 集群中。

准备工作

确保您已准备好一个 Kubernetes 集群,并配置了kubectlhelm,以便您可以管理集群资源。在这个教程中,我们将在 AWS 上使用一个三节点的 Kubernetes 集群。

这个教程需要一个现有的有状态工作负载,具有可呈现的数据来模拟灾难。为了恢复数据,我们将使用在第五章的安装 EBS CSI 驱动程序来管理 EBS 卷教程中创建的mytestapp应用程序。

克隆k8sdevopscookbook/src存储库到您的工作站,以使用chapter6目录下的清单文件,如下所示:

$ git clone https://github.com/k8sdevopscookbook/src.git
$ cd src/chapter6

K10 默认配备了 Starter Edition 许可证,允许您在最多三个工作节点的集群上免费使用该软件。K10 需要配置备份目标。

如何做…

这一部分进一步分为以下小节,以使这个过程更容易:

  • 安装 Kasten

  • 访问 Kasten 仪表板

  • 备份应用程序

  • 恢复应用程序

安装 Kasten

让我们执行以下步骤,在我们的 Kubernetes 集群中安装 Kasten 作为备份解决方案:

  1. 添加 K10 helm 存储库:
$ helm repo add kasten https://charts.kasten.io/
  1. 在开始之前,让我们验证环境。以下脚本将执行一些预安装测试,以验证您的集群:
$ curl https://docs.kasten.io/tools/k10_preflight.sh | bash
Checking for tools
 --> Found kubectl --> Found helm
Checking access to the Kubernetes context kubernetes-admin@net39dvo58
 --> Able to access the default Kubernetes namespace
Checking for required Kubernetes version (>= v1.10.0)
 --> Kubernetes version (v1.15.3) meets minimum requirements
Checking if Kubernetes RBAC is enabled
 --> Kubernetes RBAC is enabled
Checking if the Aggregated Layer is enabled
 --> The Kubernetes Aggregated Layer is enabled
Checking if the Kasten Helm repo is present
 --> The Kasten Helm repo was found
Checking for required Helm Tiller version (>= v2.11.0)
 --> Tiller version (v2.14.3) meets minimum requirements
All pre-flight checks succeeded!
  1. 确保您的首选存储类设置为默认;否则,通过向以下命令添加-set persistence.storageClass参数来定义它。在我们的示例中,我们正在使用openebs-cstor-default存储类。还要添加您的 AWS 访问密钥和秘钥并安装 K10:
$ helm install kasten/k10 --name=k10 --namespace=kasten-io \
 --set persistence.storageClass=openebs-cstor-default \
 --set persistence.size=20Gi \
 --set secrets.awsAccessKeyId="AWS_ACCESS_KEY_ID" \
 --set secrets.awsSecretAccessKey="AWS_SECRET_ACCESS_KEY"
  1. 使用以下helm命令确认部署状态为DEPLOYED
$ helm ls
NAME REVISION UPDATED                  STATUS   CHART      APP    VERSION NAMESPACE
k10  1        Tue Oct 29 07:36:19 2019 DEPLOYED k10-1.1.56 1.1.56         kasten-io

在此步骤后,所有的 pod 应该在大约一分钟内部署完成,因为 Kasten 基于 Kubernetes CRDs 提供了一个 API。您可以使用带有新 CRDs 的kubectl(参考相关链接部分中的Kasten CLI 命令链接),或者按照下一个步骤,即访问 Kasten 仪表板的步骤,使用 Kasten 仪表板。

访问 Kasten 仪表板

让我们执行以下步骤来访问 Kasten 仪表板。这是我们将进行应用程序备份和恢复的地方:

  1. 使用以下命令创建端口转发。这一步将 Kasten 仪表板服务的端口8000转发到本地工作站的端口8080
$ export KASTENDASH_POD=$(kubectl get pods --namespace kasten-io -l "service=gateway" -o jsonpath="{.items[0].metadata.name}")
$ kubectl port-forward --namespace kasten-io $KASTENDASH_POD 8080:8000 >> /dev/null &
  1. 在您的工作站上,使用浏览器打开http://127.0.0.1:8080/k10/#
$ firefox http://127.0.0.1:8080/k10/#
  1. 阅读并接受最终用户许可协议:

通过这样,您已经访问了 Kasten 仪表板。您可以通过单击主菜单并参考相关链接部分中的Kasten 文档链接来熟悉它,以获取额外的设置(如果需要)。

备份应用程序

让我们执行以下步骤来备份我们的应用程序:

  1. 如果您已经有一个应用程序和与备份相关的持久卷,您可以跳过步骤 5。否则,使用以下示例代码创建一个命名空间和 PVC:
$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Namespace
metadata:
 name: backup-example
 labels:
 app: app2backup
EOF
  1. backup-example命名空间中创建一个 PVC:
$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
 name: pvc2backup
 namespace: backup-example
 labels:
 app: app2backup
spec:
 accessModes:
 - ReadWriteOnce
 storageClassName: openebs-cstor-default
 resources:
 requests:
 storage: 4Gi
EOF
  1. 创建一个将使用 PVC 并在src/chapter6/kasten目录下的示例myapp.yaml清单中写入/data/out.txt文件的 pod:
$ kubectl apply -f - kasten/myapp.yaml
  1. 验证我们的myapp pod 是否将数据写入卷:
$ kubectl exec -it myapp cat /data/out.txt -nbackup-example
Thu Sep 12 23:18:08 UTC 2019
  1. 在 Kasten 仪表板上,点击未管理的应用程序:

  1. backup-example命名空间中,点击创建策略:

  1. 输入名称并选择快照操作:

  1. 选择每日作为操作频率:

  1. 点击创建策略:

按照这些步骤,您将使用策略创建第一个备份,以及以下备份作业的时间表。

恢复应用程序

让我们执行以下步骤来从现有备份中恢复应用程序:

  1. 在应用程序下,从符合应用程序的列表中,单击backup-example旁边的箭头图标,然后选择还原应用程序。如果应用程序已被删除,则需要选择“已删除”选项:

  1. 选择要恢复的还原点:

  1. 选择backup-example,然后单击还原:

  1. 确认您希望进行还原:

通过这样,您已经学会了如何使用 Kasten 从备份中还原应用程序及其卷。

它是如何工作的...

本教程向您展示了如何创建灾难恢复备份,从 S3 目标还原应用程序及其数据,并在 Kubernetes 上创建定期备份。

备份应用程序教程中,在步骤 2中,我们创建了一个使用 OpenEBS 作为存储供应商的 pod。在这种情况下,Kasten 使用一种通用备份方法,该方法需要一个能够挂载应用程序数据卷的 sidecar 到您的应用程序。以下是一个示例,您可以在使用非标准存储选项时添加到您的 pod 和部署中:

- name: kanister-sidecar
  image: kanisterio/kanister-tools:0.20.0
  command: ["bash", "-c"]
  args:
  - "tail -f /dev/null"
  volumeMounts:
  - name: data
    mountPath: /data

另请参阅

跨云应用程序迁移

在云上运行应用程序时,重要的是要有一个计划,以防云供应商服务中断发生,以及避免可能的云锁定,通过使用类似于 OpenEBS 管理层的云原生存储解决方案来抽象存储层,该解决方案允许您管理对每个云或数据中心的暴露。在本节中,我们将从一个 Kubernetes 集群迁移一个云原生应用程序到另一个在不同云供应商上运行的集群,以模拟迁移场景。您将学习如何使用 Kasten 和 OpenEBS Director 来使用备份来迁移应用程序。

准备就绪

确保您有两个准备好的 Kubernetes 集群,并且已配置kubectl以管理集群资源。

在本教程中,我们将使用由 D2iQ Konvoy部署和管理的 AWS 集群以及使用kops部署的集群。例如,我们将迁移一个现有的minio应用程序。

这里提供的说明需要一个 AWS 账户和一个具有使用相关服务权限的 AWS 用户策略。如果您没有,请访问aws.amazon.com/account/并创建一个。

如何做…

该部分进一步分为以下子部分,以使该过程更加简单:

  • 在 Kasten 中创建导出配置文件

  • 在 Kasten 中导出还原点

  • 在 Kasten 中创建导入配置文件

  • 在 Kasten 中迁移应用程序

  • 在 OpenEBS Director 中导入集群

  • 在 OpenEBS Director 中迁移应用程序

在 Kasten 中创建导出配置文件

首先,我们将使用 Kasten 创建一个导出配置文件,以存储迁移场景中要使用的示例应用程序的远程副本。要做到这一点,请按照以下步骤操作:

  1. 在设置下,选择移动性选项卡,然后单击新配置文件:

  1. 要创建目标配置文件,请选择导出,勾选启用数据可移植性框,选择 Amazon S3,并输入您的用户凭据。

  2. 单击验证并保存:

我们在本教程中创建的导出配置文件将在以后用于将数据移动到另一个集群。

在 Kasten 中导出还原点

让我们执行以下步骤来创建应用程序还原点:

  1. 在应用程序下,从符合应用程序的列表中,单击 minio 旁边的箭头图标,并选择导出应用程序。

  2. 选择要导出的还原点:

  1. 选择您的导出配置文件,然后点击导出:

  1. 确认还原。

  2. 将文本块复制到剪贴板中。

在 Kasten 中创建一个导入配置文件

让我们在我们想要迁移应用程序的第二个集群上执行以下步骤:

  1. 在设置下,选择移动性选项卡,然后点击新配置文件:

  1. 要创建目标配置文件,选择导入,选择 Amazon S3,并输入您的用户凭据。

  2. 使用您在源集群上为导出配置文件创建的存储桶名称。

  3. 点击验证并保存:

我们在这个教程中创建的导入配置文件将在以后用于从另一个集群导入数据。

在 Kasten 中迁移应用程序

最后,让我们执行以下步骤来使用导入配置文件并从另一个集群迁移应用程序:

  1. 在策略下,点击新策略:

  1. 选择导入并勾选导入后恢复框。

  2. 选择每日作为操作频率,并粘贴来自导出还原点教程的配置数据文本块。

  3. 选择您在创建导入配置文件教程中创建的导入配置文件:

  1. 点击创建策略按钮。

完成此步骤后,Kasten 将从还原点中恢复应用程序及其数据到新集群中。

将集群导入 OpenEBS Director

OpenEBS Director Online 是一个免费使用的SaaS(软件即服务)解决方案(企业用户可用 OnPrem 选项)用于管理 Kubernetes 中的有状态应用程序。除了其日志记录和监控功能外,它还提供数据迁移即服务DMaaS)。在这个教程中,我们将学习如何将现有的集群添加到平台,然后在下一个教程中执行 DMaaS:

  1. 转到www.mayadata.io登录到您的 OpenEBS 企业平台portal.mayadata.io/home

  1. 点击连接您的集群按钮:

  1. 命名您的项目。在这里,我们使用了名称GKECluster

  1. 选择您的 Kubernetes 集群位置。在这里,我们使用了GKE上的一个集群:

  1. 在您的第一个集群上复制并执行该命令:

  1. 从左侧菜单中,点击“集群”:

  1. 在“集群”视图中,点击“连接新集群”,然后为第二个集群重复步骤 4步骤 5

  1. 完成后,您将在平台上看到两个集群。

在 OpenEBS Director 中迁移应用程序

让我们按照以下步骤执行数据迁移(DMaaS):

  1. 在“集群”视图中,点击订阅列下的“免费”,并开始为两个集群进行高级计划评估:

  1. 在源集群的概述页面上,点击您想要迁移的工作负载。在这个示例中,我们将迁移 MinIO 工作负载:

  1. 在应用程序视图中,选择 DMaaS 选项卡,然后点击“新建计划”按钮:

  1. 在“新计划”视图中,选择 AWS 作为 S3 提供商,并选择您的凭据和地区。最后,选择备份间隔为每天,然后点击“立即计划”按钮创建备份。作为替代,您也可以使用 GCP 或 MinIO 作为 S3 目标:

  1. 从左侧菜单中,选择 DMaaS,然后点击您创建的计划旁边的“恢复”按钮:

  1. 从托管集群列表中选择目标集群,然后点击“开始恢复”:

您的工作负载将被恢复到第二个集群。

另请参阅

第七章:扩展和升级应用程序

在本章中,我们将讨论可以使用的方法和策略,以动态地扩展在 Kubernetes 上运行的容器化服务,以处理我们服务的不断变化的流量需求。在本章的配方中,您将掌握创建负载均衡器以将流量分发到多个工作节点并增加带宽所需的技能。您还将了解如何在生产环境中处理升级以最小化停机时间。

在本章中,我们将涵盖以下配方:

  • 在 Kubernetes 上扩展应用程序

  • 为节点分配应用程序的优先级

  • 创建外部负载均衡器

  • 使用 Istio 创建入口服务和服务网格

  • 使用 Linkerd 创建入口服务和服务网格

  • 在 Kubernetes 中自动修复 Pod

  • 通过蓝/绿部署管理升级

技术要求

本章的配方假定您已通过第一章中描述的推荐方法之一部署了一个功能齐全的 Kubernetes 集群,构建生产就绪的 Kubernetes 集群

Kubernetes 命令行工具kubectl将在本章的其余部分中用于配方,因为它是针对 Kubernetes 集群运行命令的主要命令行界面。我们还将在 Helm 图表可用的情况下使用 helm 来部署解决方案。

在 Kubernetes 上扩展应用程序

在本节中,我们将执行应用程序和集群扩展任务。您将学习如何在 Kubernetes 中手动和自动地扩展服务容量,以支持动态流量。

准备工作

k8sdevopscookbook/src存储库克隆到您的工作站,以便使用chapter7目录中的清单文件,如下所示:

$ git clone https://github.com/k8sdevopscookbook/src.git
$ cd /src/chapter7/

确保您已准备好一个 Kubernetes 集群,并配置了kubectlhelm来管理集群资源。

操作步骤:

此部分进一步分为以下子部分,以使此过程更加简单:

  • 验证 Metrics Server 的安装

  • 手动扩展应用程序

  • 使用水平 Pod 自动缩放器自动缩放应用程序

验证 Metrics Server 的安装

本节中的使用水平 Pod 自动缩放器自动缩放应用程序配方还需要在您的集群上安装 Metrics Server。Metrics Server 是用于核心资源使用数据的集群范围聚合器。按照以下步骤验证 Metrics Server 的安装:

  1. 通过运行以下命令确认是否需要安装 Metrics Server:
$ kubectl top node
error: metrics not available yet
  1. 如果安装正确,您应该看到以下节点指标:
$ kubectl top nodes
NAME                          CPU(cores) CPU% MEMORY(bytes) MEMORY%
ip-172-20-32-169.ec2.internal 259m       12%  1492Mi        19%
ip-172-20-37-106.ec2.internal 190m       9%   1450Mi        18%
ip-172-20-48-49.ec2.internal  262m       13%  2166Mi        27%
ip-172-20-58-155.ec2.internal 745m       37%  1130Mi        14%

如果收到错误消息,指出尚未提供指标,则需要按照使用 Kubernetes Metrics Server 添加指标配方中提供的步骤安装 Metrics Server。

手动扩展应用程序

当您的应用程序的使用量增加时,有必要将应用程序扩展。Kubernetes 被设计用来处理高规模工作负载的编排。

让我们执行以下步骤,了解如何手动扩展应用程序:

  1. 更改目录到/src/chapter7/charts/node,这是您在准备就绪部分创建的示例存储库的本地克隆所在的位置:
$ cd /charts/node/
  1. 使用以下命令安装待办事项应用程序示例。这个 Helm 图表将部署两个 pod,包括一个 Node.js 服务和一个 MongoDB 服务:
$ helm install . --name my-ch7-app
  1. 获取my-ch7-app-node的服务 IP 以连接到应用程序。以下命令将返回应用程序的外部地址:
$ export SERVICE_IP=$(kubectl get svc --namespace default my-ch7-app-node --template "{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}")
$ echo http://$SERVICE_IP/
http://mytodoapp.us-east-1.elb.amazonaws.com/
  1. 在 Web 浏览器中打开步骤 3中的地址。您将获得一个完全功能的待办事项应用程序:

  1. 使用helm status检查应用程序的状态。您将看到已部署的 pod 数量在Available列中:
$ helm status my-ch7-app
LAST DEPLOYED: Thu Oct 3 00:13:10 2019
NAMESPACE: default
STATUS: DEPLOYED
RESOURCES:
==> v1/Deployment
NAME               READY UP-TO-DATE AVAILABLE AGE
my-ch7-app-mongodb 1/1   1          1         9m9s
my-ch7-app-node    1/1   1          1         9m9s
...
  1. 将节点 pod 的规模从当前的单个副本扩展到3个副本:
$ kubectl scale --replicas 3 deployment/my-ch7-app-node
deployment.extensions/my-ch7-app-node scaled
  1. 再次检查应用程序的状态,并确认,这次可用副本的数量为3v1/Pod部分中的my-ch7-app-node pod 数量已增加到3
$ helm status my-ch7-app
...
RESOURCES:
==> v1/Deployment
NAME READY UP-TO-DATE AVAILABLE AGE
my-ch7-app-mongodb 1/1 1 1 26m
my-ch7-app-node 3/3 3 3 26m
...
==> v1/Pod(related)
NAME READY STATUS RESTARTS AGE
my-ch7-app-mongodb-5499c954b8-lcw27 1/1 Running 0 26m
my-ch7-app-node-d8b94964f-94dsb 1/1 Running 0 91s
my-ch7-app-node-d8b94964f-h9w4l 1/1 Running 3 26m
my-ch7-app-node-d8b94964f-qpm77 1/1 Running 0 91s
  1. 要缩小应用程序的规模,请重复步骤 5,但这次使用2个副本:
$ kubectl scale --replicas 2 deployment/my-ch7-app-node
deployment.extensions/my-ch7-app-node scaled

有了这个,您学会了如何在需要时扩展您的应用程序。当然,您的 Kubernetes 集群资源也应该能够支持不断增长的工作负载能力。

下一个配方将向您展示如何根据实际资源消耗而不是手动步骤来自动缩放工作负载。

使用水平 Pod 自动缩放器自动缩放应用程序

在本教程中,您将学习如何创建水平 Pod 自动缩放器HPA)来自动化我们在上一个教程中创建的应用程序的扩展过程。我们还将使用负载生成器测试 HPA,模拟增加流量击中我们的服务的情景。请按照以下步骤操作:

  1. 首先,确保您已经部署了手动扩展应用程序中的示例待办事项应用程序。当您运行以下命令时,您应该会看到 MongoDB 和 Node pods 的列表:
$ kubectl get pods | grep my-ch7-app
my-ch7-app-mongodb-5499c954b8-lcw27 1/1 Running 0 4h41m
my-ch7-app-node-d8b94964f-94dsb     1/1 Running 0 4h16m
my-ch7-app-node-d8b94964f-h9w4l     1/1 Running 3 4h41m
  1. 使用以下命令声明性地创建 HPA。这将自动化在达到targetCPUUtilizationPercentage阈值时在15个副本之间扩展应用程序的过程。在我们的示例中,pod 的 CPU 利用率目标的平均值设置为50%。当利用率超过此阈值时,您的副本将增加:
cat <<EOF | kubectl apply -f -
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
 name: my-ch7-app-autoscaler
 namespace: default
spec:
 scaleTargetRef:
 apiVersion: apps/v1
 kind: Deployment
 name: my-ch7-app-node
 minReplicas: 1
 maxReplicas: 5
 targetCPUUtilizationPercentage: 50
EOF

尽管结果大多数情况下可能是相同的,但声明性配置需要理解 Kubernetes 对象配置规范和文件格式。作为替代方案,kubectl可以用于对 Kubernetes 对象进行命令式管理。

请注意,您必须在部署中设置 CPU 请求才能使用自动缩放。如果您的部署中没有 CPU 请求,HPA 将部署但不会正常工作。

您还可以通过运行$ kubectl autoscale deployment my-ch7-app-node --cpu-percent=50 --min=1 --max=5命令来命令式地创建相同的HorizontalPodAutoscaler

  1. 确认当前副本的数量和 HPA 的状态。当您运行以下命令时,副本的数量应为1
$ kubectl get hpa
NAME                  REFERENCE                  TARGETS       MINPODS MAXPODS REPLICAS AGE
my-ch7-app-autoscaler Deployment/my-ch7-app-node 0%/50%        1       5       1        40s
  1. 获取my-ch7-app-node的服务 IP,以便在下一步中使用:
$ export SERVICE_IP=$(kubectl get svc --namespace default my-ch7-app-node --template "{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}")
$ echo http://$SERVICE_IP/
http://mytodoapp.us-east-1.elb.amazonaws.com/
  1. 打开一个新的终端窗口并创建一个负载生成器来测试 HPA。确保您在以下代码中用实际服务 IP 替换YOUR_SERVICE_IP。此命令将向您的待办事项应用程序生成流量:
$ kubectl run -i --tty load-generator --image=busybox /bin/sh

while true; do wget -q -O- YOUR_SERVICE_IP; done
  1. 等待几分钟,使自动缩放器对不断增加的流量做出响应。在一个终端上运行负载生成器的同时,在另一个终端窗口上运行以下命令,以监视增加的 CPU 利用率。在我们的示例中,这被设置为210%
$ kubectl get hpa
NAME                  REFERENCE                  TARGETS       MINPODS MAXPODS REPLICAS AGE
my-ch7-app-autoscaler Deployment/my-ch7-app-node 210%/50%      1       5       1        23m
  1. 现在,检查部署大小并确认部署已调整为5个副本,以应对工作负载的增加:
$ kubectl get deployment my-ch7-app-node
NAME            READY UP-TO-DATE AVAILABLE AGE
my-ch7-app-node 5/5   5          5         5h23m
  1. 在运行负载生成器的终端屏幕上,按下Ctrl + C来终止负载生成器。这将停止发送到您的应用程序的流量。

  2. 等待几分钟,让自动缩放器进行调整,然后通过运行以下命令来验证 HPA 状态。当前的 CPU 利用率应该更低。在我们的示例中,它显示下降到0%

$ kubectl get hpa
NAME                  REFERENCE                  TARGETS MINPODS MAXPODS REPLICAS AGE
my-ch7-app-autoscaler Deployment/my-ch7-app-node 0%/50%  1       5       1        34m
  1. 检查部署大小,并确认部署已经因停止流量生成器而缩减到1个副本:
$ kubectl get deployment my-ch7-app-node
NAME            READY UP-TO-DATE AVAILABLE AGE
my-ch7-app-node 1/1   1          1         5h35m

在这个教程中,您学会了如何根据不断变化的指标动态地自动化应用程序的扩展。当应用程序被扩展时,它们会动态地调度到现有的工作节点上。

工作原理...

这个教程向您展示了如何根据 Kubernetes 指标动态地手动和自动地扩展部署中的 Pod 数量。

在这个教程中,在步骤 2中,我们创建了一个自动缩放器,它会在minReplicas: 1maxReplicas: 5之间调整副本的数量。如下例所示,调整标准由targetCPUUtilizationPercentage: 50指标触发:

spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: my-ch7-app-node
  minReplicas: 1
  maxReplicas: 5
  targetCPUUtilizationPercentage: 50

targetCPUUtilizationPercentage是与autoscaling/v1API 一起使用的。您很快将看到targetCPUUtilizationPercentage将被一个名为 metrics 的数组所取代。

要了解新的指标和自定义指标,运行以下命令。这将返回我们使用 V1 API 创建的清单到使用 V2 API 的新清单:

$ kubectl get hpa.v2beta2.autoscaling my-ch7-app-node -o yaml

这使您能够指定额外的资源指标。默认情况下,CPU 和内存是唯一支持的资源指标。除了这些资源指标,v2 API 还支持另外两种类型的指标,这两种指标都被视为自定义指标:每个 Pod 的自定义指标和对象指标。您可以通过转到参见部分中提到的Kubernetes HPA 文档链接来了解更多信息。

参见

将应用程序分配给节点

在本节中,我们将确保 pod 不会被调度到不合适的节点上。您将学习如何使用节点选择器、污点、容忍和设置优先级将 pod 调度到 Kubernetes 节点上。

准备工作

确保您已准备好一个 Kubernetes 集群,并配置了kubectlhelm来管理集群资源。

如何做…

此部分进一步分为以下子部分,以使此过程更容易:

  • 给节点贴标签

  • 使用 nodeSelector 将 pod 分配给节点

  • 使用节点和 pod 亲和性将 pod 分配给节点

给节点贴标签

Kubernetes 标签用于指定资源的重要属性,这些属性可用于将组织结构应用到系统对象上。在这个配方中,我们将学习用于 Kubernetes 节点的常见标签,并应用一个自定义标签,以便在调度 pod 到节点时使用。

让我们执行以下步骤,列出已分配给您的节点的一些默认标签:

  1. 列出已分配给您的节点的标签。在我们的示例中,我们将使用部署在 AWS EC2 上的 kops 集群,因此您还将看到相关的 AWS 标签,例如可用区:
$ kubectl get nodes --show-labels
NAME                          STATUS ROLES AGE VERSION LABELS
ip-172-20-49-12.ec2.internal  Ready   node  23h v1.14.6 
kubernetes.io/arch=amd64,kubernetes.io/instance-type=t3.large,
kubernetes.io/os=linux,failure-domain.beta.kubernetes.io/region=us-east-1,
failure-domain.beta.kubernetes.io/zone=us-east-1a,
kops.k8s.io/instancegroup=nodes,kubernetes.io/hostname=ip-172-20-49-12.ec2.internal,
kubernetes.io/role=node,node-role.kubernetes.io/node=
...
  1. 获取您的集群中的节点列表。我们将使用节点名称在下一步中分配标签:
$ kubectl get nodes
NAME                           STATUS ROLES  AGE VERSION
ip-172-20-49-12.ec2.internal   Ready  node   23h v1.14.6
ip-172-20-50-171.ec2.internal  Ready  node   23h v1.14.6
ip-172-20-58-83.ec2.internal   Ready  node   23h v1.14.6
ip-172-20-59-8.ec2.internal    Ready  master 23h v1.14.6
  1. 将两个节点标记为productiondevelopment。使用步骤 2的输出中的工作节点名称运行以下命令:
$ kubectl label nodes ip-172-20-49-12.ec2.internal environment=production
$ kubectl label nodes ip-172-20-50-171.ec2.internal environment=production
$ kubectl label nodes ip-172-20-58-83.ec2.internal environment=development
  1. 验证新标签是否已分配给节点。这次,除了标记为role=master的节点外,您应该在所有节点上看到environment标签:
$ kubectl get nodes --show-labels

建议为将使用您的集群的其他人记录标签。虽然它们不直接暗示核心系统的语义,但确保它们对所有用户仍然有意义和相关。

使用 nodeSelector 将 pod 分配给节点

在这个配方中,我们将学习如何使用 nodeSelector 原语将 pod 调度到选定的节点:

  1. 在名为todo-dev的新目录中创建我们在手动扩展应用程序配方中使用的 Helm 图表的副本。稍后我们将编辑模板,以指定nodeSelector
$ cd src/chapter7/charts
$ mkdir todo-dev
$ cp -a node/* todo-dev/
$ cd todo-dev
  1. 编辑templates目录中的deployment.yaml文件:
$ vi templates/deployment.yaml
  1. containers:参数之前添加nodeSelector:environment: "{{ .Values.environment }}"。这应该如下所示:
...
          mountPath: {{ .Values.persistence.path }}
      {{- end }}
# Start of the addition
      nodeSelector:
        environment: "{{ .Values.environment }}"
# End of the addition
      containers:
      - name: {{ template "node.fullname" . }}

...

Helm 安装使用模板生成配置文件。如前面的示例所示,为了简化您自定义提供的值的方式,使用{{expr}},这些值来自values.yaml文件名称。values.yaml文件包含图表的默认值。

尽管在大型集群上可能不太实用,但是除了使用nodeSelector和标签之外,您还可以使用nodeName设置在一个特定的节点上安排 Pod。在这种情况下,您可以将nodeName: yournodename添加到部署清单中,而不是nodeSelector设置。

  1. 现在我们已经添加了变量,编辑values.yaml文件。这是我们将环境设置为development标签的地方:
$ vi values.yaml
  1. 在文件末尾添加environment: development行。它应该如下所示:
...
## Affinity for pod assignment
## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity
##
affinity: {}
environment: development
  1. 编辑Chart.yaml文件,并将图表名称更改为其文件夹名称。在这个配方中,它被称为todo-dev。在这些更改之后,前两行应该如下所示:
apiVersion: v1
name: todo-dev
...
  1. 更新 Helm 依赖项并构建它们。以下命令将拉取所有依赖项并构建 Helm 图表:
$ helm dep update & helm dep build
  1. 检查图表是否存在问题。如果图表文件有任何问题,linting 过程将提出问题;否则,不应该发现任何失败:
$ helm lint .
==> Linting .
Lint OK
1 chart(s) linted, no failures
  1. 使用以下命令安装示例待办应用程序。这个 Helm 图表将部署两个 Pod,包括一个 Node.js 服务和一个 MongoDB 服务,但这次节点被标记为environment: development
$ helm install . --name my-app7-dev --set serviceType=LoadBalancer
  1. 使用以下命令检查所有的 Pod 是否已经安排在开发节点上。您会发现my-app7-dev-todo-dev Pod 正在带有environment: development标签的节点上运行:
$ for n in $(kubectl get nodes -l environment=development --no-headers | cut -d " " -f1); do kubectl get pods --all-namespaces --no-headers --field-selector spec.nodeName=${n} ; done

有了这个,您已经学会了如何使用nodeSelector原语将工作负载 Pod 安排到选定的节点上。

使用节点和 Pod 之间的亲和性将 Pod 分配给节点

在这个配方中,我们将学习如何扩展我们在上一个配方中表达的约束,即使用亲和性和反亲和性特性将 Pod 分配给带标签的节点。

让我们使用基于场景的方法来简化不同的亲和性选择器选项的配方。我们将采用前面的示例,但这次是具有复杂要求:

  • todo-prod必须安排在带有environment:production标签的节点上,并且如果无法安排,则应该失败。

  • todo-prod应该在一个被标记为failure-domain.beta.kubernetes.io/zone=us-east-1aus-east-1b的节点上运行,但如果标签要求不满足,可以在任何地方运行。

  • todo-prod必须在与mongodb相同的区域运行,但不应在todo-dev运行的区域运行。

这里列出的要求只是为了代表一些亲和性定义功能的使用示例。这不是配置这个特定应用程序的理想方式。在您的环境中,标签可能完全不同。

上述情景将涵盖节点亲和性选项(requiredDuringSchedulingIgnoredDuringExecutionpreferredDuringSchedulingIgnoredDuringExecution)的两种类型。您将在我们的示例中稍后看到这些选项。让我们开始吧:

  1. 将我们在手动扩展应用程序配方中使用的 Helm 图表复制到一个名为todo-prod的新目录中。我们稍后将编辑模板,以指定nodeAffinity规则:
$ cd src/chapter7/charts
$ mkdir todo-prod
$ cp -a node/* todo-prod/
$ cd todo-prod
  1. 编辑values.yaml文件。要访问它,请使用以下命令:
$ vi values.yaml
  1. 用以下代码替换最后一行affinity: {}。这个改变将满足我们之前定义的第一个要求,意味着一个 pod 只能放置在一个带有environment标签且其值为production的节点上:
## Affinity for pod assignment
## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity
# affinity: {}
# Start of the affinity addition #1
affinity:
 nodeAffinity:
 requiredDuringSchedulingIgnoredDuringExecution:
 nodeSelectorTerms:
 - matchExpressions:
 - key: environment
 operator: In
 values:
 - production
# End of the affinity addition #1

您还可以在nodeSelectorTerms下指定多个matchExpressions。在这种情况下,pod 只能被调度到所有matchExpressions都满足的节点上,这可能会限制您成功调度的机会。

虽然在大型集群上可能不太实用,但是除了使用nodeSelector和标签之外,您还可以使用nodeName设置在特定节点上调度一个 pod。在这种情况下,将nodeName: yournodename添加到您的部署清单中,而不是nodeSelector设置。

  1. 现在,在上述代码添加的下面添加以下行。这个添加将满足我们之前定义的第二个要求,意味着带有failure-domain.beta.kubernetes.io/zone标签且其值为us-east-1aus-east-1b的节点将被优先选择:
          - production
# End of the affinity addition #1
# Start of the affinity addition #2
    preferredDuringSchedulingIgnoredDuringExecution:
    - weight: 1
      preference:
        matchExpressions:
        - key: failure-domain.beta.kubernetes.io/zone
          operator: In
          values:
          - us-east-1a
          - us-east-1b
# End of the affinity addition #2
  1. 对于第三个要求,我们将使用 pod 之间的亲和性和反亲和性功能。它们允许我们基于节点上已经运行的 pod 的标签来限制我们的 pod 有资格被调度到哪些节点,而不是根据节点上的标签进行调度。以下 podAffinity requiredDuringSchedulingIgnoredDuringExecution规则将寻找存在app: mongodb的节点,并使用failure-domain.beta.kubernetes.io/zone作为拓扑键来显示我们的 pod 允许被调度到哪里:
          - us-east-1b
# End of the affinity addition #2
# Start of the affinity addition #3a
  podAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
    - labelSelector:
        matchExpressions:
        - key: app
          operator: In
          values:
          - mongodb
      topologyKey: failure-domain.beta.kubernetes.io/zone
# End of the affinity addition #3a
  1. 添加以下行以满足要求。这次,podAntiAffinity preferredDuringSchedulingIgnoredDuringExecution规则将寻找存在app: todo-dev的节点,并使用failure-domain.beta.kubernetes.io/zone作为拓扑键:
      topologyKey: failure-domain.beta.kubernetes.io/zone
# End of the affinity addition #3a
# Start of the affinity addition #3b
  podAntiAffinity:
    preferredDuringSchedulingIgnoredDuringExecution:
    - weight: 100
      podAffinityTerm:
        labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - todo-dev
        topologyKey: failure-domain.beta.kubernetes.io/zone
# End of the affinity addition #3b
  1. 编辑Chart.yaml文件,并将图表名称更改为其文件夹名称。在这个示例中,它被称为todo-prod。做出这些更改后,前两行应如下所示:
apiVersion: v1
name: todo-prod
...
  1. 更新 Helm 依赖项并构建它们。以下命令将拉取所有依赖项并构建 Helm 图表:
$ helm dep update & helm dep build
  1. 检查图表是否存在问题。如果图表文件有任何问题,linting 过程将指出;否则,不应该发现任何失败:
$ helm lint .
==> Linting .
Lint OK
1 chart(s) linted, no failures
  1. 使用以下命令安装待办事项应用示例。这个 Helm 图表将部署两个 pod,包括一个 Node.js 服务和一个 MongoDB 服务,这次遵循我们在本示例开始时定义的详细要求:
$ helm install . --name my-app7-prod --set serviceType=LoadBalancer
  1. 使用以下命令检查已经在节点上调度的所有 pod 是否标记为environment: production。您将发现my-app7-dev-todo-dev pod 正在节点上运行:
$ for n in $(kubectl get nodes -l environment=production --no-headers | cut -d " " -f1); do kubectl get pods --all-namespaces --no-headers --field-selector spec.nodeName=${n} ; done

在本示例中,您学习了在 Kubernetes 中使用一些原语时如何进行高级 pod 调度实践,包括nodeSelector、节点亲和性和 pod 之间的亲和性。现在,您将能够配置一组应用程序,这些应用程序位于相同的定义拓扑中或在不同的区域中进行调度,以便您拥有更好的服务级别协议SLA)时间。

工作原理...

本节中的示例向您展示了如何根据复杂的要求在首选位置上调度 pod。

节点标记示例中,在步骤 1中,您可以看到一些标准标签已经应用到您的节点上。这里是它们的简要解释以及它们的用途:

  • kubernetes.io/arch:这来自runtime.GOARCH参数,并应用于节点以识别在不同架构容器映像(如 x86、arm、arm64、ppc64le 和 s390x)上运行的位置混合架构集群。

  • kubernetes.io/instance-type:只有在集群部署在云提供商上时才有用。实例类型告诉我们很多关于平台的信息,特别是对于需要在具有 GPU 或更快存储选项的实例上运行一些 Pod 的 AI 和机器学习工作负载。

  • kubernetes.io/os:这适用于节点,并来自runtime.GOOS。除非您在同一集群中有 Linux 和 Windows 节点,否则可能不太有用。

  • failure-domain.beta.kubernetes.io/region/zone:如果您的集群部署在云提供商上或您的基础设施跨不同的故障域,这也更有用。在数据中心,它可以用于定义机架解决方案,以便您可以将 Pod 安排在不同的机架上,以提高可用性。

  • kops.k8s.io/instancegroup=nodes:这是设置为实例组名称的节点标签。仅在使用 kops 集群时使用。

  • kubernetes.io/hostname:显示工作节点的主机名。

  • kubernetes.io/role:显示工作节点在集群中的角色。一些常见的值包括node(表示工作节点)和master(表示节点是主节点,并且默认情况下被标记为不可调度的工作负载)。

使用节点和跨 Pod 亲和力将 Pod 分配给节点配方中,在步骤 3中,节点亲和力规则表示 Pod 只能放置在具有键为environment且值为production的标签的节点上。

步骤 4中,首选affinity key: value要求(preferredDuringSchedulingIgnoredDuringExecution)。这里的weight字段可以是1100之间的值。满足这些要求的每个节点,Kubernetes 调度程序都会计算一个总和。总分最高的节点是首选的。

这里使用的另一个细节是In参数。节点亲和力支持以下运算符:InNotInExistsDoesNotExistGtLt。您可以通过查看“通过示例查看调度亲和力”链接来了解更多关于这些运算符的信息,该链接在另请参阅部分中提到。

如果选择器和亲和力规则规划不当,很容易阻止 pod 在节点上调度。请记住,如果同时指定了nodeSelectornodeAffinity规则,则必须同时满足这两个要求,才能将 pod 调度到可用节点上。

步骤 5中,使用podAffinity来满足 PodSpec 中的要求。在这个示例中,podAffinityrequiredDuringSchedulingIgnoredDuringExecution。在这里,matchExpressions表示一个 pod 只能在failure-domain.beta.kubernetes.io/zone与其他带有app: mongodb标签的 pod 所在的节点匹配的节点上运行。

步骤 6中,使用podAntiAffinitypreferredDuringSchedulingIgnoredDuringExecution满足了要求。在这里,matchExpressions表示一个 pod 不能在failure-domain.beta.kubernetes.io/zone与其他带有app: todo-dev标签的 pod 所在的节点匹配的节点上运行。通过将权重设置为100来增加权重。

另请参阅

创建外部负载均衡器

负载均衡器服务类型是一种相对简单的服务替代方案,用于使用基于云的外部负载均衡器而不是入口。外部负载均衡器服务类型的支持仅限于特定的云提供商,但受到大多数流行的云提供商的支持,包括 AWS、GCP、Azure、阿里云和 OpenStack。

在本节中,我们将使用负载均衡器来公开我们的工作负载端口。我们将学习如何为公共云上的集群创建外部 GCE/AWS 负载均衡器,以及如何使用inlet-operator为您的私有集群创建外部负载均衡器。

准备工作

确保您已经准备好一个 Kubernetes 集群,并且kubectlhelm已配置好以管理集群资源。在本教程中,我们使用了在 AWS 上使用kops部署的集群,如第一章中所述,构建生产就绪的 Kubernetes 集群,在亚马逊网络服务的示例中。相同的说明也适用于所有主要的云提供商。

要访问示例文件,请将k8sdevopscookbook/src存储库克隆到您的工作站,以便在src/chapter7/lb目录中使用配置文件,方法如下:

$ git clone https://github.com/k8sdevopscookbook/src.git
$ cd src/chapter7/lb/

在您克隆了示例存储库之后,您可以继续进行操作。

操作步骤

本节进一步分为以下小节,以使这个过程更容易:

  • 创建外部云负载均衡器

  • 查找服务的外部地址

创建外部云负载均衡器

当您创建一个应用程序并将其公开为 Kubernetes 服务时,通常需要使服务可以通过 IP 地址或 URL 从外部访问。在本教程中,您将学习如何创建一个负载均衡器,也称为云负载均衡器。

在前几章中,我们已经看到了一些示例,这些示例使用了负载均衡器服务类型来公开 IP 地址,包括上一章中的使用 MinIO 配置和管理 S3 对象存储使用 Kasten 进行应用程序备份和恢复,以及本章中提供的 To-Do 应用程序在将应用程序分配给节点的示例中。

让我们使用 MinIO 应用程序来学习如何创建负载均衡器。按照以下步骤创建一个服务,并使用外部负载均衡器服务公开它:

  1. 查看src/chapter7/lb目录中minio.yaml文件的内容,并使用以下命令部署它。这将创建一个 StatefulSet 和一个服务,其中 MinIO 端口通过端口号9000在集群内部公开。你可以选择应用相同的步骤并为你自己的应用程序创建一个负载均衡器。在这种情况下,跳到步骤 2
$ kubectl apply -f minio.yaml
  1. 列出 Kubernetes 上可用的服务。你会看到 MinIO 服务的服务类型为ClusterIPEXTERNAL-IP字段下为none
$ kubectl get svc
NAME       TYPE      CLUSTER-IP EXTERNAL-IP PORT(S)  AGE
kubernetes ClusterIP 100.64.0.1 <none>      443/TCP  5d
minio      ClusterIP None       <none>      9000/TCP 4m
  1. 创建一个TYPE设置为LoadBalancer的新服务。以下命令将使用TCP协议将我们的 MinIO 应用程序的port: 9000暴露到targetPort: 9000,如下所示:
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
 name: minio-service
spec:
 type: LoadBalancer
 ports:
 - port: 9000
 targetPort: 9000
 protocol: TCP
 selector:
 app: minio
EOF

上述命令将立即创建Service对象,但在云服务提供商端实际的负载均衡器可能需要 30 秒到 1 分钟才能完全初始化。尽管对象将声明它已准备就绪,但在负载均衡器初始化之前它将无法正常工作。这是云负载均衡器与入口控制器相比的一个缺点,我们将在下一个教程中看到,使用 Istio 创建入口服务和服务网格

作为步骤 3的替代方案,你也可以使用以下命令创建负载均衡器:

$ kubectl expose rc example --port=9000 --target-port=9000 --name=minio-service --type=LoadBalancer

查找服务的外部地址

让我们执行以下步骤来获取服务的外部可达地址:

  1. 列出使用LoadBalancer类型的服务。EXTERNAL-IP列将显示云供应商提供的地址:
$ kubectl get svc |grep LoadBalancer
NAME          TYPE         CLUSTER-IP    EXTERNAL-IP                                  PORT(S)        AGE
minio-service LoadBalancer 100.69.15.120 containerized.me.us-east-1.elb.amazonaws.com 9000:30705/TCP 4h39m
  1. 如果你在 AWS 等云服务提供商上运行,你也可以使用以下命令获取确切的地址。你可以复制并粘贴到网页浏览器中:
$ SERVICE_IP=http://$(kubectl get svc minio-service \
-o jsonpath='{.status.loadBalancer.ingress[0].hostname}:{.spec.ports[].targetPort}')
$ echo $SERVICE_IP
  1. 如果你在裸机服务器上运行,那么你可能不会有hostname条目。例如,如果你正在运行 MetalLB (metallb.universe.tf/),一个用于裸机 Kubernetes 集群的负载均衡器,或者 SeeSaw (github.com/google/seesaw),一个基于Linux 虚拟服务器LVS)的负载均衡平台,你需要查找ip条目:
$ SERVICE_IP=http://$(kubectl get svc minio-service \
-o jsonpath='{.status.loadBalancer.ingress[0].ip}:{.spec.ports[].targetPort}')
$ echo $SERVICE_IP

上述命令将返回一个类似于https://containerized.me.us-east-1.elb.amazonaws.com:9000的链接。

它是如何工作的...

这个教程向你展示了如何快速创建一个云负载均衡器,以便使用外部地址暴露你的服务。

创建云负载均衡器示例中,在第 3 步中,当在 Kubernetes 中创建负载均衡器服务时,将代表您创建一个云提供商负载均衡器,而无需单独通过云服务提供商 API。这个功能可以帮助您轻松地管理负载均衡器的创建,但同时需要一些时间来完成,并且需要为每个服务单独创建一个独立的负载均衡器,因此可能成本高且不太灵活。

为了使负载均衡器更加灵活并增加更多的应用级功能,您可以使用 Ingress 控制器。使用 Ingress,流量路由可以由 Ingress 资源中定义的规则来控制。您将在接下来的两个示例中了解更多关于流行的 Ingress 网关,使用 Istio 创建 Ingress 服务和服务网格使用 Linkerd 创建 Ingress 服务和服务网格

另请参阅

使用 Istio 创建 Ingress 服务和服务网格

Istio 是一个流行的开源服务网格。在本节中,我们将启动并运行基本的 Istio 服务网格功能。您将学习如何创建一个服务网格来保护、连接和监控微服务。

服务网格是一个非常详细的概念,我们不打算解释任何详细的用例。相反,我们将专注于启动和运行我们的服务。

准备工作

确保您已经准备好一个 Kubernetes 集群,并且已经配置好kubectlhelm来管理集群资源。

https://github.com/istio/istio存储库克隆到您的工作站,如下所示:

$ git clone https://github.com/istio/istio.git 
$ cd istio

我们将使用前面的存储库中的示例,在我们的 Kubernetes 集群上安装 Istio。

如何做…

这一部分进一步分为以下小节,以使这个过程更容易:

  • 使用 Helm 安装 Istio

  • 验证安装

  • 创建入口网关

使用 Helm 安装 Istio

让我们执行以下步骤来安装 Istio:

  1. 在部署 Istio 之前,创建所需的 Istio CRD:
$ helm install install/kubernetes/helm/istio-init --name istio-init \
--namespace istio-system
  1. 使用默认配置安装 Istio。这将部署 Istio 核心组件,即istio-citadelistio-galleyistio-ingressgatewayistio-pilotistio-policyistio-sidecar-injectoristio-telemetry
$ helm install install/kubernetes/helm/istio --name istio \
--namespace istio-system
  1. 通过为将运行应用程序的命名空间添加标签来启用自动 sidecar 注入。在本示例中,我们将使用default命名空间:
$ kubectl label namespace default istio-injection=enabled

为了使您的应用程序能够获得 Istio 功能,pod 需要运行一个 Istio sidecar 代理。上面的命令将自动注入 Istio sidecar。作为替代方案,您可以在安装 Istio sidecar 说明链接中找到使用istioctl命令手动向您的 pod 添加 Istio sidecar 的说明。

验证安装

让我们执行以下步骤来确认 Istio 已成功安装:

  1. 检查已创建的 Istio CRD 的数量。以下命令应返回23,这是 Istio 创建的 CRD 的数量:
$ kubectl get crds | grep 'istio.io' | wc -l
23
  1. 运行以下命令并确认已创建 Istio 核心组件服务的列表:
$ kubectl get svc -n istio-system
NAME                   TYPE         CLUSTER-IP     EXTERNAL-IP PORT(S)             AGE
istio-citadel          ClusterIP    100.66.235.211 <none>      8060/TCP,...        2m10s
istio-galley           ClusterIP    100.69.206.64  <none>      443/TCP,...         2m11s
istio-ingressgateway   LoadBalancer 100.67.29.143  domain.com  15020:31452/TCP,... 2m11s
istio-pilot            ClusterIP    100.70.130.148 <none>      15010/TCP,...       2m11s
istio-policy           ClusterIP    100.64.243.176 <none>      9091/TCP,...        2m11s
istio-sidecar-injector ClusterIP    100.69.244.156 <none>      443/TCP,...         2m10s
istio-telemetry        ClusterIP    100.68.146.30  <none>      9091/TCP,...        2m11s
prometheus             ClusterIP    100.71.172.191 <none>      9090/TCP            2m11s
  1. 确保列出的所有 pod 都处于Running状态:
$ kubectl get pods -n istio-system
  1. 确认启用了 Istio 注入的命名空间。您应该只在default命名空间中看到istio-injection
$ kubectl get namespace -L istio-injection
NAME            STATUS AGE  ISTIO-INJECTION
default         Active 5d8h enabled
istio-system    Active 40m
kube-node-lease Active 5d8h
kube-public     Active 5d8h
kube-system     Active 5d8h

您可以通过为命名空间添加istio-injection=enabled标签来始终启用其他命名空间的注入。

创建入口网关

Istio 使用网关而不是控制器来负载均衡流量。让我们执行以下步骤来为我们的示例应用程序创建一个 Istio 入口网关:

  1. src/chapter7/lb目录中的示例目录中查看minio.yaml文件的内容,并使用以下命令部署它。这将创建一个 StatefulSet 和一个服务,其中 MinIO 端口通过端口号9000在集群内部公开。您也可以选择应用相同的步骤并为您自己的应用程序创建一个入口网关。在这种情况下,跳到步骤 2
$ kubectl apply -f minio.yaml
  1. 获取入口 IP 和端口:
$ export INGRESS_HOST=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')
$ export INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].port}')
$ export SECURE_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="https")].port}')
  1. 创建一个新的 Istio 网关:
$ cat <<EOF | kubectl apply -f -
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
 name: minio-gateway
spec:
 selector:
 istio: ingressgateway 
 servers:
 - port:
 number: 80
 name: http
 protocol: HTTP
 hosts:
 - "*"
EOF
  1. 创建一个新的VirtualService来通过网关转发请求到 MinIO 实例。这有助于为网关指定路由并将网关绑定到VirtualService
$ cat <<EOF | kubectl apply -f -
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
 name: minio
spec:
 hosts:
 - "*"
 gateways:
 - minio-gateway.default
 http:
 - match:
 - uri:
 prefix: /
 route:
 - destination:
 port:
 number: 9000
 host: minio
EOF

这个配置将使用 Istio 将您的服务暴露给外部访问,并且您将对规则有更多的控制。

工作原理...

这个教程向您展示了如何快速配置 Istio 服务网格,并使用自定义的 Istio 资源,如入口网关来向外部开放服务。

为了使服务网格正常运行,网格中的每个 pod 都需要运行一个 Envoy sidecar。在使用 Helm 安装 Istio的步骤 3 中,我们启用了对default命名空间中的 pod 的自动注入,以便在该命名空间中部署的 pod 将运行 Envoy sidecar。

入口控制器是在 Kubernetes 集群中运行并配置路由规则的反向代理。在创建入口网关的步骤 2 中,与传统的 Kubernetes 入口对象不同,我们使用了 Istio CRD,如 Gateway、VirtualService 和 DestinationRule 来创建入口。

我们使用istio: ingressgateway选择器为入口网关创建了一个网关规则,以便在端口号80上接受 HTTP 流量。

步骤 4中,我们为我们想要暴露的 MinIO 服务创建了一个 VirtualService。由于网关可能在不同的命名空间中,我们使用minio-gateway.default来设置网关名称。

通过这样,我们已经使用 HTTP 暴露了我们的服务。您可以通过查看另请参阅部分中的链接来了解如何使用 HTTPS 协议暴露服务。

还有更多...

尽管它非常受欢迎,但 Istio 并不是最简单的入口处理方式。我们强烈建议您查看所有适用于您的用例的选项,并考虑替代方案。因此,了解如何删除 Istio 是很有用的。

删除 Istio

您可以使用以下命令删除 Istio:

$ helm delete istio
$ helm delete istio-init

如果您想要完全删除 Helm 记录中的已删除发布记录,并释放发布名称以供以后使用,可以在前面的命令中添加--purge参数。

另请参阅

使用 Linkerd 创建入口服务和服务网格

在本节中,我们将启动基本的 Linkerd 服务网格。您将学习如何创建一个服务网格来保护、连接和监视微服务。

服务网格本身是一个非常详细的概念,我们不打算在这里解释任何详细的用例。相反,我们将专注于启动和运行我们的服务。

准备工作

确保您已准备好 Kubernetes 集群,并配置了kubectlhelm来管理集群资源。

要访问此示例的文件,请将k8sdevopscookbook/src存储库克隆到您的工作站,以使用src/chapter7/linkerd目录中的配置文件,如下所示:

$ git clone https://github.com/k8sdevopscookbook/src.git
$ cd src/chapter7/linkerd/

在克隆了上述存储库之后,您可以开始使用这些示例。

如何做…

为了使这个过程更容易,本节进一步分为以下小节:

  • 安装 Linkerd CLI

  • 安装 Linkerd

  • 验证 Linkerd 部署

  • 查看 Linkerd 指标

安装 Linkerd CLI

要与 Linkerd 交互,您需要安装linkerd CLI。按照以下步骤进行:

  1. 通过运行以下命令安装linkerd CLI:
$ curl -sL https://run.linkerd.io/install | sh
  1. linkerd CLI 添加到您的路径:
$ export PATH=$PATH:$HOME/.linkerd2/bin
  1. 通过运行以下命令验证linkerd CLI 是否已安装。由于我们尚未安装,它应显示服务器不可用:
$ linkerd version
Client version: stable-2.5.0
Server version: unavailable
  1. 验证linkerd是否可以安装。此命令将检查集群并指出存在的问题:
$ linkerd check --pre
Status check results are √

如果状态检查看起来不错,您可以继续下一个示例。

安装 Linkerd

与其他选择相比,Linkerd 更容易入门和管理,因此它是我首选的服务网格。

使用 Linkerd CLI 安装 Linkerd 控制平面。此命令将使用默认选项并在linkerd命名空间中安装 linkerd 组件:

$ linkerd install | kubectl apply -f -

拉取所有容器镜像可能需要一分钟左右。之后,您可以通过以下步骤验证组件的健康状况,验证 Linkerd 部署

验证 Linkerd 部署

验证 Linkerd 的部署与安装过程一样简单。

运行以下命令验证安装。这将显示控制平面组件和 API 的长摘要,并确保您正在运行最新版本:

$ linkerd check
...

control-plane-version
---------------------
√ control plane is up-to-date
√ control plane and cli versions match

Status check results are √

如果状态检查良好,您可以准备使用示例应用程序测试 Linkerd。

将 Linkerd 添加到服务

按照以下步骤将 Linkerd 添加到我们的演示应用程序中:

  1. 切换到linkerd文件夹:
$ cd /src/chapter7/linkerd
  1. 部署使用 gRPC 和 HTTP 调用混合为用户提供投票应用程序的演示应用程序:
$ kubectl apply -f emojivoto.yml
  1. 获取演示应用程序的服务 IP。以下命令将返回应用程序的外部可访问地址:
$ SERVICE_IP=http://$(kubectl get svc web-svc -n emojivoto \
-o jsonpath='{.status.loadBalancer.ingress[0].hostname}:{.spec.ports[].targetPort}')
$ echo $SERVICE_IP
  1. 在 Web 浏览器中打开步骤 3中的外部地址,并确认应用程序是否正常运行:

  1. 通过为将运行应用程序的命名空间打标签来启用自动注入 sidecar。在这个示例中,我们使用了emojivoto命名空间:
$ kubectl label namespace emojivoto linkerd.io/inject=enabled

您还可以通过在运行应用程序的 pod 上手动注入linkerd sidecar 来手动注入:

kubectl get -n emojivoto deploy -o yaml | linkerd inject - | kubectl apply -f - 命令。在这个示例中,使用了emojivoto命名空间。

还有更多...

本节进一步分为以下子节,以使该过程更容易:

  • 访问仪表板

  • 删除 Linkerd

访问仪表板

我们可以使用端口转发或使用入口来访问仪表板。让我们从简单的方法开始,也就是通过端口转发到您的本地系统:

  1. 通过运行以下命令查看 Linkerd 仪表板:
$ linkerd dashboard &
  1. 在浏览器中访问以下链接以查看仪表板:
http://127.0.0.1:50750

上述命令将从您的本地系统设置端口转发到linkerd-web pod。

如果您想从外部 IP 访问仪表板,请按照以下步骤操作:

  1. 下载示例的入口定义:
$ wget https://raw.githubusercontent.com/k8sdevopscookbook/src/master/chapter7/linkerd/ingress-nginx.yaml
  1. src/chapter7/linkerd目录中的ingress-nginx.yaml文件中编辑入口配置,并将第 27 行的- host: dashboard.example.com更改为您希望暴露仪表板的 URL。使用以下命令应用配置:
$ kubectl apply -f ingress-nginx.yaml

上述示例文件使用linkerddashboard.containerized.me作为仪表板地址。它还使用admin/admin凭据对访问进行保护。强烈建议您通过更改配置中auth部分中定义的 base64 编码的密钥对来使用自己的凭据,格式为username:password

删除 Linkerd

要删除 Linkerd 控制平面,请运行以下命令:

$ linkerd install --ignore-cluster | kubectl delete -f -

此命令将拉取 Linkerd 控制平面的所有配置文件列表,包括命名空间、服务账户和 CRD,并将它们删除。

另请参阅

Kubernetes 中的自动修复 Pods

Kubernetes 在集群级别具有自愈能力。它在容器失败时重新启动容器,在节点死机时重新调度 Pod,甚至杀死不响应用户定义的健康检查的容器。

在本节中,我们将执行应用程序和集群扩展任务。您将学习如何使用存活探针和就绪探针来监视容器健康,并在失败时触发重新启动操作。

准备工作

确保您有一个准备好的 Kubernetes 集群,并配置kubectlhelm来管理集群资源。

操作步骤:

本节进一步分为以下子节,以使此过程更加简单:

  • 测试自愈 Pod

  • 向 Pod 添加存活探针

测试自愈 Pod

在这个示例中,我们将手动删除部署中的 Pod,以展示 Kubernetes 如何替换它们。稍后,我们将学习如何使用用户定义的健康检查来自动化这个过程。现在,让我们测试 Kubernetes 对被销毁的 Pod 的自愈能力:

  1. 创建具有两个或更多副本的部署或 StatefulSet。例如,我们将使用在上一章中使用的 MinIO 应用程序,在配置和管理 S3 对象存储使用 MinIO示例中。此示例有四个副本:
$ cd src/chapter7/autoheal/minio
$ kubectl apply -f minio.yaml
  1. 列出作为 StatefulSet 的一部分部署的 MinIO pods。您会看到四个 pods:
$ kubectl get pods |grep minio
minio-0 1/1 Running 0 4m38ms
minio-1 1/1 Running 0 4m25s
minio-2 1/1 Running 0 4m12s
minio-3 1/1 Running 0 3m48s
  1. 删除一个 pod 来测试 Kubernetes 的自愈功能,然后立即再次列出 pods。您会看到被终止的 pod 将被快速重新调度和部署:
$ kubectl delete pod minio-0
pod "minio-0" deleted
$ kubectl get pods |grep miniominio-0
minio-0 0/1 ContainerCreating 0 2s
minio-1 1/1 Running           0 8m9s
minio-2 1/1 Running           0 7m56s
minio-3 1/1 Running           0 7m32s

通过手动销毁一个正在运行的 pod 来测试 Kubernetes 的自愈功能。现在,我们将学习如何向 pods 添加健康状态检查,以便 Kubernetes 自动杀死无响应的 pods,然后重新启动它们。

向 pods 添加活跃性探测

Kubernetes 使用活跃性探测来确定何时重新启动容器。可以通过在容器内运行活跃性探测命令并验证它通过 TCP 套接字活跃性探测返回0,或者通过向指定路径发送 HTTP 请求来检查活跃性。在这种情况下,如果路径返回成功代码,那么 kubelet 将认为容器是健康的。在本示例中,我们将学习如何向示例应用程序发送 HTTP 请求方法。让我们执行以下步骤来添加活跃性探测:

  1. 编辑src/chapter7/autoheal/minio目录中的minio.yaml文件,并在volumeMounts部分下面添加以下livenessProbe部分,然后再添加volumeClaimTemplates。您的 YAML 清单应该类似于以下内容。这将每20秒向/minio/health/live位置发送 HTTP 请求以验证其健康状况:
...
        volumeMounts:
        - name: data
          mountPath: /data
#### Starts here 
        livenessProbe:
          httpGet:
            path: /minio/health/live
            port: 9000
          initialDelaySeconds: 120
          periodSeconds: 20
#### Ends here 
  # These are converted to volume claims by the controller
  # and mounted at the paths mentioned above.
  volumeClaimTemplates:

对于使用 HTTP 请求进行活跃性探测的应用程序,需要公开未经身份验证的健康检查端点。在我们的示例中,MinIO 通过/minio/health/live端点提供此功能。如果您的工作负载没有类似的端点,您可能希望在 pod 内部使用活跃性命令来验证其健康状况。

  1. 部署应用程序。它将创建四个 pods:
$ kubectl apply -f minio.yaml
  1. 通过描述其中一个 pods 来确认活跃性探测。您将看到类似以下的Liveness描述:
$ kubectl describe pod minio-0
...
 Liveness: http-get http://:9000/minio/health/live delay=120s timeout=1s period=20s #success=1 #failure=3
...
  1. 为了测试活动探测,我们需要再次编辑minio.yaml文件。这次,将livenessProbe端口设置为8000,这是应用程序无法响应 HTTP 请求的地方。重复步骤 23,重新部署应用程序,并检查 pod 描述中的事件。您将在事件中看到一个minio failed liveness probe, will be restarted消息:
$ kubectl describe pod minio-0
  1. 您可以通过列出 pod 来确认重启。您会看到每个 MinIO pod 由于具有失败的活动状态而多次重新启动:
$ kubectl get pods
NAME    READY STATUS  RESTARTS AGE
minio-0 1/1   Running 4        12m
minio-1 1/1   Running 4        12m
minio-2 1/1   Running 3        11m
minio-3 1/1   Running 3        11m

在这个教程中,您学会了如何为在 Kubernetes 集群中运行的应用程序实现自动修复功能。

工作原理...

这个教程向您展示了如何在 Kubernetes 上运行的应用程序中使用活动探测。

向 pod 添加活动探测教程中,在步骤 1中,我们添加了基于 HTTP 请求的健康检查。

通过添加 StatefulSet 路径和端口,我们让 kubelet 探测定义的端点。在这里,initialDelaySeconds字段告诉 kubelet 在第一次探测之前应该等待120秒。如果您的应用程序需要一段时间才能准备好端点,那么请确保在第一次探测之前允许足够的时间;否则,您的 pod 将在端点能够响应请求之前重新启动。

步骤 3中,periodSeconds字段指定 kubelet 应每20秒执行一次活动探测。同样,根据应用程序的预期可用性,您应该设置适合您的应用程序的周期。

另请参阅

通过蓝/绿部署管理升级

蓝绿部署架构是一种方法,用于通过运行两个可以在需要时切换的相同的生产环境来减少停机时间。这两个环境被标识为蓝色和绿色。在本节中,我们将执行滚动应用程序升级。您将学习如何使用 Kubernetes 中的蓝绿部署来滚动应用程序的新版本并使用持久存储。

准备工作

确保您已准备好一个 Kubernetes 集群,并配置了kubectlhelm来管理集群资源。

对于这个步骤,我们将需要一个持久存储提供程序,以从应用程序的一个版本中获取快照,并使用另一个版本的应用程序的克隆来保持持久卷内容。我们将使用 OpenEBS 作为持久存储提供程序,但您也可以使用任何兼容 CSI 的存储提供程序。

确保 OpenEBS 已经配置了 cStor 存储引擎,方法是按照第五章中的说明进行操作,即准备有状态工作负载,在使用 OpenEBS 进行持久存储的步骤中。

如何做…

本节进一步分为以下子节,以使此过程更容易:

  • 创建蓝色部署

  • 创建绿色部署

  • 从蓝色切换到绿色的流量

创建蓝色部署

有许多传统工作负载无法与 Kubernetes 的滚动更新方式配合使用。如果您的工作负载需要部署新版本并立即切换到新版本,则可能需要执行蓝绿部署。使用蓝绿部署方法,我们将标记当前生产环境为蓝色。在下一个步骤中,我们将创建一个名为绿色的相同生产环境,然后将服务重定向到绿色。

让我们执行以下步骤来创建第一个应用程序,我们将其称为蓝色:

  1. 切换到此步骤示例所在的目录:
$ cd /src/chapter7/bluegreen
  1. 查看blue-percona.yaml文件的内容,并使用它来创建应用程序的蓝色版本:
$ kubectl create -f blue-percona.yaml
pod "blue" created
persistentvolumeclaim "demo-vol1-claim" created
  1. 查看percona-svc.yaml文件的内容,并使用它来创建服务。您将看到服务中的selector设置为app: blue。此服务将所有 MySQL 流量转发到蓝色 pod:
$ kubectl create -f percona-svc.yaml
  1. 获取percona的服务 IP。在我们的示例中,集群 IP 为10.3.0.75
$ kubectl get svc percona
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
percona ClusterIP 10.3.0.75 <none> 3306/TCP 1m
  1. 编辑sql-loadgen.yaml文件,并将目标 IP 地址替换为您的 percona 服务 IP。在我们的示例中,它是10.3.0.75
      containers:
      - name: sql-loadgen
        image: openebs/tests-mysql-client
        command: ["/bin/bash"]
        args: ["-c", "timelimit -t 300 sh MySQLLoadGenerate.sh 10.3.0.75 > /dev/null 2>&1; exit 0"]
        tty: true
  1. 通过运行sql-loadgen.yaml作业来启动负载生成器:
$ kubectl create -f sql-loadgen.yaml

此作业将生成针对 Percona 工作负载(当前为蓝色)转发的服务的 IP 的 MySQL 负载。

创建绿色部署

让我们执行以下步骤来部署应用程序的新版本作为我们的绿色部署。我们将把服务切换到绿色,对蓝色的持久卷进行快照,并在新的 pod 中部署绿色工作负载:

  1. 让我们创建蓝色应用程序 PVC 的数据快照,并使用它来部署绿色应用程序:
$ kubectl create -f snapshot.yaml
volumesnapshot.volumesnapshot.external-storage.k8s.io "snapshot-blue" created
  1. 审查green-percona.yaml文件的内容,并使用它来创建应用的绿色版本:
$ kubectl create -f green-percona.yaml
pod "green" created
persistentvolumeclaim "demo-snap-vol-claim" created

这个 pod 将使用蓝色应用程序的 PVC 的快照作为其原始 PVC。

从蓝色切换到绿色的流量

让我们执行以下步骤,将流量从蓝色切换到新的绿色部署:

使用以下命令编辑服务,并将blue替换为green。服务流量将被转发到标记为green的 pod:

$ kubectl edit svc percona

在这个示例中,您已经学会了如何使用蓝/绿部署策略升级具有有状态工作负载的应用程序。

另请参阅

第八章:Kubernetes 上的可观测性和监控

在本章中,我们将讨论内置的 Kubernetes 工具和流行的第三方监控选项,适用于您的容器化 DevOps 环境。您将学习如何监视性能分析的指标,以及如何监视和管理 Kubernetes 资源的实时成本。

到本章结束时,您应该掌握以下知识:

  • 在 Kubernetes 中进行监控

  • 检查容器

  • 使用 Amazon CloudWatch 进行监控

  • 使用 Google Stackdriver 进行监控

  • 使用 Azure Monitor 进行监控

  • 使用 Prometheus 和 Grafana 监控 Kubernetes

  • 使用 Sysdig 进行监控和性能分析

  • 使用 Kubecost 管理资源成本

技术要求

本章中的配方假定您已经部署了一个功能齐全的 Kubernetes 集群,遵循第一章中描述的推荐方法之一,构建生产就绪的 Kubernetes 集群

Kubernetes 的命令行工具kubectl将用于本章中其余的配方,因为它是针对 Kubernetes 集群运行命令的主要命令行界面。我们还将使用 Helm,在 Helm 图表可用的情况下部署解决方案。

在 Kubernetes 中进行监控

在本节中,我们将配置我们的 Kubernetes 集群以获取核心指标,如 CPU 和内存。您将学习如何使用内置的 Kubernetes 工具在 CLI 和 UI 中监视 Kubernetes 指标。

做好准备

确保您已准备好 Kubernetes 集群,并配置kubectl以管理集群资源。

k8sdevopscookbook/src存储库克隆到您的工作站,以使用chapter8目录中的清单文件:

$ git clone https://github.com/k8sdevopscookbook/src.git
$ cd /src/chapter8

使用 Kubernetes 仪表板监视指标配方需要 Kubernetes 仪表板 v2.0.0 或更高版本才能正常运行。如果您想要向仪表板添加指标功能,请确保您已按照第一章中的部署 Kubernetes 仪表板配方中的说明安装了 Kubernetes 仪表板,构建生产就绪的 Kubernetes 集群

如何做…

本节进一步分为以下子节,以使流程更加简单:

  • 使用 Kubernetes Metrics Server 添加指标

  • 使用 CLI 监控指标

  • 使用 Kubernetes 仪表板监视指标

  • 监控节点健康

使用 Kubernetes Metrics Server 添加指标

获取核心系统指标,如 CPU 和内存,不仅提供有用的信息,而且还是扩展 Kubernetes 功能所必需的,比如我们在第七章中提到的扩展和升级应用中的水平 Pod 自动缩放:

  1. 通过运行以下命令将 Metrics Server 存储库克隆到您的客户端:
$ git clone https://github.com/kubernetes-incubator/metrics-        server.git
  1. 通过运行以下命令,在metrics-server/deploy/1.8+目录中应用清单来部署 Metrics Server:
$ kubectl apply -f metrics-server/deploy/1.8+

此命令将在kube-space命名空间中创建所需的资源。

使用 CLI 监控指标

作为 Metrics Server 的一部分,资源指标 API 提供对 Pod 和节点的 CPU 和内存资源指标的访问。让我们使用资源指标 API 从 CLI 访问指标数据:

  1. 首先,让我们显示节点资源利用率:
$ kubectl top nodes
NAME                          CPU(cores) CPU% MEMORY(bytes) MEMORY%
ip-172-20-32-169.ec2.internal 259m       12%  1492Mi        19%
ip-172-20-37-106.ec2.internal 190m       9%   1450Mi        18%
ip-172-20-48-49.ec2.internal  262m       13%  2166Mi        27%
ip-172-20-58-155.ec2.internal 745m       37%  1130Mi        14%

该命令将返回所有 Kubernetes 节点上已使用的 CPU 和内存。

有几种使用指标信息的方法。首先,在任何给定时间,CPU 和内存的使用量都应低于您的期望阈值,否则需要向集群添加新节点以平稳处理服务。平衡利用也很重要,这意味着如果内存使用的百分比高于 CPU 使用的平均百分比,您可能需要考虑更改云实例类型以使用更平衡的 VM 实例。

  1. 在任何命名空间中显示 Pod 资源利用率。在此示例中,我们正在列出openebs命名空间中的 Pod:
$ kubectl top pods -n openebs
NAME                                         CPU(cores) MEMORY(bytes)
maya-apiserver-6ff5bc7bdd-l5gmt              2m         10Mi
openebs-admission-server-76dbdf97d9-swjw9    0m         3Mi
openebs-localpv-provisioner-6777f78966-f6lzp 2m         8Mi
openebs-ndm-operator-797495544c-hblxv        5m         12Mi
openebs-ndm-prvcr                            1m         6Mi
openebs-ndm-qmr66                            1m         6Mi
openebs-ndm-xbc2q                            1m         6Mi
openebs-provisioner-58bbbb8575-jzch2         3m         7Mi
openebs-snapshot-operator-6d7545dc69-b2zr7   4m         15Mi

该命令应返回所有 Pod 的已使用 CPU 和内存。Kubernetes 功能,如水平 Pod 缩放器,可以利用此信息来调整您的 Pod。

使用 Kubernetes 仪表板监控指标

默认情况下,除非安装了 Kubernetes Metrics Server 并且kubernetes-metrics-scraper辅助容器正在运行,否则 Kubernetes 仪表板不会显示详细的指标。

首先验证所有必要的组件是否正在运行,然后我们将看到如何从 Kubernetes 仪表板访问指标数据:

  1. 验证kubernetes-metrics-scraper Pod 是否正在运行。如果没有,请按照第一章,构建生产就绪的 Kubernetes 集群中的部署 Kubernetes 仪表板配方中的说明安装 Kubernetes 仪表板:
$ kubectl get pods -n kubernetes-dashboard
NAME                                       READY STATUS  RESTARTS AGE
dashboard-metrics-scraper-69fcc6d9df-hhkkw 1/1   Running 0        177m
kubernetes-dashboard-566c79c67d-xqc6h      1/1   Running 0        177m
  1. 在 Kubernetes 仪表板上,选择命名空间,然后单击“概述”菜单。此视图显示该命名空间中的 Pod 及其 CPU 和内存利用率:

  1. 在 Kubernetes 仪表板上,选择一个命名空间,然后在“概述”菜单中单击 Pods。此视图显示所选命名空间中工作负载的整体 CPU 和内存利用率:

  1. 在集群菜单下选择节点。此视图显示集群中的节点以及 CPU 和内存的利用率:

如果请求和限制设置得非常高,那么它们可能会占用集群超出预期的份额。

监控节点健康

在本教程中,我们将学习如何在 Kubernetes 集群中创建一个 DaemonSet 来监视节点健康。节点问题检测器将从守护程序收集节点问题,并将其报告给 API 服务器作为 NodeCondition 和 Event:

  1. 首先,从/src/chapter8文件夹中检查node-problem-detector.yaml文件的内容,并创建 DaemonSet 来运行节点问题检测器:
$ cat debug/node-problem-detector.yaml
$ kubectl apply -f debug/node-problem-detector.yaml
  1. 获取集群中节点的列表。此命令将返回工作节点和主节点:
$ kubectl get nodes
NAME                          STATUS ROLES  AGE   VERSION
ip-172-20-32-169.ec2.internal Ready  node   6d23h v1.14.6
ip-172-20-37-106.ec2.internal Ready  node   6d23h v1.14.6
ip-172-20-48-49.ec2.internal  Ready  master 6d23h v1.14.6
ip-172-20-58-155.ec2.internal Ready  node   6d23h v1.14.6
  1. 通过将以下命令中的节点名称替换为您的节点名称并运行它来描述节点的状态。在输出中,检查Conditions部分是否有错误消息。以下是输出的示例:
$ kubectl describe node ip-172-20-32-169.ec2.internal | grep -i condition -A 20 | grep Ready -B 20
Conditions:
 Type Status LastHeartbeatTime LastTransitionTime Reason Message
 ---- ------ ----------------- ------------------ ------ -------
 NetworkUnavailable False Sat, 12 Oct 2019 00:06:46 +0000 Sat, 12 Oct 2019 00:06:46 +0000 RouteCreated RouteController created a route
 MemoryPressure False Fri, 18 Oct 2019 23:43:37 +0000 Sat, 12 Oct 2019 00:06:37 +0000 KubeletHasSufficientMemory kubelet has sufficient memory available
 DiskPressure False Fri, 18 Oct 2019 23:43:37 +0000 Sat, 12 Oct 2019 00:06:37 +0000 KubeletHasNoDiskPressure kubelet has no disk pressure
 PIDPressure False Fri, 18 Oct 2019 23:43:37 +0000 Sat, 12 Oct 2019 00:06:37 +0000 KubeletHasSufficientPID kubelet has sufficient PID available
 Ready True Fri, 18 Oct 2019 23:43:37 +0000 Sat, 12 Oct 2019 00:06:37 +0000 KubeletReady kubelet is posting ready status
  1. 此外,您可以通过将命令的最后一部分替换为其中一个条件来检查KernelDeadlockMemoryPressureDiskPressure条件。以下是KernelDeadlock的示例:
$ kubectl get node ip-172-20-32-169.ec2.internal -o yaml | grep -B5 KernelDeadlock
 - lastHeartbeatTime: "2019-10-18T23:58:53Z"
 lastTransitionTime: "2019-10-18T23:49:46Z"
 message: kernel has no deadlock
 reason: KernelHasNoDeadlock
 status: "False"
 type: KernelDeadlock

节点问题检测器可以检测无响应的运行时守护程序;硬件问题,如坏的 CPU、内存或磁盘;内核问题,包括内核死锁条件;损坏的文件系统;无响应的运行时守护程序;以及基础设施守护程序问题,如 NTP 服务中断。

另请参阅

检查容器

在本节中,我们将解决与 pod 卡在 Pending、ImagePullBackOff 或 CrashLoopBackOff 状态相关的问题。您将学习如何检查和调试在 Kubernetes 中遇到部署问题的 pod。

准备工作

确保您已准备好一个 Kubernetes 集群,并配置了kubectl以管理集群资源。

如何操作…

该部分进一步分为以下子部分,以使过程更加简单:

  • 检查处于 Pending 状态的 pod

  • 检查处于 ImagePullBackOff 状态的 pod

  • 检查处于 CrashLoopBackOff 状态的 pod

检查处于 Pending 状态的 pod

当您在 Kubernetes 上部署应用程序时,不可避免地会需要获取有关应用程序的更多信息。在这个示例中,我们将学习检查常见的 pod 问题,即 pod 卡在 Pending 状态:

  1. /src/chapter8文件夹中,检查mongo-sc.yaml文件的内容,并运行以下命令部署它。部署清单包括具有三个副本的 MongoDB Statefulset,Service,并且由于参数错误而卡在 Pending 状态,我们将对其进行检查以找到问题的根源:
$ cat debug/mongo-sc.yaml
$ kubectl apply -f debug/mongo-sc.yaml
  1. 通过运行以下命令列出 pod。您会注意到mongo-0 pod 的状态是Pending
$ kubectl get pods
NAME    READY STATUS  RESTARTS AGE
mongo-0 0/2   Pending 0        3m
  1. 使用kubectl describe pod命令获取有关 pod 的其他信息,并查找Events部分。在这种情况下,Warning指向未绑定的PersistentVolumeClaim
$ kubectl describe pod mongo-0
...
Events:
 Type    Reason           Age    From          Message
 ----    ------           ----   ----          -------
 Warning FailedScheduling 2m34s (x34 over 48m) default-scheduler pod has unbound immediate PersistentVolumeClaims (repeated 3 times)

  1. 现在我们知道需要查看 PVC 状态,这要归功于上一步的结果,让我们获取 PVC 列表以检查问题。您会看到 PVC 也处于Pending状态:
$ kubectl get pvc
NAME              STATUS  VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
mongo-pvc-mongo-0 Pending                              storageclass 53m
  1. 使用kubectl describe pvc命令获取有关 PVC 的其他信息,并查看事件的描述位置。在这种情况下,Warning指向一个名为storageclass的缺失存储类:
$ kubectl describe pvc mongo-pvc-mongo-0
...
Events:
 Type    Reason             Age  From           Message
 ----    ------             ---- ----           -------
 Warning ProvisioningFailed 70s  (x33 over 58m) persistentvolume-controller storageclass.storage.k8s.io "storageclass" not found

  1. 列出存储类。您会注意到没有名为storageclass的存储类:
$ kubectl get sc
NAME                            PROVISIONER AGE
default                         kubernetes.io/aws-ebs 16d
gp2                             kubernetes.io/aws-ebs 16d
openebs-cstor-default (default) openebs.io/provisioner-iscsi 8d
openebs-device                  openebs.io/local 15d
openebs-hostpath                openebs.io/local 15d
openebs-jiva-default            openebs.io/provisioner-iscsi 15d
openebs-snapshot-promoter       volumesnapshot.external-storage.k8s.io/snapshot-promoter 15d
  1. 现在我们知道我们在步骤 1中应用的清单文件使用了一个不存在的存储类。在这种情况下,您可以创建缺失的存储类,或者编辑清单以包含现有的存储类来解决问题。

让我们创建一个缺失的存储类,从现有的默认存储类中创建,就像下面的示例中所示gp2

$ kubectl create -f sc-gp2.yaml
  1. 通过运行以下命令列出 pod。您会注意到在步骤 2中先前处于Pending状态的所有 pod 现在的状态为Running
$ kubectl get pods
NAME    READY STATUS  RESTARTS AGE
mongo-0 2/2   Running 0        2m18s
mongo-1 2/2   Running 0        88s
mongo-2 2/2   Running 0        50s

您已成功学会了如何检查为什么 pod 处于挂起状态并修复它。

检查处于 ImagePullBackOff 状态的 pod

有时您的清单文件可能会在图像名称中出现拼写错误,或者图像位置可能已更改。因此,当您部署应用程序时,容器图像将无法找到,并且部署将被卡住。在这个教程中,我们将学习如何检查处于ImagePullBackOff状态的 pod 的常见问题:

  1. /src/chapter8文件夹中,检查mongo-image.yaml文件的内容,并通过运行以下命令部署它。部署清单包括具有三个副本的 MongoDB Statefulset,Service,并且由于容器图像名称中的拼写错误而被卡住在 ImagePullBackOff 状态,我们将对其进行检查以找到源:
$ cat debug/mongo-image.yaml
$ kubectl apply -f debug/mongo-image.yaml
  1. 通过运行以下命令列出 pod。您会注意到mongo-0 pod 的状态为ImagePullBackOff
$ kubectl get pods
NAME    READY STATUS           RESTARTS AGE
mongo-0 0/2   ImagePullBackOff 0        32s
  1. 使用kubectl describe pod命令获取有关 pod 的其他信息,并查找Events部分。在这种情况下,Warning指向未能拉取mongi图像的失败:
$ kubectl describe pod mongo-0
...
Events:
 Type    Reason           Age    From          Message
 ----    ------           ----   ----          -------
 Warning Failed 25s (x3 over 68s) kubelet, ip-172-20-32-169.ec2.internal Error: ErrImagePull
 Warning Failed 25s (x3 over 68s) kubelet, ip-172-20-32-169.ec2.internal Failed to pull image "mongi": rpc error: code = Unknown desc = Error response from daemon: pull access denied for mongi, repository does not exist or may require 'docker login'
 Normal Pulling 25s (x3 over 68s) kubelet, ip-172-20-32-169.ec2.internal Pulling image "mongi"
 Normal BackOff 14s (x4 over 67s) kubelet, ip-172-20-32-169.ec2.internal Back-off pulling image "mongi"
 Warning Failed 14s (x4 over 67s) kubelet, ip-172-20-32-169.ec2.internal Error: ImagePullBackOff
  1. 现在我们知道需要确认容器图像名称。正确的名称应该是mongo。让我们编辑清单文件mongo-image.yaml,并将图像名称更改为mongo,如下所示:
... 
spec:
 terminationGracePeriodSeconds: 10
 containers:
 - name: mongo
 image: mongo
 command:
...
  1. 通过运行以下命令删除并重新部署资源:
$ kubectl delete -f mongo-image.yaml
$ kubectl apply -f mongo-image.yaml
  1. 通过运行以下命令列出 pod。您会注意到在步骤 2中先前处于ImagePullBackOff状态的所有 pod 现在的状态为Running
$ kubectl get pods
NAME    READY STATUS  RESTARTS AGE
mongo-0 2/2   Running 0        4m55s
mongo-1 2/2   Running 0        4m55s
mongo-2 2/2   Running 0        4m55s

您已成功学会了检查状态为ImagePullBackOff的 pod 并进行故障排除。

检查处于 CrashLoopBackOff 状态的 pod

检查处于CrashLoopBackOff状态的 Pod 与检查处于挂起状态的 Pod 基本类似,但可能还需要更多关于您正在创建的容器工作负载的知识。当容器内的应用程序不断崩溃、Pod 的参数配置不正确、存活探针失败或在 Kubernetes 上部署时发生错误时,就会发生CrashLoopBackOff

在这个教程中,我们将学习如何检查 Pod 陷入CrashLoopBackOff状态的常见问题:

  1. /src/chapter8文件夹中,检查mongo-config.yaml文件的内容,并运行以下命令部署它。部署清单包括一个具有三个副本的 MongoDB 有状态集,Service,并由于缺少配置文件而陷入CrashLoopBackOff状态,我们将对其进行检查以找到源:
$ cat debug/mongo-config.yaml
$ kubectl apply -f debug/mongo-config.yaml
  1. 通过运行以下命令列出 Pod。您会注意到mongo-0 Pod 的状态为CrashLoopBackOffError
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
mongo-0 1/2 CrashLoopBackOff 3 58s
  1. 使用kubectl describe pod命令获取有关 Pod 的附加信息,并查找Events部分。在这种情况下,Warning显示容器已重新启动,但没有指向任何有用的信息:
$ kubectl describe pod mongo-0
...
Events:
 Type    Reason           Age    From          Message
 ----    ------           ----   ----          -------
...
 Normal Pulled 44s (x4 over 89s) kubelet, ip-172-20-32-169.ec2.internal Successfully pulled image "mongo"
 Warning BackOff 43s (x5 over 87s) kubelet, ip-172-20-32-169.ec2.internal Back-off restarting failed container

  1. 当来自 Pod 的事件不够用时,您可以使用kubectl logs命令从 Pod 获取附加信息。使用以下命令检查 Pod 日志中的消息。日志消息指向一个丢失的文件;需要进一步检查清单:
$ kubectl logs mongo-0 mongo
/bin/sh: 1: cannot open : No such file
  1. 检查并仔细查看应用程序清单文件mongo-config.yaml,您会发现在这种情况下缺少环境变量MYFILE
...
 spec:
 terminationGracePeriodSeconds: 10
 containers:
 - name: mongo
 image: mongo
 command: ["/bin/sh"]
 args: ["-c", "sed \"s/foo/bar/\" < $MYFILE"]
...
  1. 要解决此问题,您可以向部署中添加ConfigMap。编辑mongo-config.yaml文件,并通过在文件开头添加MYFILE参数与ConfigMap资源来添加缺失的文件,类似于以下内容:
$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
 name: app-env
data:
 MYFILE: "/etc/profile"
EOF
  1. 通过运行以下命令删除并重新部署资源:
$ kubectl delete -f mongo-image.yaml
$ kubectl apply -f mongo-image.yaml
  1. 通过运行以下命令列出 Pod。您会注意到之前处于 CrashLoopBackOff 状态的所有 Pod 现在状态为Running
$ kubectl get pods
NAME    READY STATUS  RESTARTS AGE
mongo-0 2/2   Running 0        4m15s
mongo-1 2/2   Running 0        4m15s
mongo-2 2/2   Running 0        4m15s

您已成功学会了如何检查 Pod 的 CrashLoopBackOff 问题并修复它。

另请参阅

使用 Amazon CloudWatch 进行监控

在本节中,我们将使用 Amazon CloudWatch Container Insights 来监视、隔离和诊断您的容器化应用程序和微服务环境。作为一名 DevOps 或系统工程师,您将学习如何使用 Amazon ECS CloudWatch 指标来监视服务健康状态和当前警报,使用自动化仪表板总结您的 Amazon EKS 集群的性能和健康状态,包括 pod、节点、命名空间和服务。

准备工作

k8sdevopscookbook/src存储库克隆到您的工作站,以使用chapter8目录中的清单文件:

$ git clone https://github.com/k8sdevopscookbook/src.git
$ cd src/chapter8/

确保您有一个准备好的 Amazon EKS Kubernetes 集群,并且已配置kubectl来管理集群资源。如果您还没有,可以按照第一章中的说明构建生产就绪的 Kubernetes 集群在 Amazon Web Services 上配置 Kubernetes 集群部分。

如何做…

本节进一步分为以下小节,以使流程更加简单:

  • 启用 Webhook 授权模式

  • 为 Amazon EKS 安装 Container Insights 代理程序

  • 查看 Container Insights 指标

启用 Webhook 授权模式

如果您使用kops选项在 AWS EC2 实例上部署了 Kubernetes 集群,而不是使用 Amazon EKS,则您的 kubelet 需要启用 Webhook 授权模式。

让我们按照以下步骤进行:

  1. 使用以下两个标志启用webhook授权模式。第一个标志允许使用 ServiceAccount 令牌对 kubelet 进行身份验证。第二个标志允许 kubelet 执行 RBAC 请求并决定请求资源(在本例中为 Amazon CloudWatch)是否被允许访问资源端点:
--authentication-token-webhook=true 
--authorization-mode=Webhook 
  1. 您还需要为 Kubernetes 工作节点的 IAM 角色添加必要的策略。在console.aws.amazon.com/ec2/上打开 Amazon EC2 控制台。

  2. 在资源下,点击“运行实例”:

  1. 从列表中选择一个工作节点实例,并在“描述”选项卡上选择 IAM 角色。在我们的示例中,eksctl-adorable-rainbow-157155665-NodeInstanceRole-MOT7WBCOOOHE 是 IAM 角色:

  1. 在“权限”选项卡上,点击“附加策略”按钮:

  1. 在搜索框中,键入CloudWatchAgentServerPolicy并选择该策略:

  1. 点击“附加策略”按钮将策略附加到您的 IAM 角色:

现在,您已成功启用了 Webhook 授权模式并向 IAM 角色添加了所需的策略。

为 Amazon EKS 安装容器洞察代理

在这个教程中,我们将启用 CloudWatch 代理来收集我们的 EKS Kubernetes 集群的集群指标:

  1. 使用以下命令在您的集群上创建名为amazon-cloudwatch的命名空间:
$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Namespace
metadata:
 name: amazon-cloudwatch
 labels:
 name: amazon-cloudwatch
EOF
  1. 为您在步骤 1中创建的amazon-cloudwatch命名空间创建 CloudWatch 代理的服务帐户。以下命令还将创建cloudwatch-agent-role ClusterRole 和 ClusterRoleBinding:
$ kubectl apply -f cloudwatch/cwagent-serviceaccount.yaml
  1. 使用eksctl命令或从 Amazon 容器服务仪表板获取您的 EKS 集群名称。在这里,我们将使用eksctl获取集群名称。在我们的示例中,集群名称是adorable-rainbow-1571556654
$ eksctl get cluster
NAME                        REGION
adorable-rainbow-1571556654 us-west-2
  1. 为 CloudWatch 代理创建 ConfigMap。在运行以下命令之前,请用您在步骤 3中的集群名称替换"cluster_name": "adorable-rainbow-1571556654"
$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
 name: cwagentconfig
 namespace: amazon-cloudwatch
data:
 cwagentconfig.json: |
 {
 "logs": {
 "metrics_collected": {
 "kubernetes": {
 "cluster_name": "{{cluster_name}}",
 "metrics_collection_interval": 60
 }
 },
 "force_flush_interval": 5
 }
 }
EOF
  1. 部署 CloudWatch 代理作为 DaemonSet。上述命令将使用 StatsD,这是一个监听通过 UDP 或 TCP 发送的统计信息(如计数器和计时器)的网络守护程序,并将聚合发送到 CloudWatch,如果可用还会使用可插拔的后端服务:
$ kubectl apply -f cloudwatch/cwagent.yaml
  1. 通过运行以下命令来验证 CloudWatch 代理 Pod 是否已创建。由于代理作为 DaemonSets 运行,您应该能够看到每个工作节点列出的一个 Pod。在我们的示例中,我们有两个工作节点和两个代理 Pod 正在运行:
$ kubectl get pods -n amazon-cloudwatch
NAME                   READY STATUS  RESTARTS AGE
cloudwatch-agent-dtpxt 1/1   Running 0        67s
cloudwatch-agent-j7frt 1/1   Running 0        67s

完成后,CloudWatch 代理将开始向 CloudWatch 容器洞察服务发送性能日志事件。

查看容器洞察指标

在这个教程中,我们将学习如何使用 CloudWatch 来监视我们的 Kubernetes 集群中的节点和 Pod 指标:

  1. console.aws.amazon.com/cloudwatch/上打开 CloudWatch 控制台:

  1. 单击“概览”选项旁边的向下箭头按钮,然后从列表中选择“容器洞察”:

  1. 要查看 EKS 节点的健康状况和统计信息,请在左上角切换到 EKS 节点。新视图上的图表将显示资源利用率、集群故障和节点数量,类似于以下截图的历史视图:

  1. 要查看容器性能统计信息,请在左上角切换到 EKS Pod。新视图上的图表将显示 Pod 的总资源利用率,并列出 Pod 的各自 CPU 和内存消耗百分比,类似于以下截图:

  1. 要查看任何资源的详细日志或 AWS X-Ray 跟踪,请从列表中选择资源名称,然后单击“操作”按钮。从下拉菜单中,您可以选择要查看的日志。选择后,日志将在新窗口中打开:

现在您已经学会了如何使用容器洞察来监视您的 Kubernetes 集群中的节点和 Pod 指标。

另请参阅

使用 Google Stackdriver 进行监控

在本节中,我们将使用 Google Stackdriver Kubernetes Engine 监控来监视、隔离和诊断您的容器化应用程序和微服务环境。您将学习如何使用 Stackdriver Kubernetes Engine 监控来聚合来自Google Kubernetes EngineGKE)的 Kubernetes 环境的日志、事件和指标,以帮助您了解您的应用在生产环境中的行为。

准备工作

确保您已准备好一个 GKE 集群,并配置了kubectl来管理集群资源。如果您还没有,请按照第一章,构建生产就绪的 Kubernetes 集群中的在 Google 云平台上配置 Kubernetes 集群的说明进行操作。

如何做…

本节进一步分为以下子节,以使流程更加简单:

  • 安装 GKE 的 Stackdriver Kubernetes Engine 监控支持

  • 在 Stackdriver 上配置工作空间

  • 使用 Stackdriver 监控 GKE 指标

安装 GKE 的 Stackdriver Kubernetes Engine 监控支持

安装 Stackdriver 监控支持可以让您轻松监控 GKE 集群,调试日志,并使用高级分析和跟踪功能分析您的集群性能。在这个示例中,我们将启用 Stackdriver Kubernetes Engine 监控支持,以从我们的 GKE 集群中收集集群指标:

  1. console.cloud.google.com/kubernetes上打开 Google Kubernetes Engine 控制台。在这个控制台上,您将看到您的 GKE 集群列表。在我们的示例中,我们只有一个集群,它被称为 k8s-devops-cookbook-1:

  1. 单击集群旁边的小笔形编辑图标:

  1. 在集群配置页面上,确保“传统 Stackdriver 日志记录”和“传统 Stackdriver 监控”已禁用,并且“Stackdriver Kubernetes Engine 监控”选项已设置为启用:

  1. 单击保存按钮以应用对集群的更改。

在 Stackdriver 上配置工作区

Stackdriver 监控帮助您更深入地了解您的公共云。Stackdriver 的监控功能包括监控、日志记录、跟踪、错误报告和警报,以收集您的公共云服务的性能和诊断数据。Kubernetes 监控是完整解决方案的一小部分。在本教程中,您将学习如何在首次访问后配置 Stackdriver 工作区:

  1. app.google.stackdriver.com上打开 Stackdriver 控制台。第一次访问控制台时,您需要将工作区添加到控制台,否则您将看到一个空的仪表板,类似于以下内容:

  1. 单击“添加工作区”按钮以包括您现有的工作区。您将被要求输入您的 Google Cloud Platform 项目名称。单击空的“选择项目”字段,并从列表中选择您的项目。在我们的示例中,它是 DevOpsCookBook。选择项目后,单击“创建工作区”按钮:

  1. Stackdriver 还允许您监控 AWS 账户。对于本教程,我们将跳过此选项。单击“跳过 AWS 设置”以进行下一步:

  1. 在“安装 Stackdriver 代理”窗口中,单击“继续”按钮。

  2. 在“通过电子邮件获取报告”窗口中,选择要通过电子邮件发送报告的频率。选择每周报告。请注意,您始终可以选择不发送报告,并稍后启用此功能:

  1. 最后,单击“启动监控”按钮以访问 Stackdriver 控制台:

现在您已经配置了 Stackdriver 工作区,以收集来自您的公共云服务的诊断数据。

使用 Stackdriver 监控 GKE 指标

安装 Stackdriver 监控支持可以让您轻松监视 GKE 集群,调试日志,并使用高级分析和跟踪功能分析集群性能。在本示例中,我们将启用 Stackdriver Kubernetes Engine 监控支持,以从我们的 GKE 集群收集集群指标:

  1. 在按照在 Stackdriver 上配置工作空间的步骤后,打开 Stackdriver 控制台app.google.stackdriver.com

  1. 从资源菜单中,点击“Kubernetes Engine”选项:

  1. Kubernetes Engine 视图将显示启用了 Stackdriver Kubernetes Engine 监控的集群列表。在我们的示例中,您可以看到我们有一个可用的集群:

  1. 在基础设施选项卡上,点击集群名称旁边的展开图标。Stackdriver 将展开列表,显示各个工作节点。在“就绪”列中,您可以看到每个节点上部署并处于就绪状态的 pod 数量。在“CPU 利用率”列中,左侧的值显示总可用 CPU 数,右侧的值显示当前利用率百分比。类似地,在“内存利用率”列中,左侧的值显示总可用内存(GiB),右侧的值显示当前利用率百分比:

  1. 点击节点名称旁边的展开图标,列表将展开以显示部署在该特定节点上的 pod:

  1. 点击集群中的一个 pod。Stackdriver 将显示 pod 指标的详细视图,包括 pod 重启、CPU、内存、存储和网络利用率。在我们的示例中,我们可以看到 Prometheus pod 的指标:

  1. 点击“日志”选项卡切换到日志摘要视图。此视图将只显示最近的日志:

  1. 点击“转到控制台”按钮,打开详细的日志视图,您可以在其中查看旧日志并使用过滤器创建指标:

现在您知道如何使用 Stackdriver 来监视 GKE 集群和部署在 GKE 集群上的资源的健康状况、性能指标和日志。

另请参阅

使用 Azure Monitor 进行监控

在本节中,我们将使用 Azure Monitor 来监视、隔离和诊断您的容器化应用程序和微服务环境。您将学习如何使用 Azure Monitor 来聚合来自Azure Kubernetes ServiceAKS)上的 Kubernetes 环境的日志、事件和指标,以帮助您了解应用程序在生产环境中的行为。

做好准备

确保您已经准备好一个 AKS 集群,并且已经配置好kubectl来管理集群资源。如果您还没有,您可以按照《第一章》中的说明进行操作,即《构建生产就绪的 Kubernetes 集群》,在《在 Google Cloud Platform 上配置 Kubernetes 集群》的教程中。

如何做…

本节进一步分为以下子节,以使流程更加简单:

  • 使用 CLI 为 AKS 集群启用 Azure Monitor 支持

  • 使用 Azure Monitor 监控 AKS 性能指标

  • 使用 Azure Monitor 查看实时日志

使用 CLI 为 AKS 启用 Azure Monitor 支持

启用 Azure Monitor 以便从控制器、节点和容器中收集内存和处理器指标,这些指标通过 Kubernetes Metrics API 在 Kubernetes 中可用。

在这个教程中,我们将启用从 AKS Kubernetes 集群收集指标和日志的监控,通过 Log Analytics 代理的容器化版本:

  1. 如果您按照第一章中的在 AKS 上部署托管的 Kubernetes 集群配方部署了您的 AKS 集群,您可以使用以下命令为您的集群启用 Azure Monitor。在运行以下命令之前,将名称AKSCluster替换为您的 AKS 集群名称,并将资源组k8sdevopscookbook替换为您在创建集群时使用的 Azure 资源组名称:
$ az aks enable-addons -a monitoring \
--name AKSCluster --resource-group k8sdevopscookbook

如果您正在部署新的集群,可以在 CLI 命令中添加--enable-addons monitoring参数,以在集群创建期间为您的 AKS 集群启用 Azure Monitor 功能,如下所示:$ az aks create --resource-group k8sdevopscookbook \

--name AKSCluster \

--node-count 3 \

--service-principal <appId> \

--client-secret <password> \

--enable-addons monitoring  \

--generate-ssh-keys

完成后,此命令将为您的 AKS 集群启用 Azure Monitor 和日志记录。

使用 Azure Monitor 监视 AKS 性能指标

可以直接从 AKS 集群管理仪表板和 Azure Monitor 仪表板查看 AKS 集群的性能指标。在此配方中,我们将通过 Azure Monitor 监视 AKS 性能指标:

  1. 按照使用 CLI 为 AKS 启用 Azure Monitor 支持的配方后,打开 Azure 门户网站portal.azure.com,单击“Kubernetes 服务”按钮,转到 AKS 管理仪表板:

  1. 在 Kubernetes 服务视图中,单击您的集群名称。在我们的示例中,它是 AKSCluster:

  1. 单击“监视容器”菜单,打开您的 AKS 集群的 Azure Monitor Insights 视图:

  1. 有关您的 AKS 集群的监视信息分为五个类别:集群、节点、控制器、容器和部署。在此视图中,在集群选项卡上,您将能够查看节点 CPU 和内存利用率、AKS 节点计数和活动 pod 计数,就像这样:

  1. 单击“节点”选项卡,切换到节点性能指标视图。默认情况下,CPU 使用数据显示为过去 6 小时的 95th 百分位数。可以使用页面上的下拉菜单调整这些选项:

  1. 单击节点名称旁边的展开图标,列表将展开显示部署在该特定节点上的 Pod 和容器。在此视图中,可以查看每个资源的 CPU 利用率和正常运行时间:

现在你知道如何通过 Azure Monitor insights 监视 AKS 性能指标了。

使用 Azure Monitor 查看实时日志

除了性能指标,Azure Monitor 还可以帮助查看 AKS 集群资源的日志。在本教程中,我们将学习如何使用 Azure Monitor 访问事件和日志:

  1. 在你的集群中,要显示 Pod 事件和实时指标,你需要应用ClusterRoleBinding。通过在你的 AKS 集群上运行以下命令来创建ClusterRole
$ cat <<EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1 
kind: ClusterRole 
metadata: 
 name: containerHealth-log-reader 
rules: 
 - apiGroups: [""] 
 resources: ["pods/log", "events"] 
 verbs: ["get", "list"] 
EOF
  1. 通过在你的 AKS 集群上运行以下命令来创建ClusterRoleBinding
$ cat <<EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1 
kind: ClusterRoleBinding 
metadata: 
 name: containerHealth-read-logs-global 
roleRef: 
 kind: ClusterRole 
 name: containerHealth-log-reader 
 apiGroup: rbac.authorization.k8s.io 
subjects: 
 - kind: User 
 name: clusterUser 
 apiGroup: rbac.authorization.k8s.io
EOF
  1. 单击“监视容器”菜单,打开你的 AKS 集群的 Azure Monitor insights 视图。

  2. 单击节点名称旁边的展开图标,列表将展开显示部署在该特定节点上的 Pod 和容器:

  1. 单击你的集群中的一个 Pod。Insights 将在右侧面板上显示 Pod 指标的详细视图:

  1. 在右侧窗格中,单击“查看实时数据”按钮。此选项将展开视图,显示来自 Pod 的实时事件和实时指标,如下图所示。事件可用于排除本章“检查容器”部分中讨论的 Pod 问题:

  1. 你在视图中看到的日志和事件消息取决于所选的资源类型。单击“在分析中查看”按钮以切换到 Kubernetes 事件日志:

  1. 在此视图中,您将能够查看和过滤 Pod 事件:

  1. 这次,单击 Pod 内的一个容器。Insights 将在右侧面板中显示容器信息和性能指标的详细视图:

  1. 在右侧窗格中,单击“在分析中查看”按钮以切换到“查看容器日志”:

  1. 在此视图中,您将能够查看和过滤容器日志:

现在您知道如何使用 Azure 监视来监视 AKS 集群的健康状况、性能指标和日志,以及在 AKS 集群上部署的资源。

另请参阅

使用 Prometheus 和 Grafana 监视 Kubernetes

在本节中,我们将在 Kubernetes 集群上部署 Prometheus 和 Grafana。您将学习如何使用 Prometheus 监视 Kubernetes 服务,并使用 Grafana 仪表板可视化集群和应用程序指标。

准备就绪

k8sdevopscookbook/src存储库克隆到您的工作站,以便在chapter8目录中使用清单文件:

$ git clone https://github.com/k8sdevopscookbook/src.git
$ cd /src/chapter8

确保您已准备好 Kubernetes 集群,并配置了kubectl以管理集群资源。

如何做…

本节进一步分为以下子节,以使流程更加简单:

  • 使用 Helm 图表部署 Prometheus Operator

  • 使用 Grafana 仪表板监视指标

  • 将 Grafana 仪表板添加到监视应用程序

使用 Helm 图表部署 Prometheus

Prometheus 是一个流行的开源解决方案,用于事件监视和警报。Prometheus 记录实时指标在时间序列数据库中,它是 Kubernetes 集群中最受欢迎的组件之一。几乎所有新的托管 Kubernetes 解决方案都会在集群部署的某种方式上安装 Prometheus。在本教程中,您将学习如何使用 Helm 图表在 Kubernetes 集群上部署 Prometheus:

  1. 更新 Helm 存储库。此命令将从公共图表存储库本地获取最新的图表:
$ helm repo update
  1. 使用helm install命令在monitoring命名空间中部署 Prometheus Operator。此命令将部署 Prometheus 以及 Alertmanager、Grafana、node-exporter 和 kube-state-metrics 附加组件;基本上,这是一组在 Kubernetes 集群上使用 Prometheus 所需的组件:
$ helm install stable/prometheus-operator --name prometheus \
 --namespace monitoring
  1. 验证在监视命名空间中部署的 Pod 的状态:
$ kubectl get pods -n monitoring
NAME READY STATUS RESTARTS AGE
alertmanager-prometheus-prometheus-oper-alertmanager-0 2/2 Running 0 88s
prometheus-grafana-6c6f7586b6-f9jbr 2/2 Running 0 98s
prometheus-kube-state-metrics-57d6c55b56-wf4mc 1/1 Running 0 98s
prometheus-prometheus-node-exporter-8drg7 1/1 Running 0 98s
prometheus-prometheus-node-exporter-lb7l5 1/1 Running 0 98s
prometheus-prometheus-node-exporter-vx7w2 1/1 Running 0 98s
prometheus-prometheus-oper-operator-86c9c956dd-88p82 2/2 Running 0 98s
prometheus-prometheus-prometheus-oper-prometheus-0 3/3 Running 1 78s

现在您已经安装了 Prometheus,并且具备在 Kubernetes 环境中操作所需的组件包。

使用 Grafana 仪表板监视指标

Grafana 是一个开源的分析和监控解决方案。默认情况下,Grafana 用于查询 Prometheus。按照以下说明来公开包含的 Grafana 服务实例并通过 Web 浏览器访问它:

  1. 获取monitoring命名空间中的服务列表:
$ kubectl get svc -n monitoring
NAME                                    TYPE      CLUSTER-IP   EXTERNAL-IP PORT(S)                    AGE
alertmanager-operated                   ClusterIP None         <none>      9093/TCP,9094/TCP,9094/UDP 33m
prometheus-grafana                      ClusterIP 10.0.1.132   <none>      80/TCP                     33m
prometheus-kube-state-metrics           ClusterIP 10.0.69.144  <none>      8080/TCP                   33m
prometheus-operated                     ClusterIP None         <none>      9090/TCP                   33m
prometheus-prometheus-node-exporter     ClusterIP 10.0.100.183 <none>      9100/TCP                   33m
prometheus-prometheus-oper-alertmanager ClusterIP 10.0.202.140 <none>      9093/TCP                   33m
prometheus-prometheus-oper-operator     ClusterIP 10.0.174.214 <none>      8080/TCP,443/TCP           33m
prometheus-prometheus-oper-prometheus   ClusterIP 10.0.243.177 <none>      9090/TCP                   33m
  1. 创建端口转发以使用kubectl port-forward命令访问 Grafana UI。此命令将本地端口8000转发到运行中的 Grafana pod 的端口3000
$ kubectl port-forward -n monitoring prometheus-grafana 8000:80

作为替代方案,您可以使用kubectl edit svc prometheus-grafana -n monitoring命令来修补prometheus-grafana服务,并将服务类型ClusterIP更改为LoadBalancer,以使用云负载均衡器在外部公开服务。

  1. 在 Web 浏览器中转到http://localhost:8000(或者如果使用 LoadBalancer,则是外部 IP)。您应该看到 Grafana 登录页面:

  1. 使用admin作为用户名和prom-operator作为密码登录:

  1. 单击仪表板左上角的主页按钮,列出可用的内置仪表板:

  1. 例如,从列表中选择Nodes仪表板以显示 Kubernetes 节点指标。在此视图中,您将看到节点资源的图形表示,包括 CPU、内存、磁盘和网络利用率:

现在您知道如何在 Grafana 中浏览仪表板。您可以使用 Grafana 来可视化 Kubernetes 指标和其他为 Prometheus 提供指标的工作负载指标,方法是按照下一个步骤。

添加 Grafana 仪表板以监视应用程序

Grafana 用于可视化存储在 Prometheus 上的指标。它提供具有模板变量的动态和可重用的仪表板。在本教程中,我们将学习如何从预构建的仪表板库中添加一个新的仪表板,以监视部署在 Kubernetes 上的应用程序:

  1. 每个应用程序都有不同的与应用程序的连续性相关的指标。首先,应用程序需要向 Prometheus 公开指标(有关编写 Prometheus 导出器的其他信息,请参阅“另请参阅”部分),并且必须将 Prometheus 添加为 Grafana 的数据源。对于此示例,我们将使用我们在第三章“构建 CI/CD 流水线”中部署的 Jenkins,在“在 Jenkins X 中设置 CI/CD 流水线”食谱中。

  2. 单击仪表板左上角的“主页”按钮,然后单击“在 Grafana.com 上查找仪表板”:

  1. 在搜索字段中,键入Jenkins。您将看到一些特定于 Jenkins 的仪表板:

  1. 单击“Jenkins:性能和健康概述”,并将 ID 复制到剪贴板。此时,仪表板 ID 306 是您添加此预构建仪表板到 Grafana 实例所需的全部内容:

  1. 如果未启用仪表板,请按照“概述”部分中的说明操作。

  2. 在 Grafana 界面中,单击导入仪表板。将仪表板 ID 306 粘贴到 Grafana.com 仪表板字段中。Grafana 将自动检测仪表板并显示详细信息:

  1. 选择 Prometheus 作为数据源名称,然后单击导入:

  1. 单击“主页”按钮以再次列出仪表板,您将在最近的仪表板列表中找到新的仪表板:

同样,您可以在 Grafana 上找到预构建的仪表板,用于我们在之前章节中使用的应用程序,例如云提供商服务监控(AWS、GCP、Azure、阿里巴巴)、GitLab CI、Minio、OpenEBS 以及许多其他 Kubernetes 集群指标。

另请参阅

使用 Sysdig 进行监控和性能分析

在这一部分,我们将使用 Sysdig Monitor 来监控和简化 Kubernetes 故障排除。您将学习如何安装 Sysdig Monitor 并扩展 Prometheus 功能,以满足更高级的企业需求。

准备工作

这里提到的所有操作都需要一个 Sysdig 账户。如果您还没有账户,请转到sysdig.com/sign-up/并创建一个试用或完整账户。

对于这个教程,我们需要准备好一个 Kubernetes 集群,并安装 Kubernetes 命令行工具kubectlhelm来管理集群资源。

如何做…

这一部分进一步分为以下子部分,以使流程更加简单:

  • 安装 Sysdig 代理

  • 分析应用程序性能

安装 Sysdig 代理

Sysdig Monitor 是一种用于监视和故障排除应用程序的工具,作为 Sysdig Cloud Native Visibility and Security Platform 的一部分。在这个教程中,您将学习如何部署 Sysdig Monitor 并利用 Prometheus 指标:

  1. 如果您还没有准备好您的 Sysdig Monitor 访问密钥,请转到app.sysdigcloud.com/#/settings/agentInstallation的账户设置,并检索您的访问密钥:

  1. 使用 Helm 图表安装 Sysdig 代理,将以下命令中的YourAccessKey替换为步骤 1中的 Sysdig Monitor 访问密钥。此命令将在集群中的所有 Kubernetes 工作节点上安装 Sysdig Monitor 和 Sysdig Secure 所需的 Sysdig 代理作为 DaemonSet:
$ helm install --name sysdig-agent --set sysdig.accessKey=YourAccessKey, \ sysdig.settings.tags='linux:ubuntu, dept:dev,local:ca' \
--set sysdig.settings.k8s_cluster_name='my_cluster' stable/sysdig
  1. 安装 Sysdig 代理后,节点将被 Sysdig Monitor 检测到。在这个视图中,所有节点都应该被检测到。在我们的示例中,我们检测到了四个节点。单击“转到下一步”按钮继续:

  1. Sysdig Monitor 与 AWS 深度集成。如果您的 Kubernetes 集群部署在 AWS 上,您可以选择输入 AWS 访问密钥 ID 和密钥来启用集成;否则,单击“跳过”按钮跳过 AWS 集成:

  1. 单击“让我们开始”来探索 Sysdig Monitor:

现在你知道如何部署 Sysdig Monitor 并利用 Prometheus 指标了。

分析应用程序性能

延迟、流量、错误和饱和度被谷歌 SRE 团队视为黄金信号。

让我们按照这些说明来学习如何在 Kubernetes 上的应用程序中导航 Sysdig Monitor 界面以找到黄金信号:

  1. 登录到您的 Sysdig 云原生可见性和安全平台仪表板,网址为app.sysdigcloud.com

  1. 资源会自动分组到主机和容器组中。单击组下拉菜单,然后选择部署和 pod:

  1. 单击仪表板和指标下拉菜单,然后在默认仪表板 | 应用程序下选择 HTTP 仪表板:

  1. Sysdig 可以识别和解码诸如 HTTP 之类的应用程序协议,并为您提供详细的指标。在这个视图中,您可以看到请求的数量,最常请求的 URL 或端点,最慢的 URL,以及整个基础架构的 HTTP 响应代码和请求类型:

  1. 作为性能故障排除的示例,将鼠标移动到最慢的 URL图表上,以识别问题和响应时间慢的应用程序。在我们的示例中,我们看到我们之前部署的 Kubecost Prometheus 服务器的响应时间慢,为 48 毫秒:

现在您已经对如何浏览 Sysdig 仪表板有了基本了解。Sysdig 提供了深度跟踪功能,可在监视多个容器时使用。我们将在第九章中了解更多关于 Sysdig 的安全功能和异常检测用法。您可以在另请参阅部分的Sysdig 示例链接中找到其他用例。

另请参阅

使用 Kubecost 管理资源成本

在本节中,我们将安装和配置开源 Kubecost 项目,该项目可以让您了解 Kubernetes 资源的成本相关可见性。您将学习如何监视资源成本以减少支出,并可能防止基于资源的停机。

准备就绪

此配方需要在 AWS 或 GCP 上部署的功能性 Kubernetes 集群。目前,不支持其他云提供商。

在执行以下配方中的命令之前,您需要安装kubectlhelm。您可以在第二章的在 Kubernetes 上操作应用程序中找到安装 Helm 的说明,使用 Helm 图表部署工作负载部分。

如何做…

本节进一步分为以下小节,以便简化流程:

  • 安装 Kubecost

  • 访问 Kubecost 仪表板

  • 监控 Kubernetes 资源成本分配

安装 Kubecost

Kubecost 创建了当前和历史 Kubernetes 支出的 Kubernetes 资源粒度模型。这些模型可用于在支持多个应用程序、团队和部门的 Kubernetes 环境中提供资源分配和成本透明度的监控。在本教程中,我们将看一下使 Kubecost 运行起来的基本步骤:

  1. 将 Kubecost 图表存储库添加到本地 Helm 图表存储库列表中:
$ helm repo add kubecost https://kubecost.github.io/cost-analyzer/
  1. 使用Helm install命令将 Kubecost 安装到kubecost命名空间中:
$ helm install kubecost/cost-analyzer --namespace kubecost --name kubecost --set kubecostToken="dGVzdEB0ZXN0LmNvbQ==xm343yadf98"
  1. 验证所有的 pod 都在运行。正如您所看到的,该项目还部署了自己的 Prometheus 和 Grafana 实例:
$ kubectl get pods -nkubecost
NAME READY STATUS RESTARTS AGE
cost-analyzer-checks-1571781600-6mhwh 0/1 Completed 0 7m1s
kubecost-cost-analyzer-54bc969689-8rznl 3/3 Running 0 9m7s
kubecost-grafana-844d4b9844-dkdvn 3/3 Running 0 9m7s
kubecost-prometheus-alertmanager-85bbbd6b7b-fpmqr 2/2 Running 0 9m7s
kubecost-prometheus-kube-state-metrics-857c5d4b4f-gxmgj 1/1 Running 0 9m7s
kubecost-prometheus-node-exporter-6bsp2 1/1 Running 0 9m7s
kubecost-prometheus-node-exporter-jtw2h 1/1 Running 0 9m7s
kubecost-prometheus-node-exporter-k69fh 1/1 Running 0 9m7s
kubecost-prometheus-pushgateway-7689458dc9-rx5jj 1/1 Running 0 9m7s
kubecost-prometheus-server-7b8b759d74-vww8c 2/2 Running 0 9m7s

如果您有现有的 Prometheus 部署,node-exporter pod 可能会卡在 Pending 模式。在这种情况下,您需要使用不同的端口来部署 Kubecost;否则,pod 将无法获取所请求的 pod 端口。

现在您已经安装了 Kubecost 成本分析器,并且具有在 Kubernetes 环境中操作所需的一系列组件。

访问 Kubecost 仪表板

让我们按照这些说明来访问 Kubecost 仪表板,在那里您可以实时监视您的 Kubernetes 资源及其成本:

  1. 获取kubecost命名空间中服务的列表:
$ kubectl get svc -nkubecost
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubecost-cost-analyzer ClusterIP 100.65.53.41 <none> 9001/TCP,9003/TCP,9090/TCP 13m
kubecost-grafana ClusterIP 100.69.52.23 <none> 80/TCP 13m
kubecost-prometheus-alertmanager ClusterIP 100.71.217.248 <none> 80/TCP 13m
kubecost-prometheus-kube-state-metrics ClusterIP None <none> 80/TCP 13m
kubecost-prometheus-node-exporter ClusterIP None <none> 9100/TCP 13m
kubecost-prometheus-pushgateway ClusterIP 100.69.137.163 <none> 9091/TCP 13m
kubecost-prometheus-server ClusterIP 100.64.7.82 <none> 80/TCP 13m
  1. 创建一个端口转发以使用kubectl port-forward命令访问 Kubecost UI。该命令将本地端口9090转发到 Kubecost 成本分析器 pod:
$ kubectl port-forward --namespace kubecost deployment/kubecost-cost-analyzer 9090

作为替代方案,您可以使用kubectl edit svc kubecost-cost-analyzer -nkubecost命令对kubecost-cost-analyzer服务进行修补,并将服务类型ClusterIP更改为LoadBalancer,以使用云负载均衡器在外部公开服务。

  1. 在您的 Web 浏览器中打开地址http://localhost:9090(或者如果使用 LoadBalancer,则是外部 IP)。您应该看到 Kubecost 登录页面:

  1. 通过将额外的 Kubecost 端点添加到一个中并用于监视单个仪表板上的多个集群来扩展仪表板。如果您有多个集群,请单击添加新集群图标,并添加来自其他集群的端点 URL:

监控 Kubernetes 资源成本分配

让我们按照这些说明来学习如何使用 Kubecost 监视与 Kubernetes 相关的云支出,并找到可能的节省建议:

  1. 通过按照前面的步骤“访问 Kubecost 仪表板”访问您的 Kubecost 仪表板。在仪表板上点击您的集群名称以访问详细摘要。此视图将显示月度成本和闲置资源的集群效率:

  1. 点击“实时资产”按钮。此视图显示与当前云提供商相关的实时成本。在我们的示例中,有一个主节点,三个使用kops在 AWS 集群上部署的工作节点 Kubernetes 集群,自创建以来每个节点的账单大约为 60 美元:

  1. 点击“分配”菜单。此视图显示当前命名空间中的累积成本。您可以应用范围过滤器,以获取所选命名空间中资源的每日、每周、每月或自定义范围成本:

  1. 点击“节省”菜单。此菜单中的信息非常重要,并指向您可以采取的可能的优化步骤。例如,以下视图显示我们有两个利用率不足的节点(利用率低于 60%),如果我们缩减集群,可以节省成本。在这种情况下,我们可以排空节点并缩减集群。点击每个节省类别,了解如何采取行动以实现此处显示的节省率:

  1. 点击“健康”菜单。此视图显示可靠性评估和集群健康风险:

  1. 禁用“显示全部”选项以列出需要您关注的问题。在我们的示例中,我们看到一个高优先级指向 Crash looping pods。您可以按照本章节中“检查容器”部分的说明进一步识别问题:

  1. 点击“通知”菜单。从此菜单,您可以指定如何处理通知。如果您有 Slack 频道,可以在此处点击“添加”按钮将通知转发到该频道;否则,电子邮件通知可作为选项:

现在您已经了解如何监控项目成本,并更好地了解了如何采取行动来增加 DevOps 环境的投资回报。

另请参阅

第九章:保护应用程序和集群

00000000000000 在本章中,我们将讨论在从测试到生产的过程中,减少攻击面和保护 Kubernetes 集群的基本步骤。我们将讨论安全审计,将 DevSecOps 构建到 CI/CD 流水线中,检测性能分析的指标,以及如何安全地管理秘密和凭据。

在本章中,我们将介绍以下配方:

  • 使用 RBAC 加固集群安全

  • 配置 Pod 安全策略

  • 使用 Kubernetes CIS 基准进行安全审计

  • 将 DevSecOps 构建到流水线中,使用 Aqua Security

  • 使用 Falco 监视可疑的应用程序活动

  • 使用 HashiCorp Vault 安全保护凭据

技术要求

本章中的配方要求您通过遵循第一章中描述的建议方法之一部署了功能齐全的 Kubernetes 集群,构建生产就绪的 Kubernetes 集群

Kubernetes 命令行工具kubectl将用于本章中其余的配方,因为它是针对 Kubernetes 集群运行命令的主要命令行界面。我们还将使用helm,在那里 Helm 图表可用于部署解决方案。

使用 RBAC 加固集群安全

在诸如 Kubernetes 之类的复杂系统中,授权机制用于设置谁被允许对集群资源进行何种更改并操纵它们。基于角色的访问控制RBAC)是一种高度集成到 Kubernetes 中的机制,它授予用户和应用程序对 Kubernetes API 的细粒度访问权限。

作为良好的实践,您应该与NodeRestriction准入插件一起使用 Node 和 RBAC 授权器。

在本节中,我们将介绍如何启用 RBAC 并创建角色和角色绑定,以授予应用程序和用户对集群资源的访问权限。

准备工作

确保您已准备好启用 RBAC 的 Kubernetes 集群(自 Kubernetes 1.6 以来,默认情况下已启用 RBAC),并且已配置kubectlhelm,以便您可以管理集群资源。在尝试为用户创建密钥之前,还需要确保您拥有openssl工具来创建私钥。

k8sdevopscookbook/src存储库克隆到您的工作站,以便在chapter9目录中使用清单文件,如下所示:

$ git clone https://github.com/k8sdevopscookbook/src.git
$ cd src/chapter9/rbac

RBAC 从 Kubernetes 1.6 版本开始默认启用。如果由于任何原因禁用了 RBAC,请使用--authorization-mode=RBAC启动 API 服务器以启用 RBAC。

如何做…

本节进一步分为以下子节,以使此过程更容易:

  • 查看默认角色

  • 创建用户帐户

  • 创建角色和角色绑定

  • 测试 RBAC 规则

查看默认角色

RBAC 是 Kubernetes 集群的核心组件,允许我们创建和授予对象角色,并控制对集群内资源的访问。这个步骤将帮助您了解角色和角色绑定的内容。

让我们执行以下步骤来查看我们集群中的默认角色和角色绑定:

  1. 使用以下命令查看默认的集群角色。您将看到一个长长的混合列表,其中包括system:system:controller:和一些其他带有前缀的角色。system:*角色由基础设施使用,system:controller角色由 Kubernetes 控制器管理器使用,它是一个监视集群共享状态的控制循环。一般来说,当您需要解决权限问题时,了解它们都是很好的,但我们不会经常使用它们:
$ kubectl get clusterroles
$ kubectl get clusterrolebindings
  1. 查看由 Kubernetes 拥有的系统角色之一,以了解它们的目的和限制。在下面的示例中,我们正在查看system:node,它定义了 kubelet 的权限。在规则的输出中,apiGroups:表示核心 API 组,resources表示 Kubernetes 资源类型,verbs表示角色上允许的 API 操作:
$ kubectl get clusterroles system:node -oyaml
  1. 让我们查看默认的用户角色,因为它们是我们更感兴趣的角色。没有system:前缀的角色是面向用户的角色。以下命令将仅列出非system:前缀的角色。通过 RoleBindings 在特定命名空间中授予的主要角色是admineditview角色:
$ kubectl get clusterroles | grep -v '^system'
NAME AGE
admin 8d #gives read-write access
 to all resources
cluster-admin 8d #super-user, gives read-write access
 to all resources
edit 8d #allows create/update/delete on resources except RBAC permissions
kops:dns-controller 8d
kube-dns-autoscaler 8d
view 8d #read-only access to resources
  1. 现在,使用以下命令查看默认的集群绑定,即cluster-admin。您将看到此绑定使用cluster-admin角色为system:masters组提供了集群范围的超级用户权限:
$ kubectl get clusterrolebindings/cluster-admin -o yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
...
roleRef:
 apiGroup: rbac.authorization.k8s.io
 kind: ClusterRole
 name: cluster-admin
subjects:
- apiGroup: rbac.authorization.k8s.io
 kind: Group
 name: system:masters

自 Kubernetes 1.6 版本发布以来,默认情况下启用了 RBAC,并且新用户可以创建并在管理员用户将权限分配给特定资源之前不具备任何权限。现在,您已经了解了可用的默认角色。

在接下来的教程中,您将学习如何创建新的角色和角色绑定,并授予帐户所需的权限。

创建用户帐户

正如 Kubernetes 文档中所解释的,Kubernetes 没有用于表示普通用户帐户的对象。因此,它们需要在外部进行管理(查看参见部分的Kubernetes 身份验证文档,以获取更多详细信息)。本教程将向您展示如何使用私钥创建和管理用户帐户。

让我们执行以下步骤来创建一个用户帐户:

  1. 为示例用户创建一个私钥。在我们的示例中,密钥文件是user3445.key
$ openssl genrsa -out user3445.key 2048
  1. 创建一个名为user3445.csr证书签名请求CSR),使用我们在步骤 1中创建的私钥。在-subj参数中设置用户名(/CN)和组名(/O)。在以下示例中,用户名是john.geek,而组名是development
$ openssl req -new -key user3445.key \
-out user3445.csr \
-subj "/CN=john.geek/O=development"
  1. 要使用内置签名者,您需要定位集群的集群签名证书。默认情况下,ca.crtca.key文件应位于/etc/kubernetes/pki/目录中。如果您正在使用 kops 进行部署,您可以从s3://$BUCKET_NAME/$KOPS_CLUSTER_NAME/pki/private/ca/*.keys3://$BUCKET_NAME/$KOPS_CLUSTER_NAME/pki/issued/ca/*.crt下载集群签名密钥。一旦您找到了密钥,将以下代码中提到的CERT_LOCATION更改为文件的当前位置,并生成最终签名证书:
$ openssl x509 -req -in user3445.csr \
-CA CERT_LOCATION/ca.crt \
-CAkey CERT_LOCATION/ca.key \
-CAcreateserial -out user3445.crt \
-days 500
  1. 如果所有文件都已找到,步骤 3中的命令应返回类似以下的输出:
Signature ok
subject=CN = john.geek, O = development
Getting CA Private Key

在我们继续之前,请确保将签名密钥存储在安全的目录中。作为行业最佳实践,建议使用秘密引擎或 Vault 存储。您将在本章后面的使用 HashiCorp Vault 保护凭据中了解有关 Vault 存储的更多信息。

  1. 使用新用户凭据创建一个新的上下文:
$ kubectl config set-credentials user3445 --client-certificate=user3445.crt --client-key=user3445.key
$ kubectl config set-context user3445-context --cluster=local --namespace=secureapp --user=user3445
  1. 使用以下命令列出现有上下文。您将看到已创建新的user3445-context
$ kubectl config get-contexts
CURRENT NAME                    CLUSTER AUTHINFO NAMESPACE
*       service-account-context local   kubecfg
 user3445-context        local   user3445 secureapp
  1. 现在,尝试使用新用户上下文列出 pod。由于新用户没有任何角色,并且新用户默认情况下没有分配任何角色,因此您将收到访问被拒绝的错误:
$ kubectl --context=user3445-context get pods
Error from server (Forbidden): pods is forbidden: User "john.geek" cannot list resource "pods" in API group "" in the namespace "secureapps"
  1. 可选地,您可以使用openssl base64 -in <infile> -out <outfile>命令对所有三个文件(user3445.crtuser3445.csruser3445.key)进行base64编码,并将填充的config-user3445.yml文件分发给您的开发人员。示例文件可以在本书的 GitHub 存储库的src/chapter9/rbac目录中找到。有许多方法可以分发用户凭据。使用文本编辑器查看示例:
$ cat config-user3445.yaml

通过这样,您已经学会了如何创建新用户。接下来,您将创建角色并将其分配给用户。

创建角色和 RoleBindings

角色和 RoleBindings 始终在定义的命名空间中使用,这意味着权限只能授予与角色和 RoleBindings 本身相同命名空间中的资源,而不是用于授予集群范围资源(如节点)权限的 ClusterRoles 和 ClusterRoleBindings。

让我们执行以下步骤在我们的集群中创建一个示例角色和 RoleBinding:

  1. 首先,创建一个我们将创建角色和 RoleBinding 的命名空间。在我们的示例中,命名空间是secureapp
$ kubectl create ns secureapp
  1. 使用以下规则创建一个角色。该角色基本上允许在我们在步骤 1.中创建的secureapp命名空间中对部署、副本集和 Pod 执行所有操作。请注意,授予的任何权限都只是增量的,没有拒绝规则:
$ cat <<EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
 namespace: secureapp
 name: deployer
rules:
- apiGroups: ["", "extensions", "apps"]
 resources: ["deployments", "replicasets", "pods"]
 verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
EOF
  1. 使用deployer角色为用户名john.geeksecureapp命名空间中创建一个 RoleBinding。我们这样做是因为 RoleBinding 只能引用同一命名空间中存在的角色:
$ cat <<EOF | kubectl apply -f -
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
 name: deployer-binding
 namespace: secureapp
subjects:
- kind: User
 name: john.geek
 apiGroup: ""
roleRef:
 kind: Role
 name: deployer
 apiGroup: ""
EOF

通过这样,您已经学会了如何创建一个新的角色,并使用 RoleBindings 授予用户权限。

测试 RBAC 规则

让我们执行以下步骤来测试我们之前创建的角色和 RoleBinding:

  1. 在用户有权限访问的secureapp命名空间中部署一个测试 Pod:
$ cat <<EOF | kubectl --context=user3445-context apply -f -
apiVersion: v1
kind: Pod
metadata:
 name: busybox
 namespace: secureapp
spec:
 containers:
 - image: busybox
 command:
 - sleep
 - "3600"
 imagePullPolicy: IfNotPresent
 name: busybox
 restartPolicy: Always
EOF

列出新用户上下文中的 Pod。在创建用户帐户中失败的相同命令在步骤 7中现在应该能够成功执行:

$ kubectl --context=user3445-context get pods 
NAME    READY STATUS  RESTARTS AGE
busybox 1/1   Running 1        2m

如果您尝试在不同的命名空间中创建相同的 Pod,您将看到该命令将无法执行。

工作原理...

这个示例向您展示了如何在 Kubernetes 中创建新用户,并快速创建角色和 RoleBindings 以授予用户帐户对 Kubernetes 的权限。

Kubernetes 集群有两种类型的用户:

  • 用户帐户:用户帐户是外部管理的普通用户。

  • 服务账户:服务账户是与 Kubernetes 服务相关联并由 Kubernetes API 管理其自己资源的用户。

您可以通过查看另请参阅部分中的管理服务账户链接来了解更多关于服务账户的信息。

创建角色和 RoleBindings配方中,在步骤 1中,我们创建了一个名为deployer的角色。然后,在步骤 2中,我们将与 deployer 角色关联的规则授予了用户账户john.geek

RBAC 使用rbac.authorization.k8s.io API 来做出授权决策。这允许管理员使用 Kubernetes API 动态配置策略。如果您想要使用现有的角色并给予某人集群范围的超级用户权限,您可以使用cluster-admin ClusterRole 和 ClusterRoleBinding。ClusterRoles 没有命名空间限制,并且可以在任何命名空间中执行具有授予的权限的命令。总的来说,在分配cluster-admin ClusterRole 给用户时应该小心。ClusterRoles 也可以像 Roles 一样限制到命名空间,如果它们与 RoleBindings 一起使用来授予权限。

另请参阅

配置 Pod 安全策略

Pod 安全策略(PSP)在 Kubernetes 集群上用于启用对 Pod 创建的细粒度授权,并控制 Pod 的安全方面。PodSecurityPolicy 对象定义了接受 Pod 进入集群并按预期运行的条件。

在本节中,我们将介绍在 Kubernetes 上重新创建和配置 PSP。

准备工作

确保您已准备好启用 RBAC 的 Kubernetes 集群(自 Kubernetes 1.6 以来,RBAC 默认已启用),并配置kubectlhelm来管理集群资源。

k8sdevopscookbook/src存储库克隆到您的工作站,以便使用chapter9目录中的清单文件,如下所示:

$ git clone https://github.com/k8sdevopscookbook/src.git
$ cd src/chapter9/psp

通过运行kubectl get psp命令来验证集群是否需要启用 PodSecurityPolicy。如果收到消息说明服务器没有资源类型"podSecurityPolicies"。,则需要在集群上启用 PSP。

操作步骤:

本节进一步分为以下子节,以使此过程更加简单:

  • 在 EKS 上启用 PSP

  • 在 GKE 上启用 PSP

  • 在 AKS 上启用 PSP

  • 创建受限制的 PSP

在 EKS 上启用 PSP

作为最佳实践,在创建自己的策略之前,不应该启用 PSP。本文将带您了解如何在 Amazon EKS 上启用 PSP 以及如何审查默认策略。

让我们执行以下步骤:

  1. 部署 Kubernetes 版本 1.13 或更高版本。PSP 将默认启用。默认配置带有一个名为eks.privileged的非破坏性策略,没有限制。使用以下命令查看默认策略:
$ kubectl get psp eks.privileged
NAME           PRIV CAPS SELINUX  RUNASUSER FSGROUP  SUPGROUP READONLYROOTFS VOLUMES
eks.privileged true *    RunAsAny RunAsAny  RunAsAny RunAsAny false          *
  1. 描述策略以查看其完整详情,如下所示:
$ kubectl describe psp eks.privileged
  1. 要审查、恢复或删除默认 PSP,请使用示例存储库中src/chapter9/psp目录中名为eks-privileged-psp.yaml的 YAML 清单。

在 GKE 上启用 PSP

作为最佳实践,在创建自己的策略之前,不应该启用 PSP。本文将带您了解如何在 Google Kubernetes Engine(GKE)上启用 PSP 以及如何审查默认策略。

让我们执行以下步骤:

  1. 您可以通过运行以下命令在部署的集群上启用 PSP,按照第一章中的说明,构建生产就绪的 Kubernetes 集群,在在 GKE 上配置托管的 Kubernetes 集群中。将k8s-devops-cookbook-1替换为您自己的集群名称:
$ gcloud beta container clusters update k8s-devops-cookbook-1 --enable-pod-security-policy
  1. 默认配置带有一个名为gce.privileged的非破坏性策略,没有限制,还有其他几个策略。使用以下命令查看默认策略:
$ kubectl get psp
NAME                         PRIV  CAPS SELINUX  RUNASUSER FSGROUP  SUPGROUP READONLYROOTFS VOLUMES
gce.event-exporter           false      RunAsAny RunAsAny  RunAsAny RunAsAny false          hostPath,secret
gce.fluentd-gcp              false      RunAsAny RunAsAny  RunAsAny RunAsAny false          configMap,hostPath,secret
gce.persistent-volume-binder false      RunAsAny RunAsAny  RunAsAny RunAsAny false          nfs,secret,projected
gce.privileged               true  *    RunAsAny RunAsAny  RunAsAny RunAsAny false          *
gce.unprivileged-addon       false SETPCAP,MKNOD,AUDIT_WRITE,CHOWN,NET_RAW,DAC_OVERRIDE,FOWNER,FSETID,KILL,SETGID,SETUID,NET_BIND_SERVICE,SYS_CHROOT,SETFCAP RunAsAny RunAsAny RunAsAny RunAsAny false emptyDir,configMap,secret,projected
  1. 描述策略以查看其完整详情,如下所示:
$ kubectl describe psp gce.privileged
  1. 要查看、恢复或删除默认 PSP,请使用示例存储库中的 YAML 清单,在src/chapter9/psp中命名为gce-privileged-psp.yaml

在 AKS 上启用 PodSecurityPolicy

作为最佳实践,在创建自己的策略之前,不应启用 PodSecurityPolicy。本教程将带您了解如何在Azure Kubernetes ServiceAKS)上启用 PSP 以及如何查看默认策略。

让我们执行以下步骤:

  1. 您可以按照第一章 构建生产就绪的 Kubernetes 集群中给出的说明,在在 AKS 上配置托管的 Kubernetes 集群教程中运行以下命令来在部署的集群上启用 PSP。将k8sdevopscookbook替换为您自己的资源组,将AKSCluster替换为您的集群名称:
$ az aks create --resource-group k8sdevopscookbook \
--name AKSCluster \
--enable-pod-security-policy
  1. 默认配置带有一个名为privileged的非破坏性策略,没有限制。使用以下命令查看默认策略:
$ kubectl get psp
NAME PRIV CAPS SELINUX RUNASUSER FSGROUP SUPGROUP READONLYROOTFS VOLUMES
privileged true * RunAsAny RunAsAny RunAsAny RunAsAny false * configMap,emptyDir,projected,secret,downwardAPI,persistentVolumeClaim
  1. 描述策略以查看其完整详情,如下所示:
$ kubectl describe psp privileged
  1. 要查看、恢复或删除默认 PSP,请使用示例存储库中的 YAML 清单,在src/chapter9/psp中命名为aks-privileged-psp.yaml

创建受限的 PSPs

作为安全最佳实践,建议限制容器在 Pod 中以 root 用户特权运行,以限制任何可能的风险。在特权模式下运行时,容器内运行的进程具有与容器外进程相同的特权和访问权限,这可能会增加攻击者访问一些管理能力的风险。

让我们执行以下步骤来创建一个受限的 PodSecurityPolicy:

  1. 部署一个新的受限PodSecurityPolicy
$ cat <<EOF | kubectl apply -f -
apiVersion: extensions/v1beta1
kind: PodSecurityPolicy
metadata:
 name: restricted-psp
spec:
 privileged: false
 runAsUser:
 rule: MustRunAsNonRoot
 seLinux:
 rule: RunAsAny
 fsGroup:
 rule: RunAsAny
 supplementalGroups:
 rule: RunAsAny
 volumes:
 - '*'
EOF
  1. 确认策略已创建。您会注意到RUNASUSER列显示MustRunAsNonRoot,这表示不允许使用 root 权限:
$ kubectl get psp restricted-psp
NAME           PRIV  CAPS     SELINUX  RUNASUSER        FSGROUP   SUPGROUP READONLYROOTFS VOLUMES
restricted-psp false          RunAsAny MustRunAsNonRoot RunAsAny  RunAsAny false          *
  1. 通过运行需要 root 访问权限的 pod 来验证 PSP。部署将失败,并显示一条消息,指出container has runAsNonRoot and image will run as root,如下代码所示:
$ kubectl run --image=mariadb:10.4.8 mariadb --port=3306 --env="MYSQL_ROOT_PASSWORD=my-secret-pw"
$ kubectl get pods
NAME                     READY STATUS                                                RESTARTS AGE
mariadb-5584b4f9d8-q6whd 0/1   container has runAsNonRoot and image will run as root 0        46s

通过这样,您已经学会了如何创建一个受限的 PodSecurityPolicy。

还有更多...

此部分进一步分为以下子部分,以使此过程更加简单:

  • 限制 Pod 访问特定卷类型

  • 使用 Kubernetes PSPs 顾问

限制 Pod 访问特定卷类型

作为 PodSecurityPolicy 规则的一部分,您可能希望限制使用特定类型的卷。在本教程中,您将学习如何限制容器访问卷类型。

让我们执行以下步骤来创建 PodSecurityPolicy:

  1. 创建新的受限PodSecurityPolicy。此策略仅限制卷类型为nfs
$ cat <<EOF | kubectl apply -f -
kind: PodSecurityPolicy
metadata:
 name: restricted-vol-psp
spec:
 privileged: false
 runAsUser:
 rule: RunAsAny
 seLinux:
 rule: RunAsAny
 fsGroup:
 rule: RunAsAny
 supplementalGroups:
 rule: RunAsAny
 volumes:
 - 'nfs'
EOF
  1. 通过部署需要持久存储的应用程序来验证策略。在这里,我们将使用前几章的 MinIO 示例。部署应该失败,并显示消息“不允许使用 persistentVolumeClaim 卷”。
$ kubectl create -f \
https://raw.githubusercontent.com/k8sdevopscookbook/src/master/chapter6/minio/minio.yaml
  1. 删除 PSP 和部署:
$ kubectl delete psp restricted-vol-psp
$ kubectl delete -f \
https://raw.githubusercontent.com/k8sdevopscookbook/src/master/chapter6/minio/minio.yaml
  1. 新 PSP 允许的卷集包括configMapdownwardAPIemptyDirpersistentVolumeClaimsecretprojected。您可以通过转到支持的卷类型链接在另请参阅部分找到卷类型的完整列表。使用以下内容创建新的受限 PodSecurityPolicy。此策略仅限制卷类型为persistentVolumeClaim
$ cat <<EOF | kubectl apply -f -
kind: PodSecurityPolicy
metadata:
 name: permit-pvc-psp
spec:
 privileged: false
 runAsUser:
 rule: RunAsAny
 seLinux:
 rule: RunAsAny
 fsGroup:
 rule: RunAsAny
 supplementalGroups:
 rule: RunAsAny
 volumes:
 - 'persistentVolumeClaim'
EOF
  1. 重复步骤 2以部署应用程序。这次,将允许创建persistentVolumeClaim,并将创建 Pod 请求的 PVC。

使用 Kubernetes PodSecurityPolicy 顾问

Kubernetes PodSecurityPolicy Advisor 是 Sysdig 的一个简单工具,用于强制执行 Kubernetes 中的最佳安全实践。kube-psp-advisor扫描 Kubernetes 资源的现有安全上下文,并为集群中的资源生成 PSP,以删除不必要的特权。

让我们执行以下步骤在我们的集群上启用kube-psp-advisor

  1. 克隆存储库并使用以下命令构建项目:
$ git clone https://github.com/sysdiglabs/kube-psp-advisor
$ cd kube-psp-advisor && make build
  1. 通过执行二进制文件运行扫描过程。如果要将扫描限制为命名空间,可以通过向命令添加--namespace=参数来指定,类似于以下代码中所示。如果不这样做,它将扫描整个集群。这样做后,将生成一个PodSecurityPolicy
$ ./kube-psp-advisor --namespace=secureapp > psp-advisor.yaml
  1. 审查psp-advisor.yaml文件的内容,并应用生成的 PSP:
$ cat psp-advisor.yaml
$ kubectl apply -f psp-advisor.yaml

通过这样,您已经学会了如何以更简单的方式生成 PSP,以减少可能增加攻击面的不必要权限。

另请参阅

使用 Kubernetes CIS 基准进行安全审计

Kubernetes CIS 基准是业界专家接受的安全配置最佳实践。CIS 基准指南可以从互联网安全中心CIS)网站www.cisecurity.org/下载为 PDF 文件。kube-bench是一个自动化记录检查的应用程序。

在本节中,我们将介绍安装和使用开源的kube-bench工具,以运行 Kubernetes CIS 基准,对 Kubernetes 集群进行安全审计。

做好准备

对于这个配方,我们需要准备好一个 Kubernetes 集群,并安装 Kubernetes 命令行工具kubectl

k8sdevopscookbook/src存储库克隆到您的工作站,以使用chapter9目录中的清单文件,如下所示:

$ git clone https://github.com/k8sdevopscookbook/src.git
$ cd src/chapter9/cis

一些测试针对 Kubernetes 节点,只能在完全自我管理的集群上执行,您可以控制主节点。因此,托管集群(如 EKS、GKE、AKS 等)将无法执行所有测试,并需要不同的作业描述或参数来执行测试。在必要时会提到这些。

如何操作…

本节进一步分为以下子节,以使此过程更加简单:

  • 在 Kubernetes 上运行 kube-bench

  • 在托管的 Kubernetes 服务上运行 kube-bench

  • 在 OpenShift 上运行 kube-bench

  • 运行 kube-hunter

在 Kubernetes 上运行 kube-bench

CIS 基准对主节点和工作节点都有测试。因此,只有在您可以控制主节点的自我管理集群上才能完成测试的全部范围。在这个配方中,您将学习如何直接在主节点和工作节点上运行 kube-bench。

让我们执行以下步骤来运行 CIS 推荐的测试:

  1. 下载并安装kube-bench命令行界面到您的一个主节点和一个工作节点:
$ curl --silent --location "https://github.com/aquasecurity/kube-bench/releases/download/v0.1.0/kube-bench_0.1.0_linux_amd64.tar.gz" | tar xz -C /tmp
$ sudo mv /tmp/kube-bench /usr/local/bin
  1. SSH 登录到您的 Kubernetes 主节点并运行以下命令。它将快速返回测试结果,并附有解释和建议在之后运行的其他手动测试的列表。在这里,您可以看到31个检查通过,36个测试失败:
$ kube-bench master
...
== Summary ==
31 checks PASS
36 checks FAIL
24 checks WARN
1 checks INFO
  1. 要保存结果,请使用以下命令。测试完成后,将kube-bench-master.txt文件移动到本地主机进行进一步审查:
$ kube-bench master > kube-bench-master.txt
  1. 审查kube-bench-master.txt文件的内容。您将看到与以下类似的内容,这是来自 Kubernetes 指南的 CIS 基准检查的状态:
[INFO] 1 Master Node Security Configuration
[INFO] 1.1 API Server
[PASS] 1.1.1 Ensure that the --anonymous-auth argument is set to false (Not Scored)
[FAIL] 1.1.2 Ensure that the --basic-auth-file argument is not set (Scored)
[PASS] 1.1.3 Ensure that the --insecure-allow-any-token argument is not set (Not Scored)
[PASS] 1.1.4 Ensure that the --kubelet-https argument is set to true (Scored)
[FAIL] 1.1.5 Ensure that the --insecure-bind-address argument is not set (Scored)
[FAIL] 1.1.6 Ensure that the --insecure-port argument is set to 0 (Scored)
[PASS] 1.1.7 Ensure that the --secure-port argument is not set to 0 (Scored)
[FAIL] 1.1.8 Ensure that the --profiling argument is set to false (Scored)
[FAIL] 1.1.9 Ensure that the --repair-malformed-updates argument is set to false (Scored)
[PASS] 1.1.10 Ensure that the admission control plugin AlwaysAdmit is not set (Scored)
...

测试被分成了几个类别,这些类别是根据 CIS 基准指南中建议的,比如 API 服务器、调度器、控制器管理器、配置管理器、etcd、一般安全原语和 PodSecurityPolicies。

  1. 按照报告中修复部分建议的方法来修复失败的问题,并重新运行测试以确认已进行修正。您可以在先前报告中建议的一些修复措施如下:
== Remediations ==
1.1.2 Follow the documentation and configure alternate mechanisms for authentication. Then,
edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.manifest
on the master node and remove the --basic-auth-file=<filename>
parameter.

1.1.5 Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.manife$
on the master node and remove the --insecure-bind-address
parameter.

1.1.6 Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.manife$
apiserver.yaml on the master node and set the below parameter.
--insecure-port=0

1.1.8 Edit the API server pod specification file /etc/kubernetes/manifests/kube-apiserver.manife$
on the master node and set the below parameter.
--profiling=false

1.2.1 Edit the Scheduler pod specification file /etc/kubernetes/manifests/kube-scheduler.manifest
file on the master node and set the below parameter.
--profiling=false
...
  1. 让我们从先前的列表中选取一个问题。1.2.1建议我们禁用分析 API 端点。原因是通过分析数据可以揭示高度敏感的系统信息,并且通过对集群进行分析可能会产生大量数据和负载,从而使该功能使集群无法服务(拒绝服务攻击)。编辑kube-scheduler.manifest文件,并在kube-schedule命令之后添加--profiling=false,如下所示:
...
spec:
 containers:
 - command:
 - /bin/sh
 - -c
 - mkfifo /tmp/pipe; (tee -a /var/log/kube-scheduler.log < /tmp/pipe & ) ; exec
 /usr/local/bin/kube-scheduler --profiling=False --kubeconfig=/var/lib/kube-scheduler/kubeconfig
 --leader-elect=true --v=2 > /tmp/pipe 2>&1
...
  1. 再次运行测试并确认1.2.1上的问题已经得到纠正。在这里,您可以看到通过的测试数量从31增加到32。还有一个检查已经通过:
$ kube-bench master
...
== Summary ==
32 checks PASS
35 checks FAIL
24 checks WARN
1 checks INFO
  1. 在工作节点上运行以下命令进行测试:
$ kube-bench node
...
== Summary ==
9 checks PASS
12 checks FAIL
2 checks WARN
1 checks INFO
  1. 要保存结果,请使用以下命令。测试完成后,将kube-bench-worker.txt文件移动到本地主机进行进一步审查:
$ kube-bench node > kube-bench-worker.txt
  1. 审查kube-bench-worker.txt文件的内容。您将看到与以下类似的内容,这是来自 Kubernetes 指南的 CIS 基准检查的状态:
[INFO] 2 Worker Node Security Configuration
[INFO] 2.1 Kubelet
[PASS] 2.1.1 Ensure that the --anonymous-auth argument is set to false (Scored)
[FAIL] 2.1.2 Ensure that the --authorization-mode argument is not set to AlwaysAllow (Scored)
[PASS] 2.1.3 Ensure that the --client-ca-file argument is set as appropriate (Scored)
...

同样,按照所有的修复措施,直到您清除了主节点和工作节点上的所有失败测试。

在托管的 Kubernetes 服务上运行 kube-bench

托管的 Kubernetes 服务(如 EKS、GKE、AKS 等)与您无法在主节点上运行检查的区别在于,您要么只能遵循上一个教程中的工作节点检查,要么运行一个 Kubernetes 作业来验证您的环境。在本教程中,您将学习如何在托管的 Kubernetes 服务节点上运行 kube-bench,以及在您没有直接 SSH 访问节点的情况下运行 kube-bench 的情况。

让我们执行以下步骤来运行 CIS 推荐的测试:

  1. 对于本教程,我们将使用 EKS 作为我们的 Kubernetes 服务,但如果您愿意,您可以将 Kubernetes 和容器注册服务更改为其他云提供商。首先,创建一个 ECR 存储库,我们将在其中托管 kube-bench 镜像:
$ aws ecr create-repository --repository-name k8sdevopscookbook/kube-bench --image-tag-mutability MUTABLE
  1. kube-bench存储库克隆到本地主机:
$ git clone https://github.com/aquasecurity/kube-bench.git
  1. 登录到您的弹性容器注册表ECR)帐户。在将图像推送到注册表之前,您需要进行身份验证:
$ $(aws ecr get-login --no-include-email --region us-west-2)
  1. 通过运行以下命令构建 kube-bench 镜像:
$ docker build -t k8sdevopscookbook/kube-bench 
  1. 用您的 AWS 帐户号替换<AWS_ACCT_NUMBER>并执行它以将其推送到 ECR 存储库。第一个命令将创建一个标签,而第二个命令将推送图像:
$ docker tag k8sdevopscookbook/kube-bench:latest <AWS_ACCT_NUMBER>.dkr.ecr.us-west-2.amazonaws.com/k8s/kube-bench:latest
# docker push <AWS_ACCT_NUMBER>.dkr.ecr.us-west-2.amazonaws.com/k8s/kube-bench:latest
  1. 编辑job-eks.yaml文件,并将第 12 行的图像名称替换为您在步骤 5中推送的图像的 URI。它应该看起来类似于以下内容,除了您应该在图像 URI 中使用您的 AWS 帐户号:
apiVersion: batch/v1
kind: Job
metadata:
 name: kube-bench
spec:
 template:
 spec:
 hostPID: true
 containers:
 - name: kube-bench
 # Push the image to your ECR and then refer to it here
 image: 316621595343.dkr.ecr.us-west-2.amazonaws.com/k8sdevopscookbook/kube-bench:latest
...
  1. 使用以下命令运行作业。它将很快被执行和完成:
$ kubectl apply -f job-eks.yaml
  1. 列出在您的集群中创建的 kube-bench pod。它应该显示Completed作为状态,类似于以下示例:
$ kubectl get pods |grep kube-bench
kube-bench-7lxzn 0/1 Completed 0 5m
  1. 用上一个命令的输出替换 pod 名称,并查看 pod 日志以检索kube-bench的结果。在我们的示例中,pod 名称是kube-bench-7lxzn
$ kubectl logs kube-bench-7lxzn

现在,您可以在任何托管的 Kubernetes 集群上运行 kube-bench。获取日志后,按照所有的修复建议,直到清除工作节点上的失败测试。

在 OpenShift 上运行 kube-bench

OpenShift 有不同的命令行工具,因此,如果我们运行默认的测试作业,我们将无法在我们的集群上收集所需的信息,除非另有说明。在本教程中,您将学习如何在 OpenShift 上运行kube-bench

让我们执行以下步骤来运行 CIS 推荐的测试:

  1. SSH 进入您的 OpenShift 主节点,并使用--version ocp-3.10ocp-3.11运行以下命令,根据您的 OpenShift 版本。目前,只支持 3.10 和 3.11:
$ kube-bench master --version ocp-3.11
  1. 要保存结果,请使用以下命令。测试完成后,将kube-bench-master.txt文件移动到本地主机以进行进一步审查:
$ kube-bench master --version ocp-3.11 > kube-bench-master.txt
  1. SSH 进入您的 OpenShift 工作节点,并重复此配方的前两步,但这次使用您正在运行的 OpenShift 版本的node参数。在我们的示例中,这是 OCP 3.11:
$ kube-bench node --version ocp-3.11 > kube-bench-node.txt

按照在 Kubernetes 上运行 kube-bench的配方说明来修补建议的安全问题。

它是如何工作的...

这个配方向您展示了如何快速在您的集群上使用 kube-bench 运行 CIS Kubernetes 基准。

在 Kubernetes 上运行 kube-bench的配方中,在步骤 1中,执行完检查后,kube-bench 访问了保存在以下目录中的配置文件:/var/lib/etcd/var/lib/kubelet/etc/systemd/etc/kubernetes/usr/bin。因此,运行检查的用户需要为所有配置文件提供 root/sudo 访问权限。

如果配置文件无法在其默认目录中找到,则检查将失败。最常见的问题是在/usr/bin目录中缺少kubectl二进制文件。kubectl 用于检测 Kubernetes 版本。您可以通过在命令的一部分中使用--version来跳过此目录,从而指定 Kubernetes 版本,类似于以下内容:

$ kube-bench master --version 1.14

步骤 1将返回四种不同的状态。PASSFAIL状态是不言自明的,因为它们指示测试是否成功运行或失败。WARN表示测试需要手动验证,这意味着需要注意。最后,INFO表示不需要进一步操作。

另请参阅

将 DevSecOps 构建到流水线中,使用 Aqua Security

“左移”方法逐渐变得越来越受欢迎,这意味着安全必须内置到流程和流水线中。缩短流水线的最大问题之一是它们通常留下很少的空间进行适当的安全检查。因此,另一种称为“尽快部署更改”的方法被引入,这对 DevOps 的成功至关重要。

在本节中,我们将介绍使用 Aqua Security 自动化容器镜像中的漏洞检查,以减少应用程序的攻击面。

准备工作

确保您已经使用您喜欢的 CI/CD 工具配置了现有的 CI/CD 流水线。如果没有,请按照第三章中的说明,构建 CI/CD 流水线,配置 GitLab 或 CircleCI。

k8sdevopscookbook/src存储库克隆到您的工作站,以便使用chapter9目录中的清单文件,方法如下:

$ git clone https://github.com/k8sdevopscookbook/src.git
$ cd src/chapter9

确保您有一个准备好的 Kubernetes 集群,并配置kubectl来管理集群资源。

操作步骤

本节将向您展示如何将 Aqua 集成到您的 CI/CD 平台。本节进一步分为以下子节,以使此过程更加简单:

  • 使用 Aqua Security Trivy 扫描镜像

  • 将漏洞扫描构建到 GitLab 中

  • 将漏洞扫描构建到 CircleCI 中

使用 Trivy 扫描镜像

Trivy 是一个用于识别容器漏洞的开源容器扫描工具。它是市场上最简单和最准确的扫描工具之一。在这个示例中,我们将学习如何安装和扫描使用 Trivy 的容器映像。

让我们执行以下步骤来运行 Trivy:

  1. 获取最新的 Trivy 发布号并将其保存在一个变量中:
$ VERSION=$(curl --silent "https://api.github.com/repos/aquasecurity/trivy/releases/latest" | \
grep '"tag_name":' | \
sed -E 's/.*"v([^"]+)".*/\1/')

下载并安装trivy命令行界面:

$ curl --silent --location "https://github.com/aquasecurity/trivy/releases/download/v${VERSION}/trivy_${VERSION}_Linux-64bit.tar.gz" | tar xz -C /tmp
$ sudo mv /trivy /usr/local/bin
  1. 通过运行以下命令验证trivy是否正常工作。它将返回其当前版本:
$ trivy --version
trivy version 0.1.7
  1. 通过用目标映像替换容器映像名称来执行trivy检查。在我们的示例中,我们扫描了来自 Docker Hub 存储库的postgres:12.0映像:
$ trivy postgres:12.0
2019-11-12T04:08:02.013Z INFO Updating vulnerability database...
2019-11-12T04:08:07.088Z INFO Detecting Debian vulnerabilities...

postgres:12.0 (debian 10.1)
===========================
Total: 164 (UNKNOWN: 1, LOW: 26, MEDIUM: 122, HIGH: 14, CRITICAL: 1)
...
  1. 测试摘要将显示已检测到的漏洞数量,并将包括漏洞的详细列表,以及它们的 ID 和每个漏洞的解释:
+-----------+---------------+----------+----------+-----------+------+
| LIBRARY   | V ID          | SEVERITY | INST VER | FIXED VER | TITLE|
+-----------+------------------+-------+----------+-----------+------+
| apt       | CVE-2011-3374 | LOW      | 1.8.2    |           |      |
+-----------+---------------+          +----------+-----------+------+
| bash      | TEMP-0841856  |          | 5.0-4    |           |      |
+-----------+---------------+          +----------+-----------+------+
| coreutils | CVE-2016-2781 |          | 8.30-3   |           |      |
+           +---------------+          +          +-----------+------+
|           | CVE-2017-18018|          |          |           |      |
+-----------+---------------+----------+----------+-----------+------+
| file      | CVE-2019-18218| HIGH     | 1:5.35-4 | 1:5.35-4+d| file:|
...

通过这样,您已经学会了如何快速扫描您的容器映像。Trivy 支持各种容器基础映像(CentOS,Ubuntu,Alpine,Distorless 等),并原生支持 Docker Hub、Amazon ECR 和 Google Container Registry GCR 等容器注册表。Trivy 完全适用于 CI。在接下来的两个示例中,您将学习如何将 Trivy 添加到 CI 流水线中。

将漏洞扫描构建到 GitLab 中

使用 GitLab Auto DevOps,容器扫描作业使用 CoreOS Clair 来分析 Docker 映像的漏洞。然而,它并不是针对基于 Alpine 的映像的所有安全问题的完整数据库。Aqua Trivy 几乎有两倍的漏洞数量,更适合于 CI。有关详细比较,请参阅Trivy Comparison链接中的另请参阅部分。本示例将带您完成在 GitLab CI 流水线中添加测试阶段的过程。

让我们执行以下步骤来在 GitLab 中添加 Trivy 漏洞检查:

  1. 编辑项目中的 CI/CD 流水线配置.gitlab-ci.yml文件:
$ vim .gitlab-ci.yml
  1. 在您的流水线中添加一个新的阶段并定义该阶段。您可以在src/chapter9/devsecops目录中找到一个示例。在我们的示例中,我们使用了vulTest阶段名称:
stages:
 - build
 - vulTest
 - staging
 - production
#Add the Step 3 here
  1. 添加新的阶段,即vulTest。当您定义一个新的阶段时,您需要指定一个阶段名称父键。在我们的示例中,父键是trivybefore_script部分的命令将下载trivy二进制文件:
trivy:
 stage: vulTest
 image: docker:stable-git
 before_script:
 - docker build -t trivy-ci-test:${CI_COMMIT_REF_NAME} .
 - export VERSION=$(curl --silent "https://api.github.com/repos/aquasecurity/trivy/releases/latest" | grep '"tag_name":' | sed -E 's/.*"v([^"]+)".*/\1/')
 - wget https://github.com/aquasecurity/trivy/releases/download/v${VERSION}/trivy_${VERSION}_Linux-64bit.tar.gz
 - tar zxvf trivy_${VERSION}_Linux-64bit.tar.gz
 variables:
 DOCKER_DRIVER: overlay2
 allow_failure: true
 services:
 - docker:stable-dind
#Add the Step 4 here
  1. 最后,审查并添加 Trivy 扫描脚本,并完成vulTest阶段。以下脚本将对关键严重性漏洞返回--exit-code 1,如下所示:
 script:
 - ./trivy --exit-code 0 --severity HIGH --no-progress --auto-refresh trivy-ci-test:${CI_COMMIT_REF_NAME}
 - ./trivy --exit-code 1 --severity CRITICAL --no-progress --auto-refresh trivy-ci-test:${CI_COMMIT_REF_NAME}
 cache:
 directories:
 - $HOME/.cache/trivy

现在,您可以运行您的流水线,新阶段将包含在您的流水线中。如果检测到关键漏洞,流水线将失败。如果您不希望该阶段使您的流水线失败,您还可以为关键漏洞指定--exit-code 0

将漏洞扫描构建到 CircleCI 中

CircleCI 使用 Orbs 来包装预定义的示例,以加快项目配置的速度。目前,Trivy 没有 CircleCI Orb,但是仍然很容易使用 CircleCI 配置 Trivy。本示例将带您完成向 CircleCI 流水线添加测试阶段的过程。

让我们执行以下步骤来在 CircleCI 中添加 Trivy 漏洞检查:

  1. 编辑位于我们项目存储库中的.circleci/config.yml的 CircleCI 配置文件。您可以在src/chapter9/devsecops目录中找到我们的示例:
$ vim .circleci/config.yml
  1. 首先添加作业和镜像。在这个示例中,作业名称是build
jobs:
 build:
 docker:
 - image: docker:18.09-git
#Add the Step 3 here
  1. 开始添加构建图像的步骤。checkout步骤将从其代码存储库中检出项目。由于我们的作业将需要 docker 命令,因此添加setup_remote_docker。执行此步骤时,将创建远程环境,并且将适当地配置您当前的主要容器:
 steps:
 - checkout
 - setup_remote_docker
 - restore_cache:
 key: vulnerability-db
 - run:
 name: Build image
 command: docker build -t trivy-ci-test:${CIRCLE_SHA1} .
#Add the Step 4 here
  1. 添加必要的步骤来安装 Trivy:
 - run:
 name: Install trivy
 command: |
 apk add --update curl
 VERSION=$(
 curl --silent "https://api.github.com/repos/aquasecurity/trivy/releases/latest" | \
 grep '"tag_name":' | \
 sed -E 's/.*"v([^"]+)".*/\1/'
 )

 wget https://github.com/aquasecurity/trivy/releases/download/v${VERSION}/trivy_${VERSION}_Linux-64bit.tar.gz
 tar zxvf trivy_${VERSION}_Linux-64bit.tar.gz
 mv trivy /usr/local/bin
#Add the Step 5 here
  1. 添加使用 Trivy 扫描本地镜像的步骤。根据需要修改trivy参数和首选退出代码。在这里,trivy仅检查关键漏洞(--severity CRITICAL),如果发现漏洞,则失败(--exit-code 1)。它抑制进度条(--no-progress),并在更新版本时自动刷新数据库(--auto-refresh):
 - run:
 name: Scan the local image with trivy
 command: trivy --exit-code 1 --severity CRITICAL --no-progress --auto-refresh trivy-ci-test:${CIRCLE_SHA1}
 - save_cache:
 key: vulnerability-db
 paths:
 - $HOME/.cache/trivy
#Add the Step 6 here
  1. 最后,更新工作流以触发漏洞扫描:
workflows:
 version: 2
 release:
 jobs:
 - build

现在,您可以在 CircleCI 中运行您的流水线,新阶段将包含在您的流水线中。

请参阅

使用 Falco 监视可疑的应用程序活动

Falco 是一个云原生的运行时安全工具集。Falco 通过其运行时规则引擎深入了解系统行为。它用于检测应用程序、容器、主机和 Kubernetes 编排器中的入侵和异常。

在本节中,我们将介绍在 Kubernetes 上安装和基本使用 Falco。

准备工作

k8sdevopscookbook/src存储库克隆到您的工作站,以使用chapter9目录中的清单文件,如下所示:

$ git clone https://github.com/k8sdevopscookbook/src.git
$ cd src/chapter9

确保您已准备好一个 Kubernetes 集群,并配置好kubectlhelm来管理集群资源。

如何做…

本节将向您展示如何配置和运行 Falco。本节进一步分为以下子节,以使此过程更加简单:

  • 在 Kubernetes 上安装 Falco

  • 使用 Falco 检测异常

  • 定义自定义规则

在 Kubernetes 上安装 Falco

Falco 可以通过多种方式安装,包括直接在 Linux 主机上部署 Falco 作为 DaemonSet,或者使用 Helm。本教程将向您展示如何将 Falco 安装为 DaemonSet。

让我们执行以下步骤,在我们的集群上部署 Falco:

  1. 将 Falco 存储库克隆到您当前的工作目录:
$ git clone https://github.com/falcosecurity/falco.git
$ cd falco/integrations/k8s-using-daemonset/k8s-with-rbac
  1. 为 Falco 创建一个服务账户。以下命令还将为其创建 ClusterRole 和 ClusterRoleBinding:
$ kubectl create -f falco-account.yaml
  1. 使用从克隆存储库位置的以下命令创建一个服务:
$ kubectl create -f falco-service.yaml
  1. 创建一个config目录并将部署配置文件和规则文件复制到config目录中。稍后我们需要编辑这些文件:
$ mkdir config
$ cp ../../../falco.yaml config/
$ cp ../../../rules/falco_rules.* config/
$ cp ../../../rules/k8s_audit_rules.yaml config/
  1. 使用config/目录中的配置文件创建一个 ConfigMap。稍后,DaemonSet 将使用 ConfigMap 使配置对 Falco pods 可用:
$ kubectl create configmap falco-config --from-file=config
  1. 最后,使用以下命令部署 Falco:
$ kubectl create -f falco-daemonset-configmap.yaml
  1. 验证 DaemonSet pods 已成功创建。您应该在集群上的每个可调度的工作节点上看到一个 pod。在我们的示例中,我们使用了一个具有四个工作节点的 Kubernetes 集群:
$ kubectl get pods | grep falco-daemonset
falco-daemonset-94p8w 1/1 Running 0 2m34s
falco-daemonset-c49v5 1/1 Running 0 2m34s
falco-daemonset-htrxw 1/1 Running 0 2m34s
falco-daemonset-kwms5 1/1 Running 0 2m34s

有了这个,Falco 已经部署并开始监视行为活动,以检测我们节点上应用程序中的异常活动。

使用 Falco 检测异常

Falco 检测到各种可疑行为。在这个教程中,我们将产生一些在正常生产集群中可能会引起怀疑的活动。

让我们执行以下步骤来产生可能触发系统调用事件丢弃的活动:

  1. 首先,我们需要在测试一些行为之前审查完整的规则。Falco 有两个规则文件。默认规则位于/etc/falco/falco_rules.yaml,而本地规则文件位于/etc/falco/falco_rules.local.yaml。您的自定义规则和修改应该在falco_rules.local.yaml文件中:
$ cat config/falco_rules.yaml
$ cat config/falco_rules.local.yaml
  1. 您将看到一长串的默认规则和宏。其中一些如下所示:
- rule: Disallowed SSH Connection
- rule: Launch Disallowed Container
- rule: Contact K8S API Server From Container
- rule: Unexpected K8s NodePort Connection
- rule: Launch Suspicious Network Tool in Container
- rule: Create Symlink Over Sensitive Files
- rule: Detect crypto miners using the Stratum protocol
  1. 通过获取一个 bash shell 进入其中一个 Falco pods 并查看日志来测试 Falco 是否正常工作。列出 Falco pods:
$ kubectl get pods | grep falco-daemonset
falco-daemonset-94p8w 1/1 Running 0 2m34s
falco-daemonset-c49v5 1/1 Running 0 2m34s
falco-daemonset-htrxw 1/1 Running 0 2m34s
falco-daemonset-kwms5 1/1 Running 0 2m34s
  1. 从上述命令的输出中获取对一个 Falco pod 的 bash shell 访问并查看日志:
$ kubectl exec -it falco-daemonset-94p8w bash
$ kubectl logs falco-daemonset-94p8w  
  1. 在日志中,您将看到 Falco 检测到我们对 pods 的 shell 访问:
{"output":"00:58:23.798345403: Notice A shell was spawned in a container with an attached terminal (user=root k8s.ns=default k8s.pod=falco-daemonset-94p8w container=0fcbc74d1b4c shell=bash parent=docker-runc cmdline=bash terminal=34816 container_id=0fcbc74d1b4c image=falcosecurity/falco) k8s.ns=default k8s.pod=falco-daemonset-94p8w container=0fcbc74d1b4c k8s.ns=default k8s.pod=falco-daemonset-94p8w container=0fcbc74d1b4c","priority":"Notice","rule":"Terminal shell in container","time":"2019-11-13T00:58:23.798345403Z", "output_fields": {"container.id":"0fcbc74d1b4c","container.image.repository":"falcosecurity/falco","evt.time":1573606703798345403,"k8s.ns.name":"default","k8s.pod.name":"falco-daemonset-94p8w","proc.cmdline":"bash","proc.name":"bash","proc.pname":"docker-runc","proc.tty":34816,"user.name":"root"}}

通过这样,您已经学会了如何使用 Falco 来检测异常和可疑行为。

定义自定义规则

Falco 规则可以通过添加我们自己的规则来扩展。在这个教程中,我们将部署一个简单的应用程序,并创建一个新规则来检测恶意应用程序访问我们的数据库。

执行以下步骤来创建一个应用程序并为 Falco 定义自定义规则:

  1. 切换到src/chapter9/falco目录,这是我们示例所在的位置:
$ cd src/chapter9/falco
  1. 创建一个新的falcotest命名空间:
$ kubectl create ns falcotest
  1. 审查 YAML 清单并使用以下命令部署它们。这些命令将创建一个 MySQL pod,Web 应用程序,我们将用来 ping 应用程序的客户端,以及它的服务:
$ kubectl create -f mysql.yaml
$ kubectl create -f ping.yaml
$ kubectl create -f client.yaml
  1. 现在,使用默认凭据bob/foobar的客户端 pod 发送 ping 到我们的应用程序。预期地,我们将能够进行身份验证并成功完成任务:
$ kubectl exec client -n falcotest -- curl -F "s=OK" -F "user=bob" -F "passwd=foobar" -F "ipaddr=localhost" -X POST http://ping/ping.php
  1. 编辑falco_rules.local.yaml文件:
$ vim config/falco_rules.local.yaml
  1. 将以下规则添加到文件末尾并保存:
 - rule: Unauthorized process
 desc: There is a running process not described in the base template
 condition: spawned_process and container and k8s.ns.name=falcotest and k8s.deployment.name=ping and not proc.name in (apache2, sh, ping)
 output: Unauthorized process (%proc.cmdline) running in (%container.id)
 priority: ERROR
 tags: [process]
  1. 更新用于 DaemonSet 的 ConfigMap 并通过运行以下命令删除 pod 以获得新的配置:
$ kubectl delete -f falco-daemonset-configmap.yaml
$ kubectl create configmap falco-config --from-file=config --dry-run --save-config -o yaml | kubectl apply -f -
$ kubectl apply -f falco-daemonset-configmap.yaml
  1. 我们将执行 SQL 注入攻击并访问存储我们的 MySQL 凭据的文件。我们的新自定义规则应该能够检测到它:
$ kubectl exec client -n falcotest -- curl -F "s=OK" -F "user=bad" -F "passwd=wrongpasswd' OR 'a'='a" -F "ipaddr=localhost; cat /var/www/html/ping.php" -X POST http://ping/ping.php
  1. 上述命令将返回 PHP 文件的内容。您将能够在那里找到 MySQL 凭据:
3 packets transmitted, 3 received, 0% packet loss, time 2044ms
rtt min/avg/max/mdev = 0.028/0.035/0.045/0.007 ms
<?php
$link = mysqli_connect("mysql", "root", "foobar", "employees");
?>
  1. 列出 Falco pod:
$ kubectl get pods | grep falco-daemonset
falco-daemonset-5785b 1/1 Running 0 9m52s
falco-daemonset-brjs7 1/1 Running 0 9m52s
falco-daemonset-mqcjq 1/1 Running 0 9m52s
falco-daemonset-pdx45 1/1 Running 0 9m52s
  1. 查看来自 Falco pod 的日志:
$ kubectl exec -it falco-daemonset-94p8w bash
**$ kubectl logs falco-daemonset-94p8w** 
  1. 在日志中,您将看到 Falco 检测到我们对 pod 的 shell 访问:
05:41:59.9275580001: Error Unauthorized process (cat /var/www/html/ping.php) running in (5f1b6d304f99) k8s.ns=falcotest k8s.pod=ping-74dbb488b6-6hwp6 container=5f1b6d304f99

有了这个,您就知道如何使用 Kubernetes 元数据(如k8s.ns.namek8s.deployment.name)添加自定义规则。您还可以使用其他过滤器。这在参见部分的支持的过滤器链接中有更详细的描述。

工作原理...

本教程向您展示了如何在 Kubernetes 上运行应用程序时,基于预定义和自定义规则来检测异常。

Kubernetes 上安装 Falco的步骤中,在第 5 步,我们创建了一个 ConfigMap 供 Falco pod 使用。Falco 有两种类型的规则文件。

在第 6 步中,当我们创建了 DaemonSet 时,所有默认规则都是通过 ConfigMap 中的falco_rules.yaml文件提供的。这些放置在 pod 内的/etc/falco/falco_rules.yaml中,而本地规则文件falco_rules.local.yaml可以在/etc/falco/falco_rules.local.yaml中找到。

默认规则文件包含许多常见异常和威胁的规则。所有定制的部分都必须添加到falco_rules.local.yaml文件中,我们在定义自定义规则教程中已经做到了。

定义自定义规则教程中,在第 6 步,我们创建了一个包含rules元素的自定义规则文件。Falco 规则文件是一个使用三种元素的 YAML 文件:rulesmacroslists

规则定义了发送有关特定条件的警报。规则是一个包含至少以下键的文件:

  • rule:规则的名称

  • condition:应用于事件的表达式,用于检查它们是否匹配规则

  • desc:规则用途的详细描述

  • output:显示给用户的消息

  • priority:紧急、警报、关键、错误、警告、通知、信息或调试

您可以通过转到“了解 Falco 规则”链接来了解更多关于这些规则的信息,该链接提供在“另请参阅”部分中。

另请参阅

使用 HashiCorp Vault 保护凭据

HashiCorp Vault 是一个流行的工具,用于安全存储和访问诸如凭据、API 密钥和证书之类的秘密。 Vault 提供安全的秘密存储,按需动态秘密,数据加密以及支持秘密吊销。

在本节中,我们将介绍访问和存储 Kubernetes 秘密的安装和基本用例。

准备就绪

k8sdevopscookbook/src存储库克隆到您的工作站,以便在chapter9目录中使用清单文件,方法如下:

$ git clone https://github.com/k8sdevopscookbook/src.git
$ cd src/chapter9

确保您已准备好 Kubernetes 集群,并配置了kubectlhelm以管理集群资源。

操作步骤…

本节进一步分为以下小节,以使此过程更加简单:

  • 在 Kubernetes 上安装 Vault

  • 访问 Vault UI

  • 在 Vault 上存储凭据

在 Kubernetes 上安装 Vault

此教程将向您展示如何在 Kubernetes 上获取 Vault 服务。 让我们执行以下步骤,使用 Helm 图表安装 Vault:

  1. 克隆图表存储库:
$ git clone https://github.com/hashicorp/vault-helm.git
$ cd vault-helm
  1. 检查最新的稳定版本:
$ git checkout v$(curl --silent "https://api.github.com/repos/hashicorp/vault-helm/releases/latest" | \
grep '"tag_name":' | \
sed -E 's/.*"v([^"]+)".*/\1/')
  1. 如果您想要安装高可用的 Vault,请跳至步骤 4;否则,请使用此处显示的 Helm 图表参数安装独立版本:
$ helm install --name vault --namespace vault ./
  1. 要部署使用 HA 存储后端(如 Consul)的高可用版本,请使用以下 Helm 图表参数。 这将使用具有三个副本的 StatefulSet 部署 Vault:
$ helm install --name vault --namespace vault --set='server.ha.enabled=true' ./
  1. 验证 pod 的状态。您会注意到 pod 尚未准备就绪,因为就绪探针要求首先初始化 Vault:
$ $ kubectl get pods -nvault
NAME                                  READY STATUS  RESTARTS AGE
vault-0                               0/1   Running 0        83s
vault-agent-injector-5fb898d6cd-rct82 1/1   Running 0        84s
  1. 检查初始化状态。它应该是false
$ kubectl exec -it vault-0 -nvault -- vault status
Key             Value
---             -----
Seal Type       shamir
Initialized     false
Sealed          true
Total Shares    0
Threshold       0
Unseal Progress 0/0
Unseal Nonce    n/a
Version         n/a
HA Enabled      false
  1. 初始化 Vault 实例。以下命令将返回一个解封密钥和根令牌:
$ kubectl exec -it vault-0 -nvault -- vault operator init -n 1 -t 1

Unseal Key 1: lhLeU6SRdUNQgfpWAqWknwSxns1tfWP57iZQbbYtFSE=
Initial Root Token: s.CzcefEkOYmCt70fGSbHgSZl4
Vault initialized with 1 key shares and a key threshold of 1\. Please securely
distribute the key shares printed above. When the Vault is re-sealed,
restarted, or stopped, you must supply at least 1 of these keys to unseal it
before it can start servicing requests.
  1. 使用以下命令的输出中的解封密钥解封 Vault:
$ kubectl exec -it vault-0 -nvault -- vault operator unseal lhLeU6SRdUNQgfpWAqWknwSxns1tfWP57iZQbbYtFSE=
Key          Value
---          -----
Seal Type    shamir
Initialized  true
Sealed       false
Total Shares 1
Threshold    1
Version      1.3.1
Cluster Name vault-cluster-6970c528
Cluster ID   dd88cca8-20bb-326c-acb3-2d924bb1805c
HA Enabled   false
  1. 验证 pod 的状态。您将看到就绪探针已经验证,并且 pod 已准备就绪:
$ kubectl get pods -nvault
NAME                                  READY STATUS  RESTARTS AGE
vault-0                               1/1   Running 0        6m29s
vault-agent-injector-5fb898d6cd-rct82 1/1   Running 0        6m30s

Vault 在初始化后即可使用。现在,您知道如何在 Kubernetes 上运行 Vault 了。

访问 Vault UI

默认情况下,在使用 Helm 图表安装时,启用 Vault UI。让我们执行以下步骤来访问 Vault UI:

  1. 由于访问 Vault 是一个安全问题,不建议使用服务暴露它。使用端口转发来访问 Vault UI,使用以下命令:
$ kubectl port-forward vault-0 -nvault 8200:8200
  1. 一旦转发完成,您可以在http://localhost:8200上访问 UI:

现在,您可以访问 Web UI。参加 Vault Web UI 之旅,熟悉其功能。

在 Vault 中存储凭据

此教程将向您展示如何在 Kubernetes 中使用 Vault,并从 Vault 中检索秘密。

让我们执行以下步骤来在 Vault 中启用 Kubernetes 认证方法:

  1. 使用您的令牌登录 Vault:
$ vault login <root-token-here>
  1. 向 Vault 写入一个秘密:
$ vault write secret/foo value=bar
Success! Data written to: secret/foo
$ vault read secret/foo
Key              Value
---              -----
refresh_interval 768h
value            bar
  1. 让我们配置 Vault 的 Kubernetes 认证后端。首先,创建一个 ServiceAccount:
$ kubectl -n vault create serviceaccount vault-k8s
  1. vault-k8s ServiceAccount 创建一个 RoleBinding:
$ cat <<EOF | kubectl apply -f -
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
 name: role-tokenreview-binding
 namespace: default
roleRef:
 apiGroup: rbac.authorization.k8s.io
 kind: ClusterRole
 name: system:auth-delegator
subjects:
- kind: ServiceAccount
 name: vault-k8s
 namespace: default
EOF
  1. 获取令牌:
$ SECRET_NAME=$(kubectl -n vault get serviceaccount vault-k8s -o jsonpath={.secrets[0].name})
$ ACCOUNT_TOKEN=$(kubectl -n vault get secret ${SECRET_NAME} -o jsonpath={.data.token} | base64 --decode; echo)
$ export VAULT_SA_NAME=$(kubectl get sa -n vault vault-k8s -o jsonpath=”{.secrets[*].name}”)
$ export SA_CA_CRT=$(kubectl get secret $VAULT_SA_NAME -n vault -o jsonpath={.data.'ca\.crt'} | base64 --decode; echo)
  1. 在 vault 中启用 Kubernetes 认证后端:
$ vault auth enable kubernetes
$ vault write auth/kubernetes/config kubernetes_host=”https://MASTER_IP:6443" kubernetes_ca_cert=”$SA_CA_CRT” token_reviewer_jwt=$TR_ACCOUNT_TOKEN
  1. 使用policy.hcl文件从示例存储库创建一个名为vault-policy的新策略:
$ vault write sys/policy/vault-policy policy=@policy.hcl
  1. 接下来,为 ServiceAccount 创建一个角色:
$ vault write auth/kubernetes/role/demo-role \
 bound_service_account_names=vault-coreos-test \
 bound_service_account_namespaces=default \
 policies=demo-policy \
 ttl=1h
  1. 通过运行以下命令使用角色进行身份验证:
$ DEFAULT_ACCOUNT_TOKEN=$(kubectl get secret $VAULT_SA_NAME -n vault -o jsonpath={.data.token} | base64 — decode; echo )
  1. 通过运行以下命令使用令牌登录 Vault:
$ vault write auth/kubernetes/login role=demo-role jwt=${DEFAULT_ACCOUNT_TOKEN}
  1. secret/demo路径下创建一个秘密:
$ vault write secret/demo/foo value=bar

通过这样,您已经学会了如何在 Vault 中创建 Kubernetes 认证后端,并使用 Vault 存储 Kubernetes 秘密。

另请参阅

第十章:使用 Kubernetes 记录日志

在本章中,我们将讨论 Kubernetes 集群的集群日志记录。我们将讨论如何设置集群以摄取日志,以及如何使用自管理和托管解决方案查看日志。

在本章中,我们将涵盖以下配方:

  • 在本地访问 Kubernetes 日志

  • 访问特定应用程序的日志

  • 在 Kubernetes 中使用 EFK 堆栈构建集中式日志记录

  • 使用 Google Stackdriver 在 Kubernetes 中记录日志

  • 使用托管的 Kubernetes 日志记录服务

  • 为您的 Jenkins CI/CD 环境记录日志

技术要求

本章中的配方期望您已通过遵循第一章中描述的建议方法之一部署了功能齐全的 Kubernetes 集群,构建生产就绪的 Kubernetes 集群

本章中的为您的 Jenkins CI/CD 环境记录日志配方期望您已通过遵循第三章中描述的建议方法之一创建了具有现有 CI 流水线的功能齐全的 Jenkins 服务器,构建 CI/CD 流水线

剩余的本章配方将使用 Kubernetes 命令行工具kubectl,因为它是针对 Kubernetes 集群运行命令的主要命令行界面。我们还将使用helm,在部署解决方案时提供 Helm 图表。

在本地访问 Kubernetes 日志

在 Kubernetes 中,日志可用于调试和监视活动到一定程度。基本日志记录可用于检测配置问题,但对于集群级别的日志记录,需要外部后端来存储和查询日志。集群级别的日志记录将在使用 EFK 堆栈构建 Kubernetes 中的集中式日志记录使用 Google Stackdriver 记录 Kubernetes配方中进行介绍。

在本节中,我们将学习如何根据 Kubernetes 中可用的选项访问基本日志。

准备工作

k8sdevopscookbook/src存储库克隆到您的工作站,以便在chapter10目录中使用清单文件,方法如下:

$ git clone https://github.com/k8sdevopscookbook/src.git
$ cd src/chapter10

确保您已准备好 Kubernetes 集群,并配置了kubectlhelm来管理集群资源。

如何做…

本节进一步分为以下子节,以使此过程更加简单:

  • 通过 Kubernetes 访问日志

  • 使用 Telepresence 在本地调试服务

通过 Kubernetes 访问日志

这个步骤将带你了解如何访问 Kubernetes 日志并在本地调试服务。

让我们通过使用 Kubernetes 中提供的各种选项来执行以下步骤来查看日志:

  1. 获取在kube-system命名空间中运行的 pod 列表。在这个命名空间中运行的 pod,特别是kube-apiserverkube-controller-managerkube-dnskube-scheduler,在 Kubernetes 控制平面中扮演着关键的角色。
$ kubectl get pods -n kube-system
NAME                                             READY STATUS  RST AGE
dns-controller-6577fb57f7-hx9wz                  1/1   Running 0   16d
etcd-manager-events-ip-172-20-8-2.ec2.internal   1/1   Running 0   16d
etcd-manager-main-ip-172-20-8-2.ec2.internal     1/1   Running 0   16d
kube-apiserver-ip-172-20-8-2.ec2.internal        1/1   Running 2   16d
kube-controller-manager-ip-172-20-8-2.ec2.int... 1/1   Running 0   16d
kube-dns-66d58c65d5-mw6n5                        3/3   Running 0   16d
kube-dns-66d58c65d5-rntmj                        3/3   Running 0   16d
kube-dns-autoscaler-6567f59ccb-c9rmv             1/1   Running 0   16d
kube-proxy-ip-172-20-32-123.ec2.internal         1/1   Running 0   16d
kube-proxy-ip-172-20-38-218.ec2.internal         1/1   Running 1   16d
kube-proxy-ip-172-20-45-93.ec2.internal          1/1   Running 0   16d
kube-scheduler-ip-172-20-58-244.ec2.internal     1/1   Running 0  3d6h
  1. 查看在kube-system命名空间中具有单个容器的 pod 的日志。在这个例子中,这个 pod 是kube-apiserver。替换 pod 的名称,并根据需要重复这个步骤。
$ kubectl logs kube-apiserver-ip-172-20-58-244.ec2.internal -n kube-system
...
E1112 08:11:05.662027 1 authentication.go:65] Unable to authenticate the request due to an error: [invalid bearer token, Token has been invalidated]
I1112 09:09:39.448428 1 log.go:172] http: TLS handshake error from 124.84.242.10:49016: tls: first record does not look like a TLS handshake
I1112 09:30:00.726871 1 trace.go:81] Trace[76921086]: "GuaranteedUpdate etcd3: *coordination.Lease" (started: 2019-11-12 09:30:00.177607414 +0000 UTC m=+1250671.527180434) (total time: 549.223921ms):

如前面的输出所示,你可以在日志中找到事件的时间、来源和简短的解释。

日志的输出可能会变得很长,尽管大多数情况下你只需要查看日志中的最后几个事件。如果你不想获取所有的日志,而只需要查看日志中的最后几个事件,你可以在命令的末尾添加-tail,并指定你想要查看的行数。例如,kubectl logs <podname> -n <namespace> -tail 10将返回最后 10 行。根据需要更改数字以限制输出。

  1. Pods 可以包含多个容器。当你列出 pod 时,Ready列下的数字显示了 pod 内的容器数量。让我们从kube-system命名空间中的一个包含多个容器的 pod 中查看特定容器的日志。在这里,我们要查看的 pod 叫做kube-dns。替换 pod 的名称,并根据需要重复这个步骤。
$ kubectl -n kube-system logs kube-dns-66d58c65d5-mw6n5
Error from server (BadRequest): a container name must be specified for pod kube-dns-66d58c65d5-mw6n5, choose one of: [kubedns dnsmasq sidecar]
$ kubectl -n kube-system logs kube-dns-66d58c65d5-mw6n5 kubedns
  1. 要查看特定时间之后的日志,请使用--since-time参数加上一个日期,类似于下面的代码中所示。你可以使用绝对时间或请求一个持续时间。只有在指定时间之后或在持续时间内的日志才会被显示。
$ kubectl -n kube-system logs kube-dns-66d58c65d5-mw6n5 kubedns --since-time="2019-11-14T04:59:40.417Z"
...
I1114 05:09:13.309614 1 dns.go:601] Could not find endpoints for service "minio" in namespace "default". DNS records will be created once endpoints show up.
  1. 除了 pod 名称,你还可以按标签查看日志。在这里,我们使用k8s-app=kube-dns标签列出 pod。由于 pod 包含多个容器,我们可以使用-c kubedns参数来设置目标容器。
$ kubectl -n kube-system logs -l k8s-app=kube-dns -c kubedns
  1. 如果容器崩溃或重新启动,我们可以使用-p标志来从容器的先前实例中检索日志,如下所示:
$ kubectl -n kube-system logs -l k8s-app=kube-dns -c kubedns -p

现在你知道如何通过 Kubernetes 访问 pod 日志了。

使用 Telepresence 在本地调试服务

当 CI 流水线中的构建失败或在暂存集群中运行的服务包含错误时,您可能需要在本地运行服务以正确排除故障。但是,应用程序依赖于集群中的其他应用程序和服务;例如,数据库。Telepresence 帮助您在本地运行代码,作为正常的本地进程,然后将请求转发到 Kubernetes 集群。本教程将向您展示如何在本地运行本地 Kubernetes 集群时调试服务。

让我们执行以下步骤,通过 Kubernetes 中可用的各种选项查看日志:

  1. OSX上,使用以下命令安装 Telepresence 二进制文件:
$ brew cask install osxfuse
$ brew install datawire/blackbird/telepresence

Windows上,使用Windows 子系统 LinuxWSL)上的 Ubuntu。然后,在Ubuntu上,使用以下命令下载并安装 Telepresence 二进制文件:

$ curl -s https://packagecloud.io/install/repositories/datawireio/telepresence/script.deb.sh | sudo bash
$ sudo apt install --no-install-recommends telepresence
  1. 现在,创建您的应用程序的部署。在这里,我们使用一个hello-world示例:
$ kubectl run hello-world --image=datawire/hello-world --port=8000
  1. 使用外部LoadBalancer公开服务并获取服务 IP:
$ kubectl expose deployment hello-world --type=LoadBalancer --name=hello-world
$ kubectl get service hello-world
NAME        TYPE         CLUSTER-IP     EXTERNAL-IP                                   PORT(S)        AGE
hello-world LoadBalancer 100.71.246.234 a643ea7bc0f0311ea.us-east-1.elb.amazonaws.com 8000:30744/TCP 8s
  1. 要能够查询地址,请使用以下命令将地址存储在变量中:
$ export HELLOWORLD=http://$(kubectl get svc hello-world -o jsonpath='{.status.loadBalancer.ingress[0].hostname}'):8000
  1. 向服务发送查询。这将返回类似于以下内容的Hello, world!消息:
$ curl $HELLOWORLD/
Hello, world!
  1. 接下来,我们将创建一个本地 Web 服务,并将 Kubernetes 服务hello-world的消息替换为本地 Web 服务器服务。首先,创建一个目录和一个文件,以便使用 HTTP 服务器共享:
$ mkdir /tmp/local-test && cd /tmp/local-test
$ echo "hello this server runs locally on my laptop" > index.html
  1. 创建一个 Web 服务器,并使用以下命令通过端口8000公开服务:
$ telepresence --swap-deployment hello-world --expose 8000 \
--run python3 -m http.server 8000 &

...
T: Forwarding remote port 8000 to local port 8000.
T: Guessing that Services IP range is 100.64.0.0/13\. Services started after this point will be inaccessible if are outside
T: this range; restart telepresence if you can't access a new Service.
T: Setup complete. Launching your command.
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...

上述命令将使用vpn-tcp方法启动代理。其他方法可以在参见部分的Telepresence 方法完整列表链接中找到。

当服务通过网络公开时,请记住您的计算机面临运行 Web 服务器的所有风险。当您使用此处描述的命令公开 Web 服务时,请确保您的/tmp/local-test目录中没有任何重要文件不希望外部公开。

  1. 向服务发送查询。您将看到对hello-world服务的查询将被转发到您的本地 Web 服务器:
$ curl $HELLOWORLD/
hello this server runs locally on my laptop
  1. 要结束本地服务,请使用fg命令将当前 shell 环境中的后台 Telepresence 作业移到前台。然后,使用Ctrl + C键退出它。

工作原理...

在本教程中,您学会了如何在本地访问日志并调试服务问题。

使用 Telepresence 在本地调试服务食谱中,在步骤 7中,我们运行了telepresence --swap-deployment命令,用本地 web 服务替换了服务。

Telepresence 通过构建双向网络代理来工作。--swap-deployment标志用于定义将在集群上用代理 pod 替换的 pod。Telepresence 启动vpn-tcp进程将所有请求发送到本地公开的端口,即8000--run python3 -m http.server 8000 &标志告诉 Telepresence 在后台通过端口8000运行 Python 3 中的http.server

在同一食谱中,在步骤 9中,使用fg命令将后台服务移至前台。当您退出服务时,旧的 pod 将被恢复。您可以通过查看查看部分中的Telepresence 工作原理链接来了解 Telepresence 的功能。

另请参阅

访问特定应用程序的日志

在 Kubernetes 中,与调度 pod 和容器相关的日志可以通过kubectl logs命令访问,但并非所有应用程序日志和命令都通过 Kubernetes API 公开。可能需要访问容器内部的这些日志和 shell 命令。

在本节中,我们将学习如何访问容器 shell,提取日志和更新二进制文件以进行故障排除。

准备工作

k8sdevopscookbook/src存储库克隆到您的工作站,以便在chapter10目录下使用清单文件,如下所示:

$ git clone https://github.com/k8sdevopscookbook/src.git
$ cd src/chapter10

确保您已准备好 Kubernetes 集群,并配置了kubectl以管理集群资源。

操作步骤…

本节进一步分为以下小节,以使此过程更加简单:

  • 在容器中获取 shell 访问权限

  • 在容器内访问 PostgreSQL 日志

在容器中获取 shell 访问权限

让我们执行以下步骤来创建一个具有多个容器的部署,并进入正在运行的容器的 shell:

  1. 在本教程中,我们将在 OpenEBS 持久卷上部署 PostgreSQL,以演示 shell 访问。将目录更改为src/chapter10/postgres中的示例文件目录,其中存储了此教程的所有 YAML 清单。创建一个ConfigMap,其中包含与以下类似的数据库名称和凭据,或者查看它们并使用cm-postgres.yaml文件:
$ cd postgres
$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
 name: postgres-config
 labels:
 app: postgres
data:
 POSTGRES_DB: postgresdb
 POSTGRES_USER: testuser
 POSTGRES_PASSWORD: testpassword123
EOF
  1. postgres创建服务:
$ cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Service
metadata:
 name: postgres
 labels:
 app: postgres
spec:
 type: NodePort
 ports:
 - port: 5432
 selector:
 app: postgres
EOF
  1. 查看postgres.yaml文件并应用它以创建 PostgreSQL StatefulSet。我们可以使用它来部署 pod 并自动创建 PV/PVC:
$ kubectl apply -f postgres.yaml
  1. 获取具有postgres标签的 pod:
$ kubectl get pods -l app=postgres
NAME READY STATUS RESTARTS AGE
postgres-0 1/1 Running 0 7m5s
postgres-1 1/1 Running 0 6m58s
  1. 进入postgres-0容器的 shell:
$ kubectl exec -it postgres-0 -- /bin/bash

上述命令将使您可以访问正在运行的容器的 shell。

在容器内访问 PostgreSQL 日志

让我们执行以下步骤来从容器内运行的应用程序获取日志:

  1. 当您在 shell 中时,使用用户名testuser连接到名为postgresdb的 PostgreSQL 数据库。您将看到以下内容的 PostgreSQL 提示:
$ psql --username testuser postgresdb
psql (12.1 (Debian 12.1-1.pgdg100+1))
Type "help" for help.
  1. 在 PostgreSQL 提示符上,使用以下命令创建一个表并向其中添加一些数据:
CREATE TABLE test (
   id int GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY,
   a int NOT NULL,
   created_at timestamptz NOT NULL DEFAULT CURRENT_TIMESTAMP
);
INSERT INTO test (a) SELECT * FROM generate_series(-1, -1000, -1);
  1. postgresql.conf获取日志配置详细信息。您将看到日志存储在/var/log/postgresql目录中:
$ cat /var/lib/postgresql/data/postgresql.conf |grep log
  1. 列出并访问/var/log/postgresql目录中的日志:
$ ls /var/log/postgresql
  1. 在容器内部,您可以选择在tmp目录中创建我们示例的postgresdb数据库的备份,使用以下命令:
$ pg_dump --username testuser postgresdb > /tmp/backup.sql

通过这样,您已经学会了如何在容器中获取 shell 访问权限以及如何访问容器内部的本地存储的日志和文件。

使用 EFK 堆栈在 Kubernetes 中构建集中式日志记录

在本地访问 Kubernetes 日志部分所述,基本日志记录可用于检测配置问题,但对于集群级别的日志记录,需要外部后端来存储和查询日志。集群级别的日志记录堆栈可以帮助您快速整理和分析 Kubernetes 集群中应用程序产生的大量生产日志数据。Kubernetes 生态系统中最受欢迎的集中式日志记录解决方案之一是Elasticsearch,Logstash 和 KibanaELK)堆栈。

在 ELK 堆栈中,Logstash 用作日志收集器。Logstash 使用的内存略多于 Fluent Bit,后者是 Fluentd 的低内存版本。因此,在本教程中,我们将使用 Elasticsearch、Fluent-bit 和 Kibana (EFK)堆栈。如果您的应用程序具有 Logstash 依赖项,您可以随时用 Logstash 替换 Fluentd/Fluent Bit。

在本节中,我们将学习如何使用 EFK 堆栈构建集群级别的日志系统来管理 Kubernetes 日志。

准备工作

将 k8sdevopscookbook/src 存储库克隆到您的工作站,以便在 chapter10 目录中使用清单文件:

$ git clone https://github.com/k8sdevopscookbook/src.git
$ cd src/chapter10

确保您已准备好一个 Kubernetes 集群,并配置了 kubectl 和 helm 来管理集群资源。

操作步骤…

本节将向您展示如何在 Kubernetes 集群上配置 EFK 堆栈。本节进一步分为以下子节,以使此过程更加简单:

  • 部署 Elasticsearch Operator

  • 请求 Elasticsearch 端点

  • 部署 Kibana

  • 使用 Fluent Bit 聚合日志

  • 访问 Kibana 上的 Kubernetes 日志

部署 Elasticsearch Operator

Elasticsearch 是一个高度可扩展的开源全文搜索和分析引擎。Elasticsearch 允许您快速存储、搜索和分析大量数据。在本教程中,我们将使用它来存储 Kubernetes 日志。

让我们执行以下步骤来部署 Elastic Cloud on Kubernetes (ECK):

  1. 使用以下命令部署 Elasticsearch Operator 及其 CRD:
$ kubectl apply -f https://download.elastic.co/downloads/eck/1.0.0/all-in-one.yaml
  1. Elasticsearch Operator 将创建自己的 CustomResourceDefinition (CRD)。我们将在后面使用此 CRD 来在 Kubernetes 上部署和管理 Elasticsearch 实例。使用以下命令列出新的 CRD:
$ kubectl get crds |grep elastic.co
apmservers.apm.k8s.elastic.co                2019-11-25T07:52:16Z
elasticsearches.elasticsearch.k8s.elastic.co 2019-11-25T07:52:17Z
kibanas.kibana.k8s.elastic.co                2019-11-25T07:52:17Z
  1. 创建一个名为 logging 的新命名空间:
$ kubectl create ns logging
  1. 使用以下命令在 logging 命名空间中使用默认参数创建 Elasticsearch:
$ cat <<EOF | kubectl apply -f -
apiVersion: elasticsearch.k8s.elastic.co/v1beta1
kind: Elasticsearch
metadata:
 name: elasticsearch
 namespace: logging
spec:
 version: 7.4.2
 nodeSets:
 - name: default
 count: 3
 config:
 node.master: true
 node.data: true
 node.ingest: true
 node.store.allow_mmap: false
EOF
  1. 获取 Elasticsearch 节点的状态:
$ kubectl get elasticsearch -n logging
NAME HEALTH NODES VERSION PHASE AGE
elasticsearch green 3 7.4.2 Ready 86s
  1. 您还可以使用以下命令确认 logging 命名空间中 pod 的状态:
$ kubectl get pods -n logging
NAME                       READY STATUS  RESTARTS AGE
elasticsearch-es-default-0 1/1   Running 0        2m24s
elasticsearch-es-default-1 1/1   Running 0        2m24s
elasticsearch-es-default-2 1/1   Running 0        2m24s

将创建一个三节点的 Elasticsearch 集群。默认情况下,我们在这里创建的节点都是以下类型:可选主节点、数据节点和摄取节点。随着 Elasticsearch 集群的增长,建议创建专用的可选主节点、数据节点和摄取节点。

请求 Elasticsearch 端点

创建 Elasticsearch 集群时,将生成并存储默认用户密码在 Kubernetes 秘密中。您需要完整的凭据来请求 Elasticsearch 端点。

让我们执行以下步骤来请求 Elasticsearch 访问:

  1. 获取为默认elastic用户生成的密码:
$ PASSWORD=$(kubectl get secret elasticsearch-es-elastic-user \
-n logging -o=jsonpath='{.data.elastic}' | base64 --decode)
  1. 请求 Elasticsearch 端点地址:
$ curl -u "elastic:$PASSWORD" -k "https://elasticsearch-es-http:9200"
{
 "name" : "elasticsearch-es-default-2",
 "cluster_name" : "elasticsearch",
 "cluster_uuid" : "E_ATzAz8Th6oMvd4D_QocA",
 "version" : {...},
 "tagline" : "You Know, for Search"
}

如果您远程访问 Kubernetes 集群,可以创建一个端口转发服务,并使用 localhost,类似于以下代码中所示:

$ kubectl port-forward service/quickstart-es-http 9200
$ curl -u "elastic:$PASSWORD" -k "https://localhost:9200"

现在,我们可以访问我们在 Kubernetes 上部署的三节点小型 Elasticsearch 集群。接下来,我们需要部署 Kibana 以完成堆栈。

部署 Kibana

Kibana 是一个开源的数据可视化仪表板,可以让您可视化您的 Elasticsearch 数据。

让我们执行以下步骤来部署 Kibana:

  1. 创建一个与我们之前创建的 Elasticsearch 集群相关联的 Kibana 实例:
$ cat <<EOF | kubectl apply -f -
apiVersion: kibana.k8s.elastic.co/v1beta1
kind: Kibana
metadata:
 name: mykibana
 namespace: logging
spec:
 version: 7.4.2
 count: 1
 elasticsearchRef:
 name: elasticsearch
EOF
  1. 获取 Kibana 节点的状态:
$ kubectl get elasticsearch -n logging
NAME     HEALTH NODES VERSION AGE
mykibana green  1     7.4.2   2m27s
  1. 您还可以使用以下命令确认 logging 命名空间中 pod 的状态:
$ kubectl get pods -n logging
NAME                         READY STATUS  RESTARTS AGE
elasticsearch-es-default-0   1/1   Running 0        37m
elasticsearch-es-default-1   1/1   Running 0        37m
elasticsearch-es-default-2   1/1   Running 0        37m
mykibana-kb-7864bfdb45-26lpq 1/1   Running 0        3m36s

有了这个,您已经部署了 Elasticsearch 和 Kibana 节点。接下来,我们将部署 fluent-bit 以将容器日志转发到我们的 Elasticsearch 部署。

使用 Fluent Bit 聚合日志

让我们执行以下步骤来部署 fluent-bit:

  1. 获取默认elastic用户的密码:
$ kubectl get secret elasticsearch-es-elastic-user \
-n logging -o=jsonpath='{.data.elastic}' | base64 --decode; echo
  1. 复制步骤 1的输出,并编辑fluent-bit-values.yaml文件在/src/chapter10/efk目录中。用步骤 1的输出替换http_passwd的值,并保存文件:
backend:
 type: es
 es:
 host: elasticsearch-es-http
 port: 9200
 http_user: elastic
 http_passwd: m2zr9fz49zqbkbpksprf4r76
 # Optional TLS encryption to ElasticSearch instance
 tls: "on"
 tls_verify: "off"
  1. 使用 Helm 图表部署 fluent-bit:
$ helm install stable/fluent-bit --name=fluent-bit --namespace=logging -f fluent-bit-values.yaml
  1. 使用以下命令确认logging命名空间中 pod 的状态:
$ kubectl get pods -n logging
NAME                         READY STATUS  RESTARTS AGE
elasticsearch-es-default-0   1/1   Running 0        158m
elasticsearch-es-default-1   1/1   Running 0        158m
elasticsearch-es-default-2   1/1   Running 0        158m
fluent-bit-249ct             1/1   Running 0        2m11s
fluent-bit-4nb9k             1/1   Running 0        2m11s
fluent-bit-fqtz9             1/1   Running 0        2m11s
fluent-bit-lg9hn             1/1   Running 0        2m11s
mykibana-kb-5596b888b5-qv8wn 1/1   Running 0        115m

有了这个,您已经部署了 EFK 堆栈的所有组件。接下来,我们将连接到 Kibana 仪表板。

在 Kibana 上访问 Kubernetes 日志

让我们执行以下步骤来连接到 Kibana 仪表板:

  1. 确认 Kibana 服务已创建。默认情况下,将创建一个ClusterIP服务:
$ kubectl get service mykibana-kb-http -n logging
  1. 在连接到仪表板之前,获取默认elastic用户的密码:
$ kubectl get secret elasticsearch-es-elastic-user \
-n logging -o=jsonpath='{.data.elastic}' | base64 --decode; echo
  1. 创建一个端口转发服务,以从您的工作站访问 Kibana 仪表板:
$ kubectl port-forward service/mykibana-kb-http 5601
  1. 在浏览器中打开https://localhost:5601的 Kibana 仪表板。输入elastic作为用户名和步骤 2的输出中的密码:

  1. 在主页上,点击“连接到您的 Elasticsarch 索引”按钮,如下截图所示:

  1. Kibana 将搜索 Elasticsearch 索引模式。定义与您的结果匹配的索引模式。在我们的示例中,我们使用了kubernetes_cluster-*。点击“下一步”继续:

  1. 将时间过滤器字段名称指定为@timestamp,然后点击“创建索引模式”按钮,如下面的屏幕截图所示:

  1. 点击“发现”菜单。这是从顶部开始的第一个图标:

  1. 在“发现”页面上,使用搜索字段查找关键字和过滤器:

  1. 如果您要查找的关键字在当前时间范围内找不到,您需要通过点击搜索字段旁边的日历图标并在选择新范围后点击“应用”按钮来更改日期范围:

有了这个,您已经学会了如何在 Kubernetes 集群上配置 EFK 堆栈,以便管理和可视化整个集群的日志。

另请参阅

使用 Google Stackdriver 记录 Kubernetes

在这一部分,我们将使用 Google Stackdriver Kubernetes Engine 监控来监视,隔离和诊断我们的容器化应用程序和微服务环境。您将学习如何使用 Stackdriver Kubernetes Engine 监控来聚合来自 GKE 上 Kubernetes 环境的日志,事件和指标,以帮助您了解您的应用在生产环境中的行为。

准备就绪

确保您有一个准备好的Google Kubernetes EngineGKE)集群,并且已经配置了kubectl来管理集群资源。如果没有,您可以按照第一章中的说明,构建生产就绪的 Kubernetes 集群,在在 Google 云平台上配置 Kubernetes 集群教程中进行操作。

如何操作…

这一部分进一步分为以下小节,以使这个过程更容易:

  • 为 GKE 安装 Stackdriver Kubernetes Engine 监控支持

  • 在 Stackdriver 上配置工作空间

  • 使用 Stackdriver 查看 GKE 日志

为 GKE 安装 Stackdriver Kubernetes Engine 监控支持

启用 Stackdriver 监控支持可以轻松监控 GKE 集群,调试日志,并使用高级分析和跟踪功能分析集群的性能。在这个教程中,我们将启用 Stackdriver Kubernetes Engine 监控支持,以从我们的 GKE 集群收集集群指标。按照以下步骤进行:

  1. 在 Google Kubernetes Engine 控制台上打开console.cloud.google.com/kubernetes。在这个控制台上,您将看到您的 GKE 集群列表。在这里,我们有一个名为k8s-devops-cookbook-1的集群:

  1. 单击集群旁边的小铅笔形状的编辑图标:

  1. 在集群配置页面上,确保Legacy Stackdriver LoggingLegacy Stackdriver Monitoring都为Disabled,并且Stackdriver Kubernetes Engine Monitoring选项设置为Enabled

  1. 单击保存按钮以将这些更改应用到您的集群上。

使用 Stackdriver 查看 GKE 日志

启用 Stackdriver 监控支持可以轻松监控 GKE 集群,调试日志,并使用高级分析和跟踪功能分析集群性能。在这个教程中,我们将学习如何访问我们在 GKE 上的 Kubernetes 集群的日志。按照以下步骤进行:

  1. 从 Google Cloud 控制台,通过访问console.cloud.google.com/logs/viewer来打开 Stackdriver 日志查看器:

  1. 从“资源”菜单中,点击“Kubernetes 容器”选项:

  1. Stackdriver 日志视图将显示所选 GKE 集群中容器的日志列表。在这里,您可以看到最近 7 天的容器日志被显示:

  1. 将日志级别筛选为关键,并将时间范围设置为“最近 24 小时”,以查看最近的关键容器日志。可以在以下截图中看到一个示例结果:

有了这个,您就知道如何使用 Stackdriver 查看 GKE 集群和资源的日志,比如部署在 GKE 集群上的容器。

另请参阅

使用托管的 Kubernetes 日志记录服务

在集群中运行 EFK 堆栈以存储和维护 Kubernetes 日志在您的集群中是有用的,直到集群出现问题。建议您将日志管理系统和生产集群分开,以便在集群故障时可以访问。

在本节中,我们将学习如何使用一些免费的 SaaS 解决方案,即使您的集群不可用,也可以保持集群日志的可访问性。

准备工作

确保您有一个准备好的 Kubernetes 集群,并配置了kubectl来管理集群资源。

如何做…

本节进一步分为以下子节,以使这个过程更容易:

  • 将集群添加到 Director Online

  • 使用 Director Online 访问日志

将集群连接到 Director Online

OpenEBS Director 提供了一个免费的托管 EFK 堆栈作为 SaaS 解决方案,这样您就可以存储和管理您的 Kubernetes 集群日志。在这个教程中,我们将把我们的 Kubernetes 集群添加到 Director SaaS 平台,以便在云中存储我们的日志:

  1. 转到www.mayadata.io以登录到您的 OpenEBS 企业平台,网址为portal.mayadata.io/home

  1. 单击 Connect your Cluster 按钮:

  1. 从主菜单中,选择 Clusters 并单击 Connect a new Cluster 按钮。

  2. 选择您的 Kubernetes 集群位置并命名您的项目。在这里,我们使用了一个 AWS 集群,并将AWSCluster设置为我们的集群名称:

  1. 在您的第一个集群上复制并执行以下命令:

在这样做后不久,Director Online 将在您的集群上部署一个 fluentd 转发器和聚合器,以便在其平台上收集日志。

使用 Director Online 访问日志

OpenEBS Director 的免费计划可存储集群日志长达 1 周。额外的存储空间可通过高级计划获得。在这个教程中,我们将学习如何使用 Director Online 提供的托管 EFK 堆栈来访问日志:

  1. 转到www.mayadata.io以登录到您的 OpenEBS 企业平台,网址为portal.mayadata.io/home

  2. 从主菜单中,选择 Clusters 并选择您的活动集群。

  3. 从左侧菜单中,单击 Logs:

  1. 在 Kibana Discover 仪表板上将打开一个日志视图。在这里,您可以使用 Elasticsearch 和 Kibana 的搜索和过滤功能来管理您的 Kubernetes 日志:

通过这样,您已经学会了如何简单地使用托管的 Kubernetes 日志解决方案保持日志可访问。您可以在多个集群上使用 Director Online,并从单个界面管理日志。

为您的 Jenkins CI/CD 环境记录日志

在繁忙的构建环境中,CI/CD 流水线每天都会产生大量的元数据。Elasticsearch 是从 Jenkins 获取这种数据的完美平台。

在本节中,我们将学习如何启用和访问我们的 Jenkins 实例的日志,并分析团队的效率。

准备工作

本教程中提到的所有操作都需要一个完全功能的 Jenkins 部署,如第三章中所述,“构建 CI/CD 流水线”,在“在 Jenkins X 中设置 CI/CD 流水线”部分。

k8sdevopscookbook/src存储库克隆到您的工作站,以使用chapter10目录中的清单文件:

$ git clone https://github.com/k8sdevopscookbook/src.git
$ cd src/chapter10

确保您有一个 Kubernetes 集群,Jenkins X 和 EFK 堆栈已准备就绪,并且kubectl已配置,以便您可以管理集群资源。

如何操作…

本节将向您展示如何将 Jenkins 日志馈送到 Elasticsearch。本节进一步分为以下子节,以使此过程更容易:

  • 安装 Fluentd 插件

  • 使用 Fluentd 将 Jenkins 日志流式传输到 Elasticsearch

安装 Fluentd 插件

Fluentd 是 EFK 堆栈的一部分,与 Elasticsearch 和 Kibana 一起。它是一个用于构建统一日志层的开源数据收集器。这个教程将向您展示如何为 Jenkins 安装 Fluentd 插件,它将把 Jenkins 日志转发到您的 Fluentd 记录器。

让我们执行以下步骤在 Jenkins 上安装 Fluentd 插件:

  1. 访问您的 Jenkins 服务仪表板,然后点击“管理 Jenkins”菜单:

  1. 在“管理 Jenkins”菜单中,点击“管理插件”按钮:

  1. 点击“可用”选项卡,并在过滤字段中搜索fluentd。结果应该类似于以下内容。点击“无需重启安装”按钮来安装 Fluentd 插件:

Fluentd 插件将在无需重新启动 Jenkins 实例的情况下安装。

使用 Fluentd 将 Jenkins 日志流式传输到 Elasticsearch

在这个教程中,我们将学习如何配置我们在 Jenkins 上安装的 Fluentd 插件。

让我们执行以下步骤将 Jenkins 日志馈送到 Elasticsearch:

  1. 在“管理 Jenkins”菜单中,点击“配置系统”按钮。

  2. 浏览设置。在 Fluentd 设置日志记录器下,输入日志记录器名称。日志记录器名称用作 Fluentd 的前缀。在主机字段中,输入您的 Fluentd 服务的服务名称和暴露的端口号。在我们的示例中,在我们的 Kubernetes 集群中,我们使用稳定的/fluentd Helm 图表来安装 Fluentd。服务名称是fluentd。这通过端口24220暴露。保存更改:

  1. 在管道配置下选择一个作业。

  2. 单击“添加后构建操作”按钮,并从下拉菜单中选择“发送到 Fluentd”选项。

现在,Fluentd 插件将通过日志收集器将日志推送到 Elasticsearch。

还有更多…

如果您在 EFK 堆栈中使用 ELK 堆栈而不是 Fluentd,则请按照此处给出的教程。本节进一步分为以下子节,以使此过程更加简单:

  • 安装 Logstash 插件

  • 使用 Logstash 将 Jenkins 日志流式传输到 Elasticsearch

安装 Logstash 插件

Logstash 是 Elastic Stack 的一部分,与 Beats、Elasticsearch 和 Kibana 一起。它是一个具有实时流水线功能的开源数据收集引擎。在这个教程中,您将学习如何为 Jenkins 安装 Logstash 插件。

让我们执行以下步骤为 Jenkins 安装 Logstash 插件:

  1. 访问您的 Jenkins 服务仪表板,单击“管理 Jenkins”菜单:

  1. 在“管理 Jenkins”菜单中,单击“管理插件”按钮:

  1. 单击“可用”选项卡,并在“筛选”字段中搜索logstash。结果应该类似于以下内容。单击“安装后无需重启”按钮以安装 Logstash 插件:

Logstash 插件将安装,而无需重新启动 Jenkins 实例。

使用 Logstash 将 Jenkins 日志流式传输到 Elasticsearch

在这个教程中,我们将向您展示如何配置您之前在 Jenkins 上安装的 Logstash 插件。

让我们执行以下步骤将 Jenkins 日志馈送到 Elasticsearch:

  1. 在“管理 Jenkins”菜单中,单击“配置系统”按钮。

  2. 滚动查看设置。在 Logstash 设置下,选中“启用发送日志到索引器”复选框。启用此设置后,将打开四个新字段。

  3. 在 URI 字段中,输入服务名称,然后是索引器名称;例如,http://elasticsearch-es-http:9200/logstash/jenkins。输入您的elastic用户名和密码,保存更改:

现在,Logstash 插件将通过日志收集器将日志推送到 Elasticsearch。

另请参阅

posted @ 2024-05-20 11:58  绝不原创的飞龙  阅读(26)  评论(0编辑  收藏  举报