2022年度计划
Kubernetes相关开发
Nginx相关开发
- apisix
函数计算平台建设
- refunc
ClickHouse平台建设
规模化监控平台建设
可观测平台建设
- opentelemetry
云计算服务从IaaS到PaaS到如今炙手可热的Serverless,服务对象始终是计算资源使用者。Serverless是一种让开发者无需关心基础设施(服务器等),而是专注到应用程序业务逻辑上的计算服务模型。
加州大学伯克利分校在论文中尝试给出Serverless的定义:Serverless computing = FaaS + BaaS。
Serverless 包含两个组成部分 BaaS(后端即服务)和 FaaS(函数即服务)。对象存储、关系型数据库以及 MQ 等基础支撑服务属于BaaS。FaaS为开发人员提供了一种运行应用的抽象方式,在层次上更靠近应用程序开发者。
FaaS为开发人员提供了一种运行应用的抽象方式,可以在无需管理服务器的情况下响应事件。例如,上载文件可触发自定义代码,从而将文件转码为各种格式。
FaaS通过事件驱动执行,它会随时待命,但不需要任何服务器进程在后台持续运行。当请求到来时,FaaS在毫秒内启动服务并处理各个请求,当请求减少时,FaaS会自动减少服务副本数量甚至关停服务。
动态扩缩容使FaaS在成本效益上颇具弹性空间,提供商可以仅对使用的资源收费,而不对空闲时间收费。
从服务形态看,FaaS平台需要实现几个关键部分:
函数环境可以分两个点,系统环境和函数依赖,系统环境主要指系统平台、RootFS等,函数依赖是用户代码本身依赖的第三方库等。函数执行需要为用户代码分配计算实体,具体可以是进程、容器、虚拟机、Wasm等等。
动态扩缩容是FaaS平台对函数状态感知到反馈的一个体现,可以收集函数执行环境和依赖的服务指标来实现,比如采集CPU、内存、带宽、IOPS等等指标判断函数负载采取扩缩容行为。
函数执行依靠事件驱动,事件框架是事件采集、传输的关键。所以设计FaaS平台事件框架需要考虑扩展性,事件传输效率,事件采集协议等等问题。
先上项目地址: https://github.com/refunc/refunc
Refunc是一个基于Kubernetes的开源函数计算平台,架构如下图:
基于Kubernetes开发实现,核心的CRD包括:
工作原理概括为,基于Funcdef和Xenv解决函数环境与执行,定义的Trigger收集事件通过基于Nats的事件框架传递到Funcinsts驱动函数执行并返回结果,核心Operator扩展了Kubernetes的HPA实现了从0到N的函数动态扩缩容。
Refunc拥抱AWS Lambda生态,函数Runtime完全兼容Lambda,基于Lambda的Runtime生态支持各种编程语言,平台接口API兼容Lambda核心接口,完全可以使用aws官方cli工具。
在前面文章nginx编译安装中我们提到,nginx模块是提前编译进去的,所以如果要基于nginx做扩展开发,就要相对比较收悉nginx代码结构和编译过程。
虽然未来nginx版本即使支持动态链接库,使用C语言写nginx扩展门槛也同样高。
复习一下,查询编译安装nginx模块信息,使用-V参数即可
nginx -V
nginx version: openresty/1.19.3.2
built by gcc 9.3.1 20200408 (Red Hat 9.3.1-2) (GCC)
built with OpenSSL 1.1.1k 25 Mar 2021
TLS SNI support enabled
configure arguments: --prefix=/usr/local/openresty/nginx ... --with-http_v2_module --without-mail_pop3_module --without-mail_imap_module --without-mail_smtp_module --with-http_stub_status_module --with-http_realip_module --with-http_addition_module --with-http_auth_request_module --with-http_secure_link_module --with-http_random_index_module --with-http_gzip_static_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-threads --with-compat --with-stream --with-http_ssl_module
可以看到在configure arguments中详细列出了我们当前nginx中已经编译进去的模块。
使用C并且重新编译nginx,对于我们基于nginx做业务开发,造成了诸多不便,开发测试、上线更新相对麻烦。Openresty的解决方式是首先使用C写了lua-nginx-module,将luajit嵌入了nginx中,打开了扩展的大门,然后业务开发模块可以使用lua脚本语言来开发。
openresty的官方解释为一个基于nginx的可编写脚本的Web平台,除了核心的lua-nginx-moduleopenresty还包含维护了非常多lua编写的第三方模块,开箱即用,很方便我们做业务定制开发。
官方推荐安装方式为通过软件源二进制包安装,因为编译lua-nginx-module还是非常麻烦的,对于我们使用lua快速实现业务来说,这块精力可以不花,如果要深入openresty可以尝试完全从源码编译安装。
# add the yum repo:
wget https://openresty.org/package/centos/openresty.repo
sudo mv openresty.repo /etc/yum.repos.d/
# update the yum index:
sudo yum check-update
sudo yum install openresty
通过官方源安装openresty非常简单,而且安装之后所有文件都在/usr/local/openresty下面,非常简洁:
$ ls -al
总用量 64
drwxr-xr-x 10 root root 4096 6月 3 11:46 .
drwxr-xr-x. 16 root root 4096 6月 3 11:46 ..
drwxr-xr-x 2 root root 4096 6月 3 11:46 bin
-rw-r--r-- 1 root root 22924 6月 1 13:11 COPYRIGHT
drwxr-xr-x 6 root root 4096 6月 3 11:46 luajit
drwxr-xr-x 5 root root 4096 6月 3 11:46 lualib
drwxr-xr-x 6 root root 4096 6月 3 11:46 nginx
drwxr-xr-x 4 root root 4096 6月 3 11:46 openssl111
drwxr-xr-x 3 root root 4096 6月 3 11:46 pcre
drwxr-xr-x 3 root root 4096 6月 3 11:46 site
drwxr-xr-x 3 root root 4096 6月 3 11:46 zlib
注意到这个目录下有openssl和pcre两个目录,回顾我们编译安装nginx提到的依赖,可见openresty的源已经帮我们解决好了这个依赖,统一放到当前目录下。
安装完openresty我们完全可以使用openresty命令替换nginx命令,所有的参数都一样,准备一个conf文件启动。
# mkdir -p /tmp/nginx/logs
# /tmp/nginx/demo.conf
worker_processes 1;
error_log logs/error.log debug;
events {
worker_connections 1024;
}
daemon off;
http {
server {
listen 9090;
location / {
content_by_lua_block {
ngx.say("hello world")
}
}
}
}
# openresty -p /tmp/nginx -c /tmp/nginx/demo.conf
另起终端测试
curl -v http://127.0.0.1:9090
* Trying 127.0.0.1:9090...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 9090 (#0)
> GET / HTTP/1.1
> Host: 127.0.0.1:9090
> User-Agent: curl/7.68.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Server: openresty/1.19.3.2
< Date: Fri, 18 Jun 2021 09:04:56 GMT
< Content-Type: text/plain
< Transfer-Encoding: chunked
< Connection: keep-alive
<
hello world
* Connection #0 to host 127.0.0.1 left intact
在上面demo.conf中我们已经实现了openresty lua的hello world,值得注意的是我们使用了一个content_by_lua_block指令,这个指令是lua-nginx-module提供的,意思为这个location响应内容通过执行lua产生。
在介绍更多指令之前我们先看一下lua-nginx-module的在nginx中的的流程图:
图中从上到下描述了lua-nginx-module可作用的:启动初始化lua、处理请求rewrite/access、产生响应、记录日志阶段,以及对应阶段可使用的指令。
每一个阶段的*_by_lua指令后面,我们可以引用我们的lua脚本,或者直接写片段的lua代码。对应的我们可以在lua脚本中实现请求当前阶段的业务逻辑,比如可以在access阶段做安全认证等逻辑。
更多指令: https://github.com/openresty/lua-nginx-module#directives 。
openresty除了实现lua-nginx-module开启了执行lua脚本能力外,还将许多nginx api直接封装进了lua,我们在实现业务逻辑的时候在脚本中可以直接使用,比如在上面demo.conf中我们调用的ngx.say(),便是一个类似print的api。
更多nginx lua api: https://github.com/openresty/lua-nginx-module#nginx-api-for-lua 。
总的来说,使用openresty来做基于nginx的业务开发,门槛已经大大降低了,几乎不用去熟悉nginx的代码和数据结构。了解lua-nginx-module提供的指令、封装好的api、在nginx中的作用流程,是入坑的开始。
kubernetes社区官方基于lua能力实现的ingress-controller,使用lua主要解决动态upstream的问题。
https://github.com/kubernetes/ingress-nginx
基于nginx+lua实现的api-gateway。
https://github.com/kong/kong
在Linux网络数据包的接收过程和数据包的发送过程两篇文章介绍数据包收发流程中, 已经提到了在内核协议栈处理包过程中在不同阶段提供了不同的hook点,在hook点上可以注册函数来自定义包处理逻辑,内核提供的这些hook点便是众多linux防火墙软件的基础。
在 Linux 生态系统中,iptables 是使用很广泛的防火墙工具之一,它基于内核的包过滤框架(packet filtering framework) netfilter。
netfilter最早是社区开发的防火墙框架,在内核2.4.x版本之后合并入了内核。
netfilter和iptables的关系可以简单理解为:
netfilter 提供了 5 个 hook 点。包经过协议栈时会触发内核模块注册在这里的处理函数 。触发哪个 hook 取决于包的方向(是发送还是接收)、包的目的地址、以及包在上一个 hook 点是被丢弃还是拒绝等等。
iptables 使用 table 来组织规则,根据用来做什么类型的判断(the type of decisions they are used to make)标准,将规则分为不同 table。例如,如果规则是处理 网络地址转换的,那会放到 nat table;如果是判断是否允许包继续向前,那可能会放到 filter table。
在每个 table 内部,规则被进一步组织成 chain,内置的 chain 是由内置的 hook 触发 的。chain 基本上能决定(basically determin)规则何时被匹配。
先来看看 iptables 提供的 table 类型。这些 table 是按规则类型区分的。
连接跟踪是许多网络应用的基础。例如,Kubernetes Service、ServiceMesh sidecar、 软件四层负载均衡器 LVS/IPVS、Docker network、OVS、iptables 主机防火墙等等,都依赖连接跟踪功能。
连接跟踪所做的事情就是发现并跟踪这些连接的状态,具体包括:
Linux 的连接跟踪是在 Netfilter 中实现的。