docker-java

一 所需依赖包

<dependency>
    <groupId>com.github.docker-java</groupId>
    <artifactId>docker-java</artifactId>
    <version>3.3.3</version>
</dependency>

二 前期准备

2.1 docker已安装

2.2 运行程序用户的docker使用权限

默认docker安装后是root权限运行的,比如运行程序的用户是admin用户,则需要将admin用户加加入到docker用户组

gpasswd -a admin docker
systemctl restart docker

2.3 docker.service 的访问方式,需要开启tcp访问默认,不然可能导致非root用户运行程序导致连接异常

vi /usr/lib/systemd/system/docker.service

将 ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

改为
ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix://var/run/docker.sock

然后重启

systemctl daemon-reload

systemctl restart docker

三 配置参数

3.1 配置信息类,可以放在配置文件中,为了演示直接写死
public class Docker {
    /** docker 连接方式
     * 或者 "unix:///var/run/docker.sock"
     */
    private String host = "tcp://DOCKER_HOST_IP:2375";
    private String configDir = "/home/admin/.docker";
    private String apiVersion = "1.30";
    private String registerUrl = "";
    private String registerName = "";
    private String registerPassword = "";
    private String registerEmail = "";
    private Boolean tlsVerify = false;
    private String certPath = ""; // tsl证书地址
}

3.2 创建请求参数

import java.util.Collection;
import java.util.List;
import java.util.Map;
import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class ContainerCreateParam implements Serializable {

    private String imageName;
    private String containerName;
    /**
     * 端口映射Map,key是hostPort,value是containerPort
     */
    private Map<Integer, Integer> portMap;
    /**
     *  卷绑定 /host:/container:ro
     */
    private Collection<String> volumeBindSpecs;
    private Long memory;
    private List<String> envs;
}

四 工具类

import cn.hutool.core.collection.CollectionUtil;
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.model.Bind;
import com.github.dockerjava.api.model.ExposedPort;
import com.github.dockerjava.api.model.HostConfig;
import com.github.dockerjava.api.model.PortBinding;
import com.github.dockerjava.api.model.SearchItem;
import com.github.dockerjava.core.DefaultDockerClientConfig;
import com.github.dockerjava.core.DockerClientBuilder;
import com.xz.cp.core.exception.BusinessException;
import com.xz.cp.core.utils.JsonUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import org.apache.commons.lang3.BooleanUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
public class DockerUtils {

    private static final String CONTAINER_NAME_PATTERN = "^/?[a-zA-Z0-9][a-zA-Z0-9_.-]+$";
    private static final Logger LOG = LoggerFactory.getLogger(DockerUtils.class);

    private static DockerClient dockerClient;

    public DockerUtils() {
        Docker dockerProperties = new Docker(); // 取配置信息,视情况放在配置中心读取
        DefaultDockerClientConfig.Builder builder = DefaultDockerClientConfig
            .createDefaultConfigBuilder()
            .withDockerHost(dockerProperties.getHost())
            .withDockerConfig(dockerProperties.getConfigDir())
            .withApiVersion(dockerProperties.getApiVersion()) // optional
            .withRegistryUrl(dockerProperties.getRegisterUrl())
            .withRegistryUsername(dockerProperties.getRegisterName())
            .withRegistryPassword(dockerProperties.getRegisterPassword())
            .withRegistryEmail(dockerProperties.getRegisterEmail());

        if (BooleanUtils.isTrue(dockerProperties.getTlsVerify())) {
            builder.withDockerTlsVerify(true)
                .withDockerCertPath(dockerProperties.getCertPath());
        }

        dockerClient = DockerClientBuilder.getInstance(builder.build()).build();

        LOG.info("dockerClient init success");
    }

    private void _checkContainerName(String containerName) {
        if (!Pattern.matches(CONTAINER_NAME_PATTERN, containerName)) {
            throw new BusinessException("", "非法容器名!");
        }
    }

    /**
     * 创建容器
     *
     * @param containerCreateParam containerCreateParam
     * @return 创建完的容器
     */
    public CreateContainerResponse createContainer(ContainerCreateParam containerCreateParam) {
        _checkContainerName(containerCreateParam.getContainerName());

        // 创建容器需要使用的命令
        CreateContainerCmd containerCmd = dockerClient
            .createContainerCmd(containerCreateParam.getImageName())
            .withName(containerCreateParam.getContainerName());
        // 封装端口映射
        List<PortBinding> list = new ArrayList<>();
        Map<Integer, Integer> portMap = containerCreateParam.getPortMap();
        for (Integer hostPort : portMap.keySet()) {
            // 暴露端口
            containerCmd = containerCmd
                .withExposedPorts(ExposedPort.parse(portMap.get(hostPort) + "/tcp"));
            // 绑定主机端⼝ -> docker容器端⼝
            list.add(PortBinding.parse(hostPort + ":" + portMap.get(hostPort)));
        }

        HostConfig hostConfig = HostConfig.newHostConfig()
            .withMemory(containerCreateParam.getMemory() == null ? 1024L * 1024 * 1024
                : containerCreateParam.getMemory())
            .withPortBindings(list);
        if (CollectionUtil.isNotEmpty(containerCreateParam.getVolumeBindSpecs())) {
            List<Bind> volumeBinds = containerCreateParam.getVolumeBindSpecs().stream()
                .map(Bind::parse)
                .collect(Collectors.toList());

            hostConfig.withBinds(volumeBinds);
        }

        if (CollectionUtil.isNotEmpty(containerCreateParam.getEnvs())) {
            containerCmd = containerCmd.withEnv(containerCreateParam.getEnvs());
        }

        // 执行创建命令
        CreateContainerResponse container = containerCmd
            .withHostConfig(hostConfig)
            .exec();

        LOG.info("create container res = {}", JsonUtils.toString(container));
        return container;
    }

    public List<SearchItem> searchItems(String image) {
        return dockerClient.searchImagesCmd(image).exec();
    }

    /**
     * 关闭容器
     *
     * @param id 容器ID
     */
    public void stopContainer(String id) {
        dockerClient.stopContainerCmd(id).exec();
    }

    /**
     * 暂停容器
     *
     * @param id 容器ID
     */
    public void pauseContainer(String id) {
        dockerClient.pauseContainerCmd(id).exec();
    }

    /**
     * 重启容器
     *
     * @param id 容器ID
     */
    public void restartContainer(String id) {
        dockerClient.restartContainerCmd(id).exec();
    }

    /**
     * 删除容器
     *
     * @param id 容器ID
     */
    public void startContainer(String id) {
        dockerClient.startContainerCmd(id).exec();
    }

    /**
     * docker容器commit为镜像
     *
     * @param containerID 容器id
     * @param rep         镜像的仓库,就相当于【ubuntu:latest】中的【ubuntu】
     * @param tag         镜像的标签,就相当于【ubuntu:latest】中的【latest】
     */
    public void createImageByContainer(String containerID, String rep, String tag) {
        dockerClient.commitCmd(containerID).withRepository(rep).withTag(tag).exec();
    }
}

五 测试类

@SpringBootTest
class DockerUtilsTest {

    @Autowired
    DockerUtils dockerUtils;

    @Test
    void createContainer() {
        ContainerCreateParam param = new ContainerCreateParam();

        String containerName = "customizeName-" + UUID.fastUUID();
        param.setContainerName(containerName);
        param.setEnvs(List.of("MYSQL_ROOT_PASSWORD=123456"));
        param.setImageName("mysql:5.7");
        param.setVolumeBindSpecs(List.of("/root/docker_data/" + containerName + ":/var/lib/mysql"));
        param.setPortMap(Map.of(3318, 3306));
        param.setMemory(1024L * 1024 * 1024 * 2);
        dockerUtils.createContainer(param);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值