云原生是趋势吗?学习k8s和docker的意义在哪里?
本文是在知乎上对同名问题做的回答:直接答案: 是!细细说下为什么。从前,写代码只要在单机上写即可,但是编程会演化。例如,写单机程序。写一个单机命令行程序; 写一个单机GUI程序,此时需要关心数据,模型,界面; 写一个单机网页程序。程序利用到了单机的资源: 内存,CPU,磁盘存储。为了利用内存,做了各种压榨内存的内存分配器,为了便利地使用内存,有了引用计数和垃圾回收。为了利用CPU,操作系统提供了进
直接答案: 是!
很多学生在学习 ‘云’, 这里有很多未知的新技术、工具、和流程。
很多工程师写的程序,被部署到了"云原生"平台里运行,“云原生”和“云主机”有什么区别?
请看 云原生入门技能树 。
细细说下为什么。
从前,写代码只要在单机上写即可,但是编程会演化。
例如,写单机程序。写一个单机命令行程序; 写一个单机GUI程序,此时需要关心数据,模型,界面; 写一个单机网页程序。程序利用到了单机的资源: 内存,CPU,磁盘存储。为了利用内存,做了各种压榨内存的内存分配器,为了便利地使用内存,有了引用计数和垃圾回收。为了利用CPU,操作系统提供了进程和线程抽象,用户态程序提供了协程调度。为了在多线程间共享状态,有了同步/互斥/信号量。为了多进程间共享状态,有了内存共享。为了利用磁盘,有单机数据库sqlite,有各种数据冗余编码分片存储和解码技术。
例如,写服务端/客户端程序。写一个远程服务的命令行客户端程序,例如mysql命令行客户端。写一个B/S的GUI程序,例如点菜系统。将网页部署到服务端。程序用到了服务端的资源: 服务器的内存,CPU,磁盘,数据库。对于客户端来说,核心在于业务逻辑,客户端CPU密集型计算,剩下的通过API请求完成。于是有了前后端分工。服务端让程序的状态存储和计算资源对于客户端来说是1:N的关系。这个时候服务端只要是单机即可。
例如,服务端构架演化。网站请求的静态资源请求量大了需要CDN。数据库数据多了需要做主从分离。数据库请求量大了需要做缓存。接口层顶不住了需要上高性能反向代理服务器。这样逐渐地,服务端程序变成了多机。
例如,服务端程序本身也会1变3。这个时候也不是什么微服务,就是多个服务的依赖,A服务依赖B服务,至于A和B是不是微也没人管。但是服务多了就要有服务间请求的代理问题,发布和订阅等问题,消息队列做了这些事,例如zeromq。分离的服务间除了数据库,还要有一些重要的全局元数据同步解决状态一致性问题,元数据管理做了这件事,例如zookeeper。服务多了,就需要命名,名字最后还得转成ip端口,名字服务做了这件事。这样经过一系列操作,让分布式程序能尽量像单机程序一样工作。
例如,写分布式数据处理程序。典型的是map/reduce构架。接着各种大数据处理框架卷起来。这是因为数据量大了,单机放不下也处理不过来,通过分布式数据处理来利用内存,cpu。但是对带宽提出了要求。分布式还带来了对日志收集,监控,链路跟踪的需求。
例如,写微服务程序。分布式程序变得复杂了,于是把很多经典的做法做了规范化。传统单机上写程序,也分单进程程序和多进程程序,例如Chrome浏览器。微服务通常建立在元数据同步,授权,消息队列的基建上。每个服务的状态内部化,服务间通过API解耦。代价之一是状态存储的分离。微服务也带来了服务发现和注册的需求。微服务是分布式服务利用多机内存,cpu的进一步规范化。
例如,写Dockerfile。容器化一开始只是解决依赖环境打包的问题。这带来了一层虚拟化层,在尽量少牺牲性能损耗的基础上,带来了可移植性。早期Java的JVM希望做到一次编写到处运行,运行在那里呢?运行在JVM虚拟机上。但是编程语言总是忘记了它不是本尊,本尊是操作系统环境。编程语言提供了程序运行的运行时(runtime),但是语言之下,是操作系统的环境,文件系统,环境的配置,以及所有依赖的其他程序,这些构成了大的运行时。容器提供了真自包含运行时的能力。
从容器开始,前面的那些如何写程序的形态全部都要重来一遍。单机程序的容器化,服务端客户端程序,特别是服务端程序的容器化。分布式程序当然也可以全部容器化,全部用容器来启动。连数据库,缓存,消息队列,都可以容器化。docker是典型的容器。
那么写一个在分布式环境下上传,下载,调度容器在不同服务器上运行的元程序,就可以极大简化分布式或者微服务的程序部署和运行流程。这就是“容器编排”,也就是k8s做的事情。它把分布式程序的自包含了,成为了一个更大的运行时。此时,又可以假装在写单机程序了。
这里发生了质的变化。以前,假设一个程序是一个进程,进程是被操作系统编排和调度的。你也可以说操作系统是“进程编排程序”。现在,假设一个程序是一个容器,容器是被“容器编排”程序调度的。我们可以说“进程编排”程序是操作系统,当然也可以说“容器编排”是XX系统。XX=操作?
一个视角是,在程序直接运行在操作系统假设下,微服务的管理就有服务网格的概念。就是把服务注册,发现,消息队列,流量监控,日志收集,链路跟踪之类的,都规约到微服务运行所依赖的标准套装上。这是微服务的“运行时”. 在程序容器化后运行在容器编排环境里,微服务也被容器化,当然对应的服务网格这个“运行时”也被容器化后运行在容器编排环境里。例如: istio 是服务网格的一种实现,可以容器化后运行在容器编排环境k8s里。在这个基础之上,写微服务,容器化,跑在k8s里,获得k8s里的istio的好处。一个超大的运行时。
操作系统的程序,一般通过包管理软件来下载,安装,卸载。容器编排作为一个平台,也可以有自己这层抽象层的包管理软件。例如k8s的helm包管理。
有了k8s+容器化,本质上还是对云上服务器资源的使用,也就是“云原生”的含义,程序运行所要消耗的资源,一开始就假设是云的资源,把云变成像单机一样去写程序。
如果是多云的环境,在不同环境部署k8s又是一个不同云环境依赖的问题。这个时候需要多云的基础设施部署规范,可移植。Terraform 就是做这个事情的。
这些云原生环境是如何一步一步搭建出来的呢?对于很多初学者来说,有很多未知的新技术、工具、和流程,在 “云原生入门技能树”里,我做了一个经过反复调整的设计:云原生入门技能树
到了这里,假设上面的这些,都是云提供好的,是标准的,像买云主机环境一样(本质是个虚拟化的Linux操作系统运行时,”进程编排程序”),买云原生环境(本质是个虚拟化的XX系统运行时,“容器编排程序”). 那么,对于开发者来说,就是“云原生”: 我又可以写“单机程序了”。
更多推荐
所有评论(0)