实现Java调用DockerAPI进行部署Python程序

今天来记录一下使用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依赖,只需要一个

<dependency>
            <groupId>com.github.docker-java</groupId>
            <artifactId>docker-java</artifactId>
            <version>3.0.6</version>
        </dependency>

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<Container> 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);
            }*/

        }


    }
}

搞定!

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值