今天来记录一下使用Java调用DockerAPI创建docker容器,来部署python脚本的过程。
准备工作:
一台linux服务器,本人用的是centos7
安装jdk和docker,docker的安装过程可以百度一波(本人参考了https://www.runoob.com/docker/centos-docker-install.html)
只需要执行一句命令,docker安装成功
curl -sSL https://get.daocloud.io/docker | sh
docker安装完成之后可以修改一下镜像仓库,否则可能下载镜像时可能会很慢,没有文件就创建一个
vim /etc/docker/daemon.json
修改为下面内容
{
"registry-mirrors":[ "http://hub-mirror.c.163.com" ]
}
1.使用docker下载python镜像
#搜索一下python镜像
docker search python
#拉取python镜像(根据自身情况写版本号)
docker pull python:3.7.9#查看镜像
docker images
2.启动通过docker镜像来启动容器
#启动一个容器(注意有时多复制一个换行符会报错)
docker run -dit -v /home:/home python:3.7.9
#查看容器是否启动成功
docker ps
说明 :-v /home:/home这句是将本地路径挂在到docker容器中,这样在docker容器中/home下的内容就和宿主机的/home内容一致了。
3.进入docker容器
docker exec -it d1692a8182a7 /bin/bash
docker容器是一个简化的linux系统,我们需要再上面安装python的依赖
4.安装python依赖(根据自身情况而定)
本人所有的依赖都是在文件/home/requirements.txt中的,所以执行下面命令:
pip3 install -r /home/requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
安装依赖时可能会有冲突 ,需要单独安装(这步不是必要的)
pip3 install django-cors-headers
pip3 install djangorestframework
pip3 install drf-yasg
在后面启动pyhton时会遇到下面问题
#ImportError: libGL.so.1: cannot open shared object file: No such file or dir
执行以下语句搞定(如果没有问题请忽略)
apt-get update
apt-get install sudo
sudo apt update
sudo apt install libgl1-mesa-glx
5.将需要启动的文件上传到服务器的路径/home下,这个路径在上面我们已经挂在到容器下了,启动python服务
python /home/1/manage.py runserver
启动成功说明我们的python环境已经搭建好了
如果启动失败,根据提示,继续安装缺少的依赖,知道启动成功
在保证容器能够正常运行python的前提下,我们将python容器封装成镜像,这样就不用每次都去安装依赖了。
7.将docker容器封打包为镜像
docker commit 容器id 设置打包为镜像的名字
#打包为镜像
docker commit d1692a8182a7 python-test1
#查看打包后的镜像
docker images
此时我们就可以根据这个自定义的镜像来启动docker容器了
8.启动新docker容器
docker run -dit -v /home:/home --network host --name pythontest001 python-test1
9.进入新docker容器
#进入容器
docker exec -it cbdfcfe9dceadcca08517ff8ac5267146cfca22dd7e593d6270a47e3c6b5a1a2 /bin/bash
#启动python服务
python /home/1/manage.py runserver 192.168.144.66:18001
启动成功
在浏览器通过http://192.168.144.66:18001/可以进行访问。
以上是通过命令来实现docker部署python程序,下面来记录一下使用java来实现自动化部署
在使用java调用dockerAPI之前,首先要保证docker的API端口已经开通了,开通方式如下:
编辑文件:/lib/systemd/system/docker.service
在文件中找到ExecStart开头的一行,加入 -H tcp://0.0.0.0:2375
重启服务
sudo systemctl daemon-reload # 重新加载守护进程配置
sudo systemctl restart docker.service # 重启 docker 服务
10.引入maven依赖,只需要一个
com.github.docker-java
docker-java
3.0.6
11.代码只是对上面讲解的内容进行调用,并没有很复杂的逻辑,所以直接上代码
import com.alibaba.fastjson.JSONObject;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.command.CreateContainerCmd;
import com.github.dockerjava.api.command.CreateContainerResponse;
import com.github.dockerjava.api.model.*;
import com.github.dockerjava.core.DockerClientBuilder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.ws.rs.core.UriBuilder;
@Slf4j
@Service
public class DockerClientService {
//docker服务器的ip
private final String ip = "192.168.144.66";
//docker服务器端口号
private final String port = "2375";
//镜像名称
private final String imageName = "python-test1";
/**
*
* @param path 文件路径
* @param port 端口号
* @param modelStartFileName 启动文件名
* @param containerName 文件名称
* @return 容器id
*/
public String startPythonModel(String path, String port ,String modelStartFileName , String containerName) {
log.info("path:{}\nport:{}\nmodelStartFileName:{}\ncontainerName:{}",path,port,modelStartFileName,containerName);
//连接docker服务器
DockerClient client = this.connectDocker();
//文件挂在路径
Volume volume = new Volume(path);
CreateContainerCmd createContainerCmd = client.createContainerCmd(imageName)
.withName(containerName)
.withAttachStdin(true)
.withTty(true)
//挂载路径
.withVolumes(volume)
.withBinds(new Bind(path, volume, AccessMode.DEFAULT))
//设置网络模式,直接使用宿主机端口,这样不用再做转发了
.withNetworkMode("host")
.withEntrypoint("python", path +"/" +modelStartFileName, "runserver", ip + ":" + port);
CreateContainerResponse container = createContainerCmd.exec();
//启动容器
this.startContainer(client, container.getId());
return container.getId();
}
/**
* 连接docker服务器
*
* @return
*/
public DockerClient connectDocker() {
// String url = "tcp://" + ip + ":" + port;
String url = "tcp://192.168.144.66:2375";
DockerClient dockerClient = DockerClientBuilder.getInstance(url).build();
Info info = dockerClient.infoCmd().exec();
String infoStr = JSONObject.toJSONString(info);
System.out.println("docker的环境信息如下:=================");
System.out.println(info);
return dockerClient;
}
/**
* 创建容器
*
* @param client
* @return
*/
public CreateContainerResponse createContainers(DockerClient client, String containerName, String imageName) {
//映射端口8088—>80
ExposedPort tcp80 = ExposedPort.tcp(80);
Ports portBindings = new Ports();
portBindings.bind(tcp80, Ports.Binding.bindPort(8088));
CreateContainerResponse container = client.createContainerCmd(imageName)
.withName(containerName)
.withHostConfig(new HostConfig().withPortBindings(portBindings))
.withExposedPorts(tcp80)
.exec();
return container;
}
/**
* 启动容器
*
* @param client
* @param containerId
*/
public void startContainer(DockerClient client, String containerId) {
client.startContainerCmd(containerId).exec();
}
/**
* 启动容器
*
* @param client
* @param containerId
*/
public void stopContainer(DockerClient client, String containerId) {
client.stopContainerCmd(containerId).exec();
}
/**
* 删除容器
*
* @param client
* @param containerId
*/
public void removeContainer(DockerClient client, String containerId) {
client.removeContainerCmd(containerId).exec();
}
}
测试类
import com.adc.da.system.service.DockerClientService;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.model.Container;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
import java.util.Objects;
@RunWith(SpringRunner.class)
@SpringBootTest
public class DockerClientServiceTest {
@Autowired
private DockerClientService dockerClientService;
@Test
public void test() {
/*DockerClient dockerClient = dockerClientService.connectDocker();
List containerList = dockerClient.listContainersCmd().exec();
for (Container container : containerList) {
String[] names = container.getNames();
if(Objects.nonNull(names)&&names.length>1){
String name = names[0].substring(1);
}
}
dockerClientService.stopContainer(dockerClient,"id");*/
int port = 18100;
for (int i = 0; i < 60; i++) {
port++;
String id = dockerClientService.startPythonModel("/home/1", port + "", "manage.py", "java-test5-" + port);
System.out.println("完成"+i);
/* if(i%2==0){
dockerClientService.stopContainer(dockerClient,id);
dockerClientService.removeContainer(dockerClient,id);
}*/
}
}
}
搞定!