赞
踩
目前项目中需要实现水利机理模型的容器化部署,使用docker实现模型容器化部署操作,互相隔离,就是一个不错的方案。
- 打开docker.service文件
- sudo vi /lib/systemd/system/docker.service
- 找到ExecStart 开头的配置,注释原配置 进行备份
- 插入以下内容
- ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix://var/run/docker.sock
- 保存退出
- sudo systemctl daemon-reload
- sudo systemctl restart docker
注意:
1、我使用的是Ubutun系统,需要使用sudo进行操作。防火墙如果启动,需要开发2375端口,不然无法访问到docker。
2、浏览器输入:http://IP:2375/version 如果响应正常,则配置生效
- <dependency>
- <groupId>com.github.docker-java</groupId>
- <artifactId>docker-java</artifactId>
- <version>3.2.13</version>
- </dependency>
-
- <dependency>
- <groupId>com.github.docker-java</groupId>
- <artifactId>docker-java-transport-httpclient5</artifactId>
- <version>3.2.13</version>
- </dependency>
-
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>fastjson</artifactId>
- <version>1.2.83</version>
- </dependency>

3.1.3创建普通连接
- package com.sf.engines.config;
-
- import com.alibaba.fastjson.JSONObject;
- import com.github.dockerjava.api.DockerClient;
- import com.github.dockerjava.api.model.Info;
- import com.github.dockerjava.core.DefaultDockerClientConfig;
- import com.github.dockerjava.core.DockerClientImpl;
- import com.github.dockerjava.httpclient5.ApacheDockerHttpClient;
- import com.github.dockerjava.transport.DockerHttpClient;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.context.annotation.Bean;
- import java.time.Duration;
-
- @Configuration
- public class DockerConfig {
-
- /**
- * 连接docker服务器
- * @return
- */
- @Bean("dockerClient")
- public DockerClient connectDocker(){
- DefaultDockerClientConfig config = DefaultDockerClientConfig.createDefaultConfigBuilder()
- .withDockerTlsVerify(false)
- // 这里填最上面填的ip端口号,ip换成服务器ip
- .withDockerHost("tcp://192.168.10.8:2375")
- // docker API版本号,可以用docker version查看
- .withApiVersion("1.41")
- // 默认
- .withRegistryUrl("https://index.docker.io/v1/").build();
-
- DockerHttpClient httpClient = new ApacheDockerHttpClient.Builder()
- .dockerHost(config.getDockerHost())
- .sslConfig(config.getSSLConfig())
- .maxConnections(100)
- .connectionTimeout(Duration.ofSeconds(30))
- .responseTimeout(Duration.ofSeconds(45))
- .build();
-
- DockerClient dockerClient = DockerClientImpl.getInstance(config, httpClient);
-
- Info info = dockerClient.infoCmd().exec();
- String infoStr = JSONObject.toJSONString(info);
- System.out.println("docker的环境信息如下:=================");
- System.out.println(infoStr);
- return dockerClient;
- }
-
- }

控制台打印了docker信息,说明已经连上docker。
注意:
- sudo vi /lib/systemd/system/docker.service
- 找到ExecStart 开头的配置,注释原配置 进行备份
- 插入以下内容
- ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -H tcp://0.0.0.0:2375 -H unix://var/run/docker.sock -D --tlsverify --tlscert=/etc/docker/certs.d/server-cert-docker.pem --tlskey=/etc/docker/certs.d/server-key-docker.pem --tlscacert=/etc/docker/certs.d/ca-docker.pem
- 保存退出
- sudo systemctl daemon-reload
- sudo service docker restart
2. 证书脚本编写
- #!/bin/bash
- #
- # -------------------------------------------------------------
- # 自动创建 Docker TLS 证书
- # -------------------------------------------------------------
- # 以下是配置信息
- # --[BEGIN]------------------------------
- CODE="docker"
- IP="192.168.1.1"
- PASSWORD="123456"
- COUNTRY="CN"
- STATE="SHANDONG"
- CITY="JINAN"
- ORGANIZATION="thyc"
- ORGANIZATIONAL_UNIT="Dev"
- COMMON_NAME="$IP"
- EMAIL="zjbang.ok@163.com"
- # --[END]--
- # Generate CA key
- openssl genrsa -aes256 -passout "pass:$PASSWORD" -out "ca-key-$CODE.pem" 4096
- # Generate CA
- openssl req -new -x509 -days 365 -key "ca-key-$CODE.pem" -sha256 -out "ca-$CODE.pem" -passin "pass:$PASSWORD" -subj "/C=$COUNTRY/ST=$STATE/L=$CITY/O=$ORGANIZATION/OU=$ORGANIZATIONAL_UNIT/CN=$COMMON_NAME/emailAddress=$EMAIL"
- # Generate Server key
- openssl genrsa -out "server-key-$CODE.pem" 4096
- # Generate Server Certs.
- openssl req -subj "/CN=$COMMON_NAME" -sha256 -new -key "server-key-$CODE.pem" -out server.csr
- echo "subjectAltName = IP:$IP,IP:127.0.0.1" >> extfile.cnf
- echo "extendedKeyUsage = serverAuth" >> extfile.cnf
- openssl x509 -req -days 365 -sha256 -in server.csr -passin "pass:$PASSWORD" -CA "ca-$CODE.pem" -CAkey "ca-key-$CODE.pem" -CAcreateserial -out "server-cert-$CODE.pem" -extfile extfile.cnf
- # Generate Client Certs.
- rm -f extfile.cnf
- openssl genrsa -out "key-$CODE.pem" 4096
- openssl req -subj '/CN=client' -new -key "key-$CODE.pem" -out client.csr
- echo extendedKeyUsage = clientAuth >> extfile.cnf
- openssl x509 -req -days 365 -sha256 -in client.csr -passin "pass:$PASSWORD" -CA "ca-$CODE.pem" -CAkey "ca-key-$CODE.pem" -CAcreateserial -out "cert-$CODE.pem" -extfile extfile.cnf
- rm -vf client.csr server.csr
- chmod -v 0400 "ca-key-$CODE.pem" "key-$CODE.pem" "server-key-$CODE.pem"
- chmod -v 0444 "ca-$CODE.pem" "server-cert-$CODE.pem" "cert-$CODE.pem"
- # 打包客户端证书
- mkdir -p "tls-client-certs-$CODE"
- cp -f "ca-$CODE.pem" "cert-$CODE.pem" "key-$CODE.pem" "tls-client-certs-$CODE/"
- cd "tls-client-certs-$CODE"
- tar zcf "tls-client-certs-$CODE.tar.gz" *
- mv "tls-client-certs-$CODE.tar.gz" ../
- cd ..
- rm -rf "tls-client-certs-$CODE"
- # 拷贝服务端证书
- mkdir -p /etc/docker/certs.d
- cp "ca-$CODE.pem" "server-cert-$CODE.pem" "server-key-$CODE.pem" /etc/docker/certs.d/

脚本是网上找的,可以自动生成证书并完成拷贝的脚本。脚本命名自由:sudo vi auto_gen_docker.sh
3.执行脚本
- chmod a+x auto_gen_docker.sh
- sh auto_gen_docker.sh
-
- /**
- * 从Dockerfile构建镜像
- * @return
- * @throws URISyntaxException
- */
- public String buildImage(String imageName, String imageTag, String dockerFile) throws URISyntaxException {
- ImmutableSet<String> tag = ImmutableSet.of(imageName + ":" + imageTag);
- String imageId = dockerClient.buildImageCmd(new File(dockerFile))
- .withTags(tag)
- .start()
- .awaitImageId();
- return imageId;
- }
提示:我在使用buileImageCmd时,无法正确构建镜像。不得已采取比较笨的办法,将dockerfile文件上传到服务器目标文件夹中,通过ssh远程调用的方式,进行远程镜像构建操作。具体实现代码如下:
- //远程构建镜像
- private String buildImage(EnginesModelImageEntity image) {
-
- String tag = image.getImageName() + ":" + image.getImageTag();
- //模型解压命令
- StringBuffer buildBuffer = new StringBuffer("");
- buildBuffer.append(ModelConstant.CD_STR)
- .append(image.getDockerFileUrl())
- .append(ModelConstant.AND_STR)
- .append(ModelConstant.DOCKER_BUILD)
- .append(tag)
- .append(ModelConstant.DOCKER_BUILD_END);
- //调用远程命令进行模型解压
- Connection unzipCoon = SshUtil.login(ip,userName,password);
- String result = SshUtil.execute(unzipCoon, buildBuffer.toString());
- return result;
- }

注意:远程连接的代码在以前的文章里有,可以去查阅。
1、首先通过CD名称进入到存放dockerfile的文件夹,然后执行镜像build命令: docker build -t imageName:imageTag .
2、构建命令最后的. 一定不能省略。
构建镜像有时会没有那么快,可以通过接口获取镜像ID:
- public R getImageID(EnginesModelImageEntity image) {
- if(ObjectUtils.isEmpty(dockerClient)){
- initDockerClient();
- }
- String tag = image.getImageName() + ":" + image.getImageTag();
- List<Image> images = dockerClient.listImagesCmd().withImageNameFilter(image.getImageName()).exec();
- if(images.isEmpty()){
- return R.fail("镜像构建中,请稍后再试!");
- }
- String imageId = "";
- for(Image i : images){
- if(Arrays.asList(i.getRepoTags()).contains(tag)){
- String id = i.getId();
- imageId = id.substring(id.indexOf(":")+1,id.indexOf(":")+13);
- }
- }
- if(ObjectUtils.isNotEmpty(imageId)){
- image.setImageId(imageId);
- image.setImageStatus("2");
- baseMapper.updateById(image);
- return R.success("获取镜像ID成功!");
- }
- return R.success("未查询到镜像ID,请稍后再试!");
- }

注意:如果使用同一个dockerfile文件构建镜像,则镜像ID是一致的,会存在多个镜像TAG,可以根据repoTags中是否包含自己的镜像标签来判断,镜像是否构建完成。
3.2.3删除镜像
docker-java删除镜像是通过镜像ID进行删除操作的:
-
- public void removeImage(DockerClient client,String imageId){
- dockerClient.removeImageCmd(imageId).exec();
- }
但是会把同一个dockerfile构造的镜像全部删除,我是通过镜像tag进行镜像删除操作的:
- public boolean removeImage(Long id) {
- EnginesModelImageEntity image = baseMapper.selectById(id);
- if(ObjectUtils.isEmpty(dockerClient)){
- initDockerClient();
- }
- image.setImageStatus("3");
- if(baseMapper.updateById(image)>=0){
- String tag = image.getImageName() + ":" + image.getImageTag();
- //模型解压命令
- StringBuffer removeBuffer = new StringBuffer("");
- removeBuffer.append(ModelConstant.DOCKER_REMOVE)
- .append(tag);
- //调用远程命令进行模型解压
- Connection unzipCoon = SshUtil.login(ip,userName,password);
- SshUtil.execute(unzipCoon, removeBuffer.toString());
- return true;
- }
- return false;
- }

注意:通过删除镜像命令:docker rmi imageName:imageTag进行镜像删除操作。
3.3.1创建容器
- private String createContainers(EnginesModelContainerEntity entity){
- EnginesModelImageEntity image = imageMapper.selectById(entity.getImageId());
- String result = "";
- for(int i=0;i<entity.getContainerNumber();i++){
- EnginesModelContainerChildEntity childEntity = new EnginesModelContainerChildEntity();
- childEntity.setModelId(entity.getModelId());
- String containerName = entity.getContainerName().replace(" ","") + ModelConstant.UNDERLINE +i;
- childEntity.setContainerName(containerName);
- childEntity.setContainerStatus("2");
- childEntity.setParentId(entity.getId());
- childEntity.setStatus(0);
- childEntity.setIsDeleted(0);
- childEntity.setCreateTime(new Date());
- childEntity.setCreateUser(entity.getCreateUser());
- String buffer = ModelConstant.DOCKER_RUN + containerName + ModelConstant.SPACE + image.getImageName() + ModelConstant.COLON + image.getImageTag();
- Connection pullCoon = SshUtil.login(ip,userName,password);
- result = SshUtil.execute(pullCoon, buffer);
- if(ObjectUtils.isNotEmpty(result)){
- childMapper.insert(childEntity);
- }
- }
-
- return result;
- }

使用的远程ssh方式创建容器,容器启动命令:
docker run --gpus all -itd --name= containerName imageName:imageTag
- public static void main(String[] args) {
- String containerId = "61cf0a2e4c4a0ae00ad8aa1193f3abfbdd9a48e6236f427d2c37fae23b84ae6f"; // Replace with your container ID
- String filePath = "/opt/model/twoHydrodynamic/ProcessData/Inflow_3.json";
- String fileContent = "Create JSON FILE";
- DockerClientService.initDockerClient("ip","docker端口");
- // 创建一个tar归档,将内容写入tar文件
- ByteArrayInputStream tarStream = null;
- try {
- tarStream = TarUtils.createTarArchive(filePath, fileContent);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
-
-
- ExecCreateCmdResponse response = dockerClient.execCreateCmd(containerId)
- .withCmd("tar", "-C", "/", "-x")
- .withAttachStdout(true)
- .withAttachStderr(true)
- .exec();
- ExecStartCmd startCmd = dockerClient.execStartCmd(response.getId())
- .withDetach(false)
- .withTty(true);
- ExecStartResultCallback callback = new ExecStartResultCallback();
-
- startCmd.exec(callback);
- // 发送tar归档数据
- dockerClient.copyArchiveToContainerCmd(containerId)
- .withRemotePath("/")
- .withTarInputStream(tarStream)
- .exec();
- // 关闭tarStream
- try {
- tarStream.close();
- } catch (Exception e) {
- e.printStackTrace();
- }
-
- }

- public static void main(String[] args) {
- String containerId = "61cf0a2e4c4a0ae00ad8aa1193f3abfbdd9a48e6236f427d2c37fae23b84ae6f"; // Replace with your container ID
- String filePath = "/opt/model/twoHydrodynamic/OutputData/X2DProcess.dat";
- DockerClientService.initDockerClient("IP","docker端口");
- String taskId = UUID.randomUUID().toString();
- String basePath = "/Users/admin/Documents/shuke/modelFile/depth/"+taskId;
- File folder = new File(basePath);
- //如果文件夹不存在,则创建文件夹
- if (!folder.exists()) {
- folder.mkdirs();
- }
- String outPath = basePath + "/X2DProcess.dat";
- try {
- InputStream inputStream = dockerClient.copyArchiveFromContainerCmd(containerId, filePath).exec();
- try (OutputStream outputStream = new FileOutputStream(outPath)) {
- byte[] buffer = new byte[1024];
- int bytesRead;
- while ((bytesRead = inputStream.read(buffer)) != -1) {
- outputStream.write(buffer, 0, bytesRead);
- }
-
- } catch (IOException e) {
- e.printStackTrace();
- } finally {
- try {
- inputStream.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- contentGet(folder,outPath,taskId);
- } catch (NotFoundException e) {
- System.err.println("Container not found: " + e.getMessage());
- } catch (FileNotFoundException e) {
- throw new RuntimeException(e);
- }
- }

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。