现代无状态应用程序的构建和设计可在Docker等软件容器中运行,并由Kubernetes等容器集群管理。它们使用Cloud Native和Twelve Factor原则和模式开发,以最大限度地减少人工干预并最大限度地提高可移植性和冗余性。将基于虚拟机或基于裸机的应用程序迁移到容器(称为“容器化”)并在集群内部署这些应用程序通常会导致这些应用程序的构建,打包和交付方式发生重大变化。
在本概念指南中,我们将讨论使应用程序现代化的高级步骤,最终目标是在Kubernetes集群中运行和管理它们。虽然您可以在Kubernetes上运行像数据库这样的有状态应用程序,但本指南主要关注迁移和现代化无状态应用程序,并将持久数据卸载到外部数据存储。Kubernetes提供了有效管理和扩展无状态应用程序的高级功能,我们将探索在Kubernetes上运行可扩展,可观察和可移植应用程序所需的应用程序和基础架构更改。
在容纳您的应用程序或编写Kubernetes Pod和部署配置文件之前,您应该实现应用程序级更改,以最大化您在Kubernetes中的应用程序的可移植性和可观察性。Kubernetes是一个高度自动化的环境,可以自动部署和重新启动失败的应用程序容器,因此构建适当的应用程序逻辑以与容器协调器进行通信并允许它根据需要自动扩展应用程序非常重要。
要实现的第一个应用程序级更改之一是从应用程序代码中提取应用程序配置。配置包括在部署和环境中不同的任何信息,例如服务端点,数据库地址,凭据以及各种参数和选项。举例来说,如果你有两个环境,命名为staging
和production
,每个包含一个单独的数据库,应用程序应该不会有数据库端点和凭据在代码中明确声明,而是存储在单独的位置,无论是在运行环境变量,本地文件或外部键值存储,从中将值读入应用程序。
将这些参数硬编码到代码中会带来安全风险,因为此配置数据通常由敏感信息组成,然后您可以将这些信息签入到版本控制系统中。它还会增加复杂性,因为您现在必须维护应用程序的多个版本,每个版本都包含相同的核心应用程序逻辑,但配置略有不同。随着应用程序及其配置数据的增长,硬编码配置到应用程序代码中很快变得难以处理。
通过从应用程序代码中提取配置值,而不是从运行环境或本地文件中提取它们,您的应用程序将成为可以部署到任何环境中的通用便携式程序包,前提是您提供随附的配置数据。像Docker这样的容器软件和像Kubernetes这样的集群软件就是围绕这个范例设计的,它构建了用于管理配置数据并将其注入应用程序容器的功能。
这是一个快速示例,演示如何外部化两个配置值DB_HOST
以及DB_USER
简单的Python Flask应用程序代码。我们将在应用程序的运行环境中将它们作为env vars提供,应用程序将从中读取它们:
from flask import Flask
DB_HOST = 'mydb.mycloud.com'
DB_USER = 'sammy'
app = Flask(__name__)
@app.route('/')
def print_config():
output = 'DB_HOST: {} -- DB_USER: {}'.format(DB_HOST, DB_USER)
return output
运行这个简单的应用程序(请参阅Flask快速入门以了解如何)并访问其Web端点将显示包含这两个配置值的页面。
现在,这是与应用程序运行环境外部化的配置值的相同示例:
import os
from flask import Flask
DB_HOST = os.environ.get('APP_DB_HOST')
DB_USER = os.environ.get('APP_DB_USER')
app = Flask(__name__)
@app.route('/')
def print_config():
output = 'DB_HOST: {} -- DB_USER: {}'.format(DB_HOST, DB_USER)
return output
在运行应用程序之前,我们在本地环境中设置必要的配置变量:
export APP_DB_HOST=mydb.mycloud.com
export APP_DB_USER=sammy
flask run
显示的网页应包含与第一个示例中相同的文本,但现在可以独立于应用程序代码修改应用程序的配置。您可以使用类似的方法从本地文件中读取配置参数。
在下一节中,我们将讨论在容器之外移动应用程序状态。
Cloud Native应用程序在容器中运行,并由Kubernetes或Docker Swarm等集群软件动态编排。给定的应用程序或服务可以在多个副本之间进行负载平衡,并且任何单个应用程序容器都应该能够失败,而客户端的服务中断很少或没有中断。要实现这种水平,冗余扩展,应用程序必须以无状态方式设计。这意味着它们响应客户端请求而不在本地存储持久性客户端和应用程序数据,并且在任何时间点如果正在运行的应用程序容器被销毁或重新启动,关键数据不会丢失。
例如,如果您正在运行地址簿应用程序并且您的应用程序添加,删除和修改地址簿中的联系人,则地址簿数据存储应该是外部数据库或其他数据存储,并且容器内存中保存的唯一数据应该是短期性质,一次性没有严重的信息损失。在会话等用户访问中持续存在的数据也应该移至Redis等外部数据存储中。只要有可能,您应该将应用程序中的任何状态卸载到托管数据库或缓存等服务。
对于需要持久数据存储(如复制的MySQL数据库)的有状态应用程序,Kubernetes内置了将持久块存储卷附加到容器和Pod的功能。要确保Pod在重新启动后可以维护状态并访问同一个持久卷,必须使用StatefulSet工作负载。StatefulSets非常适合将数据库和其他长期运行的数据存储部署到Kubernetes。
无状态容器实现了最大的可移植性和充分利用可用的云资源,允许Kubernetes调度程序快速扩展您的应用程序,并在资源可用的任何地方启动Pod。如果您不需要StatefulSet工作负载提供的稳定性和排序保证,则应使用Deployment工作负载来管理和扩展应用程序。
在Kubernetes模型中,可以依赖集群控制平面来修复损坏的应用程序或服务。它通过检查应用程序Pod的运行状况,重新启动或重新安排不健康或无响应的容器来实现此目的。默认情况下,如果您的应用程序容器正在运行,Kubernetes会将您的Pod视为“健康”。在许多情况下,这是运行应用程序运行状况的可靠指标。但是,如果您的应用程序已死锁且未执行任何有意义的工作,则应用程序进程和容器将继续无限期运行,默认情况下,Kubernetes将使停滞的容器保持活动状态。
要将应用程序运行状况正确地传递给Kubernetes控制平面,您应该实现自定义应用程序运行状况检查,以指示应用程序何时运行并准备好接收流量。第一种类型的运行状况检查称为准备情况调查,并让Kubernetes知道您的应用程序何时准备好接收流量。第二种类型的检查称为活动探测,让Kubernetes知道您的应用程序何时运行正常。Kubelet Node代理可以使用3种不同的方法在运行Pod上执行这些探测:
/health
)执行HTTP GET请求,如果响应状态在200到399之间,则成功您应该根据正在运行的应用程序,编程语言和框架选择适当的方法。准备和活动探测器都可以使用相同的探测方法并执行相同的检查,但是包含准备探测将确保Pod在探测开始成功之前不接收流量。
在计划和考虑将应用程序容纳在Kubernetes中并将其运行时,您应该分配计划时间来定义特定应用程序的“健康”和“就绪”含义,以及实现和测试端点和/或检查命令的开发时间。
这是上面引用的Flask示例的最小健康端点:
. . .
@app.route('/')
def print_config():
output = 'DB_HOST: {} -- DB_USER: {}'.format(DB_HOST, DB_USER)
return output
@app.route('/health')
def return_ok():
return 'Ok!', 200
检查此路径的Kubernetes活性探针将看起来像这样:
. . .
livenessProbe:
httpGet:
path: /health
port: 80
initialDelaySeconds: 5
periodSeconds: 2
initialDelaySeconds
字段指定Kubernetes(特别是Node Kubelet)应该在等待5秒后探测/health
端点,periodSeconds
告诉Kubelet每2秒进行一次探测 /health
。
要了解有关活体和准备情况探测的更多信息,请参阅Kubernetes文档。
在像Kubernetes这样的环境中运行容器化应用程序时,发布遥测和记录数据以监控和调试应用程序的性能非常重要。构建功能以发布响应持续时间和错误率等性能指标将帮助您监控应用程序并在应用程序运行状况不佳时提醒您。
可用于监控服务的一个工具是Prometheus,一个由云原生计算基金会(CNCF)托管的开源系统监控和警报工具包。Prometheus提供了多个客户端库,用于使用各种度量标准类型检测代码,以计算事件及其持续时间。例如,如果您使用的是Flask Python框架,则可以使用Prometheus Python客户端将装饰器添加到请求处理函数中,以跟踪处理请求所花费的时间。然后,Prometheus可以在HTTP端点上删除这些指标(例如/metrics
)。
在设计应用程序的工具时使用的有用方法是RED方法。它由以下三个关键请求指标组成:
这个最小的度量标准应该为您提供足够的数据,以便在应用程序性能下降时发出警报。实现此检测以及上面讨论的运行状况检查将允许您快速检测并从发生故障的应用程序中恢复。
除了考虑和设计用于发布遥测数据的功能之外,您还应该规划应用程序如何在基于群集的分布式环境中登录。理想情况下,您应该删除对本地日志文件和日志目录的硬编码配置引用,而是直接登录到stdout和stderr。您应该将日志视为连续事件流或时间顺序事件序列。然后,包含应用程序的容器将捕获此输出流,然后可以将其转发到日志层,如EFK(Elasticsearch,Fluentd和Kibana)堆栈。Kubernetes在设计日志记录体系结构时提供了很大的灵活性,我们将在下面详细介绍。
一旦您的应用程序在Kubernetes等集群环境中进行了容器化并启动并运行,您就可能无法再运行运行应用程序的容器。如果您已经实施了足够的运行状况检查,日志记录和监视,则可以快速收到警报并调试生产问题,但是在重新启动和重新部署容器之后采取措施可能会很困难。对于快速操作和维护修复,如刷新队列或清除缓存,您应该实现适当的API端点,以便您可以执行这些操作,而无需重新启动容器或exec
进入运行容器并执行一系列命令。应将容器视为不可变对象,并应在生产环境中避免手动管理。如果必须执行一次性管理任务(如清除缓存),则应通过API公开此功能。
在这些部分中,我们讨论了在将应用程序容纳并将其移至Kubernetes之前您可能希望实现的应用程序级更改。
我们现在将讨论在为应用程序构建容器时要记住的一些注意事项。
现在您已经实现了应用程序逻辑,以便在基于云的环境中最大化其可移植性和可观察性,现在是时候将应用程序打包到容器中了。出于本指南的目的,我们将使用Docker容器,但您应该使用最适合您的生产需求的容器实现。
在为应用程序创建Dockerfile之前,首要步骤之一是评估应用程序正确运行所需的软件和操作系统依赖关系。Dockerfiles允许您显式地对安装在映像中的每个软件进行版本化,您应该通过明确声明父映像,软件库和编程语言版本来利用此功能。
latest
尽可能避免标记和未版本化的包,因为这些可能会发生变化,从而可能会破坏您的应用程序。您可能希望创建公共注册表的私有注册表或私有镜像,以对图像版本控制施加更多控制,并防止上游更改无意中破坏您的图像构建。
要了解更多关于建立一个私人的图像注册表,请部署注册服务器从Docker 的正式文件和注册机构下面的部分。
在部署和提取容器映像时,大型映像会显着减慢速度并增加带宽成本。将最少的工具和应用程序文件打包到图像中可以带来以下好处:
构建图像时可以考虑的一些步骤:
alpine
,scratch
而不是使用像这样的全功能操作系统ubuntu
Docker提供了一些有用的功能,用于将配置数据注入到应用程序的运行环境中。
执行此操作的一个选项是使用ENV
语句在Dockerfile中指定环境变量及其值,以便配置数据内置于图像:
...
ENV MYSQL_USER=my_db_user
...
然后,您的应用可以从其运行环境中解析这些值并相应地配置其设置。
使用docker run
和-e
标志启动容器时,您还可以将环境变量作为参数传递:
docker run -e MYSQL_USER='my_db_user' IMAGE[:TAG]
最后,您可以使用env文件,其中包含环境变量及其值的列表。为此,请创建该文件并使用--env-file
参数将其传递给命令:
docker run --env-file var_list IMAGE[:TAG]
如果要使用像Kubernetes这样的集群管理器对应用程序进行现代化操作,则应进一步从映像外部化配置,并使用Kubernetes的内置ConfigMap和Secrets对象管理配置。这允许您将配置与映像清单分开,以便您可以单独管理应用程序并对其进行版本控制。
一旦构建了应用程序映像,为了使它们可供Kubernetes使用,您应该将它们上载到容器映像注册表。像Docker Hub这样的公共注册中心为Node.js和nginx等流行的开源项目提供最新的Docker镜像。私有注册表允许您发布内部应用程序映像,使其可供开发人员和基础架构使用,但不适用于更广泛的世界。
您可以使用现有基础架构部署私有注册表(例如,在云对象存储之上),也可以选择使用Quay.io或付费Docker Hub计划等多种Docker注册表产品之一。这些注册表可以与托管版本控制服务(如GitHub)集成,以便在更新和推送Dockerfile时,注册表服务将自动提取新的Dockerfile,构建容器映像,并使更新的映像可用于您的服务。
为了更好地控制容器映像的构建和测试以及标记和发布,您可以实现持续集成(CI)管道。
手动构建,测试,发布和部署图像可能容易出错,并且无法很好地扩展。要管理构建并将包含最新代码更改的容器连续发布到映像注册表,您应该使用构建管道。
大多数构建管道执行以下核心功能:
有许多付费的持续集成产品,它们与流行的版本控制服务(如GitHub)和图像注册表(如Docker Hub)内置集成。这些产品的替代品是Jenkins,这是一个免费的开源构建自动化服务器,可以配置为执行上述所有功能。
使用容器时,考虑将用于管理和存储所有正在运行和已停止的容器的日志的日志记录基础结构非常重要。您可以使用多个容器级别模式进行日志记录,还可以使用多个Kubernetes级别模式。
在Kubernetes中,默认情况下,容器使用json-file
Docker 日志记录驱动程序,该驱动程序捕获stdout和stderr流并将它们写入运行容器的节点上的JSON文件。有时直接登录到stderr和stdout对于您的应用程序容器来说可能不够,并且您可能希望将应用程序容器与日志记录边车配对Kubernetes Pod中的容器。然后,此sidecar容器可以从文件系统,本地套接字或systemd日志中获取日志,从而使您比仅使用stderr和stdout流更具灵活性。此容器还可以执行一些处理,然后将富集的日志流式传输到stdout / stderr,或直接流式传输到日志记录后端。
应用程序在容器级别的日志记录将取决于其复杂程度。对于简单的单用途微服务,直接记录到stdout / stderr并让Kubernetes选择这些流是推荐的方法,因为您可以利用该kubectl logs
命令从Kubernetes部署的容器访问日志流。
与日志记录类似,您应该开始考虑在容器和基于群集的环境中进行监视。Docker提供了有用的docker stats
命令,用于获取在主机上运行容器的CPU和内存使用等标准指标,并通过Remote REST API公开更多指标。此外,开源工具cAdvisor(默认情况下安装在Kubernetes Nodes上)提供了更高级的功能,如历史度量标准收集,度量标准数据导出以及用于对数据进行排序的有用Web UI。
但是,在多节点,多容器生产环境中,更复杂的指标堆栈(如Prometheus和Grafana)可能有助于组织和监控容器的性能数据。
在这些部分中,我们简要讨论了构建容器,设置CI / CD管道和映像注册表的一些最佳实践,以及提高容器可观察性的一些注意事项。
在下一节中,我们将探索Kubernetes功能,允许您在群集中运行和扩展容器化应用程序。
此时,您已经将应用程序和实现的逻辑容器化,以最大化其在Cloud Native环境中的可移植性和可观察性。我们现在将探索Kubernetes功能,这些功能提供了用于在Kubernetes集群中管理和扩展应用程序的简单界面。
一旦您将应用程序容器化并将其发布到注册表,您现在可以使用Pod工作负载将其部署到Kubernetes集群中。Kubernetes集群中最小的可部署单元不是容器,而是Pod。Pod通常由应用程序容器(如容器化Flask Web应用程序)或app容器以及执行某些辅助功能(如监视或日志记录)的任何“sidecar”容器组成。Pod中的容器共享存储资源,网络命名空间和端口空间。他们可以使用localhost
使已安装的卷相互通信,并可以使用已安装的卷共享数据。另外,Pod工作负载允许您定义在主应用程序容器开始运行之前运行安装脚本或实用程序的Init Containers。
Pod通常使用Deployments推出,Deployments是由声明特定所需状态的YAML文件定义的控制器。例如,应用程序状态可以运行Flask Web应用程序容器的三个副本并公开端口8080.一旦创建,控制平面逐渐使集群的实际状态与通过将容器调度到节点上的部署中声明的所需状态相匹配按要求。要缩放在群集中运行的应用程序副本的数量,例如从3到5,请更新部署配置文件的replicas
字段,然后更新新配置文件的kubectl apply
字段。使用这些配置文件,可以使用现有的源代码控制服务和集成来跟踪和版本化扩展和部署操作。
以下是Flask应用程序的示例Kubernetes部署配置文件:
apiVersion: apps/v1
kind: Deployment
metadata:
name: flask-app
labels:
app: flask-app
spec:
replicas: 3
selector:
matchLabels:
app: flask-app
template:
metadata:
labels:
app: flask-app
spec:
containers:
- name: flask
image: sammy/flask_app:1.0
ports:
- containerPort: 8080
此部署启动3个Pod,这些Pod运行使用sammy/flask_app
图像(版本1.0
)打开的容器flask
,并打开端口8080
。部署命名为flask-app
。
要了解有关Kubernetes Pods和Deployments的更多信息,请参阅官方Kubernetes文档的Pods and Deployments部分。
Kubernetes使用卷,持久卷(PV)和持久卷声明(PVC)管理Pod存储。卷是用于管理Pod存储的Kubernetes抽象,支持大多数云提供程序块存储产品,以及托管正在运行的Pod的节点上的本地存储。要查看支持的卷类型的完整列表,请参阅Kubernetes 文档。
例如,如果您的Pod包含两个需要在它们之间共享数据的NGINX容器(比如第一个,称为nginx
提供服务网页,第二个,称为nginx-sync
从外部位置提取页面并更新nginx
容器提供的页面), Pod规范看起来像这样(这里我们使用emptyDir
Volume类型):
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx
volumeMounts:
- name: nginx-web
mountPath: /usr/share/nginx/html
- name: nginx-sync
image: nginx-sync
volumeMounts:
- name: nginx-web
mountPath: /web-data
volumes:
- name: nginx-web
emptyDir: {}
我们使用每个容器的volumeMount
,这表明我们想安装在nginx
容器中的/usr/share/nginx/html
中和和在nginx-sync
容器中的/web-data
中包含网页文件的nginx-web
卷。我们还定义了一个命名为nginx-web
的emptyDir
类型的volume
以类似的方式,您可以使用云块存储产品配置Pod存储,方法是将volume
类型修改emptyDir
为相关的云存储卷类型。
卷的生命周期与Pod的生命周期相关联,但与容器的生命周期无关。如果Pod中的容器死亡,则Volume仍然存在,并且新启动的容器将能够装载相同的卷并访问其数据。当Pod重新启动或死亡时,其卷也会崩溃,但如果卷包含云块存储,则只需卸载未来Pod可访问的数据。
要在Pod重新启动和更新之间保留数据,必须使用PersistentVolume(PV)和PersistentVolumeClaim(PVC)对象。
PersistentVolumes是表示诸如云块存储卷或NFS存储之类的持久存储的抽象。它们与PersistentVolumeClaims分开创建,这是开发人员对存储的需求。在他们的Pod配置中,开发人员使用PVC请求持久存储,Kubernetes与可用PV卷匹配(如果使用云块存储,Kubernetes可以在创建PersistentVolumeClaims时动态创建PersistentVolumes)。
如果您的应用程序每个副本需要一个持久卷(许多数据库就是这种情况),则不应使用Deployments,而应使用StatefulSet控制器,该控制器专为需要稳定网络标识符,稳定持久存储和排序保证的应用程序而设计。部署应该用于无状态应用程序,如果您定义PersistentVolumeClaim以用于部署配置,则所有部署的副本将共享该PVC。
要了解有关StatefulSet控制器的更多信息,请参阅Kubernetes 文档。要了解有关PersistentVolumes和PersistentVolume声明的更多信息,请参阅Kubernetes存储文档。
类似Docker,Kubernetes提供env
和envFrom
领域在波德配置文件设置环境变量。以下是Pod配置文件中的示例代码段,它将运行Pod中的HOSTNAME
环境变量设置为my_hostname
:
...
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
env:
- name: HOSTNAME
value: my_hostname
...
这允许您将配置移出Dockerfiles并移入Pod和Deployment配置文件。从Dockerfiles进一步外部化配置的一个关键优势是,您现在可以将这些Kubernetes工作负载配置(例如,通过将HOSTNAME
值更改为my_hostname_2
)与应用程序容器定义分开修改。修改Pod配置文件后,可以使用其新环境重新部署Pod,而不需要重建,测试底层容器映像(通过其Dockerfile定义)并将其推送到存储库。您还可以将这些Pod和部署配置与Dockerfiles分开编辑,从而可以快速检测重大更改并进一步将配置问题与应用程序错误分开。
Kubernetes提供了另一种构造,用于进一步外化和管理配置数据:ConfigMaps和Secrets。
ConfigMaps允许您将配置数据保存为随后在Pod和Deployment配置文件中引用的对象,以便您可以避免硬编码配置数据并在Pod和部署中重复使用它。
这是一个例子,使用上面的Pod配置。我们首先将HOSTNAME
环境变量保存为ConfigMap,然后在Pod配置中引用它:
kubectl create configmap hostname --from-literal=HOSTNAME=my_host_name
要从Pod配置文件中引用它,我们使用valueFrom
和configMapKeyRef
构造:
...
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
env:
- name: HOSTNAME
valueFrom:
configMapKeyRef:
name: hostname
key: HOSTNAME
...
因此,HOSTNAME
环境变量的值已完全从配置文件中外部化。然后,我们可以在引用它们的所有Deployments和Pod中更新这些变量,并重新启动Pod以使更改生效。
如果您的应用程序使用配置文件,ConfigMaps还允许您将这些文件存储为ConfigMap对象(使用--from-file
标志),然后您可以将其作为配置文件挂载到容器中。
Secrets提供与ConfigMaps相同的基本功能,但应该用于敏感数据,如数据库凭证,因为值是base64编码的。
要了解有关ConfigMaps和Secrets的更多信息,请参阅Kubernetes 文档。
在Kubernetes中启动并运行应用程序后,将为每个Pod分配一个(内部)IP地址,由其容器共享。如果其中一个Pod被移除或死亡,则新启动的Pod将被分配不同的IP地址。
对于向内部和/或外部客户端公开功能的长期运行服务,您可能希望授予一组执行相同功能(或部署)的Pod,这是一个稳定的IP地址,可以跨容器对请求进行负载均衡。您可以使用Kubernetes服务执行此操作。
Kubernetes Services有4种类型,由服务配置文件中的type
字段指定:
ClusterIP
:这是默认类型,它为服务提供可从群集内的任何位置访问的稳定内部IP。NodePort
:这将在静态端口上的每个节点上公开您的服务,默认情况下在30000-32767之间。当请求在其节点IP地址和服务的NodePort
中命中节点时,请求将进行负载平衡并路由到您的服务的应用程序容器。LoadBalancer
:这将使用云提供商的负载平衡产品创建负载均衡器,NodePort
和ClusterIP
为将要路由外部请求的服务进行配置。ExternalName
:此服务类型允许您将Kubernetes服务映射到DNS记录。它可以用于使用Kubernetes DNS从您的Pod访问外部服务。请注意,为群集中运行的每个部署创建LoadBalancer
类型的服务将为每个服务创建新的云负载平衡器,这可能会变得昂贵。要使用单个负载均衡器管理将外部请求路由到多个服务,您可以使用Ingress Controller。入口控制器超出了本文的范围,但要了解有关它们的更多信息,可以参考Kubernetes 文档。一种流行的简单入口控制器是NGINX入口控制器。
这是本指南的Pods and Deployments 部分中使用的Flask示例的简单服务配置文件:
apiVersion: v1
kind: Service
metadata:
name: flask-svc
spec:
ports:
- port: 80
targetPort: 8080
selector:
app: flask-app
type: LoadBalancer
在这里,我们选择使用此flask-svc
服务公开部署flask-app
。我们创建了一个云负载均衡器,用于将流量从负载均衡器端口80
路由到暴露的容器端口8080
。
要了解有关Kubernetes服务的更多信息,请参阅Kubernetes文档的“ 服务”部分。
使用kubectl logs
而docker logs
对单个容器和Pod日志进行解析,并且随着正在运行的应用程序数量的增长变得乏味。为了帮助您调试应用程序或群集问题,您应该实现集中式日志记录。在较高的层次上,这包括在处理Pod日志文件和流的所有工作节点上运行的代理,使用元数据丰富它们,并将日志转发到像Elasticsearch这样的后端。从那里,可以使用像Kibana这样的可视化工具来可视化,过滤和组织日志数据。
在容器级日志记录部分,我们讨论了将容器中的应用程序登录到stdout / stderr流的推荐Kubernetes方法。我们还简要讨论了记录边车容器,它们可以在您从应用程序进行登录时为您提供更大的灵 您还可以直接在Pod中运行日志记录代理,捕获本地日志数据并将其直接转发到日志记录后端。每种方法都有其优缺点和资源利用率权衡(例如,在每个Pod内部运行日志代理容器可能会占用大量资源并迅速压倒您的日志记录后端)。要了解有关不同日志记录体系结构及其权衡的更多信息,请参阅Kubernetes 文档。
在标准设置中,每个节点都运行一个日志代理,如Filebeat或Fluentd,它可以获取由Kubernetes创建的容器日志。回想一下,Kubernetes为节点上的容器创建JSON日志文件(在大多数安装中,可以在/var/lib/docker/containers/
中找到)。这些应该使用像logrotate这样的工具旋转。Node日志代理应作为DaemonSet Controller运行,这是一种Kubernetes Workload,可确保每个Node运行DaemonSet Pod的副本。在这种情况下,Pod将包含日志记录代理及其配置,该代理处理来自安装在日志记录DaemonSet Pod中的文件和目录的日志。
与用kubectl logs
来调试容器问题的瓶颈类似,最终您可能需要考虑一个更强大的选项,而不仅仅是使用kubectl top
和Kubernetes Dashboard来监控群集上的Pod资源使用情况。可以使用Prometheus监控系统和时间序列数据库以及Grafana指标仪表板设置集群和应用程序级监控。Prometheus使用“拉”模型工作,该模型定期擦除HTTP端点(如在节点上的/metrics/cadvisor
或在应用程序REST API端点上的/metrics
)以获取度量数据,然后处理和存储。然后可以使用Grafana仪表板分析和可视化此数据。Prometheus和Grafana可以像任何其他部署和服务一样启动到Kubernetes集群。
为了增加弹性,您可能希望在单独的Kubernetes集群上运行日志记录和监视基础结构,或使用外部日志记录和度量标准服务。
迁移和现代化应用程序以使其能够在Kubernetes集群中高效运行通常涉及对软件和基础架构更改进行非常重要的规划和架构设计。实施后,这些更改允许服务所有者持续部署其应用程序的新版本,并在必要时轻松扩展,只需极少量的人工干预。从应用程序外部化配置,设置正确的日志记录和度量标准发布以及配置运行状况检查等步骤,您可以充分利用Kubernetes设计的Cloud Native范例。通过构建可移植容器并使用部署和服务等Kubernetes对象管理它们,您可以充分利用可用的计算基础架构和开发资源。
想要了解更多关于现代化Kubernetes的应用程序的相关教程,请前往腾讯云+社区学习更多知识。
参考文献:《Modernizing Applications for Kubernetes》
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。