1
13693261870
2024-12-08 864536db862bcde4ac0f281cff54cd4940380976
1
已添加1个文件
已修改3个文件
407 ■■■■■ 文件已修改
se-modules/se-docker/pom.xml 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
se-modules/se-docker/src/main/java/com/se/docker/service/SysDockerService.java 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
se-modules/se-docker/src/main/java/com/se/docker/utils/DockerUtils.java 343 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
说明.txt 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
se-modules/se-docker/pom.xml
@@ -51,6 +51,25 @@
            <groupId>com.se</groupId>
            <artifactId>se-common-swagger</artifactId>
        </dependency>
        <!-- docker -->
        <dependency>
            <groupId>com.github.docker-java</groupId>
            <artifactId>docker-java</artifactId>
            <version>3.4.0</version>
        </dependency>
        <dependency>
            <groupId>com.github.docker-java</groupId>
            <artifactId>docker-java-transport-httpclient5</artifactId>
            <version>3.4.0</version>
        </dependency>
        <!-- hutool -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.34</version>
        </dependency>
    </dependencies>
    <build>
se-modules/se-docker/src/main/java/com/se/docker/service/SysDockerService.java
@@ -1,5 +1,11 @@
package com.se.docker.service;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.command.CreateContainerResponse;
import com.github.dockerjava.api.command.InspectContainerResponse;
import com.github.dockerjava.core.DockerClientBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@@ -9,7 +15,40 @@
    //@Value("${docker.prefix}")
    public String localFilePrefix;
    private static final Logger log = LoggerFactory.getLogger(SysDockerService.class);
    public String test() throws Exception {
        return "docker: " + System.currentTimeMillis();
    }
    /**
     * java DockerClient操作
     * https://blog.csdn.net/weixin_45198228/article/details/130060333
     */
    public void t() {
        try {
            // åˆ›å»ºDocker客户端实例
            DockerClient dockerClient = DockerClientBuilder.getInstance("unix:///var/run/docker.sock").build();
            // åˆ›å»ºå¹¶å¯åŠ¨ä¸€ä¸ªæ–°çš„å®¹å™¨
            CreateContainerResponse container = dockerClient.createContainerCmd("busybox")
                    .withCmd("echo", "Hello Docker!")
                    .exec();
            // å¯åЍ容噍
            dockerClient.startContainerCmd(container.getId()).exec();
            // æ£€æŸ¥å®¹å™¨çŠ¶æ€
            InspectContainerResponse inspectContainerResponse = dockerClient.inspectContainerCmd(container.getId()).exec();
            System.out.println(inspectContainerResponse.toString());
            // åœæ­¢å¹¶ç§»é™¤å®¹å™¨
            dockerClient.removeContainerCmd(container.getId()).withRemoveVolumes(true).exec();
            // å…³é—­Docker客户端
            dockerClient.close();
        } catch (Exception ex) {
            log.error(ex.getMessage(), ex);
        }
    }
}
se-modules/se-docker/src/main/java/com/se/docker/utils/DockerUtils.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,343 @@
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
     * <p>
     * # é…ç½®æ™®é€šæ¨¡å¼ï¼Œ-H参数指定docker应用程序监听方式,或者采用下面的安全连接方式2选1
     * ExecStart=/usr/bin/dockerd -H unix://var/run/docker.sock -H tcp://0.0.0.0:2375
     * <p>
     * # é…ç½®å®‰å…¨è¿žæŽ¥ï¼Œæ³¨æ„è¿™é‡Œçš„/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
     * <p>
     * # é‡è½½é…ç½®ï¼Œé‡å¯æœåŠ¡
     * systemctl daemon-reload
     * systemctl restart docker
     * <p>
     * # æŸ¥çœ‹ç«¯å£ç›‘听
     * netstat -nlp |grep 2375
     * <p>
     * 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() {
    }
    private DockerUtils(String dockerHost, String dockerApiVersion, String dockerCertPath) {
        Objects.requireNonNull(dockerHost, "Docker ä¸»æœºåœ°å€ä¸èƒ½ä¸ºç©º.");
        Objects.requireNonNull(dockerApiVersion, "Docker API ç‰ˆæœ¬ä¸èƒ½ä¸ºç©º.");
        // ä½¿ç”¨åŒé‡æ ¡éªŒé”å®žçް Docker å®¢æˆ·ç«¯å•例
        if (dockerClient == null) {
            synchronized (DockerUtils.class) {
                if (dockerClient == null) {
                    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;
        }
    }
    /**
     * èŽ·å–æ‰€æœ‰ Docker å®¹å™¨çš„信息
     *
     * @return æ‰€æœ‰ Docker å®¹å™¨çš„信息列表
     */
    public List<Container> listContainers() {
        log.info("开始获取所有 Docker å®¹å™¨ä¿¡æ¯.");
        try {
            ListContainersCmd listContainersCmd = dockerClient.listContainersCmd();
            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<Container> containers = listContainers();
            List<String> 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());
        }
    }
    /**
     * æŽ¨é€é•œåƒ
     *
     * @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());
        }
    }
    /**
     * èŽ·å–é•œåƒ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());
        }
    }
    // ä½¿ç”¨ Builder æ¨¡å¼æž„建 DockerUtil å¯¹è±¡
    public static class Builder {
        private String dockerHost;
        private String dockerApiVersion;
        private String dockerCertPath;
        public Builder withDockerHost(String dockerHost) {
            this.dockerHost = dockerHost;
            return this;
        }
        public Builder withDockerApiVersion(String dockerApiVersion) {
            this.dockerApiVersion = dockerApiVersion;
            return this;
        }
        public Builder withDockerCertPath(String dockerCertPath) {
            this.dockerCertPath = dockerCertPath;
            return this;
        }
        public DockerUtils build() {
            return new DockerUtils(dockerHost, dockerApiVersion, dockerCertPath);
        }
    }
    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.Builder()
                //服务器ip
                .withDockerHost("tcp://10.50.80.165:2375")
                //API版本 å¯é€šè¿‡åœ¨æœåС噍 docker version å‘½ä»¤æŸ¥çœ‹
                .withDockerApiVersion("1.41")
                //安全连接密钥文件存放路径
                .withDockerCertPath("/home/user/certs/")
                .build();
        //登录
        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);
    }
}
˵Ã÷.txt
@@ -55,6 +55,12 @@
uri: lb://se-job  â†’ uri: lb://se-system
        # docker服务
        - id: se-docker
          uri: lb://se-docker
          predicates:
            - Path=/docker/**
  # ä¸æ ¡éªŒç™½åå•
  ignore:
    whites: