简介:本文介绍了一组使容器更易于运维的最佳实践。这些实践涉及安全性、监控和日志记录等广泛的主题,旨在使应用程序更容易在Kubernetes Engine 和一般的容器中运行。这里讨论的许多实践都受到12 因子方法的启发 ,12 因 ...
本文介绍了一组使容器更易于运维的最佳实践。这些实践涉及安全性、监控和日志记录等广泛的主题,旨在使应用程序更容易在Kubernetes Engine 和一般的容器中运行。这里讨论的许多实践都受到12 因子方法的启发 ,12 因素方法是一个构建云原生应用程序的优质资源。这些最佳实践的重要等级不一样。例如,对于有些实践,你可能在缺少他们的情况下在生产环境中成功运行,但另外一些实践是不可或缺的。特别是,与安全相关的最佳实践的重要性是主观的,是否实现它们取决于你的环境和约束。这些实践并不适合零基础的读者,你需要事先了解 Docker 和 Kubernetes 的一些知识。此处讨论的一些最佳实践也适用于 Windows 容器,但大多情况下数假设你使用的是 Linux 容器。有关构建容器的建议,请参阅构建容器的最佳实践。使用容器的原生日志记录机制重要性:高作为应用程序管理的一部分,日志中包含宝贵的信息,可让人了解应用程序中发生的事件。Docker 和 Kubernetes 致力于简化日志管理。在传统服务器上,你可能需要将日志写入特定文件并处理日志轮换以避免填满磁盘。如果有高级日志系统,则可以将这些日志转发到远程服务器来集中它们。通过容器可以将日志写入 stdout 和 stderr,因而容器提供了一种简单且标准化的方式来处理日志。Docker 捕获这些日志行,并允许你使用 docker logs 命令访问它们。作为应用程序开发人员,你不需要实现高级日志记录机制,试试用原生的日志记录机制吧。平台运营商必须提供一个系统来集中日志并进行搜索,你可以使用 Kubernetes Engine 提供的 fluentd 和 Stackdriver Logging。其他常见方法包括使用 EFK (Elasticsearch,Fluentd,Kibana)栈。[2018-01-01 01:01:01] foo - WARNING - foo.bar - There is something wrong.这是转换后的日志: { "date": "2018-01-01 01:01:01", "component": "foo", "subcomponent": "foo.bar", "level": "WARNING", "message": "There is something wrong."}通过这种转换,你可以在日志中轻松搜索所有 WARNING 级别日志或 foo.bar 组件中的所有日志。如果你决定记录 JSON 格式的日志,请注意必须在每一行上加入事件才能正确解析。在实际中,它看起来是下面这样: {"date":"2018-01-01 01:01:01","component":"foo","subcomponent":"foo.bar","level": "WARNING","message": "There is something wrong."}如你所见,结果远不如正常的日志可读。如果决定使用此方法,请确保你的团队不会严重依赖手动日志检查。边车模式的记录聚合器某些应用程序(如 Tomcat)无法通过简单配置来生成日志。这些应用程序在磁盘上写入不同的日志文件,所以在 Kubernetes 中处理它们的最佳方法是使用边车模式进行日志记录。边车是一个小容器,与应用程序在同一个 pod 中运行。有关边车的更详细信息,请参阅Kubernetes 官方文档。在这种解决方案中,你为应用程序的边车容器添加一个日志代理(在同一 pod 中,)并在两个容器之间共享 emptyDir 卷,示例:GitHub 上的这个 YAML 示例。然后,配置应用程序将日志写入共享卷,接着配置日志代理进行读取,并转发到需要的地方。在此模式中,因为没有使用 Docker 和 Kubernetes 原生的日志记录机制,所以必须处理日志轮换。如果你的日志代理程序不处理日志轮换,则同一 pod 中的另一个边车容器会处理。
http_requests_total{method="post",code="200"} 1027http_requests_total{method="post",code="400"} 3http_requests_total{method="get",code="200"} 10892http_requests_total{method="get",code="400"} 97在这个例子中,http_requests_total 是度量,method 和 code 是标签,最右边的数字是该指标对于这些标签的值。上图中所示,自启动以来,该应用程序已使用 400 错误码响应了 97 次 HTTP 的 GET 请求。通过已有的多种语言的Prometheus 客户端库,可以轻松生成此 HTTP 端点 。 OpenCensus 还可以使用此格式(以及许多其他功能)导出指标。不要将此端点暴露给公共网络。Prometheus 官方文档 详细介绍了该主题。你还可以阅读站点可靠性工程的第 6 章 ,以了解有关白盒(和黑盒)监控的更多信息。用于监控的边车模式并非所有应用程序都可以使用 /metrics HTTP 端点进行检测。为了保持标准化监控,我们建议使用边车模式以正确的格式导出指标。日志聚合边车模式 部分介绍如何使用边车容器来管理应用程序日志。你可以使用相同的模式进行监控:边车容器托管监控代理程序,该代理程序将应用程序公开的度量标准转换为全局监控系统可以理解的格式和协议。考虑一个具体示例:Java 应用程序和 Java Management Extensions(JMX)。许多 Java 应用程序使用 JMX 公开指标。利用jmx_exporter,你可以不必重写应用程序就公开 Prometheus 格式的指标。jmx_exporter 通过 JMX 从应用程序收集指标,并通过 Prometheus 可以读取的 /metrics 端点公开它们。这种方法还具有限制 JMX 端点暴露的优点,因为它可以用来修改应用程序设置。 注意:本节中给出的路径只是一种约定。HTTP 端点的实际路径可能因应用程序而异。活性探针实现活性探针的推荐方法是让应用程序公开 /health HTTP 端点。在此端点上收到请求后,如果认为健康,应用程序应发送“200 OK”响应。在 Kubernetes 中,健康意味着容器不需要被杀死或重新启动。影响健康的因素因应用程序而异,但通常意味着以下内容:
注意:在许多应用程序中,/health 和 /ready 端点合并为一个 /health 端点,因为它们的健康状态和就绪状态之间没有真正的区别。避免以 root 身份运行重要性:中等容器提供隔离:使用默认设置,Docker 容器内的进程无法访问来自主机或其他并置容器的信息。但是,由于容器共享主机的内核,因此隔离不像虚拟机那样完整。攻击者可以找到未知的漏洞(在 Docker 或 Linux 内核本身中),这些漏洞将允许攻击者从容器中逃脱。如果攻击者确实发现了漏洞并且你的进程在容器内以 root 身份运行,则他们将获得对主机的 root 访问权限。 docker run --user $((RANDOM + 1))[YOUR_CONTAINER]如果容器需要外部卷,则可以配置 fsGroup Kubernetes 选项 以将此卷的所有权授予给特定的 Linux 组。此配置解决了外部文件所有权的问题。如果你的进程由非特权用户运行,则它将无法绑定到 1024 以下的端口。这不是什么大问题,因为你可以配置 Kubernetes 服务将流量从一个端口路由到另一个端口。例如,你可以配置 HTTP 服务器绑定到 8080 端口,并通过 Kubernetes 服务从 80 端口将流量重定向回来。仔细选择镜像版本重要性:中等当你使用 Docker 镜像时,无论是作为 Dockerfile 中的基础镜像,还是作为 Kubernetes 中部署的镜像,你都必须选择正在使用的镜像的标签。大多数公共和私有镜像都遵循构建容器最佳实践中所述的标签系统 。如果镜像使用语义版本控制的系统 ,则必须考虑一些标签细节。最重要的是,“latest”标签可以在镜像之间频繁移动。结果是你无法依赖此标签进行可预测或可重现的构建。例如,采用以下 Dockerfile: FROM debian:latestRUN apt-get -y update && apt-get -y install nginx如果你在不同的时间使用这个 Dockerfile 构建两次镜像,你最终会得到两个不同版本的 Debian 和 NGINX。相反,考虑这个修订版: FROM debian:9.4RUN apt-get -y update && apt-get -y install nginx通过使用更精确的标签,你可以确保生成的镜像始终基于 Debian 的特定子版本。因为特定的 Debian 版本还附带了特定的 NGINX 版本,所以你可以更好地控制正在构建的镜像。这个结果不仅适用于构建时,也适用于运行时。如果你在 Kubernetes 清单中引用“latest”标签,则无法保证 Kubernetes 将使用的版本。集群的不同节点可能会在不同时刻拉取相同的“latest”标签。如果标签已经在拉动之间的某个点更新,则最终可能会在不同的节点运行不同的镜像(这是因为同时打上了“latest”标签)。理想情况下,你应始终在 FROM 行中使用不可变标签。此标签允许你重现构建。但是,存在一些安全性权衡:你固定使用的版本越多,安全补丁在镜像中的自动化程度就越低。如果你使用的镜像使用正确的语义版本控制,则补丁版本(即“X.Y.Z”中的“Z”)不应具有向后不兼容的更改:你可以使用“X.Y”标签并自动修复错误。 注意:标签在 Docker 中不是真正不变的。只要镜像的所有者决定更改标签。但是,“X.Y.Z”标签实际上几乎总是不变的。设想一下名为“SuperSoft”的软件。假设 SuperSoft 的安全过程是通过新的补丁版本来修复漏洞。你想自定义 SuperSoft,并编写了以下 Dockerfile: FROM supersoft:1.2.3RUN a-command一段时间后,供应商发现了一个漏洞,并发布了 SuperSoft 的 1.2.4 版本来解决这个问题。在这种情况下,你可以随时了解 SuperSoft 的补丁并相应地更新 Dockerfile。如果你在 Dockerfile 中使用 FROM supersoft:1.2 进行替换,则会自动拉取新版本。最后,你必须仔细检查正在使用的每个外部镜像的标签系统,判定你对构建这些镜像的人员的信任程度,并确定要使用的标签。本文仅代表作者个人观点,不代表巅云官方发声,对观点有疑义请先联系作者本人进行修改,若内容非法请联系平台管理员,邮箱2522407257@qq.com。更多相关资讯,请到巅云www.rzxsoft.cn学习互联网营销技术请到巅云建站www.rzxsoft.cn。 |