为 Kubernetes 更新应用程序

介绍

现代无状态应用程序被构建并设计为在软件容器中运行,如Docker,并由容器集群管理,如Kubernetes。它们是使用Cloud NativeTwelve Factor]的原则和模式开发的,以最大限度地减少手动干预,最大限度地实现便携性和浪费性。将虚拟机或基于纯金属的应用程序迁移到容器中(称为容器化),并在集群中部署它们,往往涉及这些应用程序的构建,包装和交付方式的重大变化。

基于 Architecting Applications for Kubernetes,在本概念指南中,我们将讨论现代化应用程序的高级别步骤,最终目标是在 Kubernetes 集群中运行和管理它们. 虽然您可以在 Kubernetes 上运行数据库等状态式应用程序,但本指南侧重于迁移和现代化无状态式应用程序,将持久数据下载到外部数据存储中。

准备移民申请

在容器化应用程序或编写 Kubernetes Pod 和部署配置文件之前,您应该实施应用程序级别的更改,以最大限度地实现应用程序在 Kubernetes 中的可移植性和可观察性。

提取配置数据

首先要实施的应用程序级别变更之一是从应用程序代码中提取应用程序配置。 配置包括任何在部署和环境中有所不同的信息,例如服务端点、数据库地址、凭证以及各种参数和选项。 例如,如果您有两个环境,比如阶段化生产,每个环境都包含一个单独的数据库,您的应用程序不应该有数据库端点和凭证在代码中明确表示,而是存储在一个单独的位置,无论是运行环境中的变量,本地文件还是外部关键值存储,从中读入应用程序的值。

将这些参数加密到您的代码中会带来安全风险,因为此配置数据通常由敏感信息组成,然后您将其检查到您的版本控制系统中。 它也增加了复杂性,因为您现在必须维护多个版本的应用程序,每个版本都由相同的核心应用程序逻辑组成,但配置略有不同。

通过从应用程序代码中提取配置值,而不是从运行环境或本地文件中提取它们,您的应用程序成为一种通用、可移植的包,可以部署到任何环境中,只要您提供随附的配置数据。

以下是一个快速示例,展示了如何从 Python Flask应用程序的代码中外包两个配置值「DB_HOST」和「DB_USER」。

 1[label hardcoded_config.py]
 2from flask import Flask
 3
 4DB_HOST = 'mydb.mycloud.com'
 5DB_USER = 'sammy'
 6
 7app = Flask(__name__)
 8
 9@app.route('/')
10def print_config():
11    output = 'DB_HOST: {} -- DB_USER: {}'.format(DB_HOST, DB_USER)
12    return output

运行此应用程序(请参阅 Flask Quickstart以了解如何)并访问其 Web 终端将显示包含这两个配置值的页面。

现在,这里有相同的例子,配置值被外包到应用程序的运行环境:

 1[label env_config.py]
 2import os
 3
 4from flask import Flask
 5
 6DB_HOST = os.environ.get('APP_DB_HOST')
 7DB_USER = os.environ.get('APP_DB_USER')
 8
 9app = Flask(__name__)
10
11@app.route('/')
12def print_config():
13    output = 'DB_HOST: {} -- DB_USER: {}'.format(DB_HOST, DB_USER)
14    return output

在运行应用程序之前,我们在本地环境中设置必要的配置变量:

1export APP_DB_HOST=mydb.mycloud.com
2export APP_DB_USER=sammy
3flask run

显示的 Web 页面应该包含与第一个示例相同的文本,但应用程序的配置现在可以独立于应用程序代码进行修改。

在下一节中,我们将讨论在容器之外移动的应用状态。

关闭应用程序状态

Cloud Native 应用程序在容器中运行,并由像 Kubernetes 或 Docker Swarm 这样的集群软件动态地编排。给定的应用程序或服务可以在多个复制品中负载均衡,任何单个应用程序容器都应该能够失败,对客户端服务的干扰很少或没有。

例如,如果您正在运行一个地址簿应用程序,您的应用程序会从地址簿中添加、删除和修改联系人,地址簿数据存储应该是外部数据库或其他数据存储,而存储在容器内的唯一数据应该是短期性质,并且可以一次性地使用,而不会导致关键信息丢失。

对于需要持久数据存储的状态式应用程序(例如复制的MySQL数据库),Kubernetes建立了将持久区块存储量附加到容器和Pod的功能,以确保Pod在重新启动后能够保持状态并访问相同持久量,必须使用 StatefulSet的工作负载。

无国有容器允许最大限度的可移植性和可用云资源的充分利用,允许Kubernetes计时器快速扩展您的应用程序,并在可用资源的任何地方启动Pods。

要了解有关无国有、云原生微服务的设计和架构的更多信息,请参阅我们的 Kubernetes 白皮书

实施健康检查

在Kubernetes模型中,集群控制平面可以依赖于修复破坏的应用程序或服务。它通过检查应用程序Pod的健康状况,并重新启动或重新安排不健康或不响应的容器。默认情况下,如果您的应用程序容器正在运行,Kubernetes将您的Pod视为健康。在许多情况下,这是运行应用程序的健康状况的可靠指标。然而,如果您的应用程序被锁定了,并且没有执行任何有意义的工作,应用程序流程和容器将继续运行无限期,并且默认情况下,Kubernetes将保持停滞的容器活着。

要正确地将应用程序健康传达给 Kubernetes 控制平板,您应该实施自定义应用程序健康检查,以显示应用程序在运行和接收流量时。第一个类型的健康检查称为 准备探测器,并允许 Kubernetes 知道您的应用程序何时准备接收流量。第二种检查称为 活力探测器,并允许 Kubernetes 知道您的应用程序在运行和健康时。

  • HTTP:Kubelet 探测器对终端执行 HTTP GET 请求(如 /health),如果响应状态在 200 到 399 之间时成功* 容器命令:Kubelet 探测器在运行容器内部执行命令.如果输出代码为 0,则探测器成功
  • TCP:Kubelet 探测器试图在指定端口连接到您的容器。

准备和活力探测器可以使用相同的探测方法并执行相同的检查,但包括准备探测器将确保Pod不会接收流量,直到探测器开始成功。

在规划并考虑容器化应用程序并在Kubernetes上运行时,您应该分配规划时间来定义健康准备对您的特定应用程序意味着什么,以及开发时间来实施和测试终端和/或检查命令。

以下是上述Flask示例的最低健康终点:

 1[label env_config.py]
 2. . .  
 3@app.route('/')
 4def print_config():
 5    output = 'DB_HOST: {} -- DB_USER: {}'.format(DB_HOST, DB_USER)
 6    return output
 7
 8@app.route('/health')
 9def return_ok():
10    return 'Ok!', 200

检查这条路径的Kubernetes活力探测器会看起来像这样:

1[label pod_spec.yaml]
2. . .
3  livenessProbe:
4      httpGet:
5        path: /health
6        port: 80
7      initialDelaySeconds: 5
8      periodSeconds: 2

初始延迟秒字段规定,Kubernetes(特别是节点Kubelet)应在等待5秒后扫描/health终端点,而periodSeconds则告诉Kubelet每2秒扫描/health

有关活力和准备探测器的更多信息,请参阅 Kubernetes 文档

登记和监控工具代码

当您在 Kubernetes 等环境中运行容器化应用程序时,发布远程测量和日志数据对于监控和调试应用程序的性能至关重要。

您可以使用的一个工具来监控您的服务是 Prometheus,一个由云原生计算基金会(CNCF)托管的开源系统监控和警报工具包。 Prometheus 提供几个客户端库,用于用不同类型的指标来仪表您的代码来计算事件及其持续时间。例如,如果您正在使用 Flask Python 框架,您可以使用 Prometheus Python 客户端将装饰器添加到您的请求处理功能中,以跟踪处理请求所花费的时间。

在设计应用程序仪表时,一个有用的方法是红色方法,它由以下三个关键请求指标组成:

  • 率:您的申请收到请求的数量
  • 错误:您的应用程序发出的错误的数量
  • 持续时间:您的应用程序提供响应所需的时间

此最小的指标组合应该为您提供足够的数据,以便在应用程序的性能下降时生成警报。 实施此仪表以及上述健康检查将使您能够快速检测和从失败的应用程序中恢复。

有关监控应用程序时要测量的信号的详细信息,请参阅 Google 网站可靠性工程书中的 监控分布式系统

除了思考和设计发布远程测量数据的功能外,您还应该决定您的应用程序将如何在分布式集群环境中登录。理想情况下,您应该删除对本地日志文件和日志目录的硬代码配置引用,并直接登录到stdoutstderr。您应该将日志视为连续事件流或时间排序事件序列。此输出流将被包装您的应用程序的容器捕获,从那里可以转移到像EFK(Elasticsearch, Fluentd和Kibana)堆栈这样的日志层。

构建管理逻辑到 API

一旦您的应用程序被集装,并在像Kubernetes这样的集群环境中运行,您可能不再可以访问运行您的应用程序的集装箱。如果您已经实施了适当的健康检查,记录和监控,您可以很快被警告和调试生产问题,但在重新启动和重新部署集装箱之外采取行动可能很困难。对于快速的操作和维护修复,如排队或清除缓存,您应该实施适当的API终端,以便您可以执行这些操作,而无需重新启动集装箱或docker exec进入运行容器。

摘要

在这些节中,我们讨论了在将您的应用程序集装到 Kubernetes 之前可能想要实施的应用程序级别的更改,如需深入了解如何构建 Cloud Native 应用程序,请参阅 Architecting Applications for Kubernetes

现在我们将讨论一些考虑在为您的应用构建容器时要记住的因素。

容器化您的应用程序

现在你已经实现了应用逻辑,以最大限度地在基于云的环境中实现可移动性和可观察性,现在是时候将应用程序包装到容器中了。

明确宣告依赖性

在为您的应用程序创建 Dockerfile 之前,第一步之一是评估您的应用程序需要正确运行的软件和操作系统依赖性。Dockerfiles 允许您明确版本每个安装在图像中的软件,您应该通过明确声明母图像、软件库和编程语言版本来利用此功能。

尽量避免最新的标签和未版本的包,因为这些包可以更改,可能破坏您的应用程序。

若要了解有关设置私人图像注册表的更多信息,请参阅Docker官方文档中的 部署注册表服务器和下面的 注册表部分。

保持图像尺寸小

在部署和拉动容器图像时,大图像可以显著减速并增加带宽成本。

  • 减少图像大小
  • 加快图像构建
  • 减少容器启动延迟
  • 加快图像传输时间
  • 通过减少攻击表面 提高安全性

您可以考虑在构建您的图像时的一些步骤:

  • 使用最小的基础操作系统图像,如alpine或从cratch构建,而不是像ubuntu这样的功能齐全的操作系统
  • 安装软件后清理不必要的文件和文物
  • 使用单独的buildruntime容器来保持生产应用程序容器小
  • 忽略在大目录中复制时不必要的构建文物和文件

有关优化 Docker 容器的完整指南,包括许多示范示例,请参阅 构建 Kubernetes 的优化容器

注射配置

Docker 提供了几个有用的功能,用于将配置数据注入到应用程序的运行环境中。

这样做的一个选项是使用ENV语句在Dockerfile中指定环境变量及其值,以便配置数据嵌入到图像中:

1[label Dockerfile]
2...
3ENV MYSQL_USER=my_db_user
4...

然后,您的应用程序可以从其运行环境中分析这些值,并相应地配置其设置。

您也可以通过环境变量作为参数,当使用docker run-e旗启动容器时:

1docker run -e MYSQL_USER='my_db_user' IMAGE[:TAG]

最后,您可以使用 env 文件,其中包含环境变量和它们的值列表. 要做到这一点,创建该文件并使用 --env-file 参数将其传输到命令中:

1docker run --env-file var_list IMAGE[:TAG]

如果您正在现代化应用程序以使用像 Kubernetes 这样的集群管理器运行,您应该进一步从图像中外包配置,并使用 Kubernetes 内置的 ConfigMap秘密对象管理配置。

将图片发布到注册表

一旦你建立了你的应用程序图像,让它们可用于Kubernetes,你应该将它们上传到一个容器图像注册表. 公共注册表,如 Docker Hub 托管最新的Docker图像为受欢迎的开源项目,如 Node.jsnginx. 私人注册表允许你发布你的内部应用程序图像,使它们可用于开发人员和基础设施,但不是更广泛的世界。

您可以使用现有的基础设施部署私人注册表(例如在云对象存储上),或者可选地使用多个 Docker 注册表产品之一,例如 Quay.io或付费 Docker Hub 计划。

为了对您的集装箱图像的构建和测试以及标签和发布进行更多控制,您可以实施连续集成(CI)管道。

构建一个管道

手动构建、测试、发布和部署您的图像进入生产可能容易出现错误,并且不会扩展得很好. 要管理构建和连续发布包含您最新的代码更改的容器到您的图像注册表,您应该使用构建管道。

大多数建筑管道执行以下核心功能:

  • 查看源代码存储库进行更改
  • 对修改代码运行烟雾和单元测试
  • 构建包含修改代码的容器图像
  • 使用嵌入式容器图像 进行进一步集成测试* 如果测试通过,标记和发布图像到注册表
  • (可选,在连续部署设置中) 更新 Kubernetes 部署并将图像部署到舞台/生产集群

有许多付费的连续集成产品具有与GitHub等流行的版本控制服务和像Docker Hub这样的图像注册表的内置集成,这些产品的替代品是 Jenkins,一个免费的和开源的构建自动化服务器,可以配置以执行上述所有功能。

实行集装箱仓储和监控

在使用集装箱时,重要的是要考虑您将使用的日志基础设施来管理和存储所有运行和停止的集装箱的日志,您可以使用多个集装箱级别的模式来日志,以及多个 Kubernetes级别的模式。

在Kubernetes中,默认容器使用json-fileDocker logging driver,它捕获 stdout 和 stderr 流,并将其写入容器正在运行的节点上的 JSON 文件中。有时,直接登录到 stderr 和 stdout 可能对您的应用程序容器不够,并且您可能希望将应用程序容器与 Kubernetes Pod 中的 logging sidecar 容器相配。 此 sidecar 容器可以从文件系统、本地接口或 systemd 日志上收集日志,从而为您提供比仅仅使用 stderr 和 stdout 流更大的灵活性。 此容器还可以进行一些处理,然后流丰富的日志到 stutdout/derst

对于单一用途的微服务,直接登录到 stdout/stderr 并让 Kubernetes 接收这些流是建议的方法,因为您可以利用kubectl logs命令从 Kubernetes 部署的容器访问日志流。

类似于日志,你应该开始考虑在集装箱和集群环境中进行监控。Docker 提供有用的docker 统计命令来抓住CPU和内存使用情况等标准指标,在主机上运行集装箱,并通过 Remote REST API曝光更多指标。

然而,在多节点的多容器生产环境中,更复杂的指标堆栈,如Prometheus(https://prometheus.io/)和Grafana(https://grafana.com/)可能有助于组织和监控您的容器性能数据。

摘要

在这些部分中,我们简要讨论了一些建筑容器的最佳实践,设置一个CI/CD管道和图像注册表,以及增加容器的可观性的一些考虑。

在下一节中,我们将探索Kubernetes的功能,允许您在集群中运行和扩展您的集装箱应用程序。

在 Kubernetes 上部署

此时,您已经集装了应用程序,并实施了逻辑,以最大限度地在云原生环境中实现可移植性和可观察性,现在我们将探索 Kubernetes 功能,这些功能为您在 Kubernetes 集群中管理和扩展应用程序提供了界面。

编写部署和Pod配置文件

一旦你集装了你的应用程序并将其发布到注册表中,你现在可以使用 Pod 工作负载将其部署到 Kubernetes 集群中。 Kubernetes 集群中最小的可部署单元不是一个集装箱,而是一个 Pod. Pods 通常由一个应用程序集装箱(如一个集装的 Flask Web 应用程序)或一个应用程序集装箱和任何侧面车集装箱组成,这些集装箱执行一些辅助功能,如监控或登记。

插件通常使用部署,这是由YAML文件定义的控制器,声明特定想要的状态。例如,一个应用状态可以运行FlaskWeb应用程序容器的三个复制品,并暴露端口8080。一旦创建,控制平面会逐步带来集群的实际状态,以匹配部署中声明的预期状态,通过按需要将集装箱安排到节点上。要将集群中运行的应用程序复制品的数量扩展到3到5,你会更新部署配置文件的复制品字段,然后kubectl应用新配置文件。使用这些配置文件,扩展和部署操作都可以使用现有源控制和服务进行跟踪和版本。

以下是 Flask 应用程序的 Kubernetes 部署配置文件示例:

 1[label flask_deployment.yaml]
 2apiVersion: apps/v1
 3kind: Deployment
 4metadata:
 5  name: flask-app
 6  labels:
 7    app: flask-app
 8spec:
 9  replicas: 3
10  selector:
11    matchLabels:
12      app: flask-app
13  template:
14    metadata:
15      labels:
16        app: flask-app
17    spec:
18      containers:
19      - name: flask
20        image: sammy/flask_app:1.0
21        ports:
22        - containerPort: 8080

此部署启动了 3 个 Pods,运行一个名为flask的容器,使用sammy/flask_app图像(版本1.0)打开端口8080

有关 Kubernetes Pods 和部署的更多信息,请参阅官方 Kubernetes 文档的 PodsDeployments部分。

配置存储

Kubernetes 使用 Volumes、Persistent Volumes (PV) 和 Persistent Volume Claims (PVC) 管理 Pod 存储。Volumes 是 Kubernetes 抽象用于管理 Pod 存储,并支持大多数云提供商的区块存储提供,以及托管正在运行的 Pods 的节点上的本地存储。

例如,如果你的Pod包含两个NGINX容器,需要在它们之间共享数据(例如,第一个被称为nginx服务于网页,第二个被称为nginx-sync从外部位置获取网页并更新由nginx容器服务的网页),你的Pod规格会看起来像这样(在这里我们使用空Dir(https://kubernetes.io/docs/concepts/storage/volumes/#emptydir)卷类型):

 1[label pod_volume.yaml]
 2apiVersion: v1
 3kind: Pod
 4metadata:
 5  name: nginx
 6spec:
 7  containers:
 8  - name: nginx
 9    image: nginx
10    volumeMounts:
11    - name: nginx-web
12      mountPath: /usr/share/nginx/html
13
14  - name: nginx-sync
15    image: nginx-sync
16    volumeMounts:
17    - name: nginx-web
18      mountPath: /web-data
19
20  volumes:
21  - name: nginx-web
22    emptyDir: {}

我们为每个容器使用volumeMount,表示我们希望将包含网页文件的nginx-web卷放在nginx容器中的/usr/share/nginx/htmlnginx-sync容器中的/web-data上。

类似的方式,您可以通过将类型从空Dir修改为相应的云存储卷类型来配置Pod存储使用云块存储产品。

一个 Volume 的生命周期与 Pod 的生命周期有关,而不是集装箱的生命周期。如果一个 Pod 中的集装箱死亡,则 Volume 仍然存在,新启动的集装箱将能够安装相同的 Volume 并访问其数据。

要在 Pod 重启和更新中保存数据,必须使用 PersistentVolume (PV) 和 PersistentVolumeClaim (PVC) 对象。

PersistentVolumes 是代表永久存储的零件的抽象,如云区块存储量或 NFS 存储量。它们是与 PersistentVolumeClaims 分开创建的,这是开发人员对存储量的要求。 在他们的 Pod 配置中,开发人员使用 PVC 要求永久存储,而 Kubernetes 与可用的 PV 卷相匹配(如果使用云区块存储,Kubernetes 可以在创建 PersistentVolumeClaims 时动态地创建 PersistentVolumes)。

如果您的應用程式需要每個複製單一持久卷,這在許多資料庫中是如此,您不應該使用部署,而是使用 StatefulSet 控制器,該控制器是為需要穩定的網路識別碼、穩定的持久儲存和訂單保證的應用程式設計的。

有关 StatefulSet 控制器的更多信息,请参阅 Kubernetes 文档。 有关 PersistentVolumes 和 PersistentVolume 声称的更多信息,请参阅 Kubernetes 存储 文档

使用 Kubernetes 注入配置数据

与 Docker 类似,Kubernetes 提供了envenvFrom字段,用于在 Pod 配置文件中设置环境变量。

 1[label sample_pod.yaml]
 2...
 3    spec:
 4      containers:
 5      - name: nginx
 6        image: nginx:1.21.6
 7        ports:
 8        - containerPort: 80
 9        env:
10        - name: HOSTNAME
11          value: my_hostname
12...

这允许您将配置从 Dockerfiles 移动到 Pod 和部署配置文件。进一步从 Dockerfiles 外包配置的关键优点是,您现在可以将这些 Kubernetes 工作负载配置(例如,将HOSTNAME值更改为my_hostname_2)从应用程序容器定义单独修改到。一旦您更改了 Pod 配置文件,您可以使用其新环境重新部署 Pod,而底层容器图像(通过其 Dockerfile 定义)不需要重建、测试和推到一个存储库。

Kubernetes 提供了进一步外包和管理配置数据的另一个构造: ConfigMaps 和 Secrets。

ConfigMaps和秘密

ConfigMaps 允许您将配置数据保存为对象,然后将其引用到您的 Pod 和部署配置文件中,以便您可以避免硬编码配置数据,并在 Pod 和部署中重复使用。

以下是一個例子,從上方使用Pod config。我們先將「HOSTNAME」環境變量儲存為ConfigMap,然後在Pod config中引用:

1kubectl create configmap hostname --from-literal=HOSTNAME=my_host_name

为了从Pod配置文件中引用它,我们使用valueFromconfigMapKeyRef构造:

 1[label sample_pod_configmap.yaml]
 2...
 3    spec:
 4      containers:
 5      - name: nginx
 6        image: nginx:1.21.6
 7        ports:
 8        - containerPort: 80
 9        env:
10        - name: HOSTNAME
11          valueFrom:
12            configMapKeyRef:
13              name: hostname
14              key: HOSTNAME
15...

因此,HOSTNAME环境变量的值已经从配置文件中完全外包化,然后我们可以在所有部署和Pod上更新这些变量,引用它们,并重新启动Pod,以便更改生效。

如果您的应用程序使用配置文件,则 ConfigMaps 还允许您将这些文件存储为 ConfigMap 对象(使用 --from-file 旗帜),然后您可以将其装入容器作为配置文件。

秘密提供与 ConfigMaps 相同的基本功能,但应该用于敏感数据,如数据库凭据,因为这些值是 base64 加密的。

有关 ConfigMaps 和秘密的更多信息,请参阅 Kubernetes 文档

创建服务

一旦你的应用程序在Kubernetes中运行,每个Pod将被分配一个(内部)IP地址,由其容器共享。如果这些Pod之一被删除或死亡,新启动的Pod将被分配不同的IP地址。

对于将功能暴露于内部和/或外部客户端的长期服务,您可能希望为执行相同功能(或部署)的 Pods 提供一个稳定的 IP 地址,该 IP 地址可在其容器上负荷平衡请求。

Kubernetes 服务有 4 种类型,由服务配置文件中的类型字段指定:

  • ClusterIP: 这是默认类型,该类型为服务提供从集群中的任何地方可访问的稳定内部IP
  • NodePort: 此方法将您的服务暴露在每个节点上的静态端口中,默认情况下在 30000-32767 之间。 当请求触及节点的 Node IP 地址和您的服务的 NodePort时,请求将负载平衡并路由到您的服务的应用容器
  • LoadBalancer: 这将使用云提供商的负载平衡产品创建负载平衡器,并为您的服务配置一个 NodePortClusterIP,向其外部请求将被路由
  • `外

请注意,为您集群中运行的每个部署创建一个类型的负载平衡器服务将为每个服务创建一个新的云负载平衡器,这可能会变得昂贵。使用单个负载平衡器来管理向多个服务的外部请求,您可以使用 Ingress 控制器。 Ingress 控制器超出本文的范围,但要了解更多信息,您可以参阅 Kubernetes 文档

以下是本指南的 Pods 和部署(https://andsky.com/tech/tutorials/modernizing-applications-for-kubernetes#write-deployment-and-pod-configuration-files)部分中使用的 Flask 示例的服务配置文件:

 1[label flask_app_svc.yaml]
 2apiVersion: v1
 3kind: Service
 4metadata:
 5  name: flask-svc
 6spec:
 7  ports:
 8  - port: 80
 9    targetPort: 8080
10  selector:
11    app: flask-app
12  type: LoadBalancer

在这里,我们选择使用这个flask-svc服务曝光flask-app部署,我们创建了一个云负荷平衡器,将流量从负荷平衡器端口 80 到曝光容器端口 8080 路由。

若要了解有关 Kubernetes 服务的更多信息,请参阅 Kubernetes 文档的 服务部分。

木材和监控

通过单个集装箱和Pod日志使用kubectl日志docker日志进行分析可能会随着运行应用程序的数量的增加而变得无聊。 为了帮助您调试应用程序或群集问题,您应该实施集中日志。 在高层次上,这包括在所有工作节点上运行的代理程序,这些代理程序处理Pod日志文件和流,用元数据丰富它们,并将日志转移到像 Elasticsearch这样的后端。

在集装箱级登录部分中,我们讨论了 Kubernetes 推荐的方法,即将集装箱中的应用程序登录到 stdout/stderr 流中。我们还简要讨论了登录的 sidecar 容器,这些容器在从您的应用程序登录时可以为您提供更多的灵活性。您还可以直接在您的 Pods 中运行登录代理来捕获本地登录数据,并将其直接传送到您的登录后端。每个方法都有其优点和缺点,以及资源利用交易(例如,在每个 Pod 中运行登录代理容器可以变得资源密集,并迅速压倒您的登录后端)。

在一个标准的设置中,每个节点运行一个日志代理,如 FilebeatFluentd以采集由Kubernetes创建的集装箱日志。请记住,Kubernetes为节点上的集装箱创建了JSON日志文件(在大多数安装中,这些可以找到在 /var/lib/docker/containers/)。这些应该通过一个工具如logrotate进行旋转。节点日志代理应该作为一个 DaemonSet Controller运行,这是一种Kubernetes工作负载类型,确保每个节点运行DaemonSet Pod的副本。在这种情况下,节点将包含登录代理及其配置,该代理将从文件中处理日志,并安装到登

类似于使用kubectl日志来调试容器问题的瓶颈,最终你可能需要考虑一个更强大的选择,而不是简单地使用kubectl 顶部Kubernetes 仪表板来监控群集上的 Pod 资源使用情况。集群和应用级监控可以使用Prometheus(https://prometheus.io/)监控系统和时间序列数据库,以及Grafana(https://github.com/grafana/grafana)计量仪表板设置。Prometheus 使用模型工作,该模型会将 HTTP 终端点(如/metrics/cadvisor在节点上,或/metrics应用程序的 REST API 终端点)定期用于计量数据,然后处理和存储。然后可以使用 Grafana 仪表板进行分析

为了增加弹性,您可能希望在单独的 Kubernetes 集群上运行您的日志和监控基础设施,或使用外部日志和指标服务。

结论

将应用程序迁移和现代化,以便在Kubernetes群集中有效地运行,通常涉及计划和架构软件和基础设施的变化。一旦实施,这些更改允许服务所有者不断部署其应用程序的新版本,并根据需要轻松扩展它们,使用最少的手动干预措施。从应用程序中外包配置、设置适当的日志和指标发布和配置健康检查等步骤允许您充分利用Kubernetes设计的云原生范式。

Published At
Categories with 技术
comments powered by Disqus