通过java操作docker启动pm2

通过java操作docker启动pm2

看到标题确实觉得很拗口,在下实在想不出什么好的标题了~~~

概述

本文目的 :

  • 使用dockerfile构建镜像,构建镜像启动pm2(不太清楚pm2的可以度娘~)
  • 实现docker volume 挂载前端代码 ,方便更新前端代码版本
  • 通过java操作docker api , 实现操作docker

1.开启docker远程访问

在/usr/lib/systemd/system/docker.service,配置远程访问。

将其中ExecStart=/usr/bin/dockerd-current替换

ps : 这种方式不安全,可以把请求换成https方式 ,docker配置改成2376端口

/usr/bin/dockerd-current -H tcp://0.0.0.0:2375 -H unix://var/run/docker.sock -H tcp://0.0.0.0:7654 \

测试一下 : 请求 http://192.168.0.11:2375/info

2. 编写dockerfile

FROM node:10.16.0

WORKDIR /home/node/app
RUN npm install -g cnpm --registry=https://registry.npm.taobao.org
RUN cnpm install -g pm2

EXPOSE 8090
CMD  cnpm install && pm2 start --no-daemon npm --name test -- run serve

FROM : 指定使用node:10.16.0作为基础的构建镜像

WORKDIR : 指定工作的目录

RUN: 安装cnpm,pm2

EXPOSE:对外暴露8090端口

CMD : docker run时执行的命令

3. 构建镜像与运行容器

docker build -t test-pm2 --file pm2 .
docker run -p 8090:8090 -v /home/gloooooof/docker-file/vertical-style-8066:/home/node/app  --privileged=true --name test-pm2 test-pm2 

docker build -t test-pm2 --file pm2 .

  • -t : 构建镜像名称
  • --file : dockerfile文件名称
  • 后面必须加.,表示当前目录作为docker build context

docker run -p 8090:8090 -v /home/gloooooof/docker-file/vertical-style-8066:/home/node/app --privileged=true --name test-pm2 test-pm2

  • -v : 将本地目录/home/gloooooof/docker-file/vertical-style-8066映射到/home/gloooooof/docker-file/vertical-style-8066 ,:后面的/home/node/app是在dockerfile标识的默认工作环境,这样代码会在宿主机上,方便维护.
  • --privileged=true : 赋予-v目录权限 (因为这 我遇到了很大的困难!!! 毕竟不太了解nodejs报错都不知道~~)
  • --name 容器名称
  • test-pm2 : 指定构建的镜像

4. java项目

1. 引入maven依赖

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

2. docker-java使用

以下是基本操作,剩下的复杂操作请大家自己研究下,很简单的api~

public class DockerUtils {
    /**
     * 连接docker服务器
     * @return
     */
    public DockerClient connectDocker(String host,int port){
        DockerClient dockerClient = DockerClientBuilder.getInstance("tcp://"+host+":"+port).build();
        return dockerClient;
    }

    /**
     * 获取全部实例
     * @param client
     * @param isAll 是否获取停止的实例
     */
    public List<Container> getContainers(DockerClient client , boolean isAll){
        return client.listContainersCmd().withShowAll(isAll).exec();
    }
    /**
     * 创建容器
     * @param client
     * @return
     */
    public CreateContainerResponse createContainers(DockerClient client, String containerName, String imageName,String buildPort){
        //解析端口
        int[] resolverPort = resolverPort(buildPort);
        ExposedPort exposedPort = ExposedPort.tcp(resolverPort[0]);
        Ports portBindings = new Ports();
        portBindings.bind(exposedPort, Ports.Binding.bindPort(resolverPort[1]));

        CreateContainerResponse container = client.createContainerCmd(imageName)
                .withName(containerName)
                .withHostConfig(new HostConfig().withPortBindings(portBindings))
                .withExposedPorts(exposedPort).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();
    }

    /**
     * 解析端口
     */
    private int[] resolverPort(String buildPort){

        String[] splitString = buildPort.split(":");
        return new int[]{Integer.valueOf(splitString[0]),Integer.valueOf(splitString[1])};
    }
}

项目的代码

package com.blaaair.webmonitor;

import com.blaaair.webmonitor.utils.DockerUtils;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.async.ResultCallback;
import com.github.dockerjava.api.command.CreateContainerResponse;
import com.github.dockerjava.api.command.InfoCmd;
import com.github.dockerjava.api.command.ListNetworksCmd;
import com.github.dockerjava.api.command.StatsCmd;
import com.github.dockerjava.api.model.*;
import com.jcraft.jsch.*;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import java.io.*;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Properties;

@SpringBootApplication
public class WebMonitorApplication {

    public static void main(String[] args) throws JSchException, IOException {
        //SpringApplication.run(WebMonitorApplication.class, args);
        DockerUtils dockerUtils = new DockerUtils();
        DockerClient dockerClient = dockerUtils.connectDocker("192.168.0.11",2375);
//        List<Container> exec = dockerClient.listContainersCmd().withShowAll(true).exec();
        ExposedPort exposedPort = ExposedPort.tcp(8090);
        Ports portBindings = new Ports();
        portBindings.bind(exposedPort, Ports.Binding.bindPort(8090));
        // 以下等于 docker run -p 8090:8090 -v /home/gloooooof/docker-file/vertical-style-8066:/home/node/app  --privileged=true --name test-pm2 test-pm2
        // 构建容器
        CreateContainerResponse exec = dockerClient.createContainerCmd("test-pm2")
                .withName("test-pm2")
                .withHostConfig(new HostConfig()
                        .withPortBindings(portBindings)
                        .withPrivileged(true)
                        .withBinds(Bind.parse("/home/gloooooof/docker-file/vertical-style-8066:/home/node/app"))
                        )
                .withExposedPorts(exposedPort)
                .exec();
        // 启动容器
        dockerClient.startContainerCmd(exec.getId()).exec();
        dockerClient.logContainerCmd(exec.getId()).exec(new ResultCallback<Frame>() {
            @Override
            public void onStart(Closeable closeable) {

            }

            @Override
            public void onNext(Frame object) {

            }

            @Override
            public void onError(Throwable throwable) {
                System.out.println("启动失败"+throwable.getMessage());
            }

            @Override
            public void onComplete() {
                System.out.println("启动完成");
            }

            @Override
            public void close() throws IOException {

            }
        });
//        exec.stream().forEach(container -> {
//            System.err.println(container.getId()+":"+container.getNames()[0]+":"+container.getState());
//            if(container.getState().equals("exited")){
//                dockerClient.startContainerCmd(container.getId()).exec();
//            }
//        });
//        List<Network> exec1 = dockerClient.listNetworksCmd().exec();
//
//        exec1.stream().forEach(container -> {
//            System.err.println(container);
//
//        });
//        CreateContainerResponse container  = dockerUtils.createContainers(dockerClient, "hello", "java-app", "1:1");
//        dockerUtils.startContainer(dockerClient,container.getId());
    }


    /**
     * java操作ssh2
     * @throws JSchException
     * @throws IOException
     */
    public static void jsch() throws JSchException, IOException {
        JSch jSch = new JSch();
        Session session = jSch.getSession("gloooooof", "192.168.0.11");
        Properties config = new Properties();
        config.put("StrictHostKeyChecking", "no");
        session.setConfig(config); // 为Session对象设置properties
        session.setPassword("87913539w");
        session.connect();
        ChannelExec channelExec = (ChannelExec) session.openChannel("exec");
        channelExec.setCommand("docker ps --format \"{{.ID}}:{{.Names}}:{{.Status}}\"");
        channelExec.setInputStream(null);
        channelExec.setErrStream(System.err);
        channelExec.connect();
        InputStream in = channelExec.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(in, Charset.forName("UTF-8")));
        String buf = null;
        StringBuffer sb = new StringBuffer();
        while ((buf = reader.readLine()) != null) {
            sb.append(buf);
            System.out.println(buf);// 打印控制台输出
        }
        reader.close();
        channelExec.disconnect();
        if (null != session) {
            session.disconnect();
        }
    }
}

尾声

这样我们只要运行java的代码就能启动一个docker容器 , 只要发送前端代码到目标的文件夹(本文指/home/gloooooof/docker-file/vertical-style-8066)就能修改前端代码,pm2就可以自动热部署代码.非常的方便


通过java操作docker启动pm2
https://www.blaaair.com/archives/tong-guo-java-cao-zuo-docker-qi-dong-pm2
作者
Glo6f
发布于
2024年01月17日
许可协议