通过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 contextdocker 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