技术分享 | 如何让上千容器同时"存活"
最近接到一个需求,用户可以申请创建一个或者多个 docker 容器,容器要一直存在,用户不管过了多长时间都可以访问,而且用户产生的数据一直存在,换而言之就是要做到容器持久化,也就是说我们要提供一个小型的服务器,但是久而久之服务器资源就会被容器占满,就只能扩容了,我要做的就是在尽可能节省服务器的情况下,提供尽可能多的 docker 容器。
简要思路
在用户使用一段时间后,把用户产生的差异数据持久化,然后停止容器,当用户再次访问,通过拦截访问地址去新建容器并把持久化数据放到新的容器中,然后重定向,用户就可以访问到与之前相同的容器,仿佛容器一直存在。
实现流程
1.当用户请求接口生成一个容器,返回域名 2.一段时间后,停止容器,并配置下次访问启动容器 3.用户访问,通过之前的配置重启容器,重定向返回用户之前的数据具体如下图
工具支持
docker-client
因为我要用 java 操作 docker,启动、停止、删除、执行命令等操作,所以找了一个快捷使用的工具。
附上官网 https://github.com/docker-java/docker-java
kong api
因为在用户访问容器内接口的时候,容器如果已经删了,那就没有办法访问了,所以我在外层做了一层代理,用的工具是 kong API,kong 是基于 nginx 开发的 API Gateway,可以通过代码控制,而不像 nginx 那样去手动修改配置文件。
简单介绍一下我用到的几个功能:
Route:是请求的转发规则,按照 Hostname 和 PATH,将请求转发给 Service。(我理解的就是 nginx 的 location)
Services:是多个 Upstream 的集合,是 Route 的转发目标。(我理解的就是 nginx 的 server)
Plugin:是插件,plugin 可以是全局的,绑定到 Service,绑定到 Router,绑定到 Consumer。(有鉴权,访问限制,监控,日志记录等插件,我这里用的是 request-transformer,要在请求里携带一些参数用于重定向)
具体实现一、生成容器
用户在访问接口的时候,后台创建并启动容器,并生成 kong 的配置,后续用户访问容器走的都是 kong 的代理,Route -> Services -> docker,设置心跳和失效时间,心跳是用户的操作产生的,失效时间是可以停止容器的时间,有心跳会更新失效时间。
代码示例
二、停止容器
停止容器要保证下一次用户访问请求的时候容器可以再次启动,所以在停止容器后要把用户访问容器的请求,通过代理转到后台的接口,这里的代理 kong 。具体步骤就是后台会有一个 job 来控制让非活跃的容器持久化数据,然后停止容器,配置 kong,让下一次请求分发到后台服务。
具体实现:
1.增加 services 设置 http 接口请求地址
2.增加 route 设置 serviceId, 用户访问域名
3.增加 plugin 设置 serviceId,后台地址 主要用于重启容器是带入参数
三、重启容器
用户通过域名访问到达 route,route 转发到对应的 service,在访问 service 配置的 http 接口,然后 http 接口启动容器,浏览器重定向,因为容器已经存在,只需要启动即可,速度可以达到秒级,以此达到容器“存活”的假象。
总结
最后再分析一下需求,其实难点主要在容器停止之后,页面访问,再把容器启动,因为用户访问的是容器绑定的域名,没有 http 接口,所以只能用 kong API 拦截域名转发到后台服务器去启动 docker 和重定向,让空闲的容器停止,节省内存,需要的时候再启动,通过处理好像容器一直是启动状态,后台虽然转发的比较多,但是前台页面没有感知.
以上就是今天要讲的内容,技术上主要用到的是 kong API 和 docker-java,其实技术使用上没有什么难度,主要是分享思路。
评论