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.