A preface.

hello,everyone.

As technology continues to evolve, containerized deployment has become the preferred service deployment for many companies. Portability, independent management, and ease of deployment are all reasons for choosing containerized deployment. Here, take docker as an example, if I want to get or execute the relevant host commands inside the Docker container. I’m sure many of you on the Devops team will be familiar with this. For example, the user can view the CPU usage of the current system. This operation is relatively simple to get the data in the form of a Java service deployed directly as a JAR package. Linux commands can be invoked directly from the relevant third-party open source libraries or code. But if deployed inside a container, which is a separate environment, jar packages and direct calls are not feasible.

This article will provide you with an idea of how to monitor various environments and systems of the host computer by Java application docker deployment. If there is any mistake, please point out.

Ii. Solutions

It is not possible for Java to invoke commands from the host directly using a single series of shell scripts to interactively perform a large number of operations. Only individual commands can be executed one by one, so how do you execute commands across containers?

2.1. Sshpass

In fact, the recommended solution is to use the sshpass command. For example, if I want to check the files in the root directory of host 1.2.3.4, I can use it

Sshpass -p password -v SSH [email protected] -p 22 ‘ls /’

The downside of this approach is that in a toB scenario, the environment is o&M to provide the installation package, the entire deployment. And then the machine belongs to the user. The parameters in the code for the sshpass command above must be configured through the configuration file. At this time if the user changes the password of the host machine, your command will be invalid, can not get the result of the command return.

This solution can solve the above problems in toC single-service deployment. However, in cluster deployment, the configuration file needs to be maintained too much, and the configuration file may change when the password is changed.

To sum up, I personally do not recommend this kind of plan, natural disadvantage.

2.1. SSH from close

Normally, we use SSH root@ip -p port number to connect to remote cloud host, and then enter the password. Ordinary SSH tools provide a way to remember the password, which can be quickly connected. If you do this in Java, you will enter the host and no subsequent commands will be invoked.

SSH provides a confidential login method. The private key and public key are generated in the docker container, and the public key is saved in ~/.ssh/authorized_keys of the host

This allows the host to execute commands on the host via SSH.

Encryption-free login mode: SSH three-step solution for encryption-free login

If the container deployment mode development is not easy to operate, you can contact the o&M department to add this configuration when initializing the environment and container.

3. Actual scene

Host monitoring is a common function of the C-terminal O&M platform or the B-terminal service platform. After knowing how to access the host in Docker, we can obtain the usage of CPU, hard disk and memory on the host.

The following uses Java applications deployed on docker containers to obtain disk usage as an example [the premise is that SSH security is configured on docker]

/** * @author baiyan */ @data public class SystemInfoBaseDTO {@apiModelProperty (" total "); private Double total; @apiModelProperty (" use ") private Double Used; @APIModelProperty (" idle ") private Double Free; @apiModelProperty (" usage ") private Double usedRate; }Copy the code
String menCommand = "SSH [email protected] df - h/p | sed - n" 2, 1 p "| awk '{print $2 $3}" "' "; String memInfo = CmdUtil.executeLinuxCmd(menCommand); String[] mem = memInfo.split(" "); Double total = this.getNumber(mem[0]); Double used = this.getNumber(mem[1]);Copy the code
Private SystemInfoBaseDTO getBaseInfo(String Command){SystemInfoBaseDTO info = new SystemInfoBaseDTO(); / / Private SystemInfoBaseDTO getBaseInfo(String Command){SystemInfoBaseDTO info = new SystemInfoBaseDTO();  String menCommand = "SSH [email protected] df - h/p | sed - n" 2, 1 p "| awk '{print $2 $3}" "' "; String memInfo = CmdUtil.executeLinuxCmd(menCommand); String[] mem = memInfo.split(" "); Double total = this.getNumber(mem[0]); Double used = this.getNumber(mem[1]); info.setTotal(total); info.setUsed(used); info.setFree(total - used); info.setUsedRate((double) Math.round(used/total * 10000)/100); return info; }Copy the code
Public class CmdUtil {/** * execute commands ** by default in the current environment, * * @param CMD * @return */ public static String executeLinuxCmd(String CMD){* * @param CMD * @return */ public static String executeLinuxCmd(String CMD){ String[] cmdArray = {"sh", "-c", cmd}; return executeShell(true, cmdArray); } @param CMD: the first parameter is an executable command program, the other parameters are required for command line execution * @return: java.lang.String **/ public static String executeShell(boolean withLine, String... cmd){ return executeShell(null, withLine, cmd); @param filePath: The default is the current working directory of the current process, usually named after the system property user.dir. * @param withLine: * @param CMD: * @return: java.lang.String **/ public static String executeShell(File filePath, boolean withLine, String... cmd){ StringBuilder cmdResult = new StringBuilder(); try { ProcessBuilder processBuilder = new ProcessBuilder(cmd); processBuilder.directory(filePath); Process process = processBuilder.redirectErrorStream(true).start(); try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))){ String line; while ((line = reader.readLine()) ! = null){ cmdResult.append(line); if (withLine){ cmdResult.append(System.lineSeparator()); } } log.debug(cmdResult.toString()); } int existCode = process.waitFor(); log.debug("execute cmd {} success, exist code {}", Arrays.toString(cmd), existCode); } catch (Exception e){ log.error(e.getMessage(),e); } if (withLine){ return cmdResult.substring(0, cmdResult.length()).trim(); } return cmdResult.toString().trim(); }}Copy the code

4. Expand your ideas

At this point, you have data on the hard disk usage of the host. However, there is a disadvantage. The command execution time is related to the SSH connection time. If SSH connection time is slow, the command execution time is also long. And that’s just counting a hard disk usage, so serialization, the interface, if you need to fetch more of the host’s content in a request, can be very slow.

Therefore, you can define a scheduled task to asynchronously perform the data fetching task, such as executing commands to drop data from the table every 30 seconds or so. When the front end needs to load the current or a period of system running status, it can directly load the data in the table or in the cache.

When the periodic task scanning finds that the relevant system indicators exceed the standard, the alarm can be triggered, and the nails or SMS interface can be called to inform the relevant system responsible person to solve the problem.

Is it like Spring-Admin or some common operational monitoring system on the market?

In distributed deployment scenarios, whether to batch pull IP addresses and configurations from the registry, and then obtain relevant parameter data, a complete online monitoring system is formed.

Five. Contact me

If there is an incorrect place in the article, welcome to correct, writing the article is not easy, point a thumbs-up, yao yao da ~

Nailing: louyanfeng25

WeChat: baiyan_lou