云原生技术与应用入门指南

一篇云原生入门指南,讲解了核心概念、架构演进、关键技术和工具,以及云原生12法则。

原文标题:企业级云原生技术与应用基础概念篇

原文作者:牧羊人的方向

冷月清谈:

本文整理了云原生技术的核心概念、架构演进、关键技术和工具。云原生是一种构建和运行应用程序的方法论,旨在充分利用云平台的优势。

云原生应用架构从ESB总线架构演进到微服务架构,再到服务网格架构。微服务将应用拆分成独立的服务,容器化技术为微服务提供实施保障,DevOps则将开发和运维结合起来。

云原生技术要素包括微服务、容器化、DevOps和持续交付。

关键技术和工具包括:容器技术(Docker、Kubernetes)、服务网格(Istio)、声明式API、不可变基础设施、云原生数据库和中间件、自动化部署工具(Helm、Operator)、GitOps和可观测性工具(Prometheus、Grafana、EFK)。

文章还介绍了云原生12法则,指导开发者构建和运维云原生应用,并探讨了Kubernetes的核心组件、对象、调度对象关系,以及云原生网络、存储和数据库中间件的管理。

怜星夜思:

1、除了文中提到的 Kubernetes,还有哪些其他的容器编排工具?它们各自的优缺点是什么?
2、文章提到了云原生12法则,大家在实际开发中是如何应用这些法则的?有没有遇到什么挑战?
3、云原生技术日新月异,大家是如何保持学习和更新知识的?有什么推荐的学习资源吗?

原文内容

云原生是什么,和容器技术、DevOps以及微服务之间又是什么关系。本文基于云原生技术与应用培训的知识点整理,加深理解。

1、云原生概述
什么是云原生,不同的人理解不同,目前来看比较权威的定义是来自Pivotal公司和云原生计算基金会(CNCF)。
  • Pivotal公司是云原生应用的提出者,也是云原生的先驱者和探路者,官网给出的云原生概括为4个要素:DevOps、持续交付、微服务以及容器化

  • CNCF对云原生的定义包括容器、服务网格、微服务、不可变基础设施和声明式API

无论哪种定义,云原生的理念和思想随着技术的发展是在不断迭代更新的,云原生的定义抽象为以下:

云原生是一种构建和运行应用程序的方法,是一套技术体系和方法论。云原生(CloudNative)是一个组合词,Cloud+Native。Cloud表示应用程序位于云中,而不是传统的数据中心;Native表示应用程序从设计之初即考虑到云的环境,原生为云而设计,在云上以最佳姿势运行,充分利用和发挥云平台的弹性+分布式优势。

1.1 云原生主要理论思想
云原生的基本理念是实现业务功能和基础设施资源解耦,将基础设施资源和能力下沉,称为云基础能力的一部分。云原生思想的理论基础包括:
  • 不可变基础设施:容器镜像作为基础设施资源,build once run anywhere,随时迁移运行,不依赖于基础设施环境

  • 声明式设计模式:云应用编排采用声明式定义文件描述应用服务之间、服务和基础架构之间的关系

1.2 云原生技术要素

  • 微服务:将应用程序拆分成小的、独立的、可独立部署的服务,以实现更轻松的维护和更新。

  • 容器化:为微服务提供实施保障,实现应用隔离。每个服务都被封装在容器中,可以无差别的管理和维护。

  • DevOps:开发和运维相结合,而不是分开进行,以实现更快速的软件开发和修复。

  • 持续交付:频繁地将新功能发布给用户,而不会影响用户使用服务。

1.3 云原生架构演进

云原生的应用架构由ESB总线架构到微服务架构,再到网格化架构(Service Mesh),经历了不同发展阶段:
  • ESB总线架构:ESB总线是一种企业级的应用程序集成架构,它提供了一种将不同系统和服务进行集成的方式。ESB总线通过一个中央总线将不同的服务和应用连接在一起,使得它们可以相互通信和交互。在云原生应用架构演进的早期,ESB总线是一种常见的集成方式,但是由于其可扩展性和可维护性等方面的限制,它已经逐渐被其他架构所取代。

  • 微服务架构:将应用程序拆分成小的、独立的、可独立部署的服务的方式。每个服务都负责处理一个特定的业务功能,并且可以独立地开发和部署。微服务架构的出现使得应用可以更好地支持持续交付和DevOps,同时也提高了应用的可扩展性和可维护性。

  • Service Mesh(服务网格):在微服务架构中,服务之间的通信通常是通过直接调用或者使用消息队列等方式进行的,这种方式会导致服务之间的耦合度较高,难以进行管理和监控。而Service Mesh通过建立一个独立于应用程序的服务网络,实现了服务之间的解耦和抽象化,从而更好地支持了服务的发现、负载均衡、监控和流量管理等功能。

在Service Mesh的基础上,还演变出了许多相关的技术和工具,例如服务注册与发现、服务注册与发现、API网关、熔断机制等,这些技术和工具都为云原生应用提供了更好的可扩展性、可靠性、可维护性和安全性等方面的支持。

1.4 云原生12法则

云原生12法则(Twelve-Factor App)是一个由Heroku提出的云原生应用开发方法论,它包括了以下12个准则:
  • 基准代码:代码被部署在运行环境中,代码库是应用的一部分,而不是单独存储的代码库。一份基准代码可以部署到多个环境中。

  • 依赖:应用依赖关系应该显式声明,并使用构建工具管理,而不是通过环境或操作系统默认库隐式依赖。

  • 配置:应用配置应该和代码完全分离,通过环境变量在运行时传递,而不是通过硬编码或者在运行时动态寻找配置。

  • 后端服务:应用应该将后端服务看作附加资源,可以在不修改应用代码的情况下进行切换和扩展。

  • 构建、发布、运行:构建和运行应该进行严格分离,通过构建工具自动化构建和测试,发布到运行环境。

  • 进程:进程必须无状态且无共享,即云应用以一个或多个无状态不共享的程序运行。

  • 端口绑定:不依赖于任何网络服务器就可以创建一个面向网络的服务,每个应用的功能都很齐全,通过端口绑定对外提供所有服务。

  • 并发:并发性即可以依靠水平扩展应用程序来实现,通过进程模型进行扩展,并且具备无共享、水平分区的特性。

  • 易处理:所有应用的架构设计都需要支持能随时销毁的特点,和状态的无关性保持一致,允许系统快速弹性扩展、改变部署及故障恢复等。

  • 环境等价:确保环境的一致性,保持研发、测试和生产环境尽可能相似,这样可以提供应用的持续交付和部署服务。

  • 日志:每一个运行的进程都会直接标准输出和错误输出事件流

  • 管理进程:管理或维护应用的运行状态是软件维护的基础部分,在与应用长期运行的程序相同环境中,作为一次性程序运行。

云原生12法则旨在帮助开发人员更好地构建和运维云原生应用程序,使应用程序具有更高的可维护性、可扩展性和可靠性。

2、云原生技术和工具
2.1 基础容器化技术

详细可参考《》

2.1.1 容器技术核心特点
容器采用namespace、cgroup和chroot实现容器隔离和资源控制的技术,它们提供了不同的隔离和限制方式,使得容器可以在一个相对独立和安全的运行环境中运行
  • Namespace(命名空间):在容器技术中,namespace被用来将容器的资源隔离开来,使得容器内部和外部的进程、网络和文件系统等不会相互干扰。

  • Cgroup(控制组):在容器技术中,cgroup被用来对容器进行资源控制,如限制容器的CPU、内存、磁盘等资源的占用,以及控制容器的生命周期等。

  • Chroot(改变根目录):在容器技术中,chroot被用来将容器的根目录改变为一个独立的目录,并将容器及其子进程限制在这个目录树中,从而实现容器的隔离和限制。

2.1.2 容器基础架构

  • 守护进程daemon:运行docker的后台进程

  • 客户端client:与用户交互,打包,拉/推镜像,运行/停止/删除容器

  • 镜像images:只读的,把环境和程序代码打成的包

  • 仓库registries:保存镜像的地方

  • 容器containers:从镜像创建的应用运行实例,在内存中实例化的应用

2.2 容器编排Kubernetes

详细可参考《》和《》

2.2.1 Kubernetes核心组件

  • 控制平面Control Plane

    • 对集群做出全局决策,以及响应和检测集群事件

    • 可以在集群任何节点上运行

  • Etcd

    • 键值数据库,保存Kubernetes所有集群数据的后台数据库

  • kube-apiserver

    • 提供集群管理的REST API接口

    • 提供其它模块之间的数据交互和通信的枢纽

    • 提供Etcd数据缓存以减少集群对Etcd的访问

  • kube-controller-manager

    • 集群的大脑,确保Kubernetes遵循声明系统规范,确保系统的真实状态和用户期望的状态一致

    • 多个控制器的组合,包括:Node Controller、Replica Controller、Endpoint Controller、服务账户和令牌控制器

  • kube-scheduler

    • 特殊的controller,用于监控当前集群所有未调度的Pod,并获取当前集群所有节点的健康状态和资源使用情况,为待调度的Pod选择最佳的计算节点,完成调度

    • 调整阶段分为:Predict、Priority和Bind

  • 数据平面

    • 运行在每个节点,维护运行的Pod并提供Kubernetes运行环境

  • Kubelet

    • 运行在每个node上的代理,保证容器都运行在Pod中

    • 将Runtime、网络和存储抽象成CRI、CNI和CSI

  • kube-proxy

    • 每个节点上运行的网络代理,实现Service概念

    • 配置相同的负载均衡策略

    • 维护节点网络规则,允许集群内部或外部的网络与Pod进行通信

  • 容器运行时(Container Runtime)

    • 负责运行容器的软件

    • 支持CRI-0;新版本不支持Docker,但是支持containered

  • 插件

    • 增强集群功能,比如kube-DNS、Ingress、Dashboard、日志采集等

2.2.2 Kubernetes核心对象
  • Namespaces命名空间

    • 一组资源和对象的抽象集合,如pods、services、deployments等都属于某个namespace,但是Node、PV不属于任何命名空间

    • 常见命名空间:default、kube-system、kube-node-lease、kube-public

  • Node

    • Pod运行的真正的主机,可以是物理机、也可以是虚拟机

    • 上面运行Container Runtime、Kubelet和kube-service

  • Pod

    • K8S集群中部署应用和服务的最小计算单元。Pod中可以部署多个容器

    • 多个容器在一个Pod中共享网络地址和文件系统

  • Service

    • 应用服务的抽象,通过labels为应用提供负载均衡和服务发现

    • 自动分配一个ClusterIP和DNS名,clusterIP是集群内部访问虚拟地址

2.2.3 Kubernetes调度对象关系

  • 副本集ReplicaSet

    • 用户定义Pod的副本数,每个Pod当作一个无状态成员进行管理

    • 调整副本数量方便进行扩缩容

  • 部署Deployment

    • 对K8S集群的一次更新操作,如创建新的服务、更新服务或者升级服务

    • 一般用于调度Pod、维护Pod数量或者定义Pod升级策略

  • StatefulSet

    • 管理有状态的应用,如数据库、中间件Zookeeper等

    • Pod的名称始终保持不变,Pod启停有先后顺序

    • 有不同的升级策略,如onDelete、滚动升级、分片升级等

  • Job

    • 控制批处理型任务的资源对象

    • 一次性任务,任务执行完成后自动退出

  • Cronjob

    • 周期性执行的批处理任务,与Linux中的Crontab类似

  • DaemonSet

    • 后台支撑服务,在每个Node上运行一个,如存储、日志和监控等服务

2.3 云原生网络和服务

1)Kubernetes三种IP地址
  • Node IP:节点设备的IP地址,容器宿主机的物理IP

  • Pod IP:Pod的IP地址,根据docker0网络IP段进行分配

  • Cluster IP:ervice IP,是一个虚拟IP,仅用于集群内部访问

  • NodePort:集群内部每个节点上开放的服务端口

2)网络服务
  • LoadBalancer

    • 负载均衡器,K8S部署到公有云上才会使用到,将流量转发到以NodePort形式开放的Service上

  • Kube-proxy

    • 每个节点都运行一个kube-proxy服务,用于监听API Server中的service和endpoint变化情况

    • 可以直接运行在物理机,也可以以static Pod或DaemonSet方式运行

  • 域名服务DNS

    • 内置域名服务,用户定义的服务自动获得域名

    • 服务重建后,主要服务名不变,对应的域名不会变化

  • Service

    • 将运行在Pod上的应用程序抽象为网络服务的方法

    • Pods有自己的IP地址,一组Pod会提供相同的DNS名并负载均衡

  • Ingress

    • 配置一个负载均衡器,将外部请求代理到群集内部

2.4 云原生存储

2.4.1 Kubernetes存储卷
  • 容器中的数据非持久化的,容器消亡后数据也会丢失

  • Kubernetes提供Volume机制,解决容器数据持久化和容器间数据共享问题

    • hostPath:数据持久在宿主机本地。Pod重新调度后,Pod中数据不一定存在

    • emptydir:临时存储,和Pod生命周期一致

2.4.2 持久存储
  • PersistentVolume:集群中的网络存储,比如SAN、NFS或NAS

  • PV的生命周期

    • Provisioning:PV的创建

    • Binding:将PV分配给PVC

    • Using:Pod通过PVC使用该Volume

    • Releasing:Pod释放Volume并删除PVC

    • Reclaiming:回收PV,可以保留下次使用,也可以删除

  • PV的4种状态

    • Avaiable:可用

    • Bound:已经分配给PVC

    • Released:PVC解绑但还未执行回收策略

    • Failed:发送错误

  • PV的3种访问模式

    • ReadWriteOnce(RWO):可读可写,只能被单个Pod使用

    • ReadOnlyMany(ROX):以只读方式被多个Pod挂载

    • ReadWriteMany(RWX):以读写方式被多个Pod共享

  • PV的3种回收策略

    • Retain:不清理保留volume,需手动清理

    • Recycle:删除数据,rm -rf方式

    • Delete:删除存储资源

  • PersistentVolumeClaim

    • 持久卷声明,即对PV的请求;PVC消费PV资源,请求特定大小和访问模式的存储卷

  • StorageClass

    • 集群中存在StorageClass时,申请PVC时会动态创建PV

    • 包括4个部分:provisioner、mountOptions、parameters、reclaimPolicy

2.5 云原生数据库和中间件

2.5.1 有状态应用StatefulSet
  • 应用场景

    • 需要保存和维护某些状态信息,比如用户数据、配置信息等;应用实例停止后,所保存的状态信息也会丢失,因此需要持久化保存

    • 每个Pod都有唯一标识,并提供滚动升级和自动扩展功能

    • 对高可用或数据一致性有较高要求

  • 最佳实践

    • 数据一致性要求

      • 数据库主备架构、分布式文件系统、分布式锁等

    • 持久化存储

      • 使用PV和PVC资源管理持久化存储

    • 环境变量管理

      • ConfigMap和Secure管理配置文件和敏感信息

    • 分配固定的网络标识

      • 确保应用副本之间的通信和外部访问的稳定性

    • 副本数量和资源分配

      • 根据应用性能和可用性分配足够的副本和资源

    • 版本控制和回滚

      • 保证应用的稳定性,制定版本策略

2.5.2 Kubernetes管理工具
1)Helm
  • Helm Chart描述应用的配置和部署信息

  • Helm命令行工具用于部署、更新和回滚等操作

  • Helm Repo存储Helm Chart,其中可以查找、下载、发布和管理Helm Chart

  • Helm管理应用:1、添加Helm仓库;2、查找和下载chart;3、定制chart配置;4、部署应用;5、管理应用

2)Operator
  • 运行在Kubernetes集群中,自动管理和协调应用生命周期,实现自动化运维

  • 组件

    • 控制器:核心组件,负责Kubernetes集群中的资源状态,并根据预定义的策略来控制和协调应用的生命周期

    • 客户端:前端组件,负责与Kubernetes集群的API进行交互,并提供命令行工具或图形化界面

  • 应用场景包括:数据库备份恢复、扩缩容等;消息队列管理、自动重试等;分布式计算应用,自动化调度、结果采集;机器学习应用,模型训练、部署等

2.6 云原生应用自动化部署

详细可参考《》和《》

2.6.1 DevOps
  • 基本目标是协调软件开发、测试和发布的工作流程,提高效率并降低风险

  • DevOps和云原生

    • DevOps和云原生相辅相成,DevOps强调持续交付和部署,云原生强调将应用与基础设施解耦

  • DevOps和微服务

    • DevOps使用自动化流程开发、测试和部署微服务,并使用容器化技术管理微服务环境

    • 微服务方便应用程序各个组件的扩展和维护,提高应用程序弹性,降低运维成本

  • DevOps和CI/CD

    • CI/CD持续集成持续交付是DevOps重要组成部分

  • DevOps和容器化

    • 容器化帮助DevOps加快软件交付速度、提高可用性和弹性、降低成本

  • DevOps平台框架

    • 自动化流水线

    • 代码仓库:GitLab

    • 持续集成工具:Jenkins

    • 容器编排工具:Kubernetes

    • 监控工具:Prometheus/EFK

    • 发布工具

    • 文档管理工具:Confluence

2.6.2 GitOps
  • 基本概念

    • 结合DevOps、CI/CD与Git版本控制系统

    • 声明式基础设施IaC(Infrastructure as Code)原则

  • 基本原则

    • 声明式、版本化与不可变性、自动拉取、持续协调

  • 与DevOps关系

    • GitOps是DevOps的一个子集,是DevOps的扩展和发展

    • 应用交付由push模式变为pull模式

    • GitOps更加适应云原生发展,工具链更为轻量

  • GitOps工具流

    • 1、开发者推送代码到GitHub仓库,然后触发GitHub Action自动构建

    • 2、GitHub Action自动构建

      • 构建应用镜像

      • 将应用镜像推送到镜像仓库

      • 更新代码仓库中的镜像版本

    • 3、GitOps工具ArgoCD对镜像进行管理

      • 定期Poll方式持续拉取Git仓库,并判断是否有新的commit

      • 从Git仓库获取K8S对象,与集群对象实时比较,自动更新集群内有差异的资源

2.7 云原生服务可观测性

1)可观测性定义
  • 通过对系统测量,能够从观测值中推断出系统的状态

  • 关注系统的动态性和复杂性,适用于微服务架构和云原生应用

2)Kubernetes集群可观测性
  • 集群监控:Prometheus和Grafana工具

  • 日志收集:EFK或ELK架构

  • 异常检测:Prometheus Alertmanager监控异常

  • 用户行为监控:ELK+Splunk跟踪用户行为

  • 可视化:Kubernetes Dashboard对集群和应用可视化

2.8 公有云产品实现云原生

  • 云原生和公有云

    • 云原生技术包括微服务、容器化、持续集成持续交付以及声明式编程等

    • 公有云是由第三方供应商通过互联网提供的可共享计算服务

  • 关键技术与工具

    • IaC代码定义基础设施,包括计算、存储和网络资源等

    • 服务网格如Istio,提供路由规则、负载均衡、重试、熔断限流、身份验证等

    • 基于Kubernetes的服务编排,实现容器自动化部署、管理和扩展等服务

    • CI/CD持续集成持续交付,实现快速、高质量的软件开发和部署

    • 云原生监控工具Prometheus、EFK等,及时发现问题

3、总结

以上是最近参加的“企业级云原生技术与应用”基础篇的知识点整理,云原生技术系统涉及到的工具和组件众多,需要结合实际操作慢慢消化。期待后续的提高篇内容。

参考资料:

  1. 企业级云原生技术与应用,程尊华老师,嘉为教育

  2. https://zhuanlan.zhihu.com/p/150190166

  3. https://zhuanlan.zhihu.com/p/30200943

我觉得 Kubernetes 虽然复杂,但社区活跃,生态完善,几乎成了容器编排的事实标准。其他工具的社区和生态相对来说就比较小了,遇到问题可能不太容易找到解决方案。

关于“环境等价”,我们实践中会尽量保持开发、测试、生产环境一致,但总有一些细微差别。数据库版本就是一个例子,测试环境用的是MySQL 5.7,生产环境是 8.0,导致一些 SQL 语句在测试环境没问题,上线就报错,很头疼。

“日志”这一条也很重要,我们用的是 EFK,日志集中管理,方便排查问题。但日志量太大,存储和查询也是个挑战,需要做好日志的过滤和清理。

说到容器编排,除了 Kubernetes,还有 Docker Swarm 和 Apache Mesos。Docker Swarm 的优点是简单易用,学习成本低,和 Docker 生态系统紧密集成。缺点是功能相对 Kubernetes 少一些,不太适合复杂场景。Apache Mesos 比较底层,可以用来构建更复杂的分布式系统,但学习曲线比较陡峭。

关注一些技术博客和公众号,比如 InfoQ、CNCF 博客,还有 Kubernetes 的官方文档,都是很好的学习资源。

实践出真知!我会在自己的环境里搭建 Kubernetes 集群,跑一些demo应用,这样学习起来更有感觉。

我觉得最难的是“进程”,要做到无状态真的不容易,尤其是一些需要维护状态的应用,比如游戏服务器。我们尝试用 Redis 来存储状态,但也带来了一些新的问题,比如 Redis 的性能瓶颈和数据一致性问题。

补充一下,Nomad 也是一个不错的选择,尤其是在多云和混合云环境下。它支持多种类型的 workload,不仅仅是容器,还包括虚拟机、Java 应用程序等等。而且 Nomad 的资源利用率也比较高。