Quickly get started with docker Java, which is the most complete example in the whole network. It will take you to step on the pit and fly with you

Step on the pit in advance

As soon as I joined the project team, I began to work with dokcer Java. Since I hadn't contacted it before, I began to look for information throughout the network. Therefore, I found a bunch of blogs, which seem to be similar. Although they can run, my needs have not been realized:

  • Unable to connect to remote docker
  • Unable to implement path mount
  • The secure connection cannot be realized (after following the operation, the error of client send an HTTP request to an HTTPS server appears, which is painful)
  • How to implement docker to execute script files and carry parameters

We're starting to avoid the pit now

After stepping on so many pits, I decided to make a summary, so I have this article called "the most complete docker Java quick start case in the whole network".

The premise is that the docker environment has been installed. If it has not been installed, please refer to my article: https://blog.csdn.net/weixin_34311210/article/details/106181740

Integrated docker Java

Download docker java source code

git clone https://github.com/docker-java/docker-java.git

If the Internet is too slow to be able to get it down, you can pay attention to the official account number AI code division, "reply docker-java" to get the latest source code.

Compile the package and generate the local jar

cd docker-java
mvn install -Dmaven.test.skip=true

Create maven project

Procedure omitted

Introduce dependency

        <dependency>
            <groupId>com.github.docker-java</groupId>
            <artifactId>docker-java</artifactId>
            <version>0-SNAPSHOT</version>
        </dependency>
        
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.4</version>
        </dependency>

Note: the warehouse Path of maven configuration set by idea should be consistent with the warehouse Path of maven just packaged, otherwise your locally packaged jar cannot be found

Modify docker information to realize remote access

Enter the docker server and modify the configuration file

vi /lib/systemd/system/docker.service
 find ExecStart Note the original configuration for backup
 Insert the following
ExecStart=/usr/bin/dockerd -H tcp://0.0.0.0:2375 -H unix://var/run/docker.sock
 Save exit
systemctl daemon-reload
service docker restart

Note: if the cloud service or firewall is open, remember to open the port
Browser input: http://IP:2375/version If the response is normal, the configuration takes effect

Create connection

    public DockerClient connectDocker(){
        DockerClient dockerClient = DockerClientBuilder.getInstance("tcp://ip:2375").build();
        Info info = dockerClient.infoCmd().exec();
        String infoStr = JSONObject.toJSONString(info);
        System.out.println("docker The environmental information is as follows:=================");
        System.out.println(info);
        return dockerClient;
    }

If the console prints a message, it means that you have connected to docker through java. If there is an unknown problem, you can leave a message and will reply to you after seeing it.

So far, we have connected docker. Next, I will write many examples for you to use, so as to avoid you looking for documents all over the network.

Strongest example

1. Let's start with a high force: discard the ordinary connection and realize the secure connection

  • Write the script to generate the certificate, which is found on the Internet. You can automatically generate the script and complete the copy

vim auto_gen_docker.sh

#!/bin/bash
#
# -------------------------------------------------------------
# Automatically create Docker TLS certificate
# -------------------------------------------------------------
# The following is the configuration information
# --[BEGIN]------------------------------
CODE="docker"
IP="192.168.1.1"
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"
# Package client certificate
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"
# Copy server certificate
mkdir -p /etc/docker/certs.d
cp "ca-$CODE.pem" "server-cert-$CODE.pem" "server-key-$CODE.pem" /etc/docker/certs.d/
  • Execute script
chmod a+x auto_gen_docker.sh
sh auto_gen.sh
  • Copy the tls-client-certs-docker.tar file in the current directory to the resource of the project and unzip it, as shown in the figure:
  • Write a method to establish a secure connection
   public static DockerClient getDockerClient() {
        // Conduct safety certification
        DockerClientConfig config = DefaultDockerClientConfig.createDefaultConfigBuilder()
                // Server ip
                .withDockerHost("tcp://IP:PORT")
                .withDockerTlsVerify(true)
                // The path to decompress the compressed package
                .withDockerCertPath("D:\\code\\my_code\\test-skill\\src\\main\\resources\\tls-client-certs-docker")
                // The API version can be viewed through the docker version command on the server
                .withApiVersion("1.37")
                // default
                .withRegistryUrl("https://index.docker.io/v1/")
                // default 
                .withRegistryUsername("docker")
                // default
                .withRegistryPassword("123456")
                // default
                .withRegistryEmail("an23gn@163.com")
                .build();
        // docker command execution factory
        DockerCmdExecFactory dockerCmdExecFactory = new JerseyDockerCmdExecFactory()
                .withReadTimeout(60000)
                .withConnectTimeout(60000)
                .withMaxTotalConnections(100)
                .withMaxPerRouteConnections(10);
        dockerClient = DockerClientBuilder.getInstance(config).withDockerCmdExecFactory(dockerCmdExecFactory).build();
        return dockerClient;
    }

Use this docker client instead of the docker client generated by the above normal connection

    public DockerClient connectDocker(){
        DockerClient dockerClient = getDockerClient();
        Info info = dockerClient.infoCmd().exec();
        String infoStr = JSONObject.toJSONString(info);
        System.out.println("docker The environmental information is as follows:=================");
        System.out.println(info);
        return dockerClient;
    }

After execution, the following error should be reported
Client sent an HTTP request to an HTTPS server
This is one of the pits I stepped on. Later, I found the problem by tracking the source code:
In the source code, you need to verify whether the authentication file exists:

However, the authentication file in our compressed package is as follows:

As a result, the authentication file is not recognized, which leads docker to think that we do not use https protocol, and http is used by default;
But our server has https enabled, so the above error will appear.

How to solve it? The source code can't be modified. We just need to modify the authentication file we generated into the name format he needs. I believe many netizens have encountered such a pit!

Modified as required

Re run the program normally

2. Create container

    public CreateContainerResponse createContainers(DockerClient client,String containerName,String imageName){
        //Mapping port 8088 - > 80
        ExposedPort tcp80 = ExposedPort.tcp(80);
        Ports portBindings = new Ports();
        portBindings.bind(tcp80, Ports.Binding.bindPort(8088));
        CreateContainerResponse container = client.createContainerCmd(imageName)
                .withName(containerName)
                .withHostConfig(newHostConfig().withPortBindings(portBindings))
                .withExposedPorts(tcp80).exec();
        return container;
    }

3. Load image

    public LoadImageCmd loadImage(DockerClient client, String filePath){
        LoadImageCmd loadImageCmd = null;
        try {
            loadImageCmd = client.loadImageCmd(new FileInputStream(filePath));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return loadImageCmd;
    }

4. Pull the image

    /**
    * repository Image name: tag name
    **/
    public PullImageCmd pullImage(DockerClient client,String repository){
        PullImageCmd pullImageCmd = client.pullImageCmd(repository);
        return pullImageCmd;
    }

5. Delete image

    public void removeImage(DockerClient client,String imageId){
        client.removeImageCmd(imageId).exec();
    }

6. Remove the container

    public void removeContainer(DockerClient client,String containerId){
        client.removeContainerCmd(containerId).exec();
    }

7. Start the container

    public void startContainer(DockerClient client,String containerId){
        client.startContainerCmd(containerId).exec();
    }

8. Stop the container

    public void stopContainer(DockerClient client,String containerId){
        client.stopContainerCmd(containerId).exec();
    }

9. Path mount

Using the hostConfig method and directly using Volumes is not feasible. I also consulted my leadership. I really thought about it for a long time.

public CreateContainerResponse createContainers(DockerClient client,String containerName,String imageName){
        HostConfig hostConfig = newHostConfig();
        Bind bind = new Bind("Server path",new Volume("Container path"));
        hostConfig.setBinds(bind);
        CreateContainerResponse container = client.createContainerCmd(imageName)
                .withName(containerName)
                .withHostConfig(hostConfig)
                .exec();
        return container;
    }

10 execute command

public CreateContainerResponse createContainers(DockerClient client,String containerName,String imageName){
        HostConfig hostConfig = newHostConfig();
        CreateContainerResponse container = client.createContainerCmd(imageName)
                .withName(containerName)
                .withHostConfig(hostConfig)
                .withCmd("python","/root/scripts/test.py")
                .exec();
        return container;
    }

11 use docker to execute script commands and pass parameters

public CreateContainerResponse createContainers(DockerClient client,String containerName,String imageName){
        HostConfig hostConfig = newHostConfig();
        CreateContainerResponse container = client.createContainerCmd(imageName)
                .withName(containerName)
                .withHostConfig(hostConfig)
                // Note that commands and parameters cannot be combined. They must be separated by commas, that is, all spaces are replaced by the division here
                .withCmd("python","/root/scripts/test.py","-t","999")
                .exec();
        return container;
    }

Here, all docker java examples have been written, and more practical use cases will be added in the future. Please look forward to it. If there are any problems during the operation, just leave a message at the bottom, and I will reply to you when I see it.

Welfare release

Pay attention to WeChat official account "AI code division", receive 2021 interview information and 2021 latest complete micro service course.

Keywords: Java Docker

Added by anf.etienne on Sat, 23 Oct 2021 13:57:38 +0300