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按照安装逻辑编写安装过程。
最后保存即可。