安全的docker-api的使用(java)

通过docker-api来执行docker相关的操作。
 

配置

可以在docker启动文件docker.service中加入如下
vi /lib/systemd/system/docker.service
在下面ExecStart 后面添加 -H tcp://0.0.0.0:2375
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -H unix://var/run/docker.sock -H tcp://0.0.0.0:2375

 


 

 

但是这样直接开放api,不安全,因此就需要指定证书。
修改 ExecStart的值如下:
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock -H tcp://0.0.0.0:2375 -H unix://var/run/docker.sock -D --tlsverify --tlscert=/etc/docker/certs.d/server-cert-docker.pem --tlskey=/etc/docker/certs.d/server-key-docker.pem --tlscacert=/etc/docker/certs.d/ca-docker.pem

 

客户端在访问docker-api的时候就需要提供证书。
 

脚本

下面是自动生成docker-api证书的脚本。
利用脚本自动生成,这样非常便捷,脚本(auto_gen_docker_tls_certs.sh)如下:
#!/bin/bash
#
# -------------------------------------------------------------
# 自动创建 Docker TLS 证书
# -------------------------------------------------------------
# 以下是配置信息
# --[BEGIN]------------------------------
CODE="docker"
IP="192.168.31.199"
PASSWORD="123456"
COUNTRY="CN"
STATE="HUNAN"
CITY="CHANGSHA"
ORGANIZATION="thyc"
ORGANIZATIONAL_UNIT="Dev"
COMMON_NAME="$IP"
EMAIL="an23gn@163.com"
# --[END]--
# Generate CA key
openssl genrsa -aes256 -passout "pass:$PASSWORD" -out "ca-key-$CODE.pem" 4096
# Generate CA
openssl req -new -x509 -days 365 -key "ca-key-$CODE.pem" -sha256 -out "ca-$CODE.pem" -passin "pass:$PASSWORD" -subj "/C=$COUNTRY/ST=$STATE/L=$CITY/O=$ORGANIZATION/OU=$ORGANIZATIONAL_UNIT/CN=$COMMON_NAME/emailAddress=$EMAIL"
# Generate Server key
openssl genrsa -out "server-key-$CODE.pem" 4096
# Generate Server Certs.
openssl req -subj "/CN=$COMMON_NAME" -sha256 -new -key "server-key-$CODE.pem" -out server.csr
echo "subjectAltName = IP:$IP,IP:127.0.0.1" >> extfile.cnf
echo "extendedKeyUsage = serverAuth" >> extfile.cnf
openssl x509 -req -days 365 -sha256 -in server.csr -passin "pass:$PASSWORD" -CA "ca-$CODE.pem" -CAkey "ca-key-$CODE.pem" -CAcreateserial -out "server-cert-$CODE.pem" -extfile extfile.cnf
# Generate Client Certs.
rm -f extfile.cnf
openssl genrsa -out "key-$CODE.pem" 4096
openssl req -subj '/CN=client' -new -key "key-$CODE.pem" -out client.csr
echo extendedKeyUsage = clientAuth >> extfile.cnf
openssl x509 -req -days 365 -sha256 -in client.csr -passin "pass:$PASSWORD" -CA "ca-$CODE.pem" -CAkey "ca-key-$CODE.pem" -CAcreateserial -out "cert-$CODE.pem" -extfile extfile.cnf
rm -vf client.csr server.csr
chmod -v 0400 "ca-key-$CODE.pem" "key-$CODE.pem" "server-key-$CODE.pem"
chmod -v 0444 "ca-$CODE.pem" "server-cert-$CODE.pem" "cert-$CODE.pem"
# 打包客户端证书
mkdir -p "tls-client-certs-$CODE"
cp -f "ca-$CODE.pem" "cert-$CODE.pem" "key-$CODE.pem" "tls-client-certs-$CODE/"
cd "tls-client-certs-$CODE"
tar zcf "tls-client-certs-$CODE.tar.gz" *
mv "tls-client-certs-$CODE.tar.gz" ../
cd ..
rm -rf "tls-client-certs-$CODE"
# 拷贝服务端证书
mkdir -p /etc/docker/certs.d
cp "ca-$CODE.pem" "server-cert-$CODE.pem" "server-key-$CODE.pem" /etc/docker/certs.d/

 

对脚本中的变量进行修改后运行,自动会创建好tls证书,服务器的证书在/etc/docker/certs.d/目录下:
 
 
客户端的证书在运行脚本的目录下,同时还自动打好了一个.tar.gz的包,很方便。
 
 

重启docker

systemctl daemon-reload && systemctl restart docker

 

以java的docker-api的访问为例子:
 

依赖

<dependency>
    <groupId>com.github.docker-java</groupId>
    <artifactId>docker-java</artifactId>
    <!-- use latest version https://github.com/docker-java/docker-java/releases -->
    <version>3.1.5</version>
</dependency>
 

实体类

import lombok.Data;
import lombok.experimental.Accessors;
 
 
/**
* @author wzm
* @version 1.0.0
* @date 2019/7/25 10:06
**/
@Data
@Accessors(chain = true)
public class DockerClientDTO {
    /**
     * 私钥和证书文件路径
     */
    private String certAndKeyFilePath;
    /**
     * 主机ip
     */
    private String host;
 
    /**
     * 端口
     */
    private String port;
 
    /**
     * 注册用户名
     */
    private String registryUsername;
 
    /**
     * 注册密码
     */
    private String registryPassword;
 
    /**
     * 注册邮箱
     */
    private String registryEmail;
 
    public DockerClientDTO(String host, String port, String certAndKeyFilePath) {
        this.host = host;
        this.port = port;
        this.certAndKeyFilePath = certAndKeyFilePath;
    }
}

 

将使用脚本生成好的客户端证书tls-client-certs-docker.tar.gz解压到“D:/docker/tls”目录下
 

java代码

import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.command.DockerCmdExecFactory;
import com.github.dockerjava.api.model.Container;
import com.github.dockerjava.api.model.Image;
import com.github.dockerjava.api.model.Info;
import com.github.dockerjava.core.DefaultDockerClientConfig;
import com.github.dockerjava.core.DockerClientBuilder;
import com.github.dockerjava.core.DockerClientConfig;
import com.github.dockerjava.jaxrs.JerseyDockerCmdExecFactory;
import net.sf.json.JSONArray;
import org.springframework.util.StringUtils;
 
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
 
/**
* docker-api操作工具类
*
* @author wzm
* @version 1.0.0
* @date 2019/7/16 11:16
**/
public class DockerOperationUtils {
 
    // D:/docker/tls
    // "tcp://192.168.2.133:2375"
    // "docker"
    // "123456"
    // "an23gn@163.com"
 
    private static DockerClient dockerClient;
 
    /**
     * 获取DOCKER客户端
     *
     * @param dockerClientDTO docker客户端连接信息
     * @return DockerClient
     */
    public static DockerClient getDockerClient(DockerClientDTO dockerClientDTO) {
        // 进行安全认证
        DockerClientConfig config = DefaultDockerClientConfig.createDefaultConfigBuilder()
                // 服务器ip
                .withDockerHost("tcp://" + dockerClientDTO.getHost() + ":" + dockerClientDTO.getPort())
                .withDockerTlsVerify(true)
                // 证书的本地位置
                .withDockerCertPath(dockerClientDTO.getCertAndKeyFilePath())
                // 私钥的本地位置
                //.withDockerConfig(dockerClientDTO.getCertAndKeyFilePath())
                // API版本 可通过在服务器 docker version 命令查看
                .withApiVersion("1.31")
                // 默认
                .withRegistryUrl("https://index.docker.io/v1/")
                // 默认
                .withRegistryUsername(dockerClientDTO.getRegistryUsername())
                // 默认
                .withRegistryPassword(dockerClientDTO.getRegistryPassword())
                // 默认
                .withRegistryEmail(dockerClientDTO.getRegistryEmail())
                .build();
 
        // docker命令执行工厂
        DockerCmdExecFactory dockerCmdExecFactory = new JerseyDockerCmdExecFactory()
                .withReadTimeout(60000)
                .withConnectTimeout(60000)
                .withMaxTotalConnections(100)
                .withMaxPerRouteConnections(10);
 
        dockerClient = DockerClientBuilder.getInstance(config).withDockerCmdExecFactory(dockerCmdExecFactory).build();
        return dockerClient;
    }
 
    public static void main(String[] args) {
        dockerClient = DockerOperationUtils.getDockerClient(new DockerClientDTO("192.168.2.134", "2375", "D:/docker/tls"));
        Info info = queryClientInfo(dockerClient);
        System.out.println(info);
    }
 
    /**
     * 连接信息
     *
     * @param dockerClient DOCKER客户端
     * @return Object
     */
    public static Info queryClientInfo(DockerClient dockerClient) {
        return dockerClient.infoCmd().exec();
    }
 
    /**
     * 查看镜像
     *
     * @param dockerClient DOCKER客户端
     * @return Object
     */
    public static List<Image> queryImagesList(DockerClient dockerClient) {
        return dockerClient.listImagesCmd().exec();
    }
 
    /**
     * 停止容器
     *
     * @param dockerClient DOCKER客户端
     * @param container    容器ID
     * @return Object
     */
    public static Object stopContainer(DockerClient dockerClient, String container) {
        return dockerClient.stopContainerCmd(container).exec();
    }
 
    /**
     * 删除镜像
     *
     * @param dockerClient DOCKER客户端
     * @param imagesID     镜像ID
     * @return Object
     */
    public static Object removeImages(DockerClient dockerClient, String imagesID) {
        return dockerClient.removeImageCmd(imagesID).exec();
    }
 
    /**
     * 删除容器
     *
     * @param dockerClient DOCKER客户端
     * @param container    容器ID
     * @return Object
     */
    public static Object removeContainer(DockerClient dockerClient, String container) {
        return dockerClient.removeContainerCmd(container).exec();
    }
 
    /**
     * 创建容器
     *
     * @param dockerClient DOCKER客户端
     * @param imagesID     镜像ID
     * @return Object
     */
    public static Object createContainer(DockerClient dockerClient, String imagesID) {
        return dockerClient.createContainerCmd(imagesID).exec();
    }
 
    /**
     * 创建一个镜像
     *
     * @param dockerClient DOCKER客户端
     * @return Object
     * @throws FileNotFoundException 找不到文件
     */
    public static Object createImages(DockerClient dockerClient) throws FileNotFoundException {
        //仓库地址
        String repository = "";
        //镜像文件流
        InputStream imageStream = new FileInputStream("");
        return dockerClient.createImageCmd(repository, imageStream).exec();
    }
 
    /**
     * 容器列表(运行中的)
     *
     * @param dockerClient DOCKER客户端
     * @return Object
     */
    public static List<Container> listContainersCmd(DockerClient dockerClient) {
        return dockerClient.listContainersCmd().exec();
    }
 
 
    public static List<String> getContainerNameList(List<Container> containerList) {
        List<String> containerNameList = new ArrayList<>();
        for (Container container : containerList) {
            String containerName = container.getNames()[0].replace("/", "");
            containerNameList.add(containerName);
        }
        return containerNameList;
    }
 
    /**
     * 启动容器
     *
     * @param dockerClient DOCKER客户端
     * @param containerID  容器ID
     */
    public static Object startContainerCmd(DockerClient dockerClient, String containerID) {
        return dockerClient.startContainerCmd(containerID).exec();
    }
 
    /**
     * 重启容器
     *
     * @param dockerClient 客户端
     * @param containerID  容器id
     * @return java.lang.Object
     * @author wzm
     * @date 2019/9/28 15:30
     */
    public static Object restartContainerCmd(DockerClient dockerClient, String containerID) {
        return dockerClient.restartContainerCmd(containerID).exec();
    }
 
    /**
     * 从本地上传资源到容器
     *
     * @param dockerClient 客户端
     * @param containerID  容器id
     * @param resource     本地资源路径
     * @param remote       服务器资源路径
     * @return Object
     */
    public static Object copyArchiveToContainerCmd(DockerClient dockerClient, String containerID, String resource, String remote) {
        return dockerClient.copyArchiveToContainerCmd(containerID).withHostResource(resource).withRemotePath(remote).exec();
    }
 
    /**
     * 从容器下载资源到本地
     *
     * @param dockerClient 客户端
     * @param containerID  容器id
     * @param local        本地路径
     * @param remote       远程容器路径
     * @return Object
     */
    public static Object copyArchiveFromContainerCmd(DockerClient dockerClient, String containerID, String local, String remote) {
        try {
 
 
            // String path = "F:\\tmp\\wealth.rar"
            // remote="/tmp/wealth.rar"
 
 
            InputStream input = dockerClient
                    .copyArchiveFromContainerCmd(containerID, remote)
                    .exec();
 
 
            int index;
            byte[] bytes = new byte[1024];
            FileOutputStream downloadFile = new FileOutputStream(local);
            while ((index = input.read(bytes)) != -1) {
                downloadFile.write(bytes, 0, index);
                downloadFile.flush();
            }
            input.close();
            downloadFile.close();
            return true;
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }
 
    /**
     * 根据容器名获取容器ID
     *
     * @param dockerClient  容器客户端
     * @param containerName 容器名
     * @return java.lang.String
     * @author wzm
     * @date 2019/9/28 15:38
     */
    public static String getContainerIdByName(DockerClient dockerClient, String containerName) {
        try {
            String containerId = "";
            Object object = DockerOperationUtils.listContainersCmd(dockerClient);
            JSONArray jsonArray = JSONArray.fromObject(object);
            for (int i = 0; i < jsonArray.size(); i++) {
                String name = jsonArray.getJSONObject(i).getString("names");
                name = name.replace("[\"/", "").replace("\"]", "");
                if (!StringUtils.isEmpty(name) && name.equals(containerName)) {
                    containerId = jsonArray.getJSONObject(i).getString("id");
                }
            }
            return containerId;
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }
}

 

 
posted @ 2020-01-23 14:52  itwetouch  阅读(4236)  评论(10编辑  收藏  举报