preface

Before, the deployment and upgrade of our company were managed by operation and maintenance. Considering that many open source platforms support automatic upgrade, I simply made a function to automatically upgrade WAR. Here, there is no docker image packet sending, gray packet sending, etc., only applicable to the deployment environment of a single Tomcat, supporting a single Docker Tomcat container.

Analysis of the

First, analyze the automatic upgrade process of war package:

  1. Check if updates are needed.
  2. Download the updated WAR package to the server’s temporary directory. (For background upload, no step 1 or 2 is required)
  3. Stop the tomcat
  4. Clear the war package decompressed directory and war package of Webapps in Tomcat.
  5. Start tomcat

There are no holes in step 1,2, but mainly steps 3, 4, and 5. If executed in Java code, the code in the war package will stop when the tomcat service is shut down, so you can only continue executing the following code if you write a separate Java program. However, I think this way is troublesome and depends too much on the environment, so I finally use shell script to execute step 3,4,5, and java-web to call this shell script.

The implementation of

Check the update

This step is relatively simple. Here you simply send a request with a version number such as a.com/checkVersio… Returns whether an update is required, and the update address:

{
    "NeedUpdate": true."downUrl": "http://a.com/1.0.war"
}Copy the code

Here we use httpClient to call the interface:

/* Note the character set"GBK""UTF-8"*/
public static String visitPost(String urlStr, String code) {
        try{
            URL url = new URL(urlStr);
            HttpURLConnection con = (HttpURLConnection)url.openConnection();
            con.setRequestMethod("GET"); con.connect(); BufferedReader reader = new BufferedReader(new InputStreamReader(con.getInputStream(),code));) ); String line; StringBuffer buffer = new StringBuffer();while((line = reader.readLine()) ! = null) { buffer.append(line); } reader.close(); con.disconnect(); String res = buffer.toString();return res;
        } catch(Exception e) {
            e.printStackTrace();
        }
        return null;
    }Copy the code

There are many ways to do this, but I’m not going to give you an example. After downloading, parse the content using Fastjson or Gson or plain String.

The download file

There are many ways to download files in Java, which are written in the form of flow and have a lot of code. If there is a framework in the project, you can use it directly. If there is no framework, you can find one online.

** @param file file entity */ public Boolean saveFile(FileEntity file) {public Boolean saveFile(FileEntity file) { BufferedOutputStream bos = null; FileOutputStream fos = null; byte[] bytes = file.getBytes();if(bytes ! = null) { try { fos = new FileOutputStream(file_Path + file.getName()); bos = new BufferedOutputStream(fos); bos.write(bytes); bos.flush(); IOUtils.closeQuietly(fos); IOUtils.closeQuietly(bos);return true;
            } catch (Exception e) {
                IOUtils.closeQuietly(fos);
                IOUtils.closeQuietly(bos);
                Log.error("Failed to save file", e);
                return false; }}return false;
    }Copy the code

Start a shell script

runBatOrShell(packagename, System.getProperties().getProperty("os.name").indexOf("Windows")! = 1)Copy the code

Here you need to check whether Windows or Linux is used. True is Windows, otherwise Linux. The package name argument is introduced to get sh files and bat files.


    private String tomcat_Path = System.getProperty("catalina.base") + File.separator; Public Boolean runBatOrShell(String name, Boolean OS) {log.info (String name, Boolean OS) {Log."RunBatOrShell start: > > > > > > > > > > > > > > > > > > > >");
        String _path;
        try {
            _path = os ? this.getClass().getResource("/batshell/web.bat").getPath() + "" + file_Path + ""+ name + "" + tomcat_Path : "sh " + this.getClass().getResource("/batshell/web.sh").getPath() + "" + file_Path + ""+ name + "" + tomcat_Path;
            Log.info(_path);
            Process ps = Runtime.getRuntime().exec(_path);
            BufferedReader br = new BufferedReader(new InputStreamReader(ps.getInputStream(), "UTF-8")); String line;while((line = br.readLine()) ! = null) { Log.info("runBatOrShell info=========>" + line);
            }
            br.close();
        } catch (IOException ioe) {
            Log.error("runBatOrShell error !!!!!!!!!!");
            ioe.printStackTrace();
            return false;
        }
        return true;
    }Copy the code

The Tomcat path is introduced here to facilitate script execution. Sh war file Directory Space File name Space Tomcat directory sh web.sh /usr/local/war/1.0. war /usr/local/tomcat/bat File The same procedure is used for web.bat d:/war/ 1.0 D :/tomcat/ The directories are as follows:

Shell script Execution

#! /bin/sh
cd The $1
echo $(date +%Y-%m-%d-%l:%M:%S) >>webvlog.txt;
echo $2>>webvlog.txt;
echo "Closing Tomcat">>webvlog.txt;
sh $3/bin/shutdown.sh
echo "Deleting war.war">>webvlog.txt;
rm $3/webapps/war.war;
echo "Deleting war folder">>webvlog.txt;
rm -r $3/webapps/war;
echo "Deploying war">>webvlog.txt;
cp  The $1$2 $3/webapps/war.war
echo "Restarting Tomcat">>webvlog.txt;
sh $3/bin/startup.sh
echo "Deployment successful">>webvlog.txt;Copy the code

The $1, $2, $3 variable indicates the value passed after the runtime, and the other code echo is a comment. Webvlog. TXT indicates deployment logs.

conclusion

After this transformation, the existing requirements are basically met and the deployment steps are simplified. However, this solution cannot be applied to multiple Tomcat environments. Many scenarios have load balance and multiple Docker environments. In this case, this solution cannot be solved.

legacy

War package upgrade may add tables, views, etc., so you need to execute SQL script, SQL script upgrade plan will be shared next time.