文章
docker-java工具类实现
ContainerInfoDTO.java
import lombok.Data;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ContainerInfoDTO {
private String id; // 容器ID
private String name; // 容器名称
private Boolean status; // 运行状态(true:运行中, false:已停止)
private String image; // 镜像名称
private String desc; // 描述信息
private ServiceTypeEnum type; // 服务类型
}
DockerInfoDTO.java
import lombok.Data;
@Data
public class DockerInfoDTO {
private Integer runningContainer; // 运行中的容器数量
private Integer stopContainer; // 已停止的容器数量
private Integer allContainer; // 全部容器数量
}
ImageInfoDTO.java
import lombok.Data;
@Data
public class ImageInfoDTO {
private String id;
private String name;
private long created;
private long size;
}
ServiceTypeEnum.java
public enum ServiceTypeEnum {
MIDDLEWARE_SERVER, // 中间件服务
BUSINESS_SERVICE; // 业务服务
}
DockerClientUtils.java
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.command.PullImageResultCallback;
import com.github.dockerjava.api.model.*;
import com.github.dockerjava.core.DockerClientBuilder;
import com.github.dockerjava.core.command.LogContainerResultCallback;
import org.apache.commons.lang3.StringUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
public class DockerClientUtils {
private final DockerClient client;
/**
* 构造函数,初始化Docker连接
*/
public DockerClientUtils(String dockerHost) {
this.client = DockerClientBuilder.getInstance(dockerHost).build();
}
/**
* 获取Docker系统信息
*/
public DockerInfoDTO getDockerInfo() {
Info info = client.infoCmd().exec();
DockerInfoDTO dto = new DockerInfoDTO();
dto.setAllContainer(info.getContainers());
dto.setStopContainer(info.getContainersStopped());
dto.setRunningContainer(info.getContainersRunning());
return dto;
}
/**
* 启动容器
*/
public void startContainer(String containerId) {
if (!isContainerRunning(containerId)) {
client.startContainerCmd(containerId).exec();
}
}
/**
* 停止容器
*/
public void stopContainer(String containerId) {
if (isContainerRunning(containerId)) {
client.stopContainerCmd(containerId).exec();
}
}
/**
* 删除容器
*
* @param containerId 容器ID
* @param force 是否强制删除运行中的容器
*/
public void removeContainer(String containerId, boolean force) {
if (isContainerRunning(containerId)) {
if (force) {
// 如果容器正在运行且强制删除,先停止容器
stopContainer(containerId);
} else {
throw new RuntimeException("容器正在运行,请先停止容器或设置force=true");
}
}
client.removeContainerCmd(containerId).exec();
}
/**
* 删除容器(不强制删除运行中的容器)
*
* @param containerId 容器ID
*/
public void removeContainer(String containerId) {
removeContainer(containerId, false);
}
/**
* 获取所有容器(运行中和已停止)
*/
public List<ContainerInfoDTO> getAllContainer() {
List<ContainerInfoDTO> result = new ArrayList<>();
result.addAll(getRunningContainer());
result.addAll(getStopContainer());
return result;
}
/**
* 获取运行中的容器
*/
public List<ContainerInfoDTO> getRunningContainer() {
return convertContainers(client.listContainersCmd().exec(), true);
}
/**
* 获取已停止的容器
*/
public List<ContainerInfoDTO> getStopContainer() {
return convertContainers(
client.listContainersCmd()
.withShowAll(true)
.withStatusFilter(Collections.singleton("exited"))
.exec(),
false
);
}
/**
* 获取容器日志
*/
public List<String> getContainerLogs(String containerId, int lineCount)
throws InterruptedException {
List<String> logs = new ArrayList<>();
client.logContainerCmd(containerId)
.withStdOut(true)
.withStdErr(true)
.withTail(lineCount)
.exec(new LogContainerResultCallback() {
@Override
public void onNext(Frame item) {
logs.add(item.toString());
}
}).awaitCompletion();
return logs;
}
/**
* 根据条件筛选容器
*/
public List<ContainerInfoDTO> filterContainers(String name, Boolean status) {
return getAllContainer().stream()
.filter(c -> name == null || c.getName().contains(name))
.filter(c -> status == null || c.getStatus().equals(status))
.collect(Collectors.toList());
}
// 辅助方法:转换Container对象为ContainerInfoDTO
private List<ContainerInfoDTO> convertContainers(List<Container> containers, boolean status) {
List<ContainerInfoDTO> result = new ArrayList<>();
containers.forEach(container -> {
ContainerInfoDTO dto = new ContainerInfoDTO();
dto.setId(StringUtils.substring(container.getId(), 0, 12));
dto.setName(container.getNames()[0].substring(1));
dto.setImage(container.getImage());
dto.setStatus(status);
if (container.getLabels() != null) {
dto.setDesc(container.getLabels().get("DESC"));
String type = container.getLabels().get("TYPE");
if (type != null) {
dto.setType(ServiceTypeEnum.valueOf(type));
}
}
result.add(dto);
});
return result;
}
// 辅助方法:检查容器是否在运行
private boolean isContainerRunning(String containerId) {
return getRunningContainer().stream()
.anyMatch(c -> c.getId().equals(containerId));
}
/**
* 拉取镜像
*
* @param imageName 镜像名称(格式: repository:tag)
* @throws InterruptedException 如果拉取过程被中断
*/
public void pullImage(String imageName) throws InterruptedException {
String[] parts = imageName.split(":");
String repository = parts[0];
String tag = parts.length > 1 ? parts[1] : "latest";
client.pullImageCmd(repository)
.withTag(tag)
.exec(new PullImageResultCallback())
.awaitCompletion();
}
/**
* 列出所有镜像
*/
public List<ImageInfoDTO> listImages() {
return client.listImagesCmd()
.exec()
.stream()
.map(image -> {
ImageInfoDTO dto = new ImageInfoDTO();
dto.setId(image.getId());
dto.setCreated(image.getCreated());
dto.setSize(image.getSize());
if (image.getRepoTags() != null && image.getRepoTags().length > 0) {
dto.setName(image.getRepoTags()[0]);
}
return dto;
})
.collect(Collectors.toList());
}
/**
* 删除镜像
*
* @param imageId 镜像ID
* @param force 是否强制删除
*/
public void removeImage(String imageId, boolean force) {
client.removeImageCmd(imageId)
.withForce(force)
.exec();
}
/**
* 运行容器(带参数)
*
* @param imageName 镜像名称
* @param containerName 容器名称(可选)
* @param ports 端口映射(格式: "主机端口:容器端口")
* @param envs 环境变量(格式: "KEY=VALUE")
* @param volumes 卷映射(格式: "主机路径:容器路径")
* @param command 容器启动命令(可选)
* @return 容器ID
*/
public String runContainer(String imageName,
String containerName,
List<String> ports,
List<String> envs,
List<String> volumes,
List<String> command) {
// 创建容器
CreateContainerCmd containerCmd = client.createContainerCmd(imageName).withName(containerName);
// 端口绑定
if (ports != null) {
List<PortBinding> portBindings = new ArrayList<>();
ExposedPort[] exposedPorts = new ExposedPort[ports.size()];
for (int i = 0; i < ports.size(); i++) {
String[] parts = ports.get(i).split(":");
int hostPort = Integer.parseInt(parts[0]);
int containerPort = Integer.parseInt(parts[1]);
exposedPorts[i] = ExposedPort.tcp(containerPort);
portBindings.add(PortBinding.parse(hostPort + ":" + containerPort));
}
containerCmd = containerCmd
.withExposedPorts(exposedPorts)
.withPortBindings(portBindings);
}
if (envs != null) {
containerCmd = containerCmd.withEnv(envs);
}
if (volumes != null) {
containerCmd = containerCmd.withVolumes(volumes.stream()
.map(v -> new Volume(v.split(":")[1]))
.toArray(Volume[]::new))
.withHostConfig(HostConfig.newHostConfig()
.withBinds(volumes.stream()
.map(Bind::parse)
.toArray(Bind[]::new)));
}
if (command != null) {
containerCmd = containerCmd.withCmd(command);
}
CreateContainerResponse response = containerCmd
.exec();
// 启动容器
client.startContainerCmd(response.getId()).exec();
return response.getId();
}
}
test.java
import java.util.Arrays;
import java.util.List;
public class Test {
public static void test01() {
// 初始化Docker客户端
DockerClientUtils docker = new DockerClientUtils("tcp://xxx.xxx.xxx.xxx:2375");
// 获取Docker系统信息
DockerInfoDTO info = docker.getDockerInfo();
System.out.println("Docker信息:");
System.out.println("运行中容器: " + info.getRunningContainer());
System.out.println("已停止容器: " + info.getStopContainer());
System.out.println("全部容器: " + info.getAllContainer());
List<ContainerInfoDTO> allContainer = docker.getAllContainer();
for (ContainerInfoDTO containerInfoDTO : allContainer) {
System.out.println(containerInfoDTO);
String id = containerInfoDTO.getId();
String containerName = containerInfoDTO.getName();
if ("my-nginx".equals(containerName)) {
docker.removeContainer(id, true);
}
}
info = docker.getDockerInfo();
System.out.println("Docker信息:");
System.out.println("运行中容器: " + info.getRunningContainer());
System.out.println("已停止容器: " + info.getStopContainer());
System.out.println("全部容器: " + info.getAllContainer());
}
public static void test02() {
// 初始化Docker客户端
DockerClientUtils docker = new DockerClientUtils("tcp://192.168.20.242:2375");
// docker.pullImage("nginx:latest");
// 运行带参数的容器
List<String> ports = Arrays.asList("8080:80", "8443:443");
List<String> envs = Arrays.asList("ENV=production", "DEBUG=false");
// List<String> volumes = Arrays.asList("/host/path:/container/path");
docker.runContainer(
"nginx:latest",
"my-nginx",
ports,
envs,
null,
null
);
DockerInfoDTO info = docker.getDockerInfo();
System.out.println("Docker信息:");
System.out.println("运行中容器: " + info.getRunningContainer());
System.out.println("已停止容器: " + info.getStopContainer());
System.out.println("全部容器: " + info.getAllContainer());
}
public static void main(String[] args) throws InterruptedException {
// test01();
test02();
}
}
windows docker desktop 启用远程API访问:
打开Docker Desktop设置
进入"General" → 勾选"Expose daemon on tcp://localhost:2375 without TLS"

防火墙配置:允许2375端口(TCP)的入站连接或者在高级防火墙规则中限制只允许特定IP访问

执行端口映射命令管理员权限开启cmd,执行以下命令:
netsh interface portproxy add v4tov4 listenport=2375 listenaddress=%EXPOSE_IP% connectaddress=127.0.0.1 connectport=2375
将上述命令中的%EXPOSE_IP% 替换成你需要暴露的ip 也就是安装docker desktop的主机ip