相关安全加固Docker 公司与美国互联网安全中心(CIS)合作,制定了 docker 的最佳安全实践,包括主机安全配 置、docker 守护进程配置、docker 守护程序配置文件、容器镜像和构建、容器运行安全、docker 安全 操作六大项,99 个控制点。几乎覆盖了 docker 安全要求的各个方面。这也是各安全方案和安全工具的 重要参考。关于加固,具体可参见《2018 绿盟科技容器安全技术报告
》。## 云原生环境的可观察性
云原生环境的可观察性
可观察性(Observability)一词最早来源于 Apple 工程师 Cindy Sridharan 的博文《监控与观察》 (Monitoring and
Observability)[31]。然而,Google 著名的 SRE[32]体系在这之前就已经奠定了可观察性 的理论基础,只不过那时候将这套理论统称为“监控”,SRE 特别的强调了“白盒监控”的重要性,而 “白盒监控”正是贴合了可观察性中“主动”的理念。随着云原生、微服务等新架构、新生态的引入和发展,可观察性越来越多的被及和重视,而可观 察性和监控这两个概念也逐渐的被区分开来。简单来讲,这种区别可以认为是,“监控告诉我们系统的 哪些部分是不工作的,而可观察性可以告诉我们那里为什么不工作了”[33]。
在回答云原生为什么需要可观察性之前,我们先来看一下 CNCF对云原生的定义,英文原文如下:
从定义中可以看出,云原生的代表技术包括容器、服务网格、微服务、不可变基础设施和声明式 API。通过这些技术,可以构建容错性好、易于管理和可观察的松耦合系统,再结合可靠的自动化手段, 对系统做出频繁和可预测的重大变更。
CNCF 的这个定义中明确的出了可观察( Observable)这一特性。而为什么云原生一定需要可观 察性,我们从以下几个方面进行分析。
传统的应用部署,无论是基于物理主机,还是基于虚拟机,其操作系统上承载的应用相对固定。而 对于大多数采用单体架构的系统,其系统内部的通信也相对简单。
到了云原生时代,从其代表技术来看,容器化的基础设施使得应用自身变的更快、更轻,一台主机 上可以快速部署运行几十个、甚至上百个容器。而 Kubernetes 等容器编排平台,又供了良好的负载 均衡、任务调度、容错等管理机制。这样,在云原生中,一台主机上应用的部署密度以及变化频率,较 传统环境,有着巨大的变化。因此,需要可观察性来清晰的发现和记录主机快速变化的应用行为。
另外,应用架构的微服务化,使得应用之间的访问关系变得异常复杂,客户端的一次服务请求,通 常会产生大量的包括服务和中间件在内的众多调用关系。清晰地观察到这种调用关系,无论是对于应用 性能提升、故障定位还是安全检测,都有着重要的意义。
正所谓“未知攻焉知防”,面对云原生架构下的大规模集群以及海量灵活的微服务应用,如果不知 道集群中都运行了什么,服务都在做什么事情,又何谈保护和防范。
从云原生的最终目标来看,通过自动化手段,实现敏捷的松耦合系统。因此,云原生安全也一定是 符合这种自动化目标的,自动化的安全检测就需要有详细准确的运行状态数据作为支撑,为自动化的云 原生安全提供充足的决策依据。可观察性恰恰天然地提供了这样的能力。
从合规角度来看,等保 2.0 将可信提升到一个新的高度,等保一级到四级均提出了关于可信的要求, 包括:计算环境可信、网络可信以及接入可信。等保 2.0 的四级要求尤其对应用可信出了明确的动态 验证需求,如何在不影响应用的功能、性能,保证用户体验的前下,做到应用的动态可信验证成为了 重要的挑战。
而在云原生环境中,解决这个问题的核心在于,如何准确地选择应用的可信度量对象、如何高性能 地确定指标的度量值,以及如何收集和管理验证这些基准值,这些都是对云原生环境实现可观察的重要 意义和应用价值。
我们知道,计算机系统一直遵循分层设计的理念,云原生同样也不例外。要实现对整个云原生的可 观察性,可以分别逐层实现对应的可观察。
从基础设施层来看,这里的可观察性跟传统的主机监控会有一些相似和重合,比如对计算、存储、 网络等主机资源的监控,进程、磁盘 IO、网络流量等系统指标的监控等。对于云原生的可观察,这些 传统的监控指标依然存在,但是考虑到云原生中采用的容器、服务网格、微服务等新技术、新架构,其 可观察性又会有新的需求和挑战。比如在资源层面要实现 CPU、内存等在容器、Pod、Service、Tenant 等不同层的识别和映射关系;在进程的监控上要能够精准识别到容器,甚至还要细粒度到进程的系统调 用、内核功能调用等层面;在网络上,除了主机物理网络之外,还要包括 Pod 之间的虚拟化网络,甚 至是应用之间的 Mesh 网络流量的观察。
从应用层来看,微服务架构下的应用,使得主机上的应用变的异常复杂,这既包括应用本身的平均 延时,应用间的 API调用链,调用参数等,同时还包括应用所承载的业务信息,比如业务调用逻辑、参 数、订单数量,商品价格等信息。
实现可观察性,通常可以有多种手段,不同的方法,其侧重点往往略有差别,下图是可观察性领域 经典的一张分类图,其描述了几种方法对应的作用域以及相互之间的关联和区别。本节接下来将简要分 析一下这几种实现方法。
图 6.1 可观察性组成
日志展现的是应用运行产生的事件或者程序在执行的过程中产生的一些记录,可以详细解释系统的 运行状态。日志描述了一些离散的、不连续的事件,对于应用程序的可见性是很好的信息来源,日志同 样也为对应用程序的分析提供了精确的数据源。
但是日志数据存在一定的局限性,它依赖于开发者暴露出来的内容,而且其存储和查询需要消耗大 量的资源,往往需要使用过滤器减少数据量。
Metrics 与 Logging 有所不同, 一个程序在特定时间内的行为进行衡量。 量单元,或者一个时间段内的柱状图。 展示。
Logging 供的是显示的数据,而 Metrics 是通过数据的聚合,来对 Metrics 是可累加的,他们具有原子性,每个都是一个逻辑计 Metrics 可以观察系统的状态和趋势,但对于问题定位缺乏细节
追踪面向的是请求,可以轻松分析出请求中的异常点,但与 Logging 有相同的问题就是资源消耗较大。 通常也需要通过采样的方式减少数据量。比如一次请求的范围,也就是从浏览器或者手机端发起的任何 一次调用,一个流程化的东西,我们需要轨迹去追踪。追踪的最大特点就是,它在单次请求的范围内处 理信息。任何数据、元数据信息都被绑定到系统中的单个事务上。
在基于微服务的云原生架构中,客户端的一次服务调用,会产生大量的包括服务和中间件在内的众 多调用关系。针对这些复杂的调用过程进行追踪,对于微服务的安全性分析、故障定位、以及性能升 等,有着重要的作用。因此,分布式追踪系统是微服务架构下不可或缺的重要组成部分。
当前的互联网服务,大多数都是通过复杂的、大规模的分布式集群来实现,而随着云原生、微服务 等架构的逐步成熟,传统的单体架构设计,向着更加松耦合的微服务架构进行演进。同时,考虑到微服 务架构下的负载均衡以及高可用等设计,服务间通信以及调用关系的复杂度,将变得异常庞大。
我们先看一个搜索查询的例子,比如前端发起的一个 Web 查询请求,其目标将可能是后端的上百
个查询服务,每一个查询都有自己的 Index。这个查询可能会被发送到多个后端的子系统,这些子系统 分别用来进行广告的处理、拼写检查或是查找一些图片、视频或新闻这样的特殊结果。根据每个子系统 的查询结果进行筛选,进而得到最终结果,汇总到返回页面上。
总的来说,服务追踪有助于在微服务架构下有效地发现并且解决系统的性能瓶颈问题,以及在请求 失败时在这样错综复杂的服务之中准确地进行故障定位。此外,服务追踪也可以用于发现服务中的威胁。 一旦前端暴露的服务被攻击者攻陷,或者是内部某个服务已被攻击者攻陷,那么,面对系统内部微服务 之间庞大复杂的调用关系,这些调用是否全部是完成这次搜索所必须发生的业务联系,是否存在 API探 测、API 滥用,是否存在针对某个服务的 DDoS,客户端服务发送的请求是否包含注入攻击,如何在海 量的正常业务调用逻辑中发现非法的异常调用请求,这些问题均可以通过服务追踪结合有效的分析算法 进行快速的检测发现。
分布式追踪技术对于微服务的故障定位是十分必要的,那么分布式追踪技术是如何实现的呢?若要 对一个微服务业务系统进行分布式追踪,会产生两个基本问题。第一,业务系统运行时可能会产生很多 脏数据或发生数据丢失,需要在这种环境下准确地生成追踪数据。第二,面对成百上千的服务所生成的 追踪数据,则需要设计合适的收集与存储方案。下面具体介绍分布式追踪技术是怎样解决这两个问题的。
在介绍追踪数据的生成之前,需要明确追踪数据中的两个基本概念:跨度(Span)和追踪链路(Trace)。 跨度是追踪数据中基本数据结构,它代表追踪中的一次操作,跨度中包含操作名、跨度 ID、当前跨度 的前一个跨度(根跨度除外)、操作起始与终止时间戳、属性键值对等信息,下面是一个跨度信息示例:
追踪链路是以跨度为根结点的树形数据结构,在微服务中,从客户端发起一次 API调用时往往后面 会产生多次服务间的 API调用以完成此次操作,因此追踪链路代表一次完整操作,其中包含了很多子 操作。
生成追踪数据所要做的,是针对每次操作生成跨度以及将跨度串联成追踪链路。对于跨度的生成, 追踪器会在网络请求或数据库访问发生时抓取有效数据并对此次操作生成一个独有的跨度 ID。对于将 跨度串联成追踪链路,在一次跨度信息生成后,追踪器会将跨度 ID加进下一次网络请求中,当请求被 接收时,追踪器会检验请求中是否包含跨度 ID信息,若包含,则创建新的跨度作为请求中跨度的子跨度, 否则创建一个新的根跨度。随后,有父子关系的跨度信息会被发送到收集器中,收集器为这组有父子关
系的跨度数据加上链路 ID,具有同一链路 ID的跨度数据组成一次完整的追踪链路。至此,包含跨度信 息和追踪链路的追踪数据被成功生成。
自 Google Dapper 首先出分布式链路追踪的设计理念以来,许多分布式追踪工具不断涌现,这些 工具应用在微服务业务系统的资源监控,故障定位,服务依赖分析,服务组织架构理解等方面,为微服 务业务系统的运维工作提供了极大便利。
当前,常见的分布式追踪工具包括 Dapper,Zipkin,Jaeger,Skywalking,Canopy,鹰眼, Hydra,Pinpoint 等,其中常用的开源分布式追踪工具为 Zipkin,Jaeger,Skywalking 和 Pinpoint。这 些分布式追踪工具可分为三个大类:基于 SDK的,基于探针的,基于 Sidecar。下面将简要介绍这三类 追踪工具的使用方法与各自的优缺点:
基于 SDK的分布式追踪工具。 以 Jaeger 为例,Jaeger 供了大量可供追踪使用的 API,通过侵入 微服务业务的软件系统,在系统源代码中添加追踪模块实现分布式追踪。此类工具可以最大限度地抓取 业务系统中的有效数据,为运维工作供了足够的可参考指标,但其通用性较差,需要针对每个服务进 行重新实现,部署成本较高,工作量较大。
基于探针的分布式追踪工具。 以 Skywalking Java 探针为例,在使用 Skywalking Java 探针时, 需将探针文件打包进服务容器镜像中,并在镜像启动程序中添加 -javaagent agent.jar 命令,以完成 Skywalking 在微服务业务上的部署。Java 探针的实现原理为字节码注入,将需要注入的类文件转换成
byte 数组,通过设置好的拦截器注入到正在运行的程序中。Java 探针通过控制 JVM 中类加载器的行为,
侵入运行时环境实现分布式追踪。此类工具无需修改业务系统的源代码,相对 SDK有更好的通用性, 但其可获取的有效数据相对 SDK类工具较少。
基于 Sidecar。 Sidecar 作为服务代理,为其所管理的容器实现服务发现,流量管理,负载均衡和 路由等功能。在流量管理过程中,Sidecar 可以抓取进出容器的网络请求与响应数据,这些数据可以记 录该服务所完成的一次单个操作,可与追踪中的跨度信息对应,因此可将 sidecar 视为一种基于数据收 集的分布式追踪工具。Sidecar 无需修改业务系统代码,也不会引入额外的系统的开销。但由于 sidecar 所抓取的跨度不包含追踪链路上下文,要将 sidecar 所抓取的跨度数据串联成追踪链路是很困难的。
虽然分布式追踪技术在应用方面已经取得了一些进展,但其仍然存在着一定的局限性。当前的分布 式追踪工具或者需要侵入微服务软件系统的源代码,或者需要侵入业务系统的镜像与运行环境,或者在 生成的跨度信息与追踪链路的准确性与完整性上仍有缺失。因此,如何实现低开销,低侵入地构建准确 且完整的追踪信息仍需要许多后续工作。