基于docker-java封装的工具类
基于docker-java封装的工具类
- 背景
- 环境
- 工具类
背景
写OJ系统时需要用docker作为代码沙箱使用,顺手封装了一个工具类,给自己做个笔记,如果可以的话也希望帮助到其他人。
环境
- docker 26.1.4
- docker-java 3.4.2
- docker-java-transport-httpclient5 3.4.2
工具类
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.PullImageResultCallback;
import com.github.dockerjava.api.model.Frame;
import com.github.dockerjava.api.model.Image;
import com.github.dockerjava.api.model.PullResponseItem;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.ObjectUtils;import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;/*** @author * @Description dockerClient工具类* @create 2025-04-19 0:30*/
@Slf4j
public class DockerClientUtil {/*** 获取镜像* @return*/public static void getImage(DockerClient dockerClient, String imageName, String imageTag) throws InterruptedException {// 判断镜像是否存在imageTag = ObjectUtils.isEmpty(imageTag)? "latest" : imageTag;// 获取所有本地镜像List<Image> images = dockerClient.listImagesCmd().exec();// 构造完整镜像名String fullImageName = imageName + ":" + imageTag;// 假设镜像不辞你在boolean isImageExists = false;// 遍历镜像列表,检查是否存在匹配的镜像for (Image image : images) {if (image.getRepoTags() != null) {// 确保 RepoTags 不为空for (String repoTag : image.getRepoTags()) {if (repoTag.equals(fullImageName)) {// 存在isImageExists = true;break;}}}}if (!isImageExists) {System.out.println("拉取镜像");// 不存在,拉取镜像dockerClient.pullImageCmd(fullImageName).exec(new PullImageResultCallback() {@Overridepublic void onNext(PullResponseItem item) {super.onNext(item);}}).awaitCompletion();}}/*** 创建可交互控制台容器*/public static CreateContainerResponse createContainer(DockerClient dockerClient, String imageName, String imageTag) {return dockerClient.createContainerCmd(String.format("%s:%s", imageName, imageTag))// 启用伪终端.withTty(true)// 保持标准输入打开.withStdinOpen(true)// 附加标准输入.withAttachStdin(true)// 附加标准输出.withAttachStdout(true)// 附加标准错误.withAttachStderr(true)// 使用登录 shell.withCmd("sh", "-l").exec();}/*** 字符串作为文件保存到容器* @param dockerClient docker客户端* @param containerId 容器id* @param filePath 文件目标路径* @param fileContent 文件内容* @return 是否保存成功* @throws InterruptedException*/public static boolean saveFileToContainer(DockerClient dockerClient, String containerId, String filePath, String fileContent) throws InterruptedException {// 准备编译命令String command = String.format("mkdir -p %s && printf \"%s\" > %s",filePath.replaceAll("([^/]+)/[^/]*$", "$1"), fileContent.replace("\"", "\\\""), filePath);// 创建exec配置String execId = dockerClient.execCreateCmd(containerId).withAttachStdout(true).withAttachStderr(true)// 通过sh -c执行.withCmd("sh", "-c", command).exec().getId();AtomicBoolean rs = new AtomicBoolean(true);// 执行并获取输出dockerClient.execStartCmd(execId).exec(new ResultCallback.Adapter<Frame>() {@Overridepublic void onNext(Frame object) {rs.set(ObjectUtils.isEmpty(object.getPayload()));if (!ObjectUtils.isEmpty(object.getPayload())) {rs.set(false);}super.onNext(object);}}).awaitCompletion();return rs.get();}/*** 运行命令* @param dockerClient* @param containerId* @param command* @return* @throws InterruptedException*/public static String runCommand(DockerClient dockerClient, String containerId, String command) throws InterruptedException {// 创建exec配置String execId = dockerClient.execCreateCmd(containerId).withAttachStdout(true).withAttachStderr(true)// 通过sh -c执行.withCmd("sh", "-c", command).exec().getId();StringBuilder rs = new StringBuilder();// 执行并获取输出dockerClient.execStartCmd(execId).exec(new ResultCallback.Adapter<Frame>() {@Overridepublic void onNext(Frame object) {rs.append(new String(object.getPayload()));super.onNext(object);}}).awaitCompletion();return rs.toString();}/*** 运行代码并批量输入* @param dockerClient* @param containerId* @param runCommand* @param inputStr* @return 运行结果* @throws InterruptedException*/public static String runCommandWithInputBatch(DockerClient dockerClient, String containerId, String runCommand, String inputStr) throws InterruptedException {return runCommand(dockerClient, containerId, String.format("echo -e \"%s\" | %s", inputStr.trim().replaceAll(" ", "\n").replaceAll("\"", "\\\""), runCommand)).replaceAll("\\n$", "");}/*** 清理容器* @param dockerClient* @param containerId*/public static void destroyContainer(DockerClient dockerClient, String containerId) throws InterruptedException {// 停止容器dockerClient.stopContainerCmd(containerId).exec();// 删除容器dockerClient.removeContainerCmd(containerId).exec();}
}