乐趣区

关于前端:技术分享-如何让上千容器同时存活

最近接到一个需要,用户能够申请创立一个或者多个 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,其实技术应用上没有什么难度,次要是分享思路。

退出移动版