最近接到一个需要,用户能够申请创立一个或者多个 docker 容器,容器要始终存在,用户不论过了多长时间都能够拜访,而且用户产生的数据始终存在,换而言之就是要做到容器长久化,也就是说咱们要提供一个小型的服务器,然而长此以往服务器资源就会被容器占满,就只能扩容了,我要做的就是在尽可能节俭服务器的状况下,提供尽可能多的 docker 容器。
简要思路
在用户应用一段时间后,把用户产生的差别数据长久化,而后进行容器,当用户再次拜访,通过拦挡拜访地址去新建容器并把长久化数据放到新的容器中,而后重定向,用户就能够拜访到与之前雷同的容器,好像容器始终存在。
实现流程
1. 当用户申请接口生成一个容器,返回域名
2. 一段时间后,进行容器,并配置下次访问启动容器
3. 用户拜访,通过之前的配置重启容器,重定向返回用户之前的数据
具体如下图
工具反对
docker-client
因为我要用 java 操作 docker, 启动、进行、删除、执行命令等操作,所以找了一个快捷应用的工具。
附上官网 https://github.com/docker-jav…
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,要在申请里携带一些参数用于重定向)
附上官网 https://docs.konghq.com/
具体实现
一、生成容器
用户在拜访接口的时候,后盾创立并启动容器,并生成 kong 的配置,后续用户拜访容器走的都是 kong 的代理,Route -> Services -> docker,设置心跳和生效工夫,心跳是用户的操作产生的,生效工夫是能够进行容器的工夫,有心跳会更新生效工夫。
代码示例
// 创立容器
CreateContainerCmd createContainerCmd = dockerClient
.createContainerCmd(docker.getImage())
.withTty(true)
.withName(this.generateContainerName(docker))
.withCmd(managerUrl + docker.getId())
.withHostConfig(hostConfig);
CreateContainerResponse containerResponse = createContainerCmd.exec();
// 启动容器
dockerClient.startContainerCmd(containerResponse.getId()).exec();
二、进行容器
进行容器要保障下一次用户拜访申请的时候容器能够再次启动,所以在进行容器后要把用户拜访容器的申请,通过代理转到后盾的接口,这里的代理 kong。具体步骤就是后盾会有一个 job 来管制让非沉闷的容器长久化数据,而后进行容器,配置 kong,让下一次申请散发到后盾服务。
具体实现:
1. 减少 services 设置 http 接口申请地址
JKongAdmin admin = new JKongAdmin(kongAdminUrl);
ServiceResp resp = admin.addService(new ServiceReq.Builder()
.host(recoverHost)
.port(recoverPort)
.path(recoverPath)
.build());
2. 减少 route 设置 serviceId, 用户拜访域名
JKongAdmin admin = new JKongAdmin(kongAdminUrl);
RouteResp resp = admin.addRoute(new RouteReq.Builder()
.serviceId(serviceId)
.host(host)
.build());
3. 减少 plugin 设置 serviceId,后盾地址 次要用于重启容器是带入参数
JKongAdmin admin = new JKongAdmin(kongAdminUrl);
Map<String, String> replaceConfigMap = new HashMap<>();
replaceConfigMap.put("uri", recoverPath);
PluginResp resp = admin.addPlugin(new PluginReq.Builder()
.name("request-transformer")
.serviceId(serviceId)
.config("replace",replaceConfigMap)
.enabled(true)
.build());
三、重启容器
用户通过域名拜访达到 route,route 转发到对应的 service,在拜访 service 配置的 http 接口,而后 http 接口启动容器,浏览器重定向,因为容器曾经存在,只须要启动即可,速度能够达到秒级, 以此达到容器“存活”的假象。
@GetMapping("/recover")
@ApiOperation(value = "资源复原")
public void recover(HttpServletRequest request, HttpServletResponse response) throws IOException {String host = request.getHeader("x-forwarded-host");
String path = request.getHeader("x-forwarded-path");
this.playgroundService.recover(host);
response.sendRedirect(host + ":" + kongClientPort + path);
}
总结
最初再剖析一下需要,其实难点次要在容器进行之后,页面拜访,再把容器启动,因为用户拜访的是容器绑定的域名,没有 http 接口,所以只能用 kong API 拦挡域名转发到后盾服务器去启动 docker 和重定向,让闲暇的容器进行,节俭内存,须要的时候再启动,通过解决如同容器始终是启动状态,后盾尽管转发的比拟多,然而前台页面没有感知.
以上就是明天要讲的内容,技术上次要用到的是 kong API 和 docker-java,其实技术应用上没有什么难度,次要是分享思路。