docker-java挂载GPU解决办法
1.docker安装
未安装docker的小伙伴,请浏览docker安装的教程
2.连接docker方法
public DockerClient connectDocker(String dockerHost,
String registryUrl,
String registryUsername,
String registryPassword) {
try {
DockerClientConfig config = DefaultDockerClientConfig.createDefaultConfigBuilder()
.withDockerHost(dockerHost)
.withRegistryUrl(registryUrl)
.withRegistryUsername(registryUsername)
.withRegistryPassword(registryPassword)
.build();
DockerCmdExecFactory dockerCmdExecFactory = new NettyDockerCmdExecFactory()
.withReadTimeout(300000)
.withConnectTimeout(300000);
DockerClient client = DockerClientBuilder.getInstance(config)
.withDockerCmdExecFactory(dockerCmdExecFactory)
.build();
System.out.println("=================docker的环境信息=================");
System.out.println(client.infoCmd().exec());
System.out.println("=================docker的环境信息=================");
return dockerClient;
} catch (Exception e) {
e.printStackTrace();
logger.error(Thread.currentThread().getStackTrace()[1].getMethodName() + ": " + e.toString());
return null;
}
}
3.挂载宿主机路径
挂载宿主机需要通过docker-java下的Bind进行挂载,可通过List< Bind> 挂载多个宿主机路径,rw为读写模式,ro为仅读模式
List<Bind> bindList = new ArrayList<>();
bindList.add(new Bind("宿主机路径", new Volume("容器内路径"), rw));
4.创建容器的entryPoint
5.GPU挂载
GPU挂载有两个要求
- docker >= 19.03
- Linux系统
第一,docker版本低于19.03需要安装并使用nvidia-docker完成显卡的挂载,可浏览nvidia-docker的官方GitHub查看详细使用规则,但是docker-java是无法使用nvidia-docker命令
第二,目前GPU挂载仅支持Linux系统的挂载,因为安装在Windows里的docker是依赖于hyper-v虚拟机的,使用hyper-v虚拟的环境完成docker的linux环境。但是hyper-v是无法进行显卡直通的,故无法完成docker的显卡挂载
满足上述两个条件后,就可以在Linux的终端通过docker命令挂载GPU到容器当中了
但是在docker-java中是没有直接的api实现对GPU挂载的,需要“绕一下圈子”,下面直接先贴一下具体代码,之后再进行解释为什么这么操作
public CreateContainerResponse createContainer(DockerClient dockerClient,
String imageName,
String containerName,
List<String> envList,
List<Bind> bindList,
Long cpu,
Long memory,
List<Integer> gpuList,
List<String> entryPoint) {
HostConfig hostConfig = newHostConfig()
.withBinds(bindList)
.withMemory(memory)
.withCpuCount(cpu)
.withReadonlyRootfs(true)
.withLogConfig(new LogConfig(LogConfig.LoggingType.JSON_FILE));
if (gpuList.size() > 0) {
List<DeviceRequest> deviceRequests = new ArrayList<>();
DeviceRequest deviceRequest = new DeviceRequest();
List<String> deviceIds = new ArrayList<>();
for (Integer index : gpuList) {
deviceIds.add(String.valueOf(index));
}
List<List<String>> capabilities = new ArrayList<>();
List<String> capabilitie = new ArrayList<>();
capabilitie.add("gpu");
capabilities.add(capabilitie);
deviceRequest.withDriver("").withCount(0).withDeviceIds(deviceIds).withOptions(new HashMap<>()).withCapabilities(capabilities);
deviceRequests.add(deviceRequest);
hostConfig.withDeviceRequests(deviceRequests);
}
return dockerClient.createContainerCmd(imageName)
.withName(containerName)
.withEnv(envList)
.withHostConfig(hostConfig)
.withEntrypoint(entryPoint)
.exec();
}
为什么这样可以成功?
首先先用终端启动一个挂载GPU的容器,然后inspect他,可以看到挂载GPU和没有挂载GPU的容器主要在配置文件上差别如下图:
那么我们就可以使用docker-java手动挂载GPU,docker-java对GPU的管理