3、一粒云二次封装与迁移 – 编写安装程序

目录 运维

第二步时已经将必须的文件和内容打包为package.tar.gz文件,下一步只需编写安装程序自动解包并编译安装程序即可。

程序使用Nodejs编写。

1、基础代码

首先初始化项目

npm init

然后安装一些UI显示类的包

npm i nodejs-md5 ora chalk mysql -d

nodejs-md5用来校验package.tar.gz是否损坏,ora展示安装动画,chalk展示彩色CLI。

在项目下创建index.js入口文件

touch index.js && vim index.js

引入所需的包

const fs = require('fs');
const md5 = require('nodejs-md5');
const path = require('path');
const exec = require('child_process');
const ora = require("ora");
const chalk = require('chalk');

声明一些单次赋值常量。

const INSTALL_PATH = process.cwd();
const INSTALL_PACKAGE_PATH = path.join(INSTALL_PATH,'package.tar.gz');
const INSTALL_PACKAGE_MD5 = "65f07f9eee608d87da2a2b4ce12cb811";
const SERVER_CORE_NUMBER = exec.execSync('cat /proc/cpuinfo | grep processor | wc -l | awk \'{printf $0}\'').toString() == 0 ? "1" : exec.execSync('cat /proc/cpuinfo | grep processor | wc -l | awk \'{printf $0}\'').toString();
const SERVER_IP = exec.execSync('hostname -I | grep -Eo "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\." | awk \'NR==1{printf $0}\'').toString().replace(/\s/g,"");

INSTALL_PATH是运行这个安装程序的路径,需要靠这个参数进行文件定位。

INSTALL_PACKAGE_PATH 顾名思义package.tar.gz的路径。

INSTALL_PACKAGE_MD5 包的摘要码,用来判断包是否损坏。

SERVER_CORE_NUMBER 系统CPU逻辑核心数量,用来优化内部应用。

SERVER_IP 系统IP地址,用来设置配置文件。

const logo = "\
        _ ___   __             ___           _        _ _  \n\
  _   _| (_) \\ / /   _ _ __   |_ _|_ __  ___| |_ __ _| | | \n\
 | | | | | |\\ V / | | | '_ \\   | || '_ \\/ __| __/ _` | | | \n\
 | |_| | | | | || |_| | | | |  | || | | \\__ \\ || (_| | | | \n\
  \\__, |_|_| |_| \\__,_|_| |_| |___|_| |_|___/\\__\\__,_|_|_| \n\
  |___/                                                    \n\
"
console.log(logo)

显示安装logo

exec.execSync('cat /etc/profile | grep "export PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin" | wc -l').toString() == 0 && exec.execSync('echo "export PATH=$PATH:/usr/sbin:/usr/bin:/sbin:/bin" >> /etc/profile && . /etc/profile')

部分系统在ssh远程时,环境目录配置不正确,比如Debian,这个操作将一些命令目录临时加入环境变量。避免出现已安装但找不到某程序的情况出现。

console.log(chalk.bold("Server IP:                ") + chalk.cyan(SERVER_IP));
console.log(chalk.bold("Server core number:       ") + chalk.cyan(SERVER_CORE_NUMBER));
console.log(chalk.bold("Installation path:        ") + chalk.cyan(INSTALL_PATH));
console.log(chalk.bold("Data packet:              ") + chalk.cyan(INSTALL_PACKAGE_PATH));
console.log(chalk.bold("Packet verification:      ") + chalk.cyan(INSTALL_PACKAGE_MD5));
console.log("\n");

展示获取的信息,如果有错误,可以直接中断。

2、包校验

var publicFileCheckUI = ora("Data verification in progress...");
publicFileCheckUI.start();

//包不存在执行目录下,直接暂停执行
let packageStat = fs.existsSync(INSTALL_PACKAGE_PATH);
!packageStat && (publicFileCheckUI.fail("Package file does not exist") && process.exit(1));

//校验包是否损坏,如果包完好,则开始进行安装
md5.file.quiet(INSTALL_PACKAGE_PATH,(err, md5) => {
    if(md5 === INSTALL_PACKAGE_MD5){
        /**校验成功,安装开始 */
        publicFileCheckUI.succeed("Data verification completed!!!");
        InstallStart();
    }
    if(md5 !== INSTALL_PACKAGE_MD5){
        /**校验失败,包被损坏 */
        publicFileCheckUI.fail("Data verification failed!!!");
        process.exit(1);
    }
    if(err){
        /**校验发生错误 */
        publicFileCheckUI.fail("Data verification failed!!!Failed to get MD5 value");
        process.exit(1);
    }
})

并校验包是否损坏根据结果进行下一步。

3、编写校验脚本

const install = require('./script');

创建安装程序./script/index.js并在index.js中引入。

 

const fs = require('fs');
const path = require('path');
const exec = require('child_process');
const ora = require("ora");
const chalk = require('chalk');
const mysql = require('mysql');

./script/index.js引入所需的包。

 

/**
 * 写入日志
 * @param {*} installPath 安装路径
 * @param {*} str 日志数据
 */
installScript.installLog = (installPath,str) => {
    let logPath = path.join(installPath,'install.log');
    fs.appendFileSync(logPath,typeof str === "string" ? str : '');
}

添加一个日志函数,将安装结果写入日志中,方便查看错误信息。

 

/**
 * 校验gcc是否安装
 * @returns 
 */
installScript.gccStauts = () => {
    return new Promise((resolve,reject) => {
        let bin = fs.existsSync("/usr/bin/gcc");
        let uSbin = fs.existsSync("/usr/sbin/gcc");
        let sbin = fs.existsSync("/sbin/gcc");

        if(bin || uSbin || sbin){
            console.log(" gcc                                              " + chalk.green('[OK]'));
            return resolve();
        }

        console.log(" gcc                                              " + chalk.red('[NO]'));
        process.exit(1)
    })
}

校验GCC是否安装,编译c语言应用时需要gcc。

 

/**
 * 校验make是否安装
 * @returns 
 */
installScript.makeStauts = () => {
    return new Promise((resolve,reject) => {
        let bin = fs.existsSync("/usr/bin/make");
        let uSbin = fs.existsSync("/usr/sbin/make");
        let sbin = fs.existsSync("/sbin/make");

        if(bin || uSbin || sbin){
            console.log(" make                                             " + chalk.green('[OK]'));
            return resolve();
        }


        console.log(" make                                             " + chalk.red('[NO]'));
        process.exit(1)
    })
}

校验make是否安装,编译安装时需要make。

 

/**
 * 校验tar是否安装
 * @returns 
 */
installScript.tarStauts = () => {
    return new Promise((resolve,reject) => {
        let bin = fs.existsSync("/usr/bin/tar");
        let uSbin = fs.existsSync("/usr/sbin/tar");
        let sbin = fs.existsSync("/sbin/tar");

        if(bin || uSbin || sbin){
            console.log(" tar                                              " + chalk.green('[OK]'));
            return resolve();
        }

        console.log(" tar                                              " + chalk.red('[NO]'));
        process.exit(1)
    })
}

校验tar命令是否安装,解包时需要此命令。

 

/**
 * 校验tcl是否安装
 * @returns 
 */
 installScript.tclStauts = () => {
    return new Promise((resolve,reject) => {

        if(fs.existsSync("/usr/bin/tclsh")){
            console.log(" tcl                                              " + chalk.green('[OK]'));
            return resolve();
        }

        console.log(" tcl                                              " + chalk.red('[NO]'));
        process.exit(1)
    })
}

校验tcl是否安装,redis需要tcl。

 

/**
 * 校验g++是否安装
 * @returns 
 */
installScript.gccgccStauts = () => {
    return new Promise((resolve,reject) => {
        let bin = fs.existsSync("/usr/bin/g++");
        let uSbin = fs.existsSync("/usr/sbin/g++");
        let sbin = fs.existsSync("/sbin/g++");

        if(bin || uSbin || sbin){
            console.log(" g++                                              " + chalk.green('[OK]'));
            return resolve();
        }

        console.log(" g++                                              " + chalk.red('[NO]'));
        process.exit(1)
    })
}

校验gcc-c++是否安装,编译c++应用时需要此应用。

/**
 * 校验autoconf是否安装
 * @returns 
 */
installScript.autoConfStauts = () => {
    return new Promise((resolve,reject) => {
        let bin = fs.existsSync("/usr/bin/autoconf");
        let uSbin = fs.existsSync("/usr/sbin/autoconf");
        let sbin = fs.existsSync("/sbin/autoconf");

        if(bin || uSbin || sbin){
            console.log(" autoconf                                         " + chalk.green('[OK]'));
            return resolve();
        }

        console.log(" autoconf                                         " + chalk.red('[NO]'));
        process.exit(1)
    })
}

校验autoconf是否安装,被mysql所依赖。

/**
 * 校验libtinfo.so.5是否安装
 * @returns 
 */
 installScript.libtinfo5Stauts = () => {
    return new Promise((resolve,reject) => {
        let lib = exec.execSync('find /usr/lib -name libtinfo.so.5 && find /lib -name libtinfo.so.5 && find /usr/lib64 -name libtinfo.so.5 | wc -l').toString();

        if(lib != 0){
            console.log(" libtinfo.so.5                                    " + chalk.green('[OK]'));
            return resolve();
        }

        console.log(" libtinfo.so.5                                    " + chalk.red('[NO]'));
        process.exit(1)
    })
}

校验libtinfo.so.5是否安装。

 

/**
 * 校验libaio.so.1是否安装
 * @returns 
 */
installScript.libaioStauts = () => {
    return new Promise((resolve,reject) => {
        let lib = exec.execSync('find /usr/lib -name libaio.so.1 && find /lib -name libaio.so.1 && find /usr/lib64 -name libaio.so.1 | wc -l').toString();

        if(lib != 0){
            console.log(" libaio.so.1                                      " + chalk.green('[OK]'));
            return resolve();
        }

        console.log(" libaio.so.1                                      " + chalk.red('[NO]'));
        process.exit(1)
    })
}

校验libaio.so.1是否安装,mysql依赖。

 

/**
 * 校验libnuma.so.1是否安装
 * @returns 
 */
installScript.libnumaStauts = () => {
    return new Promise((resolve,reject) => {
        let lib = exec.execSync('find /usr/lib -name libnuma.so.1 && find /lib -name libnuma.so.1 && find /usr/lib64 -name libnuma.so.1 | wc -l').toString();

        if(lib != 0){
            console.log(" libnuma.so.1                                     " + chalk.green('[OK]'));
            return resolve();
        }

        console.log(" libnuma.so.1                                     " + chalk.red('[NO]'));
        process.exit(1)
    })
}

校验libnuma.so.1是否安装

 

/**
 * 校验cmake是否安装
 * @returns 
 */
installScript.cmakeStauts = () => {
    return new Promise((resolve,reject) => {
        let bin = fs.existsSync("/usr/bin/cmake");
        let uSbin = fs.existsSync("/usr/sbin/cmake");
        let sbin = fs.existsSync("/sbin/cmake");

        if(bin || uSbin || sbin){
            console.log(" cmake                                            " + chalk.green('[OK]'));
            return resolve();
        }

        console.log(" cmake                                             " + chalk.red('[NO]'));
        process.exit(1)
    })
}

校验cmake是否安装,mysql必须。

 

/**
 * 校验libncurses.so.5是否安装
 * @returns 
 */
installScript.libncurses5Stauts = () => {
    return new Promise((resolve,reject) => {
        let lib = exec.execSync('find /usr/lib -name libncurses.so.5 && find /lib -name libncurses.so.5  && find /usr/lib64 -name libncurses.so.5 | wc -l').toString()

        if(lib != 0){
            console.log(" libncurses.so.5                                  " + chalk.green('[OK]'));
            return resolve();
        }

        console.log(" libncurses.so.5                                    " + chalk.red('[NO]'));
        process.exit(1)
    })
}

校验libncurses.so.5是否安装,mysql必须。

以上所校验的依赖,全部都可以从光盘镜像或者官方自带源内进行安装。所以只需要校验并提示即可。

#yum
yum install gcc gcc-g++ make cmake autoconf libaio tar tcl -y

#apt
apt install gcc g++ autoconf cmake make tcl libaio1 libnuma1 libncurses5 -y

 

3、编写安装脚本

 

/**
 * 解包
 * @param {*} packagePath 包路径
 * @param {*} targetPath 解压目标路径
 * @returns 
 */
installScript.ReleasePackage = (packagePath,targetPath,installPath) => {
    return new Promise((resolve,reject) => {
        let oarUI = ora("Decompressing package...");
        oarUI.start();
        let str = exec.spawn('tar',['-zxvf',packagePath,'-C',targetPath]);
        str.stdout.on('data',(data) => {
            installScript.installLog (installPath,data.toString());
        })
        str.stderr.on('data',(data) => {
            installScript.installLog (installPath,data.toString());
        })
        str.on('close',(code) => {
            if(code !== 0){
                oarUI.fail("Decompressing package...");
                process.exit(1);
            }
            if(code === 0){
                oarUI.succeed("Decompressing package...");
                return resolve();
            }
        })
    })
}

解开package.tar.gz包。

/**
 * 安装zlib
 * @param {*} sourcePath zlib源码路径
 * @returns 
 */
installScript.InstallZlib = (sourcePath,installPath,coreNumber) => {
    return new Promise((resolve,reject) => {
        let zlibPath = path.join(sourcePath,'package','zlib')
        let oarUI = ora("Installing zlib");
        oarUI.start();
        exec.exec("./configure && make -j " + coreNumber + " && make install",{
            cwd: zlibPath,
            maxBuffer: 10240 * 10240
        },function(err,stdout,stderr){
            if(err){
                oarUI.fail("Installing zlib");
                installScript.installLog (installPath,err);
                process.exit(1);
            }
            if(stdout){
                oarUI.succeed("Installing zlib");
                installScript.installLog (installPath,stdout);
                return resolve();
            }
            if(stderr){
                oarUI.fail("Installing zlib");
                installScript.installLog (installPath,stderr);
                process.exit(1);
            }
        });
    })
}

安装zlib,zlib是nginx开启gzip时所需的依赖。

/**
 * 安装libfastcommon
 * @param {*} sourcePath 源码路径
 * @param {*} installPath 安装路径
 * @returns 
 */
installScript.InstallLibFastCommon = (sourcePath,installPath) => {
    return new Promise((resolve,reject) => {
        let perlPath = path.posix.join(sourcePath,'package','libfastcommon');
        let oarUI = ora("Installing libfastcommon");
        oarUI.start();
        exec.exec("./make.sh && ./make.sh install",{
            cwd: perlPath,
            maxBuffer: 10240 * 10240
        },function(err,stdout,stderr){
            if(err){
                oarUI.fail("Installing libfastcommon");
                installScript.installLog (installPath,err);
                process.exit(1);
            }
            if(stdout){
                oarUI.succeed("Installing libfastcommon");
                installScript.installLog (installPath,stdout);
                return resolve();
            }
            if(stderr){
                oarUI.fail("Installing libfastcommon");
                installScript.installLog (installPath,stderr);
                process.exit(1);
            }
        });
    })
}

安装libfastcommon。

 

/**
 * 安装perl
 * @param {*} sourcePath  Tcl源码路径
 * @param {*} installPath  安装路径
 * @returns 
 */
installScript.InstallPerl = (sourcePath,installPath,coreNumber) => {
    return new Promise((resolve,reject) => {
        let perlPath = path.posix.join(sourcePath,'package','perl');
        let oarUI = ora("Installing perl (5 ~ 10min)");
        oarUI.start();
        exec.exec("./Configure -de && make -j " + coreNumber + " && make test && make install",{
            cwd: perlPath,
            maxBuffer: 10240 * 10240
        },function(err,stdout,stderr){
            if(err){
                oarUI.fail("Installing perl");
                installScript.installLog (installPath,err);
                process.exit(1);
            }
            if(stdout){
                oarUI.succeed("Installing perl");
                installScript.installLog (installPath,stdout);
                return resolve();
            }
            if(stderr){
                oarUI.fail("Installing perl");
                installScript.installLog (installPath,stderr);
                process.exit(1);
            }
        });
    })
}

安装perl

/**
 * 安装Fastdfs
 * @param {*} sourcePath  Fastdfs源码路径
 * @param {*} installPath  安装路径
 * @returns 
 */
installScript.InstallFastdfs = (sourcePath,installPath) => {
    return new Promise((resolve,reject) => {

        let fastdfsPath = path.posix.join(sourcePath,'package','fastdfs');
        let fastdfsStoragedBinPackagePath = path.posix.join(sourcePath,'package','bin','fdfs_storaged');
        let fastdfsBinPackagePath = path.posix.join(sourcePath,'package','bin','fdfs');
        let fastdfsTrackerdBinPackagePath = path.posix.join(sourcePath,'package','bin','fdfs_trackerd');

        let fastdfsStoragedBinInstallPath = path.posix.join('/usr','local','yliyun','bin','fdfs_storaged');
        let fastdfsTrackerdBinInstallPath = path.posix.join('/usr','local','yliyun','bin','fdfs_trackerd');
        let fastdfsBinInstallPath = path.posix.join('/usr','local','yliyun','bin','fdfs');

        let fastdfsStoragedConfPackagePath = path.posix.join(sourcePath,'package','conf','fdfs','storage.conf');
        let fastdfsStoragedIdsConfPackagePath = path.posix.join(sourcePath,'package','conf','fdfs','storage_ids.conf');
        let fastdfsTrackerConfPackagePath = path.posix.join(sourcePath,'package','conf','fdfs','tracker.conf');
        let fastdfsClientConfPackagePath = path.posix.join(sourcePath,'package','conf','fdfs','client.conf');
        let fastdfsHttpConfPackagePath = path.posix.join(sourcePath,'package','conf','fdfs','http.conf');
        let fastdfsMimeTypesConfPackagePath = path.posix.join(sourcePath,'package','conf','fdfs','mime.types');
        let modFastdfsConfPackagePath = path.posix.join(sourcePath,'package','conf','fdfs','mod_fastdfs.conf');

        let fastdfsConfInstallPath = path.posix.join('/usr','local','yliyun','conf','fdfs');
        
        exec.spawnSync("cp",[fastdfsStoragedBinPackagePath,fastdfsStoragedBinInstallPath]);
        exec.spawnSync("cp",[fastdfsTrackerdBinPackagePath,fastdfsTrackerdBinInstallPath]);
        exec.spawnSync("cp",[fastdfsBinPackagePath,fastdfsBinInstallPath]);
        exec.spawnSync("cp",[fastdfsStoragedConfPackagePath,fastdfsConfInstallPath]);
        exec.spawnSync("cp",[fastdfsStoragedIdsConfPackagePath,fastdfsConfInstallPath]);
        exec.spawnSync("cp",[fastdfsTrackerConfPackagePath,fastdfsConfInstallPath]);
        exec.spawnSync("cp",[fastdfsClientConfPackagePath,fastdfsConfInstallPath]);
        exec.spawnSync("cp",[fastdfsHttpConfPackagePath,fastdfsConfInstallPath]);
        exec.spawnSync("cp",[fastdfsMimeTypesConfPackagePath,fastdfsConfInstallPath]);
        exec.spawnSync("cp",[modFastdfsConfPackagePath,fastdfsConfInstallPath]);

        let oarUI = ora("Installing fastdfs");
        oarUI.start();
        exec.exec("./make.sh && ./make.sh install",{
            cwd: fastdfsPath,
            maxBuffer: 10240 * 10240
        },function(err,stdout,stderr){
            if(err){
                oarUI.fail("Installing fastdfs");
                installScript.installLog (installPath,err);
                process.exit(1);
            }
            if(stdout){
                oarUI.succeed("Installing fastdfs");
                installScript.installLog (installPath,stdout);
                return resolve();
            }
            if(stderr){
                oarUI.fail("Installing fastdfs");
                installScript.installLog (installPath,stderr);
                process.exit(1);
            }
        });
    })
}

安装Fastdfs

/**
 * 安装redis
 * @param {*} sourcePath  redis源码路径
 * @param {*} installPath  安装路径
 * @returns 
 */
installScript.InstallRedis = (sourcePath,installPath,coreNumber) => {
    return new Promise((resolve,reject) => {
        let redisPath = path.posix.join(sourcePath,'package','redis');

        let redisConfigPackagePath = path.posix.join(sourcePath,'package','conf','redis');
        let redisConfigPath = path.posix.join("/usr","local","yliyun","conf","redis");
        let redisConfigFilePackagePath = path.posix.join(redisConfigPackagePath,"redis.conf");
        let redisConfigFilePackage = path.posix.join(redisConfigPath,"redis.conf")
        let redisBinPackagePath = path.posix.join(sourcePath,'package','bin','redis');
        let redisBinInstallPath = path.posix.join("/usr","local","yliyun","bin",'redis');

        exec.spawnSync("cp",[redisConfigFilePackagePath,redisConfigFilePackage]);
        exec.spawnSync("cp",[redisBinPackagePath,redisBinInstallPath]);
        exec.spawnSync("cp",["-R",redisPath,"/usr/local"]);
        let oarUI = ora("Installing redis");
        oarUI.start();
        exec.exec("make -j " + coreNumber + " && make PREFIX=/usr/local/redis install",{
            cwd: "/usr/local/redis",
            maxBuffer: 10240 * 10240
        },function(err,stdout,stderr){
            if(err){
                oarUI.fail("Installing redis");
                installScript.installLog (installPath,err);
                process.exit(1);
            }
            if(stdout){
                oarUI.succeed("Installing redis");
                installScript.installLog (installPath,stdout);
                return resolve();
            }
            if(stderr){
                oarUI.fail("Installing redis");
                installScript.installLog (installPath,stderr);
                process.exit(1);
            }
        });
    })
}

安装redis

/**
 * 安装openresty
 * @param {*} sourcePath  openresty源码路径
 * @param {*} installPath  安装路径
 * @returns 
 */
installScript.InstallOpenResty = (sourcePath,installPath,coreNumber) => {
    return new Promise((resolve,reject) => {
        //ulimit -n 102400
        let openRestyPath = path.posix.join(sourcePath,'package','openresty');
        let oarUI = ora("Installing Openresty");
        oarUI.start();
        exec.exec("./configure --with-pcre=" + path.posix.join(sourcePath,'package','openresty','pcre') + " --with-openssl=" + path.posix.join(sourcePath,'package','openresty','openssl') + " --add-module=" + path.posix.join(sourcePath,'package','openresty','fastdfs-nginx-module','src') + " --add-module=" + path.posix.join(sourcePath,'package','openresty','nginx-upload-module-2.2') + " && make -j " + coreNumber + " && make install",{
            cwd: openRestyPath,
            maxBuffer: 10240 * 10240
        },function(err,stdout,stderr){
            if(err){
                oarUI.fail("Installing Openresty");
                installScript.installLog (installPath,err);
                process.exit(1);
            }
            if(stdout){
                oarUI.succeed("Installing Openresty");
                installScript.installLog (installPath,stdout);
                return resolve();
            }
            if(stderr){
                oarUI.fail("Installing Openresty");
                installScript.installLog (installPath,stderr);
                process.exit(1);
            }
        });
    })
}

安装openresty

/**
 * 安装nodejs
 * @param {*} sourcePath  nodejs源码路径
 * @returns 
 */
installScript.InstallNodejs = (sourcePath) => {
    return new Promise((resolve,reject) => {
        let nodejsPath = path.posix.join(sourcePath,'package','nodejs');
        let nodejsBinPackagePath = path.posix.join(sourcePath,'package','bin','nodejs');
        let nodejsBinInstallPath = path.posix.join('/usr','local','yliyun','bin','node');
        let oarUI = ora("Installing Nodejs");
        oarUI.start();
        exec.spawnSync("cp",["-r",nodejsPath,"/usr/local/nodejs"]);
        exec.spawnSync("cp",[nodejsBinPackagePath,nodejsBinInstallPath]);
        exec.spawnSync("ln",["-s",path.posix.join('/usr','local','nodejs','bin','node'),path.posix.join('/usr','bin','node')]);
        exec.spawnSync("ln",["-s",path.posix.join('/usr','local','nodejs','bin','npm'),path.posix.join('/usr','bin','npm')]);
        exec.spawnSync("ln",["-s",path.posix.join('/usr','local','nodejs','bin','npx'),path.posix.join('/usr','bin','npx')]);

        if(fs.existsSync(path.posix.join('/usr','bin','node')) || 
            fs.existsSync(path.posix.join('/usr','bin','npm')) || 
            fs.existsSync(path.posix.join('/usr','bin','npx')) || 
            exec.execSync('node -v | grep -Eo "v8.8.1" | awk \'{printf $0}\'').toString() === "v8.8.1"
        ){
            oarUI.succeed("Installing Nodejs");
            return resolve();
        }else{
            oarUI.fail("Installing Nodejs");
            process.exit(1);
        }
    })
}

安装nodejs

 

/**
 * 安装mysql
 * @param {*} sourcePath  mysql源码路径
 * @returns 
 */
installScript.InstallMysql = (sourcePath,installPath,coreNumber) => {
    return new Promise((resolve,reject) => {
        let mysqlPackerPath = path.posix.join(sourcePath,'package','mysql');
        let mysqlInstallPath = path.posix.join('/usr','local','mysql');
        let mysqlServerPath = path.posix.join('/usr','local','mysql','support-files','mysql.server');
        let mysqlBinPath = path.posix.join('/usr','local','yliyun','bin','mysqld');
        let mysqlConfPackerPath = path.posix.join('/usr','local','mysql','my.cnf');
        let mysqlConfInstallPath = path.posix.join('/usr','local','yliyun','conf','mysql','my.cnf');
        let mysqlConfSystemInstallPath = path.posix.join('/etc','my.cnf');

        let oarUI = ora("Installing mysql");
        oarUI.start();
        //创建账户和组
        if(exec.execSync('cat /etc/passwd | grep -Eo "mysql" | wc -l').toString() == 0){
            exec.execSync('groupadd mysql && useradd -r -g mysql -s /sbin/nologin mysql').toString();
            if(exec.execSync('cat /etc/passwd | grep -Eo "mysql" | wc -l').toString() == 0){
                oarUI.fail("Installing mysql");
                installScript.installLog(installPath,"\nFailed to create mysql account and group");
                process.exit(1);
            } 
        }
        
        //拷贝二进制mysql到/usr/local
        exec.spawnSync("cp",["-r",mysqlPackerPath,mysqlInstallPath]);
        exec.spawnSync("mkdir",["-p",mysqlInstallPath]);
        //./mysql_install_db --user=mysql --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data --defaults-file=' + mysqlCnfPath + '
        exec.execSync('chown -R mysql.mysql ' + mysqlInstallPath);
        exec.exec('./scripts/mysql_install_db --user=mysql  --explicit_defaults_for_timestamp',{
            cwd: mysqlInstallPath,
            maxBuffer: 10240 * 10240
        },function(err,stdout,stderr){
            if(err){
                oarUI.fail("Installing mysql");
                installScript.installLog (installPath,err);
                process.exit(1);
            }
            if(stdout){
                installScript.installLog (installPath,stdout);
                //尝试启动
                exec.execSync("nohup " + mysqlServerPath + " start > /dev/null 2>&1 &").toString();
                setTimeout(() => {
                    let mysqlStatus = exec.execSync("ps -ef | grep mysql | grep -v grep | wc -l").toString();
                    if(mysqlStatus == 0){
                        oarUI.fail("Installing mysql");
                        process.exit(1);
                    }else{
                        oarUI.succeed("Installing mysql");
                        exec.spawnSync("rm",["-f",mysqlConfSystemInstallPath]);
                        exec.spawnSync("cp",["-r",mysqlConfPackerPath,mysqlConfInstallPath]);
                        exec.spawnSync("ln",["-s",mysqlConfInstallPath,mysqlConfSystemInstallPath]);
                        exec.spawnSync("ln",["-s",mysqlServerPath,mysqlBinPath]);
                        return resolve();
                    }
                },5000)
                return resolve();
            }
            if(stderr){
                oarUI.fail("Installing mysql");
                installScript.installLog (installPath,stderr);
                process.exit(1);
            }
        })
    })
}

安装mysql

 

/**
 * 初始化mysql
 * @param {*} sourcePath  mysql源码路径
 * @returns 
 */
installScript.InstallMysqlInitialize = (sourcePath,installPath) => {
    return new Promise((resolve,reject) => {
        let yliyunSqlPackerPath = path.posix.join(sourcePath,'package','yliyun.sql');
        let yliyunLogSqlPackerPath = path.posix.join(sourcePath,'package','yliyun_log.sql');
        let mysqlServerPath = path.posix.join('/usr','local','mysql','support-files','mysql.server');

        let oarUI = ora("Mysql initialize");
        oarUI.start();
        let connection = mysql.createConnection({
            host     : '127.0.0.1',
            user     : 'root',
            password : ''
        });

        connection.connect((error) => {
            if (error) {
                oarUI.fail("Mysql initialize");
                console.log(chalk.red("\nFailed to connect to database\n"));
                installScript.installLog (installPath,"\n" + error.message);
                process.exit(1);
            }else{
                //创建yliyun_log数据库
                connection.query('CREATE DATABASE `yliyun_log` CHARACTER SET utf8 COLLATE utf8_general_ci;', function (error, results, fields) {
                    if(error){
                        oarUI.fail("Mysql initialize");
                        console.log(chalk.red("\nFailed to create database yliyun_log\n"));
                        installScript.installLog (installPath,"\n" + error.message);
                        process.exit(1);
                    }
                    //创建yliyun数据库
                    connection.query('CREATE DATABASE `yliyun` CHARACTER SET utf8 COLLATE utf8_general_ci;', function (error, results, fields) {
                        if(error){
                            oarUI.fail("Mysql initialize");
                            console.log(chalk.red("\nFailed to create database yliyun\n"));
                            installScript.installLog (installPath,"\n" + error.message);
                            process.exit(1);
                        }
                        //更换密码
                        connection.query('update mysql.user set password=password("*****") where user="root";', function (error, results, fields) {
                            if(error){
                                oarUI.fail("Mysql initialize");
                                console.log(chalk.red("\nFailed to reset database password\n"));
                                installScript.installLog (installPath,"\n" + error.message);
                                process.exit(1);
                            }
                            //权限生效
                            connection.query("flush privileges;", function (error, results, fields) {
                                if(error){
                                    oarUI.fail("Mysql initialize");
                                    console.log(chalk.red("\nFailed to update permissions\n"));
                                    installScript.installLog (installPath,"\n" + error.message);
                                    process.exit(1);
                                }
                                exec.execSync("sed -i '3 i[mysql]\\nuser=root\\npassword=yliyun123@' /etc/my.cnf");
                                connection.end((error) => {
                                    if(error){
                                        oarUI.fail("Mysql initialize");
                                        installScript.installLog (installPath,"\n" + error.message);
                                        process.exit(1);
                                    }
                                    exec.execSync("nohup " + mysqlServerPath + " restart > /dev/null 2>&1 &");
                                    setTimeout(() => {
                                        exec.execSync("nohup /usr/local/mysql/bin/mysql yliyun < " + yliyunSqlPackerPath + " > /dev/null 2>&1 &");
                                        exec.execSync("nohup /usr/local/mysql/bin/mysql yliyun_log < " + yliyunLogSqlPackerPath + " > /dev/null 2>&1 &");
                                        setTimeout(() => {
                                            let yliyunConnection = mysql.createConnection({
                                                host     : '127.0.0.1',
                                                user     : 'root',
                                                password : '****',
                                                database: 'yliyun'
                                            });
                                            let yliyunLogConnection = mysql.createConnection({
                                                host     : '127.0.0.1',
                                                user     : 'root',
                                                password : '****',
                                                database: 'yliyun_log'
                                            });
                                            yliyunConnection.connect((error) => {
                                                if(error){
                                                    oarUI.fail("Mysql initialize");
                                                    console.log(chalk.red("\nFailed to connect to database\n"));
                                                    installScript.installLog (installPath,"\n" + error.message);
                                                    process.exit(1);
                                                }else{
                                                    yliyunConnection.query('show tables;', function (error, results, fields) {
                                                        if(error){
                                                            oarUI.fail("Mysql initialize");
                                                            console.log(chalk.red("\nFailed to import data successfully\n"));
                                                            installScript.installLog (installPath,"\n" + error.message);
                                                            process.exit(1);
                                                        }
                                                        yliyunLogConnection.connect((error) => {
                                                            if(error){
                                                                oarUI.fail("Mysql initialize");
                                                                console.log(chalk.red("\nFailed to connect to database\n"));
                                                                installScript.installLog (installPath,"\n" + error.message);
                                                                process.exit(1);
                                                            }else{
                                                                yliyunLogConnection.query('show tables;', function (error, results, fields) {
                                                                    if(error){
                                                                        oarUI.fail("Mysql initialize");
                                                                        console.log(chalk.red("\nFailed to import data successfully\n"));
                                                                        installScript.installLog (installPath,"\n" + error.message);
                                                                        process.exit(1);
                                                                    }
                                                                    oarUI.succeed("Mysql initialize");
                                                                    return resolve();
                                                                })
                                                            }
                                                        })
                                                    })
                                                }
                                            })
                                        },5000)
                                    },10000)
                                })
                            });
                        });
                    });
                });
            }
        });
    })
}

初始化mysql

/**
 * 创建基础目录结构
 * @returns 
 */
installScript.InstallCreateYliyun = () => {
    return new Promise((resolve,reject) => {
        let oarUI = ora("Create a yliyun directory structure");
        oarUI.start();

        let bin = path.posix.join('/usr','local','yliyun','bin');
        let conf = path.posix.join('/usr','local','yliyun','conf');
        let logs = path.posix.join('/usr','local','yliyun','logs');
        let temp = path.posix.join('/usr','local','yliyun','temp');
        let data = path.posix.join('/usr','local','yliyun','data');
        let redisLogs = path.posix.join('/usr','local','yliyun','logs','redis');
        let redisData = path.posix.join('/usr','local','yliyun','data','redis');
        let redisConf = path.posix.join('/usr','local','yliyun','conf','redis');
        let nginxConf = path.posix.join('/usr','local','yliyun','conf','nginx');
        let nginxUpload = path.posix.join('/usr','local','yliyun','temp','upload');
        let nginxLogs = path.posix.join('/usr','local','yliyun','logs','nginx');
        let nodejsLogs = path.posix.join('/usr','local','yliyun','logs','node');

        let fdfsLogs = path.posix.join('/usr','local','yliyun','logs','fdfs');
        let fdfsConf = path.posix.join('/usr','local','yliyun','conf','fdfs');
        let fdfsTrackerData = path.posix.join('/usr','local','yliyun','data','fdfs','tracker');
        let fdfsStorageData = path.posix.join('/usr','local','yliyun','data','fdfs','storage');

        let mysqlLogs = path.posix.join('/usr','local','yliyun','logs','mysql');
        let mysqlConf = path.posix.join('/usr','local','yliyun','conf','mysql');
        let mysqlData = path.posix.join('/usr','local','yliyun','data','mysql');

        exec.spawnSync("mkdir",["-p",bin]);
        exec.spawnSync("mkdir",["-p",conf]);
        exec.spawnSync("mkdir",["-p",logs]);
        exec.spawnSync("mkdir",["-p",temp]);
        exec.spawnSync("mkdir",["-p",data]);
        exec.spawnSync("mkdir",["-p",redisLogs]);
        exec.spawnSync("mkdir",["-p",redisData]);
        exec.spawnSync("mkdir",["-p",nodejsLogs]);
        exec.spawnSync("mkdir",["-p",fdfsLogs]);
        exec.spawnSync("mkdir",["-p",nginxLogs]);
        exec.spawnSync("mkdir",["-p",redisConf]);
        exec.spawnSync("mkdir",["-p",fdfsConf]);
        exec.spawnSync("mkdir",["-p",nginxConf]);
        exec.spawnSync("mkdir",["-p",nginxUpload]);
        exec.spawnSync("mkdir",["-p",fdfsTrackerData]);
        exec.spawnSync("mkdir",["-p",fdfsStorageData]);

        exec.spawnSync("mkdir",["-p",mysqlLogs]);
        exec.spawnSync("mkdir",["-p",mysqlConf]);
        exec.spawnSync("mkdir",["-p",mysqlData]);

        if(
            fs.existsSync(data) ||
            fs.existsSync(temp) ||
            fs.existsSync(logs) ||
            fs.existsSync(conf) ||
            fs.existsSync(bin)  ||
            fs.existsSync(redisLogs) ||
            fs.existsSync(redisData)
        ){
            oarUI.succeed("Create a yliyun directory structure");
            return resolve();
        }else{
            oarUI.fail("Create a yliyun directory structure");
            process.exit(1);
        }
    })
}

创建基础目录结构

 

/**
 * 安装工作目录
 * @param {*} sourcePath  工作目录路径
 * @returns 
 */
installScript.InstallWork = (sourcePath) => {
    return new Promise((resolve,reject) => {
        let workPackagePath = path.posix.join(sourcePath,'package','work');
        let workInstallPath = path.posix.join('/usr','local','yliyun');

        let licPackagePath = path.posix.join(sourcePath,'package','yliyun.lic');
        let licInstallPath = path.posix.join('/usr','local','yliyun');

        let oarUI = ora("Installing work");
        oarUI.start();
        exec.spawnSync("mkdir",["-p",workInstallPath]);
        exec.spawnSync("cp",["-R",workPackagePath,workInstallPath]);
        exec.spawnSync("cp",["-R",licPackagePath,licInstallPath]);

        let work = fs.existsSync(path.posix.join(workInstallPath,'work'));
        if(work){
            oarUI.succeed("Installing work");
            return resolve();
        }else{
            oarUI.fail("Installing work");
            process.exit(1);
        }
    })
}

安装工作目录

 

/**
 * 安装pm2
 * @returns 
 */
installScript.InstallPm2 = () => {
    return new Promise((resolve,reject) => {
        let pm2Path = path.posix.join('/usr','local','yliyun','work','node','node_modules','pm2','bin','pm2');
        let pm2DevPath = path.posix.join('/usr','local','yliyun','work','node','node_modules','pm2','bin','pm2-dev');
        let pm2DockerPath = path.posix.join('/usr','local','yliyun','work','node','node_modules','pm2','bin','pm2-docker');
        let pm2RuntimePath = path.posix.join('/usr','local','yliyun','work','node','node_modules','pm2','bin','pm2-runtime');

        let oarUI = ora("Installing pm2");
        oarUI.start();
        exec.spawnSync("ln",["-s",pm2Path,path.posix.join('/usr','bin','pm2')]);
        exec.spawnSync("ln",["-s",pm2DevPath,path.posix.join('/usr','bin','pm2-dev')]);
        exec.spawnSync("ln",["-s",pm2DockerPath,path.posix.join('/usr','bin','pm2-docker')]);
        exec.spawnSync("ln",["-s",pm2RuntimePath,path.posix.join('/usr','bin','pm2-runtime')]);

        exec.spawnSync("ln",["-s",pm2Path,path.posix.join('/usr','local','yliyun','bin','pm2')]);
        exec.spawnSync("ln",["-s",pm2DevPath,path.posix.join('/usr','local','yliyun','bin','pm2-dev')]);
        exec.spawnSync("ln",["-s",pm2DockerPath,path.posix.join('/usr','local','yliyun','bin','pm2-docker')]);
        exec.spawnSync("ln",["-s",pm2RuntimePath,path.posix.join('/usr','local','yliyun','bin','pm2-runtime')]);

        let pm2 = fs.existsSync(path.posix.join('/usr','bin','pm2'));
        let pm2Dev = fs.existsSync(path.posix.join('/usr','bin','pm2-dev'));
        let pm2Docker = fs.existsSync(path.posix.join('/usr','bin','pm2-docker'));
        let pm2Runtime = fs.existsSync(path.posix.join('/usr','bin','pm2-runtime'));

        if(pm2 || pm2Dev || pm2Docker || pm2Runtime){
            oarUI.succeed("Installing pm2");
            return resolve();
        }else{
            oarUI.fail("Installing pm2");
            process.exit(1);
        }
    })
}

安装pm2

 

/**
 * 安装common
 * @param {*} sourcePath  工作目录路径
 * @returns 
 */
installScript.InstallCommon = (sourcePath) => {
    return new Promise((resolve,reject) => {
        let commonPackagePath = path.posix.join(sourcePath,'package','common');
        let commonInstallPath = path.posix.join('/usr','local','yliyun');

        let oarUI = ora("Installing common");
        oarUI.start();
        exec.spawnSync("cp",["-R",commonPackagePath,commonInstallPath]);

        let common = fs.existsSync(path.posix.join(commonInstallPath,'common'));
        if(common){
            oarUI.succeed("Installing common");
            return resolve();
        }else{
            oarUI.fail("Installing common");
            process.exit(1);
        }
    })
}

安装common

 

/**
 * 安装plugins
 * @param {*} sourcePath  工作目录路径
 * @returns 
 */
installScript.InstallPlugins = (sourcePath) => {
    return new Promise((resolve,reject) => {
        let pluginsPackagePath = path.posix.join(sourcePath,'package','plugins');
        let pluginsInstallPath = path.posix.join('/usr','local','yliyun');

        let oarUI = ora("Installing plugins");
        oarUI.start();
        exec.spawnSync("cp",["-R",pluginsPackagePath,pluginsInstallPath]);

        let plugins = fs.existsSync(path.posix.join(pluginsInstallPath,'plugins'));
        if(plugins){
            oarUI.succeed("Installing plugins");
            return resolve();
        }else{
            oarUI.fail("Installing plugins");
            process.exit(1);
        }
    })
}

安装plugins

 

/**
 * 迁移openresty配置文件
 * @returns 
 */
installScript.configOpenrestyMove = (sourcePath,coreNumber) => {
    return new Promise((resolve,reject) => {
        let myOpenrestyPath = path.posix.join('/usr','local','yliyun','conf','nginx');
        let openrestyPath = path.posix.join('/usr','local','yliyun','work','lua','nginx');
        let openrestyInstallPath = path.posix.join('/usr','local','openresty','nginx','conf');
        let openrestyPackageBin = path.posix.join(sourcePath,'package','bin','nginx');
        let openrestyInstallBin = path.posix.join('/usr','local','yliyun','bin','nginx');
       
        let oarUI = ora("Create openresty configuration");
        oarUI.start();

        //创建配置文件更改路径
        exec.spawnSync("cp",[openrestyPackageBin,openrestyInstallBin]);
        //分配合适的
        exec.execSync("sed -i 's/AAAAAAAAAA/" + coreNumber + "/g' " + path.posix.join(openrestyPath,'nginx.conf'));
        //删除openresty默认配置文件
        exec.spawnSync("rm",["-rf",'nginx.conf'],{
            cwd: openrestyInstallPath
        });
        //建立软链接
        exec.spawnSync("ln",["-s",path.posix.join(openrestyPath,"nginx.conf"),path.posix.join(openrestyInstallPath,"nginx.conf")]);
        exec.spawnSync("ln",["-s",path.posix.join(openrestyPath,"nginx.conf"),path.posix.join(myOpenrestyPath,"nginx.conf")]);

        if(fs.existsSync(openrestyInstallBin) || 
        fs.existsSync(path.posix.join(openrestyPath,'nginx.conf')) ||
        fs.existsSync(path.posix.join(myOpenrestyPath,'nginx.conf')) ||
        fs.existsSync(path.posix.join(openrestyInstallPath,'nginx.conf'))){
            oarUI.succeed("Create openresty configuration");
            return resolve();
        }else{
            oarUI.fail("Create openresty configuration");
            process.exit(1);
        }
    })
}

迁移openresty配置文件

 

/**
 * 迁移启动文件
 * @returns 
 */
installScript.yliyunBinMove = (sourcePath) => {
    return new Promise((resolve,reject) => {

        let yliyunPackageBin = path.posix.join(sourcePath,'package','bin','yliyun');
        let yliyunInstallBin = path.posix.join('/usr','local','yliyun','bin','yliyun');
        let yliyunSystemBin = path.posix.join('/usr','bin','yliyun');
       
        let oarUI = ora("Create startup file");
        oarUI.start();

        //创建配置文件更改路径
        exec.spawnSync("cp",[yliyunPackageBin,yliyunInstallBin]);
        exec.spawnSync("ln",["-s",yliyunInstallBin,yliyunSystemBin]);

        if(fs.existsSync(yliyunInstallBin)){
            oarUI.succeed("Create startup file");
            return resolve();
        }else{
            oarUI.fail("Create startup file");
            process.exit(1);
        }
    })
}

迁移启动文件

 

/**
 * 迁移fastDfs配置文件
 * @returns 
 */
installScript.configFastDFSMove = (sourcePath,serverIp,coreNumber) => {
    return new Promise((resolve,reject) => {

        let oarUI = ora("Create FastDFS configuration");
        oarUI.start();
        let fastDFSConfigPackagePath = path.posix.join(sourcePath,'package','conf','fdfs');
        let fastDFSPath = path.posix.join('/usr','local','yliyun','conf','fdfs');
        let fastDFSSystemConfPath = path.posix.join('/etc','fdfs');

        //exec.spawnSync("rm",["-rf",fastDFSSystemPath]);
        exec.spawnSync("mkdir",["-p","/usr/local/yliyun/data/fdfs"]);
        //exec.spawnSync("mkdir",["-p",fastDFSSystemPath]);
        exec.spawnSync("mkdir",["-p","/yliyun_data_01"]);
        exec.spawnSync("mkdir",["-p","/yliyun_data_02"]);
        exec.spawnSync("mkdir",["-p","/yliyun_data_03"]);
        exec.spawnSync("mkdir",["-p","/yliyun_data_04"]);
        exec.spawnSync("cp",["-R",fastDFSConfigPackagePath,path.posix.join("/usr","local","yliyun","conf")]);
        exec.spawnSync("rm",["-rf",fastDFSSystemConfPath,fastDFSSystemConfPath]);
        exec.spawnSync("ln",["-s",fastDFSPath,fastDFSSystemConfPath]);
        exec.execSync("sed -i 's/AAAAAAAAAA/" + serverIp + "/g' " + path.posix.join(fastDFSPath,'storage.conf'));
        exec.execSync("sed -i 's/BBBBBBBBBB/" + coreNumber + "/g' " + path.posix.join(fastDFSPath,'storage.conf'));
        exec.execSync("sed -i 's/BBBBBBBBBB/" + coreNumber + "/g' " + path.posix.join(fastDFSPath,'tracker.conf'));
        exec.execSync("sed -i 's/AAAAAAAAAA/" + serverIp + "/g' " + path.posix.join(fastDFSPath,'client.conf'));
        
        exec.execSync("sed -i 's/AAAAAAAAAA/" + serverIp + "/g' " + path.posix.join(fastDFSPath,'mod_fastdfs.conf'));

        setTimeout(() => {
            if(fs.existsSync(fastDFSPath)){
                oarUI.succeed("Create FastDFS configuration");
                return resolve();
            }else{
                oarUI.fail("Create FastDFS configuration");
                process.exit(1);
            }
        },3000)

    })
}

迁移fastDfs配置文件

module.exports = installScript;

最后暴露安装程序给index.js

 

//安装执行程序
async function InstallStart(){
    await install.gccStauts(INSTALL_PATH);
    await install.gccgccStauts(INSTALL_PATH);
    await install.makeStauts(INSTALL_PATH);
    await install.cmakeStauts(INSTALL_PATH);
    await install.autoConfStauts(INSTALL_PATH);
    await install.libaioStauts(INSTALL_PATH);
    await install.libnumaStauts(INSTALL_PATH);
    await install.libncurses5Stauts(INSTALL_PATH);
    await install.libtinfo5Stauts(INSTALL_PATH);
    await install.tarStauts(INSTALL_PATH);
    await install.tclStauts(INSTALL_PATH);
    await install.ReleasePackage(INSTALL_PACKAGE_PATH,INSTALL_PATH,INSTALL_PATH);
    await install.InstallCreateYliyun();
    await install.InstallWork(INSTALL_PATH);
    await install.InstallZlib(INSTALL_PATH,INSTALL_PATH,SERVER_CORE_NUMBER);
    await install.InstallLibFastCommon(INSTALL_PATH,INSTALL_PATH);
    await install.InstallFastdfs(INSTALL_PATH,INSTALL_PATH);
    await install.configFastDFSMove(INSTALL_PATH,SERVER_IP,SERVER_CORE_NUMBER );
    await install.InstallRedis(INSTALL_PATH,INSTALL_PATH,SERVER_CORE_NUMBER);
    await install.InstallOpenResty(INSTALL_PATH,INSTALL_PATH,SERVER_CORE_NUMBER);
    await install.configOpenrestyMove(INSTALL_PATH,SERVER_CORE_NUMBER);
    await install.InstallNodejs(INSTALL_PATH);
    await install.InstallMysql(INSTALL_PATH,INSTALL_PATH,SERVER_CORE_NUMBER);
    await install.InstallPm2();
    await install.InstallCommon(INSTALL_PATH);
    await install.InstallPlugins(INSTALL_PATH);
    await install.InstallMysqlInitialize(INSTALL_PATH,INSTALL_PATH);
    await install.yliyunBinMove(INSTALL_PATH);
    console.log("\n");
    console.log("Installation completed");
    console.log("yliyun {start|stop}");
    process.exit(1);
}

有了上面的安装和校验代码后,就可以回到index.js按照安装逻辑编写安装过程。

最后保存即可。