package com.se.docker.utils; import cn.hutool.core.util.ObjectUtil; import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.command.*; import com.github.dockerjava.api.model.AuthConfig; import com.github.dockerjava.api.model.Container; import com.github.dockerjava.api.model.PullResponseItem; import com.github.dockerjava.core.DefaultDockerClientConfig; import com.github.dockerjava.core.DockerClientConfig; import com.github.dockerjava.core.DockerClientImpl; import com.github.dockerjava.httpclient5.ApacheDockerHttpClient; import com.github.dockerjava.transport.DockerHttpClient; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.BufferedOutputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.time.Duration; import java.util.List; import java.util.Objects; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @SuppressWarnings("ALL") public class DockerUtils { private static volatile DockerClient dockerClient; private static final Logger log = LoggerFactory.getLogger(DockerUtils.class); /** * vim /lib/systemd/system/docker.service *

* # 配置普通模式,-H参数指定docker应用程序监听方式,或者采用下面的安全连接方式2选1 * ExecStart=/usr/bin/dockerd -H unix://var/run/docker.sock -H tcp://0.0.0.0:2375 *

* # 配置安全连接,注意这里的/home/user/certs/ 根据自己情况替换为实际的的密钥存放路径 * ExecStart=/usr/bin/dockerd -D --tlsverify=true --tlscert=/home/user/certs/server-cert.pem --tlskey=/home/user/certs/server-key.pem --tlscacert=/home/user/certs/ca.pem -H tcp://0.0.0.0:2375 -H unix://var/run/docker.sock *

* # 重载配置,重启服务 * systemctl daemon-reload * systemctl restart docker *

* # 查看端口监听 * netstat -nlp |grep 2375 *

* vi /etc/docker/daemon.json * # 配置insecure-registries * { * "insecure-registries": ["122.12.12.12:5000"], * "registry-mirrors": ["https://xxxxx.mirror.aliyuncs.com"] * } * # 重载配置,重启服务 * systemctl daemon-reload * systemctl restart docker */ private DockerUtils() { } public DockerUtils(String dockerHost, String dockerApiVersion) { Objects.requireNonNull(dockerHost, "Docker 主机地址不能为空."); Objects.requireNonNull(dockerApiVersion, "Docker API 版本不能为空."); // 使用双重校验锁实现 Docker 客户端单例 if (null == dockerClient) { synchronized (DockerUtils.class) { if (null == dockerClient) { dockerClient = createDockerClient(dockerHost, dockerApiVersion); } } } } private DockerClient createDockerClient(String dockerHost, String dockerApiVersion) { DockerClientConfig config = DefaultDockerClientConfig.createDefaultConfigBuilder() .withApiVersion(dockerApiVersion) .withDockerHost(dockerHost) .build(); DockerHttpClient httpClient = new ApacheDockerHttpClient.Builder() .dockerHost(config.getDockerHost()) .sslConfig(config.getSSLConfig()) .maxConnections(1000) .connectionTimeout(Duration.ofSeconds(60)) .responseTimeout(Duration.ofMinutes(30)) .build(); return DockerClientImpl.getInstance(config, httpClient); } public DockerUtils(String dockerHost, String dockerApiVersion, String dockerCertPath) { Objects.requireNonNull(dockerHost, "Docker 主机地址不能为空."); Objects.requireNonNull(dockerApiVersion, "Docker API 版本不能为空."); // 使用双重校验锁实现 Docker 客户端单例 if (null == dockerClient) { synchronized (DockerUtils.class) { if (null == dockerClient) { dockerClient = createDockerClient(dockerHost, dockerApiVersion, dockerCertPath); } } } } private DockerClient createDockerClient(String dockerHost, String dockerApiVersion, String dockerCertPath) { DockerClientConfig config = DefaultDockerClientConfig.createDefaultConfigBuilder() .withApiVersion(dockerApiVersion) .withDockerHost(dockerHost) // 如果开启安全连接,需要配置这行 .withDockerTlsVerify(true).withDockerCertPath(dockerCertPath) .build(); DockerHttpClient httpClient = new ApacheDockerHttpClient.Builder() .dockerHost(config.getDockerHost()) .sslConfig(config.getSSLConfig()) .maxConnections(1000) .connectionTimeout(Duration.ofSeconds(60)) .responseTimeout(Duration.ofMinutes(30)) .build(); return DockerClientImpl.getInstance(config, httpClient); } /** * 登录 Docker 镜像仓库 * * @param authConfig 登录所需的认证信息 * @throws RuntimeException 登录失败时抛出异常 */ public void login(AuthConfig authConfig) { try { Objects.requireNonNull(authConfig, "认证信息不能为空."); log.info("开始登录镜像仓库:{};username:{};password:{}", authConfig.getRegistryAddress(), authConfig.getUsername(), authConfig.getPassword()); dockerClient.authCmd() .withAuthConfig(authConfig) .exec(); log.info("镜像仓库登录成功:{}", authConfig.getRegistryAddress()); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("镜像仓库登录失败:" + e.getMessage()); } } /** * 从registry拉取Docker镜像 * * @param tag 镜像名称 * @return true表示拉取成功,false表示拉取失败 */ public void pullImage(AuthConfig authConfig, String tag) { Objects.requireNonNull(authConfig, "认证信息不能为空."); if (ObjectUtil.isEmpty(tag)) { throw new RuntimeException("镜像信息不能为空"); } log.info("开始拉取 Docker 镜像: {}", tag); try { PullImageResultCallback exec = new PullImageResultCallback() { @Override public void onNext(PullResponseItem item) { System.out.println(item.getStatus()); } }; PullImageCmd pullImageCmd = dockerClient.pullImageCmd(tag); pullImageCmd.withAuthConfig(authConfig) .exec(exec) .awaitCompletion(30, TimeUnit.MINUTES); exec.close(); log.info("镜像拉取成功:{};", tag); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("镜像拉取失败:{}" + e.getMessage()); } } /** * 保存Docker镜像 * * @param imageId 镜像Id * @param filePath 保存文件名 * @return true表示保存成功,false表示保存失败 */ public void saveImage(java.lang.String imageId, String filePath) { if (ObjectUtil.isEmpty(filePath)) { throw new RuntimeException("参数错误:保存路径不能为空"); } log.info("开始保存镜像:{}", imageId); try (OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(filePath)); InputStream inputStream = dockerClient.saveImageCmd(imageId) .exec()) { if (null == inputStream) { throw new RuntimeException("无法获取镜像"); } byte[] bytesArray = new byte[4096]; int bytesRead = -1; while ((bytesRead = inputStream.read(bytesArray)) != -1) { outputStream.write(bytesArray, 0, bytesRead); } log.info("镜像保存成功:{}", imageId); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("保存镜像异常:" + e.getMessage()); } } /** * 删除Docker镜像 * * @param imageId 镜像标签 * @return true表示删除成功,false表示删除失败 */ public boolean removeImage(String imageId) { Objects.requireNonNull(imageId, "镜像 ID 不能为空."); log.info("开始删除 Docker 镜像: {}", imageId); try { // 如果镜像当前有容器在运行,则不进行删除操作 if (isRunContainer(imageId)) { log.warn("Docker 镜像正在使用中,无法删除: {}", imageId); return false; } RemoveImageCmd removeImageCmd = dockerClient.removeImageCmd(imageId); removeImageCmd.exec(); log.info("Docker 镜像删除成功: {}", imageId); return true; } catch (Exception e) { log.error("Docker 镜像删除失败: {};{}", imageId, e.getMessage()); return false; } } /** * 推送镜像 * * @param authConfig * @param tag */ public static void pushImage(AuthConfig authConfig, String tag) { Objects.requireNonNull(authConfig, "认证信息不能为空."); Objects.requireNonNull(tag, "镜像信息不能为空."); log.info("开始推送 Docker 镜像: {}", tag); try { PushImageCmd pushImageCmd = dockerClient.pushImageCmd(tag); pushImageCmd.withAuthConfig(authConfig) .start() .awaitCompletion(30, TimeUnit.SECONDS); log.info("镜像push成功:{}", tag); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("镜像push失败:{}" + e.getMessage()); } } /** * 获取所有 Docker 容器的信息 * * @return 所有 Docker 容器的信息列表 */ public List listContainers() { log.info("开始获取所有 Docker 容器信息."); try { ListContainersCmd listContainersCmd = dockerClient.listContainersCmd(); listContainersCmd.withShowAll(true); return listContainersCmd.exec(); } catch (Exception e) { log.error("获取所有 Docker 容器信息失败: {}", e.getMessage()); throw new RuntimeException("获取所有 Docker 容器信息失败: " + e.getMessage()); } } /** * 是否有在运行的容器 * * @param imageId * @return */ public boolean isRunContainer(String imageId) { Objects.requireNonNull(imageId, "镜像 ID 不能为空."); log.info("检查 Docker 镜像是否正在使用中: {}", imageId); try { List containers = listContainers(); List containerNames = containers.stream() .map(Container::getImageId) .collect(Collectors.toList()); log.info("列出所有容器成功,数量:{}", containerNames.size()); if (ObjectUtil.isNotEmpty(containerNames) && containerNames.contains(imageId)) { return true; } return false; } catch (Exception e) { log.error("检查 Docker 镜像是否正在使用中失败: {}", e.getMessage()); throw new RuntimeException("检查 Docker 镜像是否正在使用中失败: " + e.getMessage()); } } /** * 获取镜像Id * * @param tag * @return */ public String getImageId(String tag) { try { InspectImageCmd inspectImageCmd = dockerClient.inspectImageCmd(tag); InspectImageResponse image = inspectImageCmd.exec(); if (null == image) { throw new RuntimeException("未获取到镜像信息:"); } return image.getId(); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("无法获取镜像信息:" + e.getMessage()); } } public void start(String id) { try { InspectContainerResponse resp = dockerClient.inspectContainerCmd(id).exec(); if (null == resp) return; dockerClient.startContainerCmd(id).exec(); } catch (Exception ex) { log.error(ex.getMessage(), ex); } } public void restart(String id) { try { InspectContainerResponse resp = dockerClient.inspectContainerCmd(id).exec(); if (null == resp) return; dockerClient.restartContainerCmd(id).exec(); } catch (Exception ex) { log.error(ex.getMessage(), ex); } } public void stop(String id) { try { InspectContainerResponse resp = dockerClient.inspectContainerCmd(id).exec(); if (null == resp) return; dockerClient.stopContainerCmd(id).exec(); } catch (Exception ex) { log.error(ex.getMessage(), ex); } } public void pause(String id) { try { InspectContainerResponse resp = dockerClient.inspectContainerCmd(id).exec(); if (null == resp) return; if (null != resp.getState().getRunning() && resp.getState().getRunning()) { dockerClient.pauseContainerCmd(id).exec(); } } catch (Exception ex) { log.error(ex.getMessage(), ex); } } public void unpause(String id) { try { InspectContainerResponse resp = dockerClient.inspectContainerCmd(id).exec(); if (null == resp) return; if (null != resp.getState().getPaused() && resp.getState().getPaused()) { dockerClient.unpauseContainerCmd(id).exec(); } } catch (Exception ex) { log.error(ex.getMessage(), ex); } } public static void main2(String[] args) throws InterruptedException { String tag = "10.20.152.16:18080/test/redis:t1"; AuthConfig authConfig = new AuthConfig() .withRegistryAddress("10.20.152.16:18080") .withUsername("admin") .withPassword("admin123"); DockerUtils dockerUtil = new DockerUtils( "tcp://192.168.11.203:2375", "1.45", "/home/user/certs/"); //登录 dockerUtil.login(authConfig); /* DockerUtil.pushImage(authConfig , tag); */ //拉取镜像 dockerUtil.pullImage(authConfig, tag); String imageId1 = dockerUtil.getImageId(tag); //保存镜像 dockerUtil.saveImage(imageId1, "E:\\pdfTest\\docker\\redis.tar"); //删除镜像 dockerUtil.removeImage(imageId1); } }